WebGPU - Next-Generation GPU API for the Web

20 min read | 2025.01.21

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

FeatureWebGL 2.0WebGPU
Design Year20172023
Based OnOpenGL ES 3.0Vulkan/Metal/D3D12
Compute Shaders×
Multi-threading×
Memory ManagementAutomaticExplicit
Bind Groups×
Shader LanguageGLSLWGSL

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

BrowserSupport Status
Chrome 113+◎ Full Support
Edge 113+◎ Full Support
Firefox△ Behind Flag
Safari 17+○ Supported

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