Skip to content

Instantly share code, notes, and snippets.

@hjlld
Created December 23, 2019 11:20
Show Gist options
  • Save hjlld/d2c6037981cac9db64feb4c4fd1811b2 to your computer and use it in GitHub Desktop.
Save hjlld/d2c6037981cac9db64feb4c4fd1811b2 to your computer and use it in GitHub Desktop.
Create a triangle with WebGPU
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