Created
December 23, 2019 11:20
-
-
Save hjlld/d2c6037981cac9db64feb4c4fd1811b2 to your computer and use it in GitHub Desktop.
Create a triangle with WebGPU
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import glslangModule from 'https://unpkg.com/@webgpu/[email protected]/dist/web-devel/glslang.js'; | |
import vertexShaderCode from '/shader/vertex.glsl.js'; | |
import fragmentShaderCode from '/shader/fragment.glsl.js'; | |
const VERTICES = new Float32Array( [ 0, 0.5, 0, -0.5, -0.5, 0, 0.5, -0.5, 0 ] ); | |
const INDICES = new Uint16Array( [ 0, 1, 2 ] ); | |
let main = async () => { | |
let adapter = await navigator.gpu.requestAdapter(); | |
let glslang = await glslangModule(); | |
let device = await adapter.requestDevice(); | |
let canvas = document.getElementById( 'renderCanvas' ); | |
canvas.width = canvas.clientWidth; | |
canvas.height = canvas.clientHeight; | |
let context = canvas.getContext( 'gpupresent' ); | |
let swapChain = context.configureSwapChain( { | |
device, format: 'bgra8unorm' | |
} ); | |
let colorTexture = device.createTexture( { | |
size: { | |
width: canvas.clientWidth * window.devicePixelRatio, | |
height: canvas.clientHeight * window.devicePixelRatio, | |
depth: 1 | |
}, | |
sampleCount: 4, | |
format: 'bgra8unorm', | |
usage: GPUTextureUsage.OUTPUT_ATTACHMENT | |
} ); | |
let colorAttachment = colorTexture.createView(); | |
let depthStencilTexture = device.createTexture( { | |
size: { | |
width: canvas.clientWidth * window.devicePixelRatio, | |
height: canvas.clientHeight * window.devicePixelRatio, | |
depth: 1 | |
}, | |
sampleCount: 4, | |
format: 'depth24plus-stencil8', | |
usage: GPUTextureUsage.OUTPUT_ATTACHMENT | |
} ); | |
let depthStencilAttachment = depthStencilTexture.createView(); | |
let commandEncoder = device.createCommandEncoder( {} ); | |
let renderPassDescriptor = { | |
colorAttachments: [ { | |
attachment: colorAttachment, | |
resolveTarget: swapChain.getCurrentTexture().createView(), | |
loadValue: { r: 1.0, g: 1.0, b: 1.0, a: 1.0 } | |
} ], | |
depthStencilAttachment: { | |
attachment: depthStencilAttachment, | |
depthLoadValue: 1.0, | |
depthStoreOp: 'store', | |
stencilLoadValue: 0, | |
stencilStoreOp: 'store' | |
} | |
}; | |
let uniformGroupLayout = device.createBindGroupLayout( { | |
bindings: [ | |
{ | |
binding: 0, | |
visibility: GPUShaderStage.VERTEX, | |
type: 'uniform-buffer' | |
}, | |
{ | |
binding: 1, | |
visibility: GPUShaderStage.FRAGMENT, | |
type: 'uniform-buffer' | |
} | |
] | |
} ); | |
let WebGPUPipeline = device.createRenderPipeline( { | |
layout: device.createPipelineLayout( { | |
bindGroupLayouts: [ ] | |
// bindGroupLayouts: [ uniformGroupLayout ] | |
} ), | |
vertexStage: { | |
module: device.createShaderModule( { | |
code: glslang.compileGLSL( vertexShaderCode, 'vertex' ), | |
source: vertexShaderCode, | |
transform: source => glslang.compileGLSL( source, 'vertex' ) | |
} ), | |
entryPoint: 'main' | |
}, | |
fragmentStage: { | |
module: device.createShaderModule( { | |
code: glslang.compileGLSL( fragmentShaderCode, 'fragment' ), | |
source: fragmentShaderCode, | |
transform: source => glslang.compileGLSL( source, 'fragment' ) | |
} ), | |
entryPoint: 'main' | |
}, | |
primitiveTopology: 'triangle-list', | |
depthStencilState: { | |
depthWriteEnabled: true, | |
depthCompare: 'less', | |
format: 'depth24plus-stencil8' | |
}, | |
vertexState: { | |
indexFormat: 'uint16', | |
vertexBuffers: [ { | |
arrayStride: 4 * 3, | |
attributes: [ | |
// position | |
{ | |
shaderLocation: 0, | |
offset: 0, | |
format: 'float3' | |
} | |
] | |
} ] | |
}, | |
colorStates: [ | |
{ | |
format: 'bgra8unorm', | |
colorBind: { | |
srcFactor: 'src-alpha', | |
dstFactor: 'one-minus-src-alpha', | |
operation: 'add' | |
} | |
} | |
], | |
sampleCount: 4 | |
} ); | |
let passEncoder = commandEncoder.beginRenderPass( renderPassDescriptor ); | |
passEncoder.setPipeline( WebGPUPipeline ); | |
let verticesBuffer = device.createBuffer( { | |
size: VERTICES.length * 4, | |
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST | |
} ); | |
verticesBuffer.setSubData( 0, VERTICES ); | |
let indicesBuffer = device.createBuffer( { | |
size: INDICES.length * 4, | |
usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST | |
} ); | |
let indicesData = new Uint16Array( INDICES.length + ( ( INDICES.length % 2 ) === 1 ? 1 : 0 ) ); | |
for ( let i = 0; i < INDICES.length; i++ ) { | |
indicesData[ i ] = INDICES[ i ]; | |
} | |
indicesBuffer.setSubData( 0, indicesData ); | |
passEncoder.setVertexBuffer( 0, verticesBuffer ); | |
passEncoder.setIndexBuffer( indicesBuffer ); | |
passEncoder.drawIndexed( INDICES.length, 1, 0, 0, 0 ); | |
passEncoder.endPass(); | |
device.defaultQueue.submit( [ commandEncoder.finish() ] ); | |
} | |
window.addEventListener( 'DOMContentLoaded', main ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment