Skip to content

SOP: Create a Render Pipeline

Fresh 🌱

Version: 1.0 | Chrome: 113+

Overview

A WebGPU render pipeline encapsulates all rendering state in one immutable object: shaders, vertex layout, color targets, depth/stencil, and blend state. This replaces WebGL's error-prone global state.

Pipeline Flowchart

Step-by-Step

Step 1 — Write WGSL Shaders

wgsl
// Vertex shader: outputs clip-space position
@vertex
fn vertexMain(@builtin(vertex_index) i : u32) -> @builtin(position) vec4f {
  // Triangle positions in clip space
  const pos = array(
    vec2f( 0.0,  0.5),   // top center
    vec2f(-0.5, -0.5),   // bottom left
    vec2f( 0.5, -0.5)    // bottom right
  );
  return vec4f(pos[i], 0.0, 1.0);
}

// Fragment shader: outputs RGBA color
@fragment
fn fragmentMain() -> @location(0) vec4f {
  return vec4f(0.31, 0.19, 0.89, 1.0); // Indigo
}

Step 2 — Create Shader Module

javascript
const shaderModule = device.createShaderModule({
  label: 'Triangle shader',
  code: wgslCode  // the WGSL string above
});

Step 3 — Create Render Pipeline

javascript
const pipeline = device.createRenderPipeline({
  label: 'Triangle pipeline',
  layout: 'auto',  // auto-generate bind group layouts
  vertex: {
    module: shaderModule,
    entryPoint: 'vertexMain'
  },
  fragment: {
    module: shaderModule,
    entryPoint: 'fragmentMain',
    targets: [{
      format: navigator.gpu.getPreferredCanvasFormat()
    }]
  },
  primitive: {
    topology: 'triangle-list'  // or 'triangle-strip', 'line-list', 'point-list'
  }
});

Step 4 — Render Frame

javascript
function renderFrame() {
  // Create fresh encoder each frame
  const commandEncoder = device.createCommandEncoder({ label: 'Frame encoder' });

  const renderPass = commandEncoder.beginRenderPass({
    colorAttachments: [{
      view: context.getCurrentTexture().createView(),
      loadOp: 'clear',
      clearValue: { r: 0.05, g: 0.05, b: 0.05, a: 1.0 },
      storeOp: 'store'
    }]
  });

  renderPass.setPipeline(pipeline);
  renderPass.draw(3); // 3 vertices = 1 triangle
  renderPass.end();

  // Submit to GPU queue
  device.queue.submit([commandEncoder.finish()]);

  requestAnimationFrame(renderFrame);
}

requestAnimationFrame(renderFrame);

Step 5 — Full Triangle Example

javascript
async function main() {
  const adapter = await navigator.gpu.requestAdapter();
  const device = await adapter.requestDevice();
  const canvas = document.querySelector('canvas');
  const context = canvas.getContext('webgpu');
  const format = navigator.gpu.getPreferredCanvasFormat();
  context.configure({ device, format });

  const shaderCode = `
    @vertex
    fn vs(@builtin(vertex_index) i: u32) -> @builtin(position) vec4f {
      const p = array(vec2f(0,0.5), vec2f(-0.5,-0.5), vec2f(0.5,-0.5));
      return vec4f(p[i], 0, 1);
    }
    @fragment fn fs() -> @location(0) vec4f {
      return vec4f(0.31, 0.19, 0.89, 1.0);
    }
  `;

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

  function frame() {
    const enc = device.createCommandEncoder();
    const pass = enc.beginRenderPass({
      colorAttachments: [{ view: context.getCurrentTexture().createView(), loadOp: 'clear', clearValue: [0,0,0,1], storeOp: 'store' }]
    });
    pass.setPipeline(pipeline);
    pass.draw(3);
    pass.end();
    device.queue.submit([enc.finish()]);
    requestAnimationFrame(frame);
  }
  requestAnimationFrame(frame);
}
main();

Verification Checklist

  • [ ] Shader module created without compilation errors
  • [ ] Pipeline layout: 'auto' or explicit layout defined
  • [ ] Canvas format matches getPreferredCanvasFormat()
  • [ ] loadOp and storeOp specified on all attachments
  • [ ] renderPass.end() called before commandEncoder.finish()
  • [ ] Commands submitted via device.queue.submit()

Topology Options

TopologyUse Case
triangle-listStandard mesh rendering
triangle-stripEfficient quad rendering
line-listDebug wireframes
line-stripCurves and paths
point-listParticle systems

See Also

Based on Chrome for Developers WebGPU Documentation