What is WebGPU?
WebGPU is a next-generation API for accessing low-level GPU capabilities from web browsers. Designed as the successor to WebGL, it abstracts modern graphics APIs like Vulkan, Metal, and Direct3D 12.
flowchart TB
subgraph Web["Web Application"]
App["JavaScript/TypeScript"]
end
subgraph API["Graphics API"]
WebGPU["WebGPU API"]
end
subgraph Native["Native APIs"]
Vulkan["Vulkan<br/>(Linux/Android)"]
Metal["Metal<br/>(macOS/iOS)"]
D3D12["Direct3D 12<br/>(Windows)"]
end
subgraph GPU["GPU"]
Hardware["GPU Hardware"]
end
App --> WebGPU
WebGPU --> Vulkan
WebGPU --> Metal
WebGPU --> D3D12
Vulkan --> Hardware
Metal --> Hardware
D3D12 --> Hardware
WebGL vs WebGPU
| Feature | WebGL 2.0 | WebGPU |
|---|---|---|
| Design Year | 2017 | 2023 |
| Based On | OpenGL ES 3.0 | Vulkan/Metal/D3D12 |
| Compute Shaders | × | ◎ |
| Multi-threading | × | ◎ |
| Memory Management | Automatic | Explicit |
| Bind Groups | × | ◎ |
| Shader Language | GLSL | WGSL |
Basic Usage
1. Getting a GPU Adapter
async function initWebGPU(): Promise<{ device: GPUDevice; context: GPUCanvasContext }> {
// Request GPU adapter
const adapter = await navigator.gpu?.requestAdapter();
if (!adapter) {
throw new Error('WebGPU not supported');
}
// Get GPU device
const device = await adapter.requestDevice();
// Configure canvas context
const canvas = document.querySelector('canvas')!;
const context = canvas.getContext('webgpu')!;
const format = navigator.gpu.getPreferredCanvasFormat();
context.configure({
device,
format,
alphaMode: 'premultiplied',
});
return { device, context };
}
2. Creating Shaders (WGSL)
// Vertex shader
@vertex
fn vertexMain(@location(0) position: vec3f) -> @builtin(position) vec4f {
return vec4f(position, 1.0);
}
// Fragment shader
@fragment
fn fragmentMain() -> @location(0) vec4f {
return vec4f(1.0, 0.5, 0.2, 1.0); // Orange color
}
3. Render Pipeline
function createPipeline(device: GPUDevice, format: GPUTextureFormat): GPURenderPipeline {
const shaderModule = device.createShaderModule({
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);
}
`,
});
return device.createRenderPipeline({
layout: 'auto',
vertex: {
module: shaderModule,
entryPoint: 'vertexMain',
buffers: [{
arrayStride: 12, // 3 floats * 4 bytes
attributes: [{
format: 'float32x3',
offset: 0,
shaderLocation: 0,
}],
}],
},
fragment: {
module: shaderModule,
entryPoint: 'fragmentMain',
targets: [{ format }],
},
});
}
Compute Shaders (GPGPU)
WebGPU’s standout feature is its support for general-purpose computing (GPGPU) beyond graphics.
Matrix Multiplication Example
async function matrixMultiply(device: GPUDevice, a: Float32Array, b: Float32Array): Promise<Float32Array> {
const size = Math.sqrt(a.length);
// Create buffers
const bufferA = device.createBuffer({
size: a.byteLength,
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
});
const bufferB = device.createBuffer({
size: b.byteLength,
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
});
const bufferResult = device.createBuffer({
size: a.byteLength,
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,
});
device.queue.writeBuffer(bufferA, 0, a);
device.queue.writeBuffer(bufferB, 0, b);
// Compute shader
const shaderModule = device.createShaderModule({
code: `
@group(0) @binding(0) var<storage, read> matrixA: array<f32>;
@group(0) @binding(1) var<storage, read> matrixB: array<f32>;
@group(0) @binding(2) var<storage, read_write> result: array<f32>;
@compute @workgroup_size(8, 8)
fn main(@builtin(global_invocation_id) id: vec3u) {
let row = id.x;
let col = id.y;
let size = ${size}u;
if (row >= size || col >= size) { return; }
var sum = 0.0;
for (var i = 0u; i < size; i++) {
sum += matrixA[row * size + i] * matrixB[i * size + col];
}
result[row * size + col] = sum;
}
`,
});
// Create pipeline
const pipeline = device.createComputePipeline({
layout: 'auto',
compute: {
module: shaderModule,
entryPoint: 'main',
},
});
// Bind group
const bindGroup = device.createBindGroup({
layout: pipeline.getBindGroupLayout(0),
entries: [
{ binding: 0, resource: { buffer: bufferA } },
{ binding: 1, resource: { buffer: bufferB } },
{ binding: 2, resource: { buffer: bufferResult } },
],
});
// Execute
const commandEncoder = device.createCommandEncoder();
const passEncoder = commandEncoder.beginComputePass();
passEncoder.setPipeline(pipeline);
passEncoder.setBindGroup(0, bindGroup);
passEncoder.dispatchWorkgroups(Math.ceil(size / 8), Math.ceil(size / 8));
passEncoder.end();
// Read results
const readBuffer = device.createBuffer({
size: a.byteLength,
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ,
});
commandEncoder.copyBufferToBuffer(bufferResult, 0, readBuffer, 0, a.byteLength);
device.queue.submit([commandEncoder.finish()]);
await readBuffer.mapAsync(GPUMapMode.READ);
const result = new Float32Array(readBuffer.getMappedRange().slice(0));
readBuffer.unmap();
return result;
}
WGSL (WebGPU Shading Language)
A shader language designed specifically for WebGPU with Rust-like syntax.
Basic Syntax
// Variable declaration
var<private> count: u32 = 0;
let constant: f32 = 3.14159;
// Struct
struct Vertex {
@location(0) position: vec3f,
@location(1) color: vec4f,
}
// Function
fn add(a: f32, b: f32) -> f32 {
return a + b;
}
// Built-in functions
fn example() {
let v = vec3f(1.0, 2.0, 3.0);
let len = length(v); // Vector length
let n = normalize(v); // Normalize
let d = dot(v, n); // Dot product
let c = cross(v, n); // Cross product
let m = max(1.0, 2.0); // Maximum
let s = sin(3.14 / 2.0); // Trigonometry
}
Use Cases
1. Machine Learning Inference
// Neural network inference in the browser
import * as tf from '@tensorflow/tfjs';
import '@tensorflow/tfjs-backend-webgpu';
await tf.setBackend('webgpu');
const model = await tf.loadGraphModel('model.json');
const prediction = model.predict(inputTensor);
2. Image/Video Processing
@group(0) @binding(0) var inputTexture: texture_2d<f32>;
@group(0) @binding(1) var outputTexture: texture_storage_2d<rgba8unorm, write>;
@compute @workgroup_size(8, 8)
fn blur(@builtin(global_invocation_id) id: vec3u) {
// Gaussian blur processing
var sum = vec4f(0.0);
let weights = array<f32, 9>(
0.0625, 0.125, 0.0625,
0.125, 0.25, 0.125,
0.0625, 0.125, 0.0625
);
for (var dy = -1; dy <= 1; dy++) {
for (var dx = -1; dx <= 1; dx++) {
let coord = vec2i(id.xy) + vec2i(dx, dy);
let color = textureLoad(inputTexture, coord, 0);
sum += color * weights[(dy + 1) * 3 + (dx + 1)];
}
}
textureStore(outputTexture, vec2i(id.xy), sum);
}
3. Physics Simulation
struct Particle {
position: vec3f,
velocity: vec3f,
}
@group(0) @binding(0) var<storage, read_write> particles: array<Particle>;
@compute @workgroup_size(64)
fn simulate(@builtin(global_invocation_id) id: vec3u) {
let index = id.x;
var p = particles[index];
// Gravity
p.velocity.y -= 9.8 * deltaTime;
// Update position
p.position += p.velocity * deltaTime;
// Ground collision
if (p.position.y < 0.0) {
p.position.y = 0.0;
p.velocity.y *= -0.8; // Restitution coefficient
}
particles[index] = p;
}
Browser Support
| Browser | Support Status |
|---|---|
| Chrome 113+ | ◎ Full Support |
| Edge 113+ | ◎ Full Support |
| Firefox | △ Behind Flag |
| Safari 17+ | ○ Supported |
Related Articles
- WebAssembly - Wasm Basics
- Performance Optimization - Optimization Techniques
- Async Programming - Asynchronous Processing
Summary
WebGPU brings revolutionary GPU capabilities to the web platform.
- Modern API: Abstraction over Vulkan/Metal/D3D12
- Compute Shaders: GPGPU support
- WGSL: Safe and expressive shader language
- High Performance: Low-overhead design
It greatly expands possibilities for web applications requiring GPU performance, including 3D graphics, machine learning, and scientific computing.
← Back to list