Add alphaToCoverage validation aligning with WebGPU V1

Add alphaToCoverage validation regards to targets[0] has alpha channel.

This change reflecting WebGPU V1 spec update is aimed to ship together
with WebGPU in Chromium.

Bug: dawn:1759
Change-Id: I0aef60cf8c4dc828e05d6027644ffed35b33f652
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/128061
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Auto-Submit: Shrek Shao <shrekshao@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Loko Kung <lokokung@google.com>
This commit is contained in:
Shrek Shao 2023-04-19 23:42:36 +00:00 committed by Dawn LUCI CQ
parent ff75ab9a87
commit a965f520f9
4 changed files with 106 additions and 5 deletions

View File

@ -80,6 +80,11 @@ bool Format::HasDepthOrStencil() const {
return aspects & (Aspect::Depth | Aspect::Stencil);
}
bool Format::HasAlphaChannel() const {
// This is true for current formats. May need revisit if new formats and extensions are added.
return componentCount == 4 && IsColor();
}
bool Format::IsMultiPlanar() const {
return aspects & (Aspect::Plane0 | Aspect::Plane1);
}

View File

@ -106,6 +106,7 @@ struct Format {
bool HasDepth() const;
bool HasStencil() const;
bool HasDepthOrStencil() const;
bool HasAlphaChannel() const;
// IsMultiPlanar() returns true if the format allows selecting a plane index. This is only
// allowed by multi-planar formats (ex. NV12).

View File

@ -427,10 +427,23 @@ MaybeError ValidateFragmentState(DeviceBase* device,
}
DAWN_TRY(ValidateColorAttachmentBytesPerSample(device, colorAttachmentFormats));
DAWN_INVALID_IF(fragmentMetadata.usesSampleMaskOutput && alphaToCoverageEnabled,
"alphaToCoverageEnabled is true when the sample_mask builtin is a "
"pipeline output of fragment stage of %s.",
descriptor->module);
if (alphaToCoverageEnabled) {
DAWN_INVALID_IF(fragmentMetadata.usesSampleMaskOutput,
"alphaToCoverageEnabled is true when the sample_mask builtin is a "
"pipeline output of fragment stage of %s.",
descriptor->module);
DAWN_INVALID_IF(descriptor->targetCount == 0 ||
descriptor->targets[0].format == wgpu::TextureFormat::Undefined,
"alphaToCoverageEnabled is true when color target[0] is not present.");
const Format* format;
DAWN_TRY_ASSIGN(format, device->GetInternalFormat(descriptor->targets[0].format));
DAWN_INVALID_IF(
!format->HasAlphaChannel(),
"alphaToCoverageEnabled is true when target[0].format (%s) has no alpha channel.",
format->format);
}
return {};
}
@ -533,6 +546,10 @@ MaybeError ValidateRenderPipelineDescriptor(DeviceBase* device,
DAWN_TRY_CONTEXT(ValidateMultisampleState(&descriptor->multisample),
"validating multisample state.");
DAWN_INVALID_IF(
descriptor->multisample.alphaToCoverageEnabled && descriptor->fragment == nullptr,
"alphaToCoverageEnabled is true when fragment state is not present.");
if (descriptor->fragment != nullptr) {
DAWN_TRY_CONTEXT(ValidateFragmentState(device, descriptor->fragment, descriptor->layout,
descriptor->depthStencil,

View File

@ -848,7 +848,7 @@ TEST_F(RenderPipelineValidationTest, AlphaToCoverageAndSampleCount) {
}
// Tests if the sample_mask builtin is a pipeline output of fragment shader,
// then alphaToCoverageEnabled must be false
// then alphaToCoverageEnabled must be false.
TEST_F(RenderPipelineValidationTest, AlphaToCoverageAndSampleMaskOutput) {
wgpu::ShaderModule fsModuleSampleMaskOutput = utils::CreateShaderModule(device, R"(
struct Output {
@ -897,6 +897,84 @@ TEST_F(RenderPipelineValidationTest, AlphaToCoverageAndSampleMaskOutput) {
}
}
// Tests when alphaToCoverageEnabled is true, targets[0] must exist and have alpha channel.
TEST_F(RenderPipelineValidationTest, AlphaToCoverageAndColorTargetAlpha) {
{
// Control case
utils::ComboRenderPipelineDescriptor descriptor;
descriptor.vertex.module = vsModule;
descriptor.cFragment.module = fsModule;
descriptor.cTargets[0].format = wgpu::TextureFormat::RGBA8Unorm;
descriptor.multisample.count = 4;
descriptor.multisample.alphaToCoverageEnabled = true;
device.CreateRenderPipeline(&descriptor);
}
{
// Fragment state must exist
utils::ComboRenderPipelineDescriptor descriptor;
descriptor.vertex.module = vsModule;
descriptor.fragment = nullptr;
descriptor.multisample.count = 4;
descriptor.multisample.alphaToCoverageEnabled = true;
ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
}
{
// Fragment targets[0] must exist
utils::ComboRenderPipelineDescriptor descriptor;
descriptor.vertex.module = vsModule;
descriptor.cFragment.module = fsModule;
descriptor.cFragment.targetCount = 0;
descriptor.cFragment.targets = nullptr;
descriptor.multisample.count = 4;
descriptor.multisample.alphaToCoverageEnabled = true;
descriptor.EnableDepthStencil(wgpu::TextureFormat::Depth32Float);
ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
}
{
// Fragment targets[0].format must have alpha channel (only 1 target)
utils::ComboRenderPipelineDescriptor descriptor;
descriptor.vertex.module = vsModule;
descriptor.cFragment.module = fsModule;
descriptor.cTargets[0].format = wgpu::TextureFormat::R8Unorm;
descriptor.multisample.count = 4;
descriptor.multisample.alphaToCoverageEnabled = true;
ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
}
wgpu::ShaderModule fsModule2 = utils::CreateShaderModule(device, R"(
struct FragmentOut {
@location(0) target0 : vec4f,
@location(1) target1 : vec4f,
}
@fragment fn main() -> FragmentOut {
var out: FragmentOut;
out.target0 = vec4f(0, 0, 0, 1);
out.target1 = vec4f(1, 0, 0, 0);
return out;
})");
{
// Fragment targets[0].format must have alpha channel (2 targets)
utils::ComboRenderPipelineDescriptor descriptor;
descriptor.vertex.module = vsModule;
descriptor.cFragment.module = fsModule2;
descriptor.cFragment.targetCount = 2;
descriptor.cTargets[0].format = wgpu::TextureFormat::R8Unorm;
descriptor.cTargets[1].format = wgpu::TextureFormat::RGBA8Unorm;
descriptor.multisample.count = 4;
descriptor.multisample.alphaToCoverageEnabled = true;
ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
}
}
// Tests that the texture component type in shader must match the bind group layout.
TEST_F(RenderPipelineValidationTest, TextureComponentTypeCompatibility) {
constexpr uint32_t kNumTextureComponentType = 3u;