Description
Introduction
When the color attachment is multi-sampled, the explicit APIs provide the following additional configurations to affect the coverage of the samples for each pixel:
- Sample Mask (In pipeline state object)
- Sample Mask (In fragment shader)
- Alpha-to-coverage
This document discusses how to expose these configurations to WebGPU.
Native APIs
D3D12
D3D12 supports specifying a 32-bit UINT
as the sample mask in the structure D3D12_GRAPHICS_PIPELINE_STATE_DESC.
D3D12 supports SV_Coverage
in HLSL as a mask in pixel shaders.
D3D12 supports enabling alpha-to-coverage in D3D12_BLEND_DESC. According to the document for alpha-to-coverage on MSDN, “AlphaToCoverageEnable
is used to toggle if the runtime converts the .a
component (alpha) of output register SV_Target0
from the pixel shader to an n-step coverage mask (given an n-sample RenderTarget). The runtime performs an AND operation of this mask with the typical sample coverage for the pixel in the primitive (in addition to the sample mask) to determine which samples to update in all the active RenderTargets”.
Note that D3D12 document mentions “if the pixel shader outputs SV_Coverage
, the runtime disables alpha-to-coverage”.
D3D12 document also mentions "graphics hardware doesn't precisely specify exactly how it converts pixel shader SV_Target0.a
(alpha) to a coverage mask. Hardware might perform area dithering to provide some better quantization of alpha values at the cost of spatial resolution and noise."
Metal
Metal does not support the configuration of sample mask in MTLRenderPipelineDescriptor.
According to Metal Shading Language Specification (Chapter 5.2.3.4, Chapter 5.2.3.5), Metal shading language supports an uint
attribute [[sample_mask]]
as the coverage mask.
Metal supports enabling alpha-to-coverage in the rendering pipeline through alphaToCoverageEnabled in MTLRenderPipelineDescriptor
.
Metal document provides a Pseudo-Code for computing a coverage mask. This Pseudo-Code implies alpha-to-coverage only works for colorAttachment0
.
if (alphaToCoverageEnabled) then
alphaCoverageMask = coverageToMask(colorAttachment0.alpha);
finalCoverageMask = originalRasterizerCoverageMask & alphaCoverageMask & fragShaderSampleMaskOutput;
Metal document mentions the algorithm to convert the alpha channel of the fragment output to a coverage mask is implementation-dependent.
Vulkan
Vulkan supports configuring sample mask in the rendering pipeline by setting pSampleMask
in VkPipelineMultisampleStateCreateInfo. pSampleMask
is an array of uint32_t
, which means Vulkan allows sample mask to have more than 32 bits.
SPIR-V supports SampleMask
as a built-in variable in fragment shader.
Vulkan supports enabling alpha-to-coverage in the rendering pipeline by setting alphaToCoverageEnable
in VkPipelineMultisampleStateCreateInfo
to VK_TRUE
.
Vulkan specification mentions alpha-to-coverage only works for “the alpha component of the fragment shader output that has a Location
and Index decoration of zero”, and “if alphaToCoverageEnable
is enabled, a temporary coverage value with rasterizationSamples bits is generated where each bit is determined by the fragment’s alpha value. The temporary coverage value is then ANDed with the fragment coverage value to generate a new fragment coverage value”.
Vulkan specification mentions “no specific algorithm is specified for converting the alpha value to a temporary coverage mask”.
Proposal
Here is the summary on the support of multisample coverage on D3D12, Metal and Vulkan.
D3D12 | Metal | Vulkan | |
---|---|---|---|
Sample Mask (PSO) | Yes | No | Yes |
Sample Mask (shader) | Yes | Yes | Yes |
Alpha-to-coverage | Yes for SV_target0 when pixel shader doesn’t output SV_Coverage |
Yes for colorAttachments0 (?) |
Yes for the fragment shader output that has a Location and Index decoration of 0 |
Based on the above investigations, one feasible way to support the configuration on multisample coverage in WebGPU is as follows:
- Do not expose sample mask in pipeline state objects because Metal does not support such usage. Another choice is to re-compile the fragment shader when building pipeline state object on Metal.
- Support sample mask in the fragment shader as it is available in HLSL, Metal shading language and SPIR-V.
- Support alpha-to-coverage and always disable alpha-to-coverage when the fragment shader outputs sample mask. It is because on D3D12 when the pixel shader outputs
SV_Coverage
, the runtime always disables alpha-to-coverage.
Note that another challenge to support alpha-to-coverage in WebGPU is the algorithm of converting the alpha value to a coverage mask is implementation-dependent, which means the behaviors of alpha-to-coverage may differ among different WebGPU implementations.