v148 · WebGPU · demo

Shader Code Comparison

The same compute shader task — squaring every element in a flat array — written the old way (manual index arithmetic) and the new way (using global_invocation_index directly).

Checking WebGPU linear_indexing support…
Without linear_indexing Chrome < 148
// Shader params passed as uniforms
struct Params {
  width:  u32,
  height: u32,
};
@group(0) @binding(0) var<uniform>
  params: Params;
@group(0) @binding(1) var<storage, read_write>
  data: array<f32>;

@compute @workgroup_size(8, 8)
fn main(
  @builtin(global_invocation_id)
  id: vec3u,
) {
  // ↓ boilerplate everyone writes manually
  let idx = id.x
           + id.y * params.width
           + id.z * params.width * params.height;
  if (idx >= arrayLength(&data)) { return; }
  data[idx] = data[idx] * data[idx];
}
Lines of index boilerplate: 3 Correctness risk: high
With linear_indexing Chrome 148+
// Enable the language extension
enable linear_indexing;

@group(0) @binding(0) var<storage, read_write>
  data: array<f32>;

@compute @workgroup_size(8, 8)
fn main(
  @builtin(global_invocation_index)
  idx: u32,
) {
  // ↓ flat index handed to you directly
    // (no arithmetic needed)
  if (idx >= arrayLength(&data)) { return; }
  data[idx] = data[idx] * data[idx];
}
Lines of index boilerplate: 0 Correctness risk: none
What changed

Feature detection

// JavaScript — check before compiling the shader
const supported =
  navigator.gpu &&
  navigator.gpu.wgslLanguageFeatures.has('linear_indexing');

if (!supported) {
  // Fall back to manual index calculation shader
}

The two new built-ins

Built-in Type Value
global_invocation_index u32 Linear index of this invocation across the entire dispatch grid
workgroup_index u32 Linear index of the workgroup within the dispatch (analogous, at workgroup granularity)

see also

implementation reference

Need the exact API surface, compatibility boundaries, errors, lifecycle, and source links? Read the matching gendn reference ↗