Canvas Format

Choosing a Format with getPreferredCanvasFormat

A canvas accepts only bgra8unorm, rgba8unorm and rgba16float; configure() threw a TypeError here for bgra8unorm-srgb and r8unorm. navigator.gpu.getPreferredCanvasFormat() returns the 8-bit format the system displays best (bgra8unorm here). Pipelines must name the canvas's format (Validation Mistakes), so query it once and pass it everywhere.

For gamma-correct output, configure the plain format, list its -srgb twin in viewFormats, and render through an sRGB view. This page clears to 0.5 grey through each view and reads the bytes back:

The same clear value stored through a plain view and an sRGB viewHTMLLive
<canvas id="swatch" width="4" height="4"></canvas>
<script type="module">
  const device = await (await navigator.gpu.requestAdapter()).requestDevice();
  const context = swatch.getContext('webgpu');
  context.configure({ device, format: 'bgra8unorm', viewFormats: ['bgra8unorm-srgb'],
    usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC });
  for (const format of ['bgra8unorm', 'bgra8unorm-srgb']) {
    const texture = context.getCurrentTexture(), encoder = device.createCommandEncoder();
    encoder.beginRenderPass({ colorAttachments: [{ view: texture.createView({ format }),
      clearValue: [0.5, 0.5, 0.5, 1], loadOp: 'clear', storeOp: 'store' }] }).end();
    const read = device.createBuffer({ size: 1024, usage: 9 });   // MAP_READ | COPY_DST
    encoder.copyTextureToBuffer({ texture }, { buffer: read, bytesPerRow: 256 }, [4, 4]);
    device.queue.submit([encoder.finish()]), await read.mapAsync(GPUMapMode.READ);
    console.log(`${format}: ${new Uint8Array(read.getMappedRange(), 0, 4)}`);
    await new Promise(requestAnimationFrame);              // next frame, next texture
  }
</script>

The sRGB view encodes 0.5 as 188, which the display decodes back to half the light. Use it when shaders work in linear light (sRGB), and the plain view for colors already in sRGB, such as BookNest's blue.