WebGPU
WebGPU is a web API for GPU computation and graphics rendering. It provides low-level access to a GPU similar to modern graphics APIs like Vulkan, Metal, and DirectX 12. It uses WGSL (WebGPU Shading Language) as its shading language.
It offers better performance and more advanced GPU features than WebGL.
Code Example
<!DOCTYPE html> <html> <head> <title>WebGPU Triangle</title> <style> canvas {width: 100%; height: 400px; background-color: #000;} </style> </head> <body> <canvas id="canvas"></canvas> <div id="status">Checking WebGPU...</div> <script type="module"> async function init() { // 1. Check if WebGPU is supported if (!navigator.gpu) { document.getElementById("status").textContent = "WebGPU not supported!"; return; } // 2. Get the GPU adapter const adapter = await navigator.gpu.requestAdapter(); if (!adapter) { document.getElementById("status").textContent = "Couldn't request WebGPU adapter!"; return; } // 3. Create the device const device = await adapter.requestDevice(); if (!device) { document.getElementById("status").textContent = "Couldn't request WebGPU device!"; return; } // 4. Configure canvas const canvas = document.getElementById("canvas"); const context = canvas.getContext("webgpu"); const canvasFormat = navigator.gpu.getPreferredCanvasFormat(); const devicePixelRatio = window.devicePixelRatio || 1; canvas.width = canvas.clientWidth * devicePixelRatio; canvas.height = canvas.clientHeight * devicePixelRatio; context.configure({ device: device, format: canvasFormat, alphaMode: "premultiplied" }); // 5. Create the vertex buffer (triangle vertices) const vertices = new Float32Array([ 0.0, 0.5, 0.0, // top -0.5, -0.5, 0.0, // bottom left 0.5, -0.5, 0.0 // bottom right ]); const vertexBuffer = device.createBuffer({ label: "Triangle vertices", size: vertices.byteLength, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST, }); device.queue.writeBuffer(vertexBuffer, 0, vertices); // 6. Define vertex layout const vertexLayout = { arrayStride: 12, // 3 floats, 4 bytes each attributes: [{ format: "float32x3", offset: 0, shaderLocation: 0 // position }] }; // 7. Create the shader module const shaderModule = device.createShaderModule({ label: "Triangle shader", code: ` @vertex fn vertexMain(@location(0) position: vec3f) -> @builtin(position) vec4f { return vec4f(position, 1.0); } @fragment fn fragmentMain() -> @location(0) vec4f { return vec4f(1.0, 0.5, 0.2, 1.0); // Orange color } ` }); // 8. Create render pipeline const pipeline = device.createRenderPipeline({ label: "Triangle render pipeline", layout: "auto", vertex: { module: shaderModule, entryPoint: "vertexMain", buffers: [vertexLayout] }, fragment: { module: shaderModule, entryPoint: "fragmentMain", targets: [{ format: canvasFormat }] } }); // 9. Draw function function draw() { // Create command encoder const commandEncoder = device.createCommandEncoder(); // Create render pass const renderPassDescriptor = { colorAttachments: [{ view: context.getCurrentTexture().createView(), loadOp: "clear", storeOp: "store", clearValue: { r: 0.1, g: 0.1, b: 0.1, a: 1.0 } }] }; const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor); passEncoder.setPipeline(pipeline); passEncoder.setVertexBuffer(0, vertexBuffer); passEncoder.draw(3); // Draw 3 vertices passEncoder.end(); // Submit the commands device.queue.submit([commandEncoder.finish()]); } // Initial draw and set up resize handling draw(); window.addEventListener("resize", () => { canvas.width = canvas.clientWidth * devicePixelRatio; canvas.height = canvas.clientHeight * devicePixelRatio; draw(); }); document.getElementById("status").textContent = "WebGPU triangle rendered successfully!"; } init(); </script> </body> </html>
cat << 'EOF' > "index.html" <!DOCTYPE html> <html> <head> <title>WebGPU Triangle</title> <style> canvas {width: 100%; height: 400px; background-color: #000;} </style> </head> <body> <canvas id="canvas"></canvas> <div id="status">Checking WebGPU...</div> <script type="module"> async function init() { // 1. Check if WebGPU is supported if (!navigator.gpu) { document.getElementById("status").textContent = "WebGPU not supported!"; return; } // 2. Get the GPU adapter const adapter = await navigator.gpu.requestAdapter(); if (!adapter) { document.getElementById("status").textContent = "Couldn't request WebGPU adapter!"; return; } // 3. Create the device const device = await adapter.requestDevice(); if (!device) { document.getElementById("status").textContent = "Couldn't request WebGPU device!"; return; } // 4. Configure canvas const canvas = document.getElementById("canvas"); const context = canvas.getContext("webgpu"); const canvasFormat = navigator.gpu.getPreferredCanvasFormat(); const devicePixelRatio = window.devicePixelRatio || 1; canvas.width = canvas.clientWidth * devicePixelRatio; canvas.height = canvas.clientHeight * devicePixelRatio; context.configure({ device: device, format: canvasFormat, alphaMode: "premultiplied" }); // 5. Create the vertex buffer (triangle vertices) const vertices = new Float32Array([ 0.0, 0.5, 0.0, // top -0.5, -0.5, 0.0, // bottom left 0.5, -0.5, 0.0 // bottom right ]); const vertexBuffer = device.createBuffer({ label: "Triangle vertices", size: vertices.byteLength, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST, }); device.queue.writeBuffer(vertexBuffer, 0, vertices); // 6. Define vertex layout const vertexLayout = { arrayStride: 12, // 3 floats, 4 bytes each attributes: [{ format: "float32x3", offset: 0, shaderLocation: 0 // position }] }; // 7. Create the shader module const shaderModule = device.createShaderModule({ label: "Triangle shader", code: ` @vertex fn vertexMain(@location(0) position: vec3f) -> @builtin(position) vec4f { return vec4f(position, 1.0); } @fragment fn fragmentMain() -> @location(0) vec4f { return vec4f(1.0, 0.5, 0.2, 1.0); // Orange color } ` }); // 8. Create render pipeline const pipeline = device.createRenderPipeline({ label: "Triangle render pipeline", layout: "auto", vertex: { module: shaderModule, entryPoint: "vertexMain", buffers: [vertexLayout] }, fragment: { module: shaderModule, entryPoint: "fragmentMain", targets: [{ format: canvasFormat }] } }); // 9. Draw function function draw() { // Create command encoder const commandEncoder = device.createCommandEncoder(); // Create render pass const renderPassDescriptor = { colorAttachments: [{ view: context.getCurrentTexture().createView(), loadOp: "clear", storeOp: "store", clearValue: { r: 0.1, g: 0.1, b: 0.1, a: 1.0 } }] }; const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor); passEncoder.setPipeline(pipeline); passEncoder.setVertexBuffer(0, vertexBuffer); passEncoder.draw(3); // Draw 3 vertices passEncoder.end(); // Submit the commands device.queue.submit([commandEncoder.finish()]); } // Initial draw and set up resize handling draw(); window.addEventListener("resize", () => { canvas.width = canvas.clientWidth * devicePixelRatio; canvas.height = canvas.clientHeight * devicePixelRatio; draw(); }); document.getElementById("status").textContent = "WebGPU triangle rendered successfully!"; } init(); </script> </body> </html> EOF trap "rm index.html" EXIT python -m http.server # $BROWSER -new-tab localhost:8080