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:
parent
4840b8a518
commit
821b1cbf96
|
@ -277,10 +277,17 @@ namespace dawn_native {
|
||||||
return DAWN_VALIDATION_ERROR(
|
return DAWN_VALIDATION_ERROR(
|
||||||
"Color format must be blendable when blending is enabled");
|
"Color format must be blendable when blending is enabled");
|
||||||
}
|
}
|
||||||
if (fragmentWritten &&
|
if (fragmentWritten) {
|
||||||
fragmentOutputBaseType != format->GetAspectInfo(Aspect::Color).baseType) {
|
if (fragmentOutputBaseType != format->GetAspectInfo(Aspect::Color).baseType) {
|
||||||
return DAWN_VALIDATION_ERROR(
|
return DAWN_VALIDATION_ERROR(
|
||||||
"Color format must match the fragment stage output type");
|
"Color format must match the fragment stage output type");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (descriptor->writeMask != wgpu::ColorWriteMask::None) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"writeMask must be zero for color targets with no corresponding fragment "
|
||||||
|
"stage output");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -155,6 +155,7 @@ struct FragInputs {
|
||||||
pipelineDesc.cBuffers[0].attributeCount = 1;
|
pipelineDesc.cBuffers[0].attributeCount = 1;
|
||||||
pipelineDesc.cAttributes[0].format = wgpu::VertexFormat::Float32x4;
|
pipelineDesc.cAttributes[0].format = wgpu::VertexFormat::Float32x4;
|
||||||
pipelineDesc.cTargets[0].format = renderPass.colorFormat;
|
pipelineDesc.cTargets[0].format = renderPass.colorFormat;
|
||||||
|
pipelineDesc.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
|
||||||
|
|
||||||
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDesc);
|
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDesc);
|
||||||
|
|
||||||
|
|
|
@ -208,6 +208,7 @@ TEST_P(ObjectCachingTest, RenderPipelineDeduplicationOnLayout) {
|
||||||
EXPECT_EQ(pl.Get() == samePl.Get(), !UsesWire());
|
EXPECT_EQ(pl.Get() == samePl.Get(), !UsesWire());
|
||||||
|
|
||||||
utils::ComboRenderPipelineDescriptor desc;
|
utils::ComboRenderPipelineDescriptor desc;
|
||||||
|
desc.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
|
||||||
desc.vertex.module = utils::CreateShaderModule(device, R"(
|
desc.vertex.module = utils::CreateShaderModule(device, R"(
|
||||||
[[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> {
|
[[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> {
|
||||||
return vec4<f32>(0.0, 0.0, 0.0, 0.0);
|
return vec4<f32>(0.0, 0.0, 0.0, 0.0);
|
||||||
|
@ -248,6 +249,7 @@ TEST_P(ObjectCachingTest, RenderPipelineDeduplicationOnVertexModule) {
|
||||||
EXPECT_EQ(module.Get() == sameModule.Get(), !UsesWire());
|
EXPECT_EQ(module.Get() == sameModule.Get(), !UsesWire());
|
||||||
|
|
||||||
utils::ComboRenderPipelineDescriptor desc;
|
utils::ComboRenderPipelineDescriptor desc;
|
||||||
|
desc.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
|
||||||
desc.cFragment.module = utils::CreateShaderModule(device, R"(
|
desc.cFragment.module = utils::CreateShaderModule(device, R"(
|
||||||
[[stage(fragment)]] fn main() {
|
[[stage(fragment)]] fn main() {
|
||||||
})");
|
})");
|
||||||
|
@ -288,6 +290,7 @@ TEST_P(ObjectCachingTest, RenderPipelineDeduplicationOnFragmentModule) {
|
||||||
})");
|
})");
|
||||||
|
|
||||||
desc.cFragment.module = module;
|
desc.cFragment.module = module;
|
||||||
|
desc.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
|
||||||
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&desc);
|
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&desc);
|
||||||
|
|
||||||
desc.cFragment.module = sameModule;
|
desc.cFragment.module = sameModule;
|
||||||
|
|
|
@ -145,6 +145,7 @@ TEST_P(RenderPassTest, NoCorrespondingFragmentShaderOutputs) {
|
||||||
descriptor.cFragment.module = fsModule;
|
descriptor.cFragment.module = fsModule;
|
||||||
descriptor.primitive.topology = wgpu::PrimitiveTopology::TriangleList;
|
descriptor.primitive.topology = wgpu::PrimitiveTopology::TriangleList;
|
||||||
descriptor.cTargets[0].format = kFormat;
|
descriptor.cTargets[0].format = kFormat;
|
||||||
|
descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
|
||||||
|
|
||||||
wgpu::RenderPipeline pipelineWithNoFragmentOutput =
|
wgpu::RenderPipeline pipelineWithNoFragmentOutput =
|
||||||
device.CreateRenderPipeline(&descriptor);
|
device.CreateRenderPipeline(&descriptor);
|
||||||
|
|
|
@ -370,12 +370,17 @@ fn IsEqualTo(pixel : vec4<f32>, expected : vec4<f32>) -> bool {
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
auto workgroupSize = !strcmp(stage, "compute") ? ", workgroup_size(1)" : "";
|
const char* workgroupSize = !strcmp(stage, "compute") ? ", workgroup_size(1)" : "";
|
||||||
|
const bool isFragment = strcmp(stage, "fragment") == 0;
|
||||||
|
|
||||||
std::ostringstream ostream;
|
std::ostringstream ostream;
|
||||||
ostream << GetImageDeclaration(format, "write", dimension, 0) << "\n";
|
ostream << GetImageDeclaration(format, "write", dimension, 0) << "\n";
|
||||||
ostream << "[[stage(" << stage << ")" << workgroupSize << "]]\n";
|
ostream << "[[stage(" << stage << ")" << workgroupSize << "]]\n";
|
||||||
ostream << "fn main() {\n";
|
ostream << "fn main() ";
|
||||||
|
if (isFragment) {
|
||||||
|
ostream << "-> [[location(0)]] vec4<f32> ";
|
||||||
|
}
|
||||||
|
ostream << "{\n";
|
||||||
ostream << " let size : vec2<i32> = textureDimensions(storageImage0).xy;\n";
|
ostream << " let size : vec2<i32> = textureDimensions(storageImage0).xy;\n";
|
||||||
ostream << " let sliceCount : i32 = " << sliceCount << ";\n";
|
ostream << " let sliceCount : i32 = " << sliceCount << ";\n";
|
||||||
ostream << " for (var slice : i32 = 0; slice < sliceCount; slice = slice + 1) {\n";
|
ostream << " for (var slice : i32 = 0; slice < sliceCount; slice = slice + 1) {\n";
|
||||||
|
@ -388,6 +393,9 @@ fn IsEqualTo(pixel : vec4<f32>, expected : vec4<f32>) -> bool {
|
||||||
ostream << " }\n";
|
ostream << " }\n";
|
||||||
ostream << " }\n";
|
ostream << " }\n";
|
||||||
ostream << " }\n";
|
ostream << " }\n";
|
||||||
|
if (isFragment) {
|
||||||
|
ostream << "return vec4<f32>();\n";
|
||||||
|
}
|
||||||
ostream << "}\n";
|
ostream << "}\n";
|
||||||
|
|
||||||
return ostream.str();
|
return ostream.str();
|
||||||
|
@ -616,11 +624,11 @@ fn IsEqualTo(pixel : vec4<f32>, expected : vec4<f32>) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteIntoStorageTextureInRenderPass(wgpu::Texture writeonlyStorageTexture,
|
void WriteIntoStorageTextureInRenderPass(wgpu::Texture writeonlyStorageTexture,
|
||||||
const char* kVertexShader,
|
const char* vertexShader,
|
||||||
const char* kFragmentShader) {
|
const char* fragmentShader) {
|
||||||
// Create a render pipeline that writes the expected pixel values into the storage texture
|
// Create a render pipeline that writes the expected pixel values into the storage texture
|
||||||
// without fragment shader outputs.
|
// without fragment shader outputs.
|
||||||
wgpu::RenderPipeline pipeline = CreateRenderPipeline(kVertexShader, kFragmentShader);
|
wgpu::RenderPipeline pipeline = CreateRenderPipeline(vertexShader, fragmentShader);
|
||||||
wgpu::BindGroup bindGroup = utils::MakeBindGroup(
|
wgpu::BindGroup bindGroup = utils::MakeBindGroup(
|
||||||
device, pipeline.GetBindGroupLayout(0), {{0, writeonlyStorageTexture.CreateView()}});
|
device, pipeline.GetBindGroupLayout(0), {{0, writeonlyStorageTexture.CreateView()}});
|
||||||
|
|
||||||
|
@ -1263,8 +1271,9 @@ fn doTest() -> bool {
|
||||||
const char* kCommonWriteOnlyZeroInitTestCodeFragment = R"(
|
const char* kCommonWriteOnlyZeroInitTestCodeFragment = R"(
|
||||||
[[group(0), binding(0)]] var dstImage : texture_storage_2d<r32uint, write>;
|
[[group(0), binding(0)]] var dstImage : texture_storage_2d<r32uint, write>;
|
||||||
|
|
||||||
[[stage(fragment)]] fn main() {
|
[[stage(fragment)]] fn main() -> [[location(0)]] vec4<f32> {
|
||||||
textureStore(dstImage, vec2<i32>(0, 0), vec4<u32>(1u, 0u, 0u, 1u));
|
textureStore(dstImage, vec2<i32>(0, 0), vec4<u32>(1u, 0u, 0u, 1u));
|
||||||
|
return vec4<f32>();
|
||||||
})";
|
})";
|
||||||
const char* kCommonWriteOnlyZeroInitTestCodeCompute = R"(
|
const char* kCommonWriteOnlyZeroInitTestCodeCompute = R"(
|
||||||
[[group(0), binding(0)]] var dstImage : texture_storage_2d<r32uint, write>;
|
[[group(0), binding(0)]] var dstImage : texture_storage_2d<r32uint, write>;
|
||||||
|
|
|
@ -226,8 +226,15 @@ TEST_P(SwapChainValidationTests, ReturnedViewCharacteristics) {
|
||||||
return vec4<f32>(0.0, 0.0, 0.0, 1.0);
|
return vec4<f32>(0.0, 0.0, 0.0, 1.0);
|
||||||
})");
|
})");
|
||||||
pipelineDesc.cFragment.module = utils::CreateShaderModule(device, R"(
|
pipelineDesc.cFragment.module = utils::CreateShaderModule(device, R"(
|
||||||
[[stage(fragment)]] fn main() -> [[location(0)]] vec4<f32> {
|
struct FragmentOut {
|
||||||
return vec4<f32>(0.0, 1.0, 0.0, 1.0);
|
[[location(0)]] target0 : vec4<f32>;
|
||||||
|
[[location(1)]] target1 : f32;
|
||||||
|
};
|
||||||
|
[[stage(fragment)]] fn main() -> FragmentOut {
|
||||||
|
var out : FragmentOut;
|
||||||
|
out.target0 = vec4<f32>(0.0, 1.0, 0.0, 1.0);
|
||||||
|
out.target1 = 0.5;
|
||||||
|
return out;
|
||||||
})");
|
})");
|
||||||
// Validation will check that the sample count of the view matches this format.
|
// Validation will check that the sample count of the view matches this format.
|
||||||
pipelineDesc.multisample.count = 1;
|
pipelineDesc.multisample.count = 1;
|
||||||
|
|
|
@ -1359,6 +1359,7 @@ class SetBindGroupValidationTest : public ValidationTest {
|
||||||
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
|
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
|
||||||
pipelineDescriptor.vertex.module = vsModule;
|
pipelineDescriptor.vertex.module = vsModule;
|
||||||
pipelineDescriptor.cFragment.module = fsModule;
|
pipelineDescriptor.cFragment.module = fsModule;
|
||||||
|
pipelineDescriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
|
||||||
wgpu::PipelineLayout pipelineLayout =
|
wgpu::PipelineLayout pipelineLayout =
|
||||||
utils::MakeBasicPipelineLayout(device, &mBindGroupLayout);
|
utils::MakeBasicPipelineLayout(device, &mBindGroupLayout);
|
||||||
pipelineDescriptor.layout = pipelineLayout;
|
pipelineDescriptor.layout = pipelineLayout;
|
||||||
|
@ -1818,6 +1819,7 @@ class SetBindGroupPersistenceValidationTest : public ValidationTest {
|
||||||
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
|
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
|
||||||
pipelineDescriptor.vertex.module = mVsModule;
|
pipelineDescriptor.vertex.module = mVsModule;
|
||||||
pipelineDescriptor.cFragment.module = fsModule;
|
pipelineDescriptor.cFragment.module = fsModule;
|
||||||
|
pipelineDescriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
|
||||||
pipelineDescriptor.layout = pipelineLayout;
|
pipelineDescriptor.layout = pipelineLayout;
|
||||||
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDescriptor);
|
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDescriptor);
|
||||||
|
|
||||||
|
@ -1957,6 +1959,7 @@ class BindGroupLayoutCompatibilityTest : public ValidationTest {
|
||||||
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
|
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
|
||||||
pipelineDescriptor.vertex.module = vsModule;
|
pipelineDescriptor.vertex.module = vsModule;
|
||||||
pipelineDescriptor.cFragment.module = fsModule;
|
pipelineDescriptor.cFragment.module = fsModule;
|
||||||
|
pipelineDescriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
|
||||||
wgpu::PipelineLayout pipelineLayout = device.CreatePipelineLayout(&descriptor);
|
wgpu::PipelineLayout pipelineLayout = device.CreatePipelineLayout(&descriptor);
|
||||||
pipelineDescriptor.layout = pipelineLayout;
|
pipelineDescriptor.layout = pipelineLayout;
|
||||||
return device.CreateRenderPipeline(&pipelineDescriptor);
|
return device.CreateRenderPipeline(&pipelineDescriptor);
|
||||||
|
@ -2350,6 +2353,7 @@ class SamplerTypeBindingTest : public ValidationTest {
|
||||||
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
|
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
|
||||||
pipelineDescriptor.vertex.module = vsModule;
|
pipelineDescriptor.vertex.module = vsModule;
|
||||||
pipelineDescriptor.cFragment.module = fsModule;
|
pipelineDescriptor.cFragment.module = fsModule;
|
||||||
|
pipelineDescriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
|
||||||
wgpu::PipelineLayout pipelineLayout =
|
wgpu::PipelineLayout pipelineLayout =
|
||||||
utils::MakeBasicPipelineLayout(device, bindGroupLayout);
|
utils::MakeBasicPipelineLayout(device, bindGroupLayout);
|
||||||
pipelineDescriptor.layout = pipelineLayout;
|
pipelineDescriptor.layout = pipelineLayout;
|
||||||
|
|
|
@ -31,6 +31,7 @@ class GetBindGroupLayoutTests : public ValidationTest {
|
||||||
descriptor.layout = nullptr;
|
descriptor.layout = nullptr;
|
||||||
descriptor.vertex.module = vsModule;
|
descriptor.vertex.module = vsModule;
|
||||||
descriptor.cFragment.module = fsModule;
|
descriptor.cFragment.module = fsModule;
|
||||||
|
descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
|
||||||
|
|
||||||
return device.CreateRenderPipeline(&descriptor);
|
return device.CreateRenderPipeline(&descriptor);
|
||||||
}
|
}
|
||||||
|
@ -77,6 +78,7 @@ TEST_F(GetBindGroupLayoutTests, SameObject) {
|
||||||
descriptor.layout = nullptr;
|
descriptor.layout = nullptr;
|
||||||
descriptor.vertex.module = vsModule;
|
descriptor.vertex.module = vsModule;
|
||||||
descriptor.cFragment.module = fsModule;
|
descriptor.cFragment.module = fsModule;
|
||||||
|
descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
|
||||||
|
|
||||||
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor);
|
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor);
|
||||||
|
|
||||||
|
@ -213,6 +215,7 @@ TEST_F(GetBindGroupLayoutTests, DefaultTextureSampleType) {
|
||||||
utils::ComboRenderPipelineDescriptor descriptor;
|
utils::ComboRenderPipelineDescriptor descriptor;
|
||||||
descriptor.vertex.module = vertexModule;
|
descriptor.vertex.module = vertexModule;
|
||||||
descriptor.cFragment.module = fragmentModule;
|
descriptor.cFragment.module = fragmentModule;
|
||||||
|
descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
|
||||||
return device.CreateRenderPipeline(&descriptor).GetBindGroupLayout(0);
|
return device.CreateRenderPipeline(&descriptor).GetBindGroupLayout(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -637,6 +640,7 @@ TEST_F(GetBindGroupLayoutTests, DuplicateBinding) {
|
||||||
descriptor.layout = nullptr;
|
descriptor.layout = nullptr;
|
||||||
descriptor.vertex.module = vsModule;
|
descriptor.vertex.module = vsModule;
|
||||||
descriptor.cFragment.module = fsModule;
|
descriptor.cFragment.module = fsModule;
|
||||||
|
descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
|
||||||
|
|
||||||
device.CreateRenderPipeline(&descriptor);
|
device.CreateRenderPipeline(&descriptor);
|
||||||
}
|
}
|
||||||
|
@ -707,6 +711,7 @@ TEST_F(GetBindGroupLayoutTests, MinBufferSize) {
|
||||||
|
|
||||||
utils::ComboRenderPipelineDescriptor descriptor;
|
utils::ComboRenderPipelineDescriptor descriptor;
|
||||||
descriptor.layout = nullptr;
|
descriptor.layout = nullptr;
|
||||||
|
descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
|
||||||
|
|
||||||
// Check with both stages using 4 bytes.
|
// Check with both stages using 4 bytes.
|
||||||
{
|
{
|
||||||
|
@ -773,6 +778,7 @@ TEST_F(GetBindGroupLayoutTests, StageAggregation) {
|
||||||
|
|
||||||
utils::ComboRenderPipelineDescriptor descriptor;
|
utils::ComboRenderPipelineDescriptor descriptor;
|
||||||
descriptor.layout = nullptr;
|
descriptor.layout = nullptr;
|
||||||
|
descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
|
||||||
|
|
||||||
// Check with only the vertex shader using the sampler
|
// Check with only the vertex shader using the sampler
|
||||||
{
|
{
|
||||||
|
@ -999,6 +1005,7 @@ TEST_F(GetBindGroupLayoutTests, Reflection) {
|
||||||
pipelineDesc.layout = pipelineLayout;
|
pipelineDesc.layout = pipelineLayout;
|
||||||
pipelineDesc.vertex.module = vsModule;
|
pipelineDesc.vertex.module = vsModule;
|
||||||
pipelineDesc.cFragment.module = fsModule;
|
pipelineDesc.cFragment.module = fsModule;
|
||||||
|
pipelineDesc.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
|
||||||
|
|
||||||
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDesc);
|
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDesc);
|
||||||
|
|
||||||
|
|
|
@ -193,6 +193,7 @@ class MinBufferSizeTestsBase : public ValidationTest {
|
||||||
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
|
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
|
||||||
pipelineDescriptor.vertex.module = vsModule;
|
pipelineDescriptor.vertex.module = vsModule;
|
||||||
pipelineDescriptor.cFragment.module = fsModule;
|
pipelineDescriptor.cFragment.module = fsModule;
|
||||||
|
pipelineDescriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
|
||||||
pipelineDescriptor.layout = nullptr;
|
pipelineDescriptor.layout = nullptr;
|
||||||
if (!layouts.empty()) {
|
if (!layouts.empty()) {
|
||||||
wgpu::PipelineLayoutDescriptor descriptor;
|
wgpu::PipelineLayoutDescriptor descriptor;
|
||||||
|
|
|
@ -102,6 +102,7 @@ namespace {
|
||||||
descriptor->layout = pipelineLayout;
|
descriptor->layout = pipelineLayout;
|
||||||
descriptor->vertex.module = vsModule;
|
descriptor->vertex.module = vsModule;
|
||||||
descriptor->cFragment.module = fsModule;
|
descriptor->cFragment.module = fsModule;
|
||||||
|
descriptor->cTargets[0].writeMask = wgpu::ColorWriteMask::None;
|
||||||
descriptor->vertex.bufferCount = 1;
|
descriptor->vertex.bufferCount = 1;
|
||||||
descriptor->cBuffers[0].arrayStride = 2 * sizeof(float);
|
descriptor->cBuffers[0].arrayStride = 2 * sizeof(float);
|
||||||
descriptor->cBuffers[0].attributeCount = 1;
|
descriptor->cBuffers[0].attributeCount = 1;
|
||||||
|
@ -735,6 +736,9 @@ TEST_F(RenderBundleValidationTest, PipelineColorFormatMismatch) {
|
||||||
desc->cTargets[0].format = wgpu::TextureFormat::RGBA8Unorm;
|
desc->cTargets[0].format = wgpu::TextureFormat::RGBA8Unorm;
|
||||||
desc->cTargets[1].format = wgpu::TextureFormat::RG16Float;
|
desc->cTargets[1].format = wgpu::TextureFormat::RG16Float;
|
||||||
desc->cTargets[2].format = wgpu::TextureFormat::R16Sint;
|
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.
|
// Test the success case.
|
||||||
|
|
|
@ -456,6 +456,7 @@ TEST_F(RenderPipelineValidationTest, TextureComponentTypeCompatibility) {
|
||||||
ignore(textureDimensions(myTexture));
|
ignore(textureDimensions(myTexture));
|
||||||
})";
|
})";
|
||||||
descriptor.cFragment.module = utils::CreateShaderModule(device, stream.str().c_str());
|
descriptor.cFragment.module = utils::CreateShaderModule(device, stream.str().c_str());
|
||||||
|
descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
|
||||||
|
|
||||||
wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
|
wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
|
||||||
device, {{0, wgpu::ShaderStage::Fragment, kTextureComponentTypes[j]}});
|
device, {{0, wgpu::ShaderStage::Fragment, kTextureComponentTypes[j]}});
|
||||||
|
@ -504,6 +505,7 @@ TEST_F(RenderPipelineValidationTest, TextureViewDimensionCompatibility) {
|
||||||
ignore(textureDimensions(myTexture));
|
ignore(textureDimensions(myTexture));
|
||||||
})";
|
})";
|
||||||
descriptor.cFragment.module = utils::CreateShaderModule(device, stream.str().c_str());
|
descriptor.cFragment.module = utils::CreateShaderModule(device, stream.str().c_str());
|
||||||
|
descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
|
||||||
|
|
||||||
wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
|
wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
|
||||||
device, {{0, wgpu::ShaderStage::Fragment, wgpu::TextureSampleType::Float,
|
device, {{0, wgpu::ShaderStage::Fragment, wgpu::TextureSampleType::Float,
|
||||||
|
@ -753,6 +755,138 @@ TEST_F(RenderPipelineValidationTest, FragmentOutputCorrectEntryPoint) {
|
||||||
ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
|
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
|
// 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.
|
// TODO(dawn:216): Re-enable when we correctly reflect which bindings are used for an entryPoint.
|
||||||
TEST_F(RenderPipelineValidationTest, DISABLED_BindingsFromCorrectEntryPoint) {
|
TEST_F(RenderPipelineValidationTest, DISABLED_BindingsFromCorrectEntryPoint) {
|
||||||
|
|
|
@ -57,6 +57,7 @@ namespace {
|
||||||
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
|
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
|
||||||
pipelineDescriptor.vertex.module = vsModule;
|
pipelineDescriptor.vertex.module = vsModule;
|
||||||
pipelineDescriptor.cFragment.module = fsModule;
|
pipelineDescriptor.cFragment.module = fsModule;
|
||||||
|
pipelineDescriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
|
||||||
pipelineDescriptor.layout = utils::MakeBasicPipelineLayout(device, nullptr);
|
pipelineDescriptor.layout = utils::MakeBasicPipelineLayout(device, nullptr);
|
||||||
return device.CreateRenderPipeline(&pipelineDescriptor);
|
return device.CreateRenderPipeline(&pipelineDescriptor);
|
||||||
}
|
}
|
||||||
|
@ -768,6 +769,7 @@ namespace {
|
||||||
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
|
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
|
||||||
pipelineDescriptor.vertex.module = vsModule;
|
pipelineDescriptor.vertex.module = vsModule;
|
||||||
pipelineDescriptor.cFragment.module = fsModule;
|
pipelineDescriptor.cFragment.module = fsModule;
|
||||||
|
pipelineDescriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
|
||||||
pipelineDescriptor.layout = utils::MakeBasicPipelineLayout(device, &bgl0);
|
pipelineDescriptor.layout = utils::MakeBasicPipelineLayout(device, &bgl0);
|
||||||
wgpu::RenderPipeline rp = device.CreateRenderPipeline(&pipelineDescriptor);
|
wgpu::RenderPipeline rp = device.CreateRenderPipeline(&pipelineDescriptor);
|
||||||
|
|
||||||
|
@ -1578,6 +1580,7 @@ namespace {
|
||||||
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
|
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
|
||||||
pipelineDescriptor.vertex.module = vsModule;
|
pipelineDescriptor.vertex.module = vsModule;
|
||||||
pipelineDescriptor.cFragment.module = fsModule;
|
pipelineDescriptor.cFragment.module = fsModule;
|
||||||
|
pipelineDescriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
|
||||||
pipelineDescriptor.layout = utils::MakeBasicPipelineLayout(device, &readBGL);
|
pipelineDescriptor.layout = utils::MakeBasicPipelineLayout(device, &readBGL);
|
||||||
wgpu::RenderPipeline rp = device.CreateRenderPipeline(&pipelineDescriptor);
|
wgpu::RenderPipeline rp = device.CreateRenderPipeline(&pipelineDescriptor);
|
||||||
|
|
||||||
|
|
|
@ -178,6 +178,7 @@ TEST_F(StorageTextureValidationTests, RenderPipeline) {
|
||||||
descriptor.layout = nullptr;
|
descriptor.layout = nullptr;
|
||||||
descriptor.vertex.module = mDefaultVSModule;
|
descriptor.vertex.module = mDefaultVSModule;
|
||||||
descriptor.cFragment.module = fsModule;
|
descriptor.cFragment.module = fsModule;
|
||||||
|
descriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
|
||||||
device.CreateRenderPipeline(&descriptor);
|
device.CreateRenderPipeline(&descriptor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,7 @@ TEST_F(UnsafeAPIValidationTest, DrawIndexedIndirectDisallowed) {
|
||||||
return vec4<f32>();
|
return vec4<f32>();
|
||||||
})");
|
})");
|
||||||
desc.cFragment.module = utils::CreateShaderModule(device, "[[stage(fragment)]] fn main() {}");
|
desc.cFragment.module = utils::CreateShaderModule(device, "[[stage(fragment)]] fn main() {}");
|
||||||
|
desc.cTargets[0].writeMask = wgpu::ColorWriteMask::None;
|
||||||
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&desc);
|
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&desc);
|
||||||
|
|
||||||
// Control cases: DrawIndirect and DrawIndexed are allowed inside a render pass.
|
// Control cases: DrawIndirect and DrawIndexed are allowed inside a render pass.
|
||||||
|
|
Loading…
Reference in New Issue