Validate that the color write mask is zero if there is no fragment output

Following spec change https://github.com/gpuweb/gpuweb/pull/1918

Fixed: dawn:962
Change-Id: I9d7eaee588301227736cf523bec46e5a60fe861b
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/59042
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Jiawei Shao <jiawei.shao@intel.com>
This commit is contained in:
Austin Eng
2021-07-26 19:43:19 +00:00
committed by Dawn LUCI CQ
parent 4840b8a518
commit 821b1cbf96
14 changed files with 195 additions and 12 deletions

View File

@@ -1359,6 +1359,7 @@ class SetBindGroupValidationTest : public ValidationTest {
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
pipelineDescriptor.vertex.module = vsModule;
pipelineDescriptor.cFragment.module = fsModule;
pipelineDescriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
wgpu::PipelineLayout pipelineLayout =
utils::MakeBasicPipelineLayout(device, &mBindGroupLayout);
pipelineDescriptor.layout = pipelineLayout;
@@ -1818,6 +1819,7 @@ class SetBindGroupPersistenceValidationTest : public ValidationTest {
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
pipelineDescriptor.vertex.module = mVsModule;
pipelineDescriptor.cFragment.module = fsModule;
pipelineDescriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
pipelineDescriptor.layout = pipelineLayout;
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDescriptor);
@@ -1957,6 +1959,7 @@ class BindGroupLayoutCompatibilityTest : public ValidationTest {
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
pipelineDescriptor.vertex.module = vsModule;
pipelineDescriptor.cFragment.module = fsModule;
pipelineDescriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
wgpu::PipelineLayout pipelineLayout = device.CreatePipelineLayout(&descriptor);
pipelineDescriptor.layout = pipelineLayout;
return device.CreateRenderPipeline(&pipelineDescriptor);
@@ -2350,6 +2353,7 @@ class SamplerTypeBindingTest : public ValidationTest {
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
pipelineDescriptor.vertex.module = vsModule;
pipelineDescriptor.cFragment.module = fsModule;
pipelineDescriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
wgpu::PipelineLayout pipelineLayout =
utils::MakeBasicPipelineLayout(device, bindGroupLayout);
pipelineDescriptor.layout = pipelineLayout;

View File

@@ -31,6 +31,7 @@ class GetBindGroupLayoutTests : public ValidationTest {
descriptor.layout = nullptr;
descriptor.vertex.module = vsModule;
descriptor.cFragment.module = fsModule;
descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
return device.CreateRenderPipeline(&descriptor);
}
@@ -77,6 +78,7 @@ TEST_F(GetBindGroupLayoutTests, SameObject) {
descriptor.layout = nullptr;
descriptor.vertex.module = vsModule;
descriptor.cFragment.module = fsModule;
descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor);
@@ -213,6 +215,7 @@ TEST_F(GetBindGroupLayoutTests, DefaultTextureSampleType) {
utils::ComboRenderPipelineDescriptor descriptor;
descriptor.vertex.module = vertexModule;
descriptor.cFragment.module = fragmentModule;
descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
return device.CreateRenderPipeline(&descriptor).GetBindGroupLayout(0);
};
@@ -637,6 +640,7 @@ TEST_F(GetBindGroupLayoutTests, DuplicateBinding) {
descriptor.layout = nullptr;
descriptor.vertex.module = vsModule;
descriptor.cFragment.module = fsModule;
descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
device.CreateRenderPipeline(&descriptor);
}
@@ -707,6 +711,7 @@ TEST_F(GetBindGroupLayoutTests, MinBufferSize) {
utils::ComboRenderPipelineDescriptor descriptor;
descriptor.layout = nullptr;
descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
// Check with both stages using 4 bytes.
{
@@ -773,6 +778,7 @@ TEST_F(GetBindGroupLayoutTests, StageAggregation) {
utils::ComboRenderPipelineDescriptor descriptor;
descriptor.layout = nullptr;
descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
// Check with only the vertex shader using the sampler
{
@@ -999,6 +1005,7 @@ TEST_F(GetBindGroupLayoutTests, Reflection) {
pipelineDesc.layout = pipelineLayout;
pipelineDesc.vertex.module = vsModule;
pipelineDesc.cFragment.module = fsModule;
pipelineDesc.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDesc);

View File

@@ -193,6 +193,7 @@ class MinBufferSizeTestsBase : public ValidationTest {
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
pipelineDescriptor.vertex.module = vsModule;
pipelineDescriptor.cFragment.module = fsModule;
pipelineDescriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
pipelineDescriptor.layout = nullptr;
if (!layouts.empty()) {
wgpu::PipelineLayoutDescriptor descriptor;

View File

@@ -102,6 +102,7 @@ namespace {
descriptor->layout = pipelineLayout;
descriptor->vertex.module = vsModule;
descriptor->cFragment.module = fsModule;
descriptor->cTargets[0].writeMask = wgpu::ColorWriteMask::None;
descriptor->vertex.bufferCount = 1;
descriptor->cBuffers[0].arrayStride = 2 * sizeof(float);
descriptor->cBuffers[0].attributeCount = 1;
@@ -735,6 +736,9 @@ TEST_F(RenderBundleValidationTest, PipelineColorFormatMismatch) {
desc->cTargets[0].format = wgpu::TextureFormat::RGBA8Unorm;
desc->cTargets[1].format = wgpu::TextureFormat::RG16Float;
desc->cTargets[2].format = wgpu::TextureFormat::R16Sint;
desc->cTargets[0].writeMask = wgpu::ColorWriteMask::None;
desc->cTargets[1].writeMask = wgpu::ColorWriteMask::None;
desc->cTargets[2].writeMask = wgpu::ColorWriteMask::None;
};
// Test the success case.

View File

@@ -456,6 +456,7 @@ TEST_F(RenderPipelineValidationTest, TextureComponentTypeCompatibility) {
ignore(textureDimensions(myTexture));
})";
descriptor.cFragment.module = utils::CreateShaderModule(device, stream.str().c_str());
descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Fragment, kTextureComponentTypes[j]}});
@@ -504,6 +505,7 @@ TEST_F(RenderPipelineValidationTest, TextureViewDimensionCompatibility) {
ignore(textureDimensions(myTexture));
})";
descriptor.cFragment.module = utils::CreateShaderModule(device, stream.str().c_str());
descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Fragment, wgpu::TextureSampleType::Float,
@@ -753,6 +755,138 @@ TEST_F(RenderPipelineValidationTest, FragmentOutputCorrectEntryPoint) {
ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
}
// Test that unwritten fragment outputs must have a write mask of 0.
TEST_F(RenderPipelineValidationTest, UnwrittenFragmentOutputsMask0) {
wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"(
[[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> {
return vec4<f32>();
}
)");
wgpu::ShaderModule fsModuleWriteNone = utils::CreateShaderModule(device, R"(
[[stage(fragment)]] fn main() {}
)");
wgpu::ShaderModule fsModuleWrite0 = utils::CreateShaderModule(device, R"(
[[stage(fragment)]] fn main() -> [[location(0)]] vec4<f32> {
return vec4<f32>();
}
)");
wgpu::ShaderModule fsModuleWrite1 = utils::CreateShaderModule(device, R"(
[[stage(fragment)]] fn main() -> [[location(1)]] vec4<f32> {
return vec4<f32>();
}
)");
wgpu::ShaderModule fsModuleWriteBoth = utils::CreateShaderModule(device, R"(
struct FragmentOut {
[[location(0)]] target0 : vec4<f32>;
[[location(1)]] target1 : vec4<f32>;
};
[[stage(fragment)]] fn main() -> FragmentOut {
var out : FragmentOut;
return out;
}
)");
// Control case: write to target 0
{
utils::ComboRenderPipelineDescriptor descriptor;
descriptor.vertex.module = vsModule;
descriptor.cFragment.targetCount = 1;
descriptor.cFragment.module = fsModuleWrite0;
device.CreateRenderPipeline(&descriptor);
}
// Control case: write to target 0 and target 1
{
utils::ComboRenderPipelineDescriptor descriptor;
descriptor.vertex.module = vsModule;
descriptor.cFragment.targetCount = 2;
descriptor.cFragment.module = fsModuleWriteBoth;
device.CreateRenderPipeline(&descriptor);
}
// Write only target 1 (not in pipeline fragment state).
// Errors because target 0 does not have a write mask of 0.
{
utils::ComboRenderPipelineDescriptor descriptor;
descriptor.vertex.module = vsModule;
descriptor.cFragment.targetCount = 1;
descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::All;
descriptor.cFragment.module = fsModuleWrite1;
ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
}
// Write only target 1 (not in pipeline fragment state).
// OK because target 0 has a write mask of 0.
{
utils::ComboRenderPipelineDescriptor descriptor;
descriptor.vertex.module = vsModule;
descriptor.cFragment.targetCount = 1;
descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
descriptor.cFragment.module = fsModuleWrite1;
device.CreateRenderPipeline(&descriptor);
}
// Write only target 0 with two color targets.
// Errors because target 1 does not have a write mask of 0.
{
utils::ComboRenderPipelineDescriptor descriptor;
descriptor.vertex.module = vsModule;
descriptor.cFragment.targetCount = 2;
descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::Red;
descriptor.cTargets[1].writeMask = wgpu::ColorWriteMask::Alpha;
descriptor.cFragment.module = fsModuleWrite0;
ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
}
// Write only target 0 with two color targets.
// OK because target 1 has a write mask of 0.
{
utils::ComboRenderPipelineDescriptor descriptor;
descriptor.vertex.module = vsModule;
descriptor.cFragment.targetCount = 2;
descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::All;
descriptor.cTargets[1].writeMask = wgpu::ColorWriteMask::None;
descriptor.cFragment.module = fsModuleWrite0;
device.CreateRenderPipeline(&descriptor);
}
// Write nothing with two color targets.
// Errors because both target 0 and 1 have nonzero write masks.
{
utils::ComboRenderPipelineDescriptor descriptor;
descriptor.vertex.module = vsModule;
descriptor.cFragment.targetCount = 2;
descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::Red;
descriptor.cTargets[1].writeMask = wgpu::ColorWriteMask::Green;
descriptor.cFragment.module = fsModuleWriteNone;
ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
}
// Write nothing with two color targets.
// OK because target 0 and 1 have write masks of 0.
{
utils::ComboRenderPipelineDescriptor descriptor;
descriptor.vertex.module = vsModule;
descriptor.cFragment.targetCount = 2;
descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
descriptor.cTargets[1].writeMask = wgpu::ColorWriteMask::None;
descriptor.cFragment.module = fsModuleWriteNone;
device.CreateRenderPipeline(&descriptor);
}
}
// Test that fragment output validation is for the correct entryPoint
// TODO(dawn:216): Re-enable when we correctly reflect which bindings are used for an entryPoint.
TEST_F(RenderPipelineValidationTest, DISABLED_BindingsFromCorrectEntryPoint) {

View File

@@ -57,6 +57,7 @@ namespace {
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
pipelineDescriptor.vertex.module = vsModule;
pipelineDescriptor.cFragment.module = fsModule;
pipelineDescriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
pipelineDescriptor.layout = utils::MakeBasicPipelineLayout(device, nullptr);
return device.CreateRenderPipeline(&pipelineDescriptor);
}
@@ -768,6 +769,7 @@ namespace {
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
pipelineDescriptor.vertex.module = vsModule;
pipelineDescriptor.cFragment.module = fsModule;
pipelineDescriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
pipelineDescriptor.layout = utils::MakeBasicPipelineLayout(device, &bgl0);
wgpu::RenderPipeline rp = device.CreateRenderPipeline(&pipelineDescriptor);
@@ -1578,6 +1580,7 @@ namespace {
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
pipelineDescriptor.vertex.module = vsModule;
pipelineDescriptor.cFragment.module = fsModule;
pipelineDescriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
pipelineDescriptor.layout = utils::MakeBasicPipelineLayout(device, &readBGL);
wgpu::RenderPipeline rp = device.CreateRenderPipeline(&pipelineDescriptor);

View File

@@ -178,6 +178,7 @@ TEST_F(StorageTextureValidationTests, RenderPipeline) {
descriptor.layout = nullptr;
descriptor.vertex.module = mDefaultVSModule;
descriptor.cFragment.module = fsModule;
descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
device.CreateRenderPipeline(&descriptor);
}
}

View File

@@ -55,6 +55,7 @@ TEST_F(UnsafeAPIValidationTest, DrawIndexedIndirectDisallowed) {
return vec4<f32>();
})");
desc.cFragment.module = utils::CreateShaderModule(device, "[[stage(fragment)]] fn main() {}");
desc.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&desc);
// Control cases: DrawIndirect and DrawIndexed are allowed inside a render pass.