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
| Approach | Draw calls | Textures | Dual 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',
}
}