Initializing stencil reference for render pass in D3D12
When creating a new render pass in D3D12, call the OMSetStencilRef
to set the stencil reference value to zero.
Bug: dawn:1097
Change-Id: I5dd94691b1b354b601c06a02d3d5fa619d8b58ee
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/63360
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
Reviewed-by: Jiawei Shao <jiawei.shao@intel.com>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/src/dawn_native/d3d12/CommandBufferD3D12.cpp b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
index 50c5236..638f17d 100644
--- a/src/dawn_native/d3d12/CommandBufferD3D12.cpp
+++ b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
@@ -1304,6 +1304,8 @@
static constexpr std::array<float, 4> defaultBlendFactor = {0, 0, 0, 0};
commandList->OMSetBlendFactor(&defaultBlendFactor[0]);
+
+ commandList->OMSetStencilRef(0);
}
RenderPipeline* lastPipeline = nullptr;
diff --git a/src/tests/end2end/DepthStencilStateTests.cpp b/src/tests/end2end/DepthStencilStateTests.cpp
index b65ab02..0d96819 100644
--- a/src/tests/end2end/DepthStencilStateTests.cpp
+++ b/src/tests/end2end/DepthStencilStateTests.cpp
@@ -92,6 +92,7 @@
float depth;
uint32_t stencil;
wgpu::FrontFace frontFace = wgpu::FrontFace::CCW;
+ bool setStencilReference = true;
};
// Check whether a depth comparison function works as expected
@@ -265,7 +266,8 @@
// expected colors for the frontfaces and backfaces
void DoTest(const std::vector<TestSpec>& testParams,
const RGBA8& expectedFront,
- const RGBA8& expectedBack) {
+ const RGBA8& expectedBack,
+ bool isSingleEncoderMultiplePass = false) {
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
struct TriangleData {
@@ -274,11 +276,32 @@
};
utils::ComboRenderPassDescriptor renderPass({renderTargetView}, depthTextureView);
- wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
+ wgpu::RenderPassEncoder pass;
+
+ if (isSingleEncoderMultiplePass) {
+ // The render pass to clear up the depthTextureView (using LoadOp = clear)
+ utils::ComboRenderPassDescriptor clearingPass({renderTargetView}, depthTextureView);
+
+ // The render pass to do the test with depth and stencil result kept
+ renderPass.cDepthStencilAttachmentInfo.depthLoadOp = wgpu::LoadOp::Load;
+ renderPass.cDepthStencilAttachmentInfo.stencilLoadOp = wgpu::LoadOp::Load;
+
+ // Clear the depthStencilView at the beginning
+ {
+ pass = encoder.BeginRenderPass(&renderPass);
+ pass.EndPass();
+ }
+ } else {
+ pass = encoder.BeginRenderPass(&renderPass);
+ }
for (size_t i = 0; i < testParams.size(); ++i) {
const TestSpec& test = testParams[i];
+ if (isSingleEncoderMultiplePass) {
+ pass = encoder.BeginRenderPass(&renderPass);
+ }
+
TriangleData data = {
{static_cast<float>(test.color.r) / 255.f, static_cast<float>(test.color.g) / 255.f,
static_cast<float>(test.color.b) / 255.f},
@@ -305,12 +328,21 @@
device, pipeline.GetBindGroupLayout(0), {{0, buffer, 0, sizeof(TriangleData)}});
pass.SetPipeline(pipeline);
- pass.SetStencilReference(test.stencil); // Set the stencil reference
+ if (test.setStencilReference) {
+ pass.SetStencilReference(test.stencil); // Set the stencil reference
+ }
pass.SetBindGroup(0,
bindGroup); // Set the bind group which contains color and depth data
pass.Draw(6);
+
+ if (isSingleEncoderMultiplePass) {
+ pass.EndPass();
+ }
}
- pass.EndPass();
+
+ if (!isSingleEncoderMultiplePass) {
+ pass.EndPass();
+ }
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
@@ -321,8 +353,10 @@
<< "Back face check failed";
}
- void DoTest(const std::vector<TestSpec>& testParams, const RGBA8& expected) {
- DoTest(testParams, expected, expected);
+ void DoTest(const std::vector<TestSpec>& testParams,
+ const RGBA8& expected,
+ bool isSingleEncoderMultiplePass = false) {
+ DoTest(testParams, expected, expected, isSingleEncoderMultiplePass);
}
wgpu::Texture renderTarget;
@@ -752,6 +786,51 @@
DoTest({{state, RGBA8::kRed, 0.f, 0u, wgpu::FrontFace::CW}}, RGBA8::kZero, RGBA8::kRed);
}
+// Test that the depth reference of a new render pass is initialized to default value 0
+TEST_P(DepthStencilStateTest, StencilReferenceInitialized) {
+ wgpu::DepthStencilState stencilAlwaysReplaceState;
+ stencilAlwaysReplaceState.stencilFront.compare = wgpu::CompareFunction::Always;
+ stencilAlwaysReplaceState.stencilFront.passOp = wgpu::StencilOperation::Replace;
+ stencilAlwaysReplaceState.stencilBack.compare = wgpu::CompareFunction::Always;
+ stencilAlwaysReplaceState.stencilBack.passOp = wgpu::StencilOperation::Replace;
+
+ wgpu::DepthStencilState stencilEqualKeepState;
+ stencilEqualKeepState.stencilFront.compare = wgpu::CompareFunction::Equal;
+ stencilEqualKeepState.stencilFront.passOp = wgpu::StencilOperation::Keep;
+ stencilEqualKeepState.stencilBack.compare = wgpu::CompareFunction::Equal;
+ stencilEqualKeepState.stencilBack.passOp = wgpu::StencilOperation::Keep;
+
+ // Test that stencil reference is not inherited
+ {
+ // First pass sets the stencil to 0x1, and the second pass tests the stencil
+ // Only set the stencil reference in the first pass, and test that for other pass it should
+ // be default value rather than inherited
+ std::vector<TestSpec> testParams = {
+ {stencilAlwaysReplaceState, RGBA8::kRed, 0.f, 0x1, wgpu::FrontFace::CCW, true},
+ {stencilEqualKeepState, RGBA8::kGreen, 0.f, 0x0, wgpu::FrontFace::CCW, false}};
+
+ // Since the stencil reference is not inherited, second draw won't pass the stencil test
+ std::pair<RGBA8, RGBA8> expectation = {RGBA8::kZero, RGBA8::kZero};
+
+ DoTest(testParams, expectation.first, expectation.second, true);
+ }
+
+ // Test that stencil reference is initialized as zero for new render pass
+ {
+ // First pass sets the stencil to 0x1, the second pass sets the stencil to its default
+ // value, and the third pass tests if the stencil is zero
+ std::vector<TestSpec> testParams = {
+ {stencilAlwaysReplaceState, RGBA8::kRed, 0.f, 0x1, wgpu::FrontFace::CCW, true},
+ {stencilAlwaysReplaceState, RGBA8::kGreen, 0.f, 0x1, wgpu::FrontFace::CCW, false},
+ {stencilEqualKeepState, RGBA8::kBlue, 0.f, 0x0, wgpu::FrontFace::CCW, true}};
+
+ // The third draw should pass the stencil test since the second pass set it to default zero
+ std::pair<RGBA8, RGBA8> expectation = {RGBA8::kBlue, RGBA8::kBlue};
+
+ DoTest(testParams, expectation.first, expectation.second, true);
+ }
+}
+
DAWN_INSTANTIATE_TEST(DepthStencilStateTest,
D3D12Backend(),
MetalBackend(),