Implement readonly depth/stencil without sample from it

This change add a couple end2end tests when readonly depth/stencil
attahcment is enabled in render pass and the pipeline doesn't
sample from the depth/stencil attachment. The pipeline only do
depth/stencil test.

This situation may not be useful in real world applications. But
it is possible that developers do it in this way. And it impacts
the implementation on some backend like Vulkan.

Bug: dawn:485
Change-Id: I8a81330659295cd4a2f00591b6ead719538babd9
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/71441
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Yunchao He <yunchao.he@intel.com>
This commit is contained in:
Yunchao He 2021-12-21 04:02:22 +00:00 committed by Dawn LUCI CQ
parent bd5eb6fa26
commit b9467591a4
2 changed files with 91 additions and 26 deletions

View File

@ -537,6 +537,9 @@ namespace dawn_native { namespace vulkan {
return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
}
case kReadOnlyRenderAttachment:
return VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
case kPresentTextureUsage:
return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;

View File

@ -61,7 +61,8 @@ class ReadOnlyDepthStencilAttachmentTests
}
wgpu::RenderPipeline CreateRenderPipeline(wgpu::TextureAspect aspect,
wgpu::TextureFormat format) {
wgpu::TextureFormat format,
bool sampleFromAttachment) {
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
// Draw a rectangle via two triangles. The depth value of the top of the rectangle is 0.4.
@ -83,8 +84,16 @@ class ReadOnlyDepthStencilAttachmentTests
return vec4<f32>(pos[VertexIndex], 1.0);
})");
if (aspect == wgpu::TextureAspect::DepthOnly) {
if (!sampleFromAttachment) {
// Draw a solid blue into color buffer if not sample from depth/stencil attachment.
pipelineDescriptor.cFragment.module = utils::CreateShaderModule(device, R"(
[[stage(fragment)]] fn main() -> [[location(0)]] vec4<f32> {
return vec4<f32>(0.0, 0.0, 1.0, 0.0);
})");
} else {
// Sample from depth/stencil attachment and draw that sampled texel into color buffer.
if (aspect == wgpu::TextureAspect::DepthOnly) {
pipelineDescriptor.cFragment.module = utils::CreateShaderModule(device, R"(
[[group(0), binding(0)]] var samp : sampler;
[[group(0), binding(1)]] var tex : texture_depth_2d;
@ -92,23 +101,24 @@ class ReadOnlyDepthStencilAttachmentTests
fn main([[builtin(position)]] FragCoord : vec4<f32>) -> [[location(0)]] vec4<f32> {
return vec4<f32>(textureSample(tex, samp, FragCoord.xy), 0.0, 0.0, 0.0);
})");
// Enable depth test. But depth write is not enabled.
wgpu::DepthStencilState* depthStencil = pipelineDescriptor.EnableDepthStencil(format);
depthStencil->depthCompare = wgpu::CompareFunction::LessEqual;
} else {
ASSERT(aspect == wgpu::TextureAspect::StencilOnly);
pipelineDescriptor.cFragment.module = utils::CreateShaderModule(device, R"(
} else {
ASSERT(aspect == wgpu::TextureAspect::StencilOnly);
pipelineDescriptor.cFragment.module = utils::CreateShaderModule(device, R"(
[[group(0), binding(0)]] var tex : texture_2d<u32>;
[[stage(fragment)]]
fn main([[builtin(position)]] FragCoord : vec4<f32>) -> [[location(0)]] vec4<f32> {
var texel = textureLoad(tex, vec2<i32>(FragCoord.xy), 0);
var texel = textureLoad(tex, vec2<i32>(FragCoord.xy), 0);
return vec4<f32>(f32(texel[0]) / 255.0, 0.0, 0.0, 0.0);
})");
}
}
// Enable stencil test. But stencil write is not enabled.
wgpu::DepthStencilState* depthStencil = pipelineDescriptor.EnableDepthStencil(format);
// Enable depth or stencil test. But depth/stencil write is not enabled.
wgpu::DepthStencilState* depthStencil = pipelineDescriptor.EnableDepthStencil(format);
if (aspect == wgpu::TextureAspect::DepthOnly) {
depthStencil->depthCompare = wgpu::CompareFunction::LessEqual;
} else {
depthStencil->stencilFront.compare = wgpu::CompareFunction::LessEqual;
}
@ -126,7 +136,8 @@ class ReadOnlyDepthStencilAttachmentTests
void DoTest(wgpu::TextureAspect aspect,
wgpu::TextureFormat format,
wgpu::Texture colorTexture,
DepthStencilValues* values) {
DepthStencilValues* values,
bool sampleFromAttachment) {
wgpu::Texture depthStencilTexture = CreateTexture(
format, wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TextureBinding);
@ -165,18 +176,22 @@ class ReadOnlyDepthStencilAttachmentTests
// been initialized. The pipeline in this render pass will sample from the attachment.
// The pipeline will read from the attachment to do depth/stencil test too.
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
wgpu::RenderPipeline pipeline = CreateRenderPipeline(aspect, format);
wgpu::RenderPipeline pipeline = CreateRenderPipeline(aspect, format, sampleFromAttachment);
pass.SetPipeline(pipeline);
if (aspect == wgpu::TextureAspect::DepthOnly) {
wgpu::BindGroup bindGroup = utils::MakeBindGroup(
device, pipeline.GetBindGroupLayout(0),
{{0, device.CreateSampler()}, {1, depthStencilViewInBindGroup}});
pass.SetBindGroup(0, bindGroup);
if (sampleFromAttachment) {
wgpu::BindGroup bindGroup = utils::MakeBindGroup(
device, pipeline.GetBindGroupLayout(0),
{{0, device.CreateSampler()}, {1, depthStencilViewInBindGroup}});
pass.SetBindGroup(0, bindGroup);
}
} else {
ASSERT(aspect == wgpu::TextureAspect::StencilOnly);
wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
{{0, depthStencilViewInBindGroup}});
pass.SetBindGroup(0, bindGroup);
if (sampleFromAttachment) {
wgpu::BindGroup bindGroup = utils::MakeBindGroup(
device, pipeline.GetBindGroupLayout(0), {{0, depthStencilViewInBindGroup}});
pass.SetBindGroup(0, bindGroup);
}
pass.SetStencilReference(values->stencilRefValue);
}
pass.Draw(6);
@ -198,7 +213,7 @@ class ReadOnlyDepthAttachmentTests : public ReadOnlyDepthStencilAttachmentTests
}
};
TEST_P(ReadOnlyDepthAttachmentTests, Test) {
TEST_P(ReadOnlyDepthAttachmentTests, SampleFromAttachment) {
wgpu::Texture colorTexture =
CreateTexture(wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc);
@ -207,7 +222,8 @@ TEST_P(ReadOnlyDepthAttachmentTests, Test) {
DepthStencilValues values;
values.depthInitValue = 0.2;
DoTest(wgpu::TextureAspect::DepthOnly, depthFormat, colorTexture, &values);
DoTest(wgpu::TextureAspect::DepthOnly, depthFormat, colorTexture, &values, true);
// The top part is not rendered by the pipeline. Its color is the default clear color for
// color attachment.
@ -221,6 +237,28 @@ TEST_P(ReadOnlyDepthAttachmentTests, Test) {
{kSize, kSize / 2});
}
TEST_P(ReadOnlyDepthAttachmentTests, NotSampleFromAttachment) {
wgpu::Texture colorTexture =
CreateTexture(wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc);
wgpu::TextureFormat depthFormat = GetParam().mTextureFormat;
DepthStencilValues values;
values.depthInitValue = 0.2;
DoTest(wgpu::TextureAspect::DepthOnly, depthFormat, colorTexture, &values, false);
// The top part is not rendered by the pipeline. Its color is the default clear color for
// color attachment.
const std::vector<RGBA8> kExpectedTopColors(kSize * kSize / 2, {0, 0, 0, 0});
// The bottom part is rendered. Its color is set to blue.
const std::vector<RGBA8> kExpectedBottomColors(kSize * kSize / 2, {0, 0, 255, 0});
EXPECT_TEXTURE_EQ(kExpectedTopColors.data(), colorTexture, {0, 0}, {kSize, kSize / 2});
EXPECT_TEXTURE_EQ(kExpectedBottomColors.data(), colorTexture, {0, kSize / 2},
{kSize, kSize / 2});
}
class ReadOnlyStencilAttachmentTests : public ReadOnlyDepthStencilAttachmentTests {
protected:
void SetUp() override {
@ -229,7 +267,7 @@ class ReadOnlyStencilAttachmentTests : public ReadOnlyDepthStencilAttachmentTest
}
};
TEST_P(ReadOnlyStencilAttachmentTests, Test) {
TEST_P(ReadOnlyStencilAttachmentTests, SampleFromAttachment) {
wgpu::Texture colorTexture =
CreateTexture(wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc);
@ -241,14 +279,38 @@ TEST_P(ReadOnlyStencilAttachmentTests, Test) {
values.stencilRefValue = 2;
// stencilRefValue < stencilValue (stencilInitValue), so stencil test passes. The pipeline
// samples from stencil buffer and writes into color buffer.
DoTest(wgpu::TextureAspect::StencilOnly, stencilFormat, colorTexture, &values);
DoTest(wgpu::TextureAspect::StencilOnly, stencilFormat, colorTexture, &values, true);
const std::vector<RGBA8> kSampledColors(kSize * kSize, {3, 0, 0, 0});
EXPECT_TEXTURE_EQ(kSampledColors.data(), colorTexture, {0, 0}, {kSize, kSize});
values.stencilInitValue = 1;
// stencilRefValue > stencilValue (stencilInitValue), so stencil test fails. The pipeline
// doesn't change color buffer. Sampled data from stencil buffer is discarded.
DoTest(wgpu::TextureAspect::StencilOnly, stencilFormat, colorTexture, &values);
DoTest(wgpu::TextureAspect::StencilOnly, stencilFormat, colorTexture, &values, true);
const std::vector<RGBA8> kInitColors(kSize * kSize, {0, 0, 0, 0});
EXPECT_TEXTURE_EQ(kInitColors.data(), colorTexture, {0, 0}, {kSize, kSize});
}
TEST_P(ReadOnlyStencilAttachmentTests, NotSampleFromAttachment) {
wgpu::Texture colorTexture =
CreateTexture(wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc);
wgpu::TextureFormat stencilFormat = GetParam().mTextureFormat;
DepthStencilValues values;
values.stencilInitValue = 3;
values.stencilRefValue = 2;
// stencilRefValue < stencilValue (stencilInitValue), so stencil test passes. The pipeline
// draw solid blue into color buffer.
DoTest(wgpu::TextureAspect::StencilOnly, stencilFormat, colorTexture, &values, false);
const std::vector<RGBA8> kSampledColors(kSize * kSize, {0, 0, 255, 0});
EXPECT_TEXTURE_EQ(kSampledColors.data(), colorTexture, {0, 0}, {kSize, kSize});
values.stencilInitValue = 1;
// stencilRefValue > stencilValue (stencilInitValue), so stencil test fails. The pipeline
// doesn't change color buffer. drawing data is discarded.
DoTest(wgpu::TextureAspect::StencilOnly, stencilFormat, colorTexture, &values, false);
const std::vector<RGBA8> kInitColors(kSize * kSize, {0, 0, 0, 0});
EXPECT_TEXTURE_EQ(kInitColors.data(), colorTexture, {0, 0}, {kSize, kSize});
}