-
Notifications
You must be signed in to change notification settings - Fork 345
Description
Overview
Dual-source blending is a feature available on most platforms that allows a developer to specify blending from two fragment shader outputs to a single framebuffer. This feature has some desirable applications and should be considered as an optional post-V1 WebGPU feature.
Usages
This feature was requested previously in issue #391 with some brief discussion of usages.
Additionally, I've pulled these two scenarios from the spec of the similar OpenGL extension:
Implementation of sub-pixel accurate font rendering algorithms. Given a known layout of
pixel elements (red, green and blue components) coverage may be calculated independently
for each element and passed to the blender in the second source color as a per-channel opacity.
Consider rendering a partially reflective colored glass window.
It will attenuate light passing through it, and reflect some of the light
that strikes it. Using an appropriate combination of functions, this effect
may be simulated in a single pass using only fixed-function blending
hardware.
D3D12
Dual source blending is supported on all D3D12 platforms as a core feature. [MSDN]
When using dual-source blending, writing to other render targets is undefined. [MSDN]
typedef enum D3D12_BLEND {
...,
D3D12_BLEND_SRC1_COLOR,
D3D12_BLEND_INV_SRC1_COLOR,
D3D12_BLEND_SRC1_ALPHA,
D3D12_BLEND_INV_SRC1_ALPHA,
};
HLSL
To specify the two blend sources in an HLSL shader, you must use SV_Target0 and SV_Target1 as fragment shader outputs, which correspond to the indices of the dual-source blend. [MSDN]
Vulkan
Dual source blending is available on Vulkan as an extension. You must query the dualSrcBlend feature to determine if the required enumerations can be used. [Khronos]
The dualSrcBlend feature is available on 72.6% of devices. This feature is overwhelmingly supported on Windows, Linux, MacOS and iOS devices, however, only 49.5% of Android devices have support. Android devices that do not support dualSrcBlend primarily use ARM, ImgTec, and Qualcomm GPUs. [GPUInfo]
Vulkan's maxFragmentDualSrcAttachments limit is 1 for most platforms.
Vulkan specifies that the dual-source blend operation is undefined if the secondary source is not set. [Khronos]
typedef enum VkBlendFactor {
...,
VK_BLEND_FACTOR_SRC1_COLOR,
VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR,
VK_BLEND_FACTOR_SRC1_ALPHA,
VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA,
}
SPIR-V
SPIR-V uses the index n decoration following a location n decoration to specify the blend index of the output. [Khronos]
Metal
Dual-source blending appears to be available on all currently supported platforms [Metal Feature Set Tables]
Metal doesn't support multiple render targets when using dual-source blending [Apple Developer]
typedef enum MTLBlendFactor {
...,
MTLBlendFactorSource1Color,
MTLBlendFactorOneMinusSource1Color,
MTLBlendFactorSource1Alpha,
MTLBlendFactorOneMinusSource1Alpha,
};
MSL
Metal Shading Language uses the index(n) attribute following a color(n) attribute to specify the blend index of the output. [Apple Developer]
Proposal
WebGPU:
Because dual source blending is a desirable feature, but is not supported on all platforms, we should add dual-source-blending as an optional post-V1 WebGPU feature.
dual-source-blending should add the following enums to GPUBlendFactor:
enum GPUBlendFactor {
...,
"src1",
"one-minus-src1",
"src1-alpha",
"one-minus-src1-alpha",
};
WGSL:
When dual-source-blending is enabled, allow the @index attribute to specify the dual-source blend index when added to a fragment shader output alongside the @location attribute.
An example shader:
struct ShaderIO {
@location(0) @index(0) fragColor: vec4f,
@location(0) @index(1) fragBlend: vec4f,
}
@fragment fn main() -> ShaderIO {
var io: ShaderIO;
io.fragColor = vec4f(1.0, 1.0, 1.0, 1.0);
io.fragBlend = vec4f(0.5, 0.5, 0.5, 0.5);
return io;
}
Restrictions:
src1GPUBlendFactors must be restricted to color attachment 0. (Due to HLSL's restricted dual source blend output targets)@indexattribute must be restricted to@location(0). (Due to HLSL's restricted dual source blend output targets)- The developer must not write to any other render targets. (Due to this being unsupported on almost all platforms)
- The developer must define the secondary blend source. (Due to this being undefined on at least Vulkan)