demo · v130

Alpha Masking

WebGPU's dual-source-blending feature (Chrome 130) allows a fragment shader to output two values from a single colour attachment — the RGB colour AND a separate blend factor. This unlocks single-pass alpha-masked compositing: the mask value modulates the blend weight without needing a second draw call or a separate mask texture. Canvas 2D simulates the result below.

Checking WebGPU dual-source-blending support…
0.80
With dual-source blend (mask applied)
Fragment outputs: color0 (rgba) + color0 blend src1 (mask alpha)
Standard blend (no mask)
Standard alpha blend — mask ignored

Dual-source blending vs alternatives

ApproachDraw callsTexturesDual source needed
Standard alpha blend 1 1 (source) No
Separate mask pass (legacy) 2 2 (source + mask) No
Packed RGBA (alpha = mask) 1 1 No (limited)
Dual-source blend (Chrome 130) 1 1 Yes — true independent mask alpha
// Chrome 130: dual-source-blending feature
const adapter = await navigator.gpu.requestAdapter();
const hasDSB  = adapter.features.has('dual-source-blending');
const device  = await adapter.requestDevice({
  requiredFeatures: hasDSB ? ['dual-source-blending'] : []
});

// WGSL fragment shader — output two values from one attachment
@fragment
fn main() -> @location(0) @blend_src(0) vec4f,
              @location(0) @blend_src(1) vec4f {
  let maskAlpha = computeMask(uv);   // 0..1 mask weight
  let color     = sampleTexture(uv);
  return color, vec4f(maskAlpha);    // src1 drives blend weight
}

// Pipeline: blend uses src1 as the factor
blend: {
  color: {
    srcFactor:    'src1',          // ← uses @blend_src(1)
    dstFactor:    'one-minus-src1',
    operation:    'add',
  }
}

see also