Skip to main content

WebGPU – Graphics Programming in the Browser

September 1, 2024

WebGPU is a new web standard that brings modern GPU programming to the browser. It's a successor to WebGL and is designed to be closer in capabilities to native graphics APIs like Vulkan, Metal, or DirectX 12.

Unlike WebGL, which is mainly for rendering graphics, WebGPU is also great for general-purpose GPU computing (GPGPU). That means you can use it not only for 3D scenes but also for high-performance tasks like physics simulations, image processing, and machine learning.

Why WebGPU matters

  • More control over GPU pipelines
  • Better performance with lower-level access
  • Modern shader language (WGSL)
  • Access to compute shaders in the browser

By 2023, WebGPU had started shipping in Chrome stable, and in 2024, more browsers are rolling it out or supporting it behind flags.

Simple example – a colored triangle

Here’s a minimal setup using WebGPU to render a triangle. This assumes WebGPU is supported and enabled in your browser.

const canvas = document.querySelector('canvas')
const adapter = await navigator.gpu.requestAdapter()
const device = await adapter.requestDevice()
const context = canvas.getContext('webgpu')

const format = navigator.gpu.getPreferredCanvasFormat()
context.configure({
  device,
  format
})

// Create a basic shader
const shaderCode = `
  @vertex
  fn vs_main(@builtin(vertex_index) VertexIndex : u32)
       -> @builtin(position) vec4<f32> {
    var pos = array<vec2<f32>, 3>(
      vec2<f32>(0.0, 0.5),
      vec2<f32>(-0.5, -0.5),
      vec2<f32>(0.5, -0.5)
    )
    return vec4<f32>(pos[VertexIndex], 0.0, 1.0)
  }

  @fragment
  fn fs_main() -> @location(0) vec4<f32> {
    return vec4<f32>(1.0, 0.0, 0.0, 1.0)
  }
`

const module = device.createShaderModule({ code: shaderCode })
const pipeline = device.createRenderPipeline({
  layout: 'auto',
  vertex: { module, entryPoint: 'vs_main' },
  fragment: {
    module,
    entryPoint: 'fs_main',
    targets: [{ format }]
  },
  primitive: { topology: 'triangle-list' }
})

const commandEncoder = device.createCommandEncoder()
const textureView = context.getCurrentTexture().createView()
const pass = commandEncoder.beginRenderPass({
  colorAttachments: [{
    view: textureView,
    clearValue: { r: 0, g: 0, b: 0, a: 1 },
    loadOp: 'clear',
    storeOp: 'store'
  }]
})

pass.setPipeline(pipeline)
pass.draw(3)
pass.end()
device.queue.submit([commandEncoder.finish()])

Learning curve

Working with WebGPU means writing shaders in WGSL and managing your rendering pipeline manually. It's more verbose than WebGL, but it's also much more powerful and flexible.

If you're familiar with lower-level graphics APIs or GPU compute frameworks, you’ll find WebGPU familiar. If not, start small, like with the triangle example above.

What to explore next

  • Compute shaders for non-graphics tasks
  • Integrating with React or other frameworks
  • Animations and post-processing
  • Using WebGPU in frameworks like Babylon.js or Three.js (early support)

WebGPU is still new, but it’s stable enough to experiment with today.

Recent posts