Appendix B: WebGPU API Reference
Initialization#
if (!navigator.gpu) { }
const adapter = await navigator.gpu.requestAdapter({
powerPreference: 'high-performance',
});
const device = await adapter.requestDevice({
requiredFeatures: [],
requiredLimits: {},
});
Canvas Configuration#
const context = canvas.getContext('webgpu') as GPUCanvasContext;
context.configure({
device,
format: 'bgra8unorm',
alphaMode: 'opaque',
});
context.configure({
device,
format: 'rgba16float',
alphaMode: 'opaque',
colorSpace: 'display-p3',
toneMapping: { mode: 'extended' },
});
Buffer#
const buffer = device.createBuffer({
size: 256,
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
label: 'MyBuffer',
});
device.queue.writeBuffer(buffer, 0, data, byteOffset, byteLength);
await buffer.mapAsync(GPUMapMode.READ);
const data = buffer.getMappedRange();
buffer.unmap();
buffer.destroy();
Texture#
const texture = device.createTexture({
size: { width: 1024, height: 1024 },
format: 'rgba8unorm',
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT,
mipLevelCount: 1,
sampleCount: 1,
label: 'MyTexture',
});
const cubeTexture = device.createTexture({
size: { width: 512, height: 512, depthOrArrayLayers: 6 },
format: 'rgba16float',
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST,
});
const depthTexture = device.createTexture({
size: { width, height },
format: 'depth32float',
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,
});
const view = texture.createView();
const arrayView = texture.createView({ dimension: '2d-array' });
const cubeView = cubeTexture.createView({ dimension: 'cube' });
device.queue.copyExternalImageToTexture(
{ source: imageBitmap },
{ texture, premultipliedAlpha: false },
{ width, height },
);
texture.destroy();
Sampler#
const sampler = device.createSampler({
addressModeU: 'repeat',
addressModeV: 'repeat',
addressModeW: 'clamp-to-edge',
magFilter: 'linear',
minFilter: 'linear',
mipmapFilter: 'linear',
lodMinClamp: 0,
lodMaxClamp: 32,
maxAnisotropy: 1,
compare: undefined,
});
Bind Group / Layout#
const layout = device.createBindGroupLayout({
entries: [{
binding: 0,
visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
buffer: { type: 'uniform' },
}, {
binding: 1,
visibility: GPUShaderStage.FRAGMENT,
texture: { sampleType: 'float' },
}, {
binding: 2,
visibility: GPUShaderStage.FRAGMENT,
sampler: { type: 'filtering' },
}],
});
const pipelineLayout = device.createPipelineLayout({
bindGroupLayouts: [layout0, layout1, layout2],
});
const bindGroup = device.createBindGroup({
layout,
entries: [
{ binding: 0, resource: { buffer, offset: 0, size: 256 } },
{ binding: 1, resource: textureView },
{ binding: 2, resource: sampler },
],
});
Render Pipeline#
const pipeline = device.createRenderPipeline({
layout: pipelineLayout,
vertex: {
module: shaderModule,
entryPoint: 'vs_main',
buffers: [{
arrayStride: 48,
attributes: [
{ shaderLocation: 0, offset: 0, format: 'float32x3' },
{ shaderLocation: 1, offset: 12, format: 'float32x3' },
{ shaderLocation: 2, offset: 24, format: 'float32x2' },
{ shaderLocation: 3, offset: 32, format: 'float32x4' },
],
}],
},
fragment: {
module: shaderModule,
entryPoint: 'fs_main',
targets: [
{ format: 'rgba8unorm', blend: { } },
{ format: 'rgba16float' },
],
},
depthStencil: {
format: 'depth32float',
depthWriteEnabled: true,
depthCompare: 'less',
depthBias: 0,
depthBiasSlopeScale: 0,
depthBiasClamp: 0,
},
primitive: {
topology: 'triangle-list',
stripIndexFormat: undefined,
frontFace: 'ccw',
cullMode: 'back',
},
multisample: {
count: 1,
mask: 0xFFFFFFFF,
alphaToCoverageEnabled: false,
},
});
Compute Pipeline#
const computePipeline = device.createComputePipeline({
layout: pipelineLayout,
compute: {
module: shaderModule,
entryPoint: 'cs_main',
},
});
Command Encoding#
const encoder = device.createCommandEncoder();
const pass = encoder.beginRenderPass({
colorAttachments: [{
view: colorTextureView,
clearValue: [0, 0, 0, 0],
loadOp: 'clear',
storeOp: 'store',
}],
depthStencilAttachment: {
view: depthTextureView,
depthClearValue: 1.0,
depthLoadOp: 'clear',
depthStoreOp: 'store',
},
});
pass.setPipeline(renderPipeline);
pass.setBindGroup(0, bindGroup);
pass.setVertexBuffer(0, vertexBuffer);
pass.setIndexBuffer(indexBuffer, 'uint32');
pass.drawIndexed(indexCount, instanceCount, firstIndex, baseVertex, firstInstance);
pass.draw(vertexCount, instanceCount, firstVertex, firstInstance);
pass.end();
const computePass = encoder.beginComputePass();
computePass.setPipeline(computePipeline);
computePass.setBindGroup(0, bindGroup);
computePass.dispatchWorkgroups(x, y, z);
computePass.end();
encoder.copyBufferToBuffer(src, srcOffset, dst, dstOffset, size);
encoder.copyBufferToTexture(src, dst, copySize);
encoder.copyTextureToBuffer(src, dst, copySize);
const commandBuffer = encoder.finish();
device.queue.submit([commandBuffer]);
Error Scopes#
device.pushErrorScope('validation');
const error = await device.popErrorScope();
if (error) console.error(error.message);
Limits#
const limits = device.limits;