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:
parent
ff75ab9a87
commit
a965f520f9
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue