• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Dawn Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "tests/DawnTest.h"
16 
17 #include "common/Assert.h"
18 #include "utils/ComboRenderPipelineDescriptor.h"
19 #include "utils/WGPUHelpers.h"
20 
21 constexpr static unsigned int kRTSize = 64;
22 
23 class DepthStencilStateTest : public DawnTest {
24   protected:
SetUp()25     void SetUp() override {
26         DawnTest::SetUp();
27 
28         // TODO(crbug.com/dawn/737): Test output is wrong with D3D12 + WARP.
29         DAWN_SUPPRESS_TEST_IF(IsD3D12() && IsWARP());
30 
31         wgpu::TextureDescriptor renderTargetDescriptor;
32         renderTargetDescriptor.dimension = wgpu::TextureDimension::e2D;
33         renderTargetDescriptor.size.width = kRTSize;
34         renderTargetDescriptor.size.height = kRTSize;
35         renderTargetDescriptor.size.depthOrArrayLayers = 1;
36         renderTargetDescriptor.sampleCount = 1;
37         renderTargetDescriptor.format = wgpu::TextureFormat::RGBA8Unorm;
38         renderTargetDescriptor.mipLevelCount = 1;
39         renderTargetDescriptor.usage =
40             wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc;
41         renderTarget = device.CreateTexture(&renderTargetDescriptor);
42 
43         renderTargetView = renderTarget.CreateView();
44 
45         wgpu::TextureDescriptor depthDescriptor;
46         depthDescriptor.dimension = wgpu::TextureDimension::e2D;
47         depthDescriptor.size.width = kRTSize;
48         depthDescriptor.size.height = kRTSize;
49         depthDescriptor.size.depthOrArrayLayers = 1;
50         depthDescriptor.sampleCount = 1;
51         depthDescriptor.format = wgpu::TextureFormat::Depth24PlusStencil8;
52         depthDescriptor.mipLevelCount = 1;
53         depthDescriptor.usage = wgpu::TextureUsage::RenderAttachment;
54         depthTexture = device.CreateTexture(&depthDescriptor);
55 
56         depthTextureView = depthTexture.CreateView();
57 
58         vsModule = utils::CreateShaderModule(device, R"(
59             [[block]] struct UBO {
60                 color : vec3<f32>;
61                 depth : f32;
62             };
63             [[group(0), binding(0)]] var<uniform> ubo : UBO;
64 
65             [[stage(vertex)]]
66             fn main([[builtin(vertex_index)]] VertexIndex : u32) -> [[builtin(position)]] vec4<f32> {
67                 var pos = array<vec2<f32>, 6>(
68                         vec2<f32>(-1.0,  1.0),
69                         vec2<f32>(-1.0, -1.0),
70                         vec2<f32>( 1.0, -1.0), // front-facing
71                         vec2<f32>(-1.0,  1.0),
72                         vec2<f32>( 1.0,  1.0),
73                         vec2<f32>( 1.0, -1.0)); // back-facing
74                 return vec4<f32>(pos[VertexIndex], ubo.depth, 1.0);
75             })");
76 
77         fsModule = utils::CreateShaderModule(device, R"(
78             [[block]] struct UBO {
79                 color : vec3<f32>;
80                 depth : f32;
81             };
82             [[group(0), binding(0)]] var<uniform> ubo : UBO;
83 
84             [[stage(fragment)]] fn main() -> [[location(0)]] vec4<f32> {
85                 return vec4<f32>(ubo.color, 1.0);
86             })");
87     }
88 
89     struct TestSpec {
90         const wgpu::DepthStencilState& depthStencil;
91         RGBA8 color;
92         float depth;
93         uint32_t stencil;
94         wgpu::FrontFace frontFace = wgpu::FrontFace::CCW;
95         bool setStencilReference = true;
96     };
97 
98     // Check whether a depth comparison function works as expected
99     // The less, equal, greater booleans denote wether the respective triangle should be visible
100     // based on the comparison function
CheckDepthCompareFunction(wgpu::CompareFunction compareFunction,bool less,bool equal,bool greater)101     void CheckDepthCompareFunction(wgpu::CompareFunction compareFunction,
102                                    bool less,
103                                    bool equal,
104                                    bool greater) {
105         wgpu::StencilFaceState stencilFace;
106         stencilFace.compare = wgpu::CompareFunction::Always;
107         stencilFace.failOp = wgpu::StencilOperation::Keep;
108         stencilFace.depthFailOp = wgpu::StencilOperation::Keep;
109         stencilFace.passOp = wgpu::StencilOperation::Keep;
110 
111         wgpu::DepthStencilState baseState;
112         baseState.depthWriteEnabled = true;
113         baseState.depthCompare = wgpu::CompareFunction::Always;
114         baseState.stencilBack = stencilFace;
115         baseState.stencilFront = stencilFace;
116         baseState.stencilReadMask = 0xff;
117         baseState.stencilWriteMask = 0xff;
118 
119         wgpu::DepthStencilState state;
120         state.depthWriteEnabled = true;
121         state.depthCompare = compareFunction;
122         state.stencilBack = stencilFace;
123         state.stencilFront = stencilFace;
124         state.stencilReadMask = 0xff;
125         state.stencilWriteMask = 0xff;
126 
127         RGBA8 baseColor = RGBA8(255, 255, 255, 255);
128         RGBA8 lessColor = RGBA8(255, 0, 0, 255);
129         RGBA8 equalColor = RGBA8(0, 255, 0, 255);
130         RGBA8 greaterColor = RGBA8(0, 0, 255, 255);
131 
132         // Base triangle at depth 0.5, depth always, depth write enabled
133         TestSpec base = {baseState, baseColor, 0.5f, 0u};
134 
135         // Draw the base triangle, then a triangle in stencilFront of the base triangle with the
136         // given depth comparison function
137         DoTest({base, {state, lessColor, 0.f, 0u}}, less ? lessColor : baseColor);
138 
139         // Draw the base triangle, then a triangle in at the same depth as the base triangle with
140         // the given depth comparison function
141         DoTest({base, {state, equalColor, 0.5f, 0u}}, equal ? equalColor : baseColor);
142 
143         // Draw the base triangle, then a triangle behind the base triangle with the given depth
144         // comparison function
145         DoTest({base, {state, greaterColor, 1.0f, 0u}}, greater ? greaterColor : baseColor);
146     }
147 
148     // Check whether a stencil comparison function works as expected
149     // The less, equal, greater booleans denote wether the respective triangle should be visible
150     // based on the comparison function
CheckStencilCompareFunction(wgpu::CompareFunction compareFunction,bool less,bool equal,bool greater)151     void CheckStencilCompareFunction(wgpu::CompareFunction compareFunction,
152                                      bool less,
153                                      bool equal,
154                                      bool greater) {
155         wgpu::StencilFaceState baseStencilFaceDescriptor;
156         baseStencilFaceDescriptor.compare = wgpu::CompareFunction::Always;
157         baseStencilFaceDescriptor.failOp = wgpu::StencilOperation::Keep;
158         baseStencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
159         baseStencilFaceDescriptor.passOp = wgpu::StencilOperation::Replace;
160         wgpu::DepthStencilState baseState;
161         baseState.depthWriteEnabled = false;
162         baseState.depthCompare = wgpu::CompareFunction::Always;
163         baseState.stencilBack = baseStencilFaceDescriptor;
164         baseState.stencilFront = baseStencilFaceDescriptor;
165         baseState.stencilReadMask = 0xff;
166         baseState.stencilWriteMask = 0xff;
167 
168         wgpu::StencilFaceState stencilFaceDescriptor;
169         stencilFaceDescriptor.compare = compareFunction;
170         stencilFaceDescriptor.failOp = wgpu::StencilOperation::Keep;
171         stencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
172         stencilFaceDescriptor.passOp = wgpu::StencilOperation::Keep;
173         wgpu::DepthStencilState state;
174         state.depthWriteEnabled = false;
175         state.depthCompare = wgpu::CompareFunction::Always;
176         state.stencilBack = stencilFaceDescriptor;
177         state.stencilFront = stencilFaceDescriptor;
178         state.stencilReadMask = 0xff;
179         state.stencilWriteMask = 0xff;
180 
181         RGBA8 baseColor = RGBA8(255, 255, 255, 255);
182         RGBA8 lessColor = RGBA8(255, 0, 0, 255);
183         RGBA8 equalColor = RGBA8(0, 255, 0, 255);
184         RGBA8 greaterColor = RGBA8(0, 0, 255, 255);
185 
186         // Base triangle with stencil reference 1
187         TestSpec base = {baseState, baseColor, 0.0f, 1u};
188 
189         // Draw the base triangle, then a triangle with stencil reference 0 with the given stencil
190         // comparison function
191         DoTest({base, {state, lessColor, 0.f, 0u}}, less ? lessColor : baseColor);
192 
193         // Draw the base triangle, then a triangle with stencil reference 1 with the given stencil
194         // comparison function
195         DoTest({base, {state, equalColor, 0.f, 1u}}, equal ? equalColor : baseColor);
196 
197         // Draw the base triangle, then a triangle with stencil reference 2 with the given stencil
198         // comparison function
199         DoTest({base, {state, greaterColor, 0.f, 2u}}, greater ? greaterColor : baseColor);
200     }
201 
202     // Given the provided `initialStencil` and `reference`, check that applying the
203     // `stencilOperation` produces the `expectedStencil`
CheckStencilOperation(wgpu::StencilOperation stencilOperation,uint32_t initialStencil,uint32_t reference,uint32_t expectedStencil)204     void CheckStencilOperation(wgpu::StencilOperation stencilOperation,
205                                uint32_t initialStencil,
206                                uint32_t reference,
207                                uint32_t expectedStencil) {
208         wgpu::StencilFaceState baseStencilFaceDescriptor;
209         baseStencilFaceDescriptor.compare = wgpu::CompareFunction::Always;
210         baseStencilFaceDescriptor.failOp = wgpu::StencilOperation::Keep;
211         baseStencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
212         baseStencilFaceDescriptor.passOp = wgpu::StencilOperation::Replace;
213         wgpu::DepthStencilState baseState;
214         baseState.depthWriteEnabled = false;
215         baseState.depthCompare = wgpu::CompareFunction::Always;
216         baseState.stencilBack = baseStencilFaceDescriptor;
217         baseState.stencilFront = baseStencilFaceDescriptor;
218         baseState.stencilReadMask = 0xff;
219         baseState.stencilWriteMask = 0xff;
220 
221         wgpu::StencilFaceState stencilFaceDescriptor;
222         stencilFaceDescriptor.compare = wgpu::CompareFunction::Always;
223         stencilFaceDescriptor.failOp = wgpu::StencilOperation::Keep;
224         stencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
225         stencilFaceDescriptor.passOp = stencilOperation;
226         wgpu::DepthStencilState state;
227         state.depthWriteEnabled = false;
228         state.depthCompare = wgpu::CompareFunction::Always;
229         state.stencilBack = stencilFaceDescriptor;
230         state.stencilFront = stencilFaceDescriptor;
231         state.stencilReadMask = 0xff;
232         state.stencilWriteMask = 0xff;
233 
234         CheckStencil(
235             {
236                 // Wipe the stencil buffer with the initialStencil value
237                 {baseState, RGBA8(255, 255, 255, 255), 0.f, initialStencil},
238 
239                 // Draw a triangle with the provided stencil operation and reference
240                 {state, RGBA8(255, 0, 0, 255), 0.f, reference},
241             },
242             expectedStencil);
243     }
244 
245     // Draw a list of test specs, and check if the stencil value is equal to the expected value
CheckStencil(std::vector<TestSpec> testParams,uint32_t expectedStencil)246     void CheckStencil(std::vector<TestSpec> testParams, uint32_t expectedStencil) {
247         wgpu::StencilFaceState stencilFaceDescriptor;
248         stencilFaceDescriptor.compare = wgpu::CompareFunction::Equal;
249         stencilFaceDescriptor.failOp = wgpu::StencilOperation::Keep;
250         stencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
251         stencilFaceDescriptor.passOp = wgpu::StencilOperation::Keep;
252         wgpu::DepthStencilState state;
253         state.depthWriteEnabled = false;
254         state.depthCompare = wgpu::CompareFunction::Always;
255         state.stencilBack = stencilFaceDescriptor;
256         state.stencilFront = stencilFaceDescriptor;
257         state.stencilReadMask = 0xff;
258         state.stencilWriteMask = 0xff;
259 
260         testParams.push_back({state, RGBA8(0, 255, 0, 255), 0, expectedStencil});
261         DoTest(testParams, RGBA8(0, 255, 0, 255));
262     }
263 
264     // Each test param represents a pair of triangles with a color, depth, stencil value, and
265     // depthStencil state, one frontfacing, one backfacing Draw the triangles in order and check the
266     // expected colors for the frontfaces and backfaces
DoTest(const std::vector<TestSpec> & testParams,const RGBA8 & expectedFront,const RGBA8 & expectedBack,bool isSingleEncoderMultiplePass=false)267     void DoTest(const std::vector<TestSpec>& testParams,
268                 const RGBA8& expectedFront,
269                 const RGBA8& expectedBack,
270                 bool isSingleEncoderMultiplePass = false) {
271         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
272 
273         struct TriangleData {
274             float color[3];
275             float depth;
276         };
277 
278         utils::ComboRenderPassDescriptor renderPass({renderTargetView}, depthTextureView);
279         wgpu::RenderPassEncoder pass;
280 
281         if (isSingleEncoderMultiplePass) {
282             // The render pass to clear up the depthTextureView (using LoadOp = clear)
283             utils::ComboRenderPassDescriptor clearingPass({renderTargetView}, depthTextureView);
284 
285             // The render pass to do the test with depth and stencil result kept
286             renderPass.cDepthStencilAttachmentInfo.depthLoadOp = wgpu::LoadOp::Load;
287             renderPass.cDepthStencilAttachmentInfo.stencilLoadOp = wgpu::LoadOp::Load;
288 
289             // Clear the depthStencilView at the beginning
290             {
291                 pass = encoder.BeginRenderPass(&renderPass);
292                 pass.EndPass();
293             }
294         } else {
295             pass = encoder.BeginRenderPass(&renderPass);
296         }
297 
298         for (size_t i = 0; i < testParams.size(); ++i) {
299             const TestSpec& test = testParams[i];
300 
301             if (isSingleEncoderMultiplePass) {
302                 pass = encoder.BeginRenderPass(&renderPass);
303             }
304 
305             TriangleData data = {
306                 {static_cast<float>(test.color.r) / 255.f, static_cast<float>(test.color.g) / 255.f,
307                  static_cast<float>(test.color.b) / 255.f},
308                 test.depth,
309             };
310             // Upload a buffer for each triangle's depth and color data
311             wgpu::Buffer buffer = utils::CreateBufferFromData(device, &data, sizeof(TriangleData),
312                                                               wgpu::BufferUsage::Uniform);
313 
314             // Create a pipeline for the triangles with the test spec's depth stencil state
315 
316             utils::ComboRenderPipelineDescriptor descriptor;
317             descriptor.vertex.module = vsModule;
318             descriptor.cFragment.module = fsModule;
319             wgpu::DepthStencilState* depthStencil = descriptor.EnableDepthStencil();
320             *depthStencil = test.depthStencil;
321             depthStencil->format = wgpu::TextureFormat::Depth24PlusStencil8;
322             descriptor.primitive.frontFace = test.frontFace;
323 
324             wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor);
325 
326             // Create a bind group for the data
327             wgpu::BindGroup bindGroup = utils::MakeBindGroup(
328                 device, pipeline.GetBindGroupLayout(0), {{0, buffer, 0, sizeof(TriangleData)}});
329 
330             pass.SetPipeline(pipeline);
331             if (test.setStencilReference) {
332                 pass.SetStencilReference(test.stencil);  // Set the stencil reference
333             }
334             pass.SetBindGroup(0,
335                               bindGroup);  // Set the bind group which contains color and depth data
336             pass.Draw(6);
337 
338             if (isSingleEncoderMultiplePass) {
339                 pass.EndPass();
340             }
341         }
342 
343         if (!isSingleEncoderMultiplePass) {
344             pass.EndPass();
345         }
346 
347         wgpu::CommandBuffer commands = encoder.Finish();
348         queue.Submit(1, &commands);
349 
350         EXPECT_PIXEL_RGBA8_EQ(expectedFront, renderTarget, kRTSize / 4, kRTSize / 2)
351             << "Front face check failed";
352         EXPECT_PIXEL_RGBA8_EQ(expectedBack, renderTarget, 3 * kRTSize / 4, kRTSize / 2)
353             << "Back face check failed";
354     }
355 
DoTest(const std::vector<TestSpec> & testParams,const RGBA8 & expected,bool isSingleEncoderMultiplePass=false)356     void DoTest(const std::vector<TestSpec>& testParams,
357                 const RGBA8& expected,
358                 bool isSingleEncoderMultiplePass = false) {
359         DoTest(testParams, expected, expected, isSingleEncoderMultiplePass);
360     }
361 
362     wgpu::Texture renderTarget;
363     wgpu::Texture depthTexture;
364     wgpu::TextureView renderTargetView;
365     wgpu::TextureView depthTextureView;
366     wgpu::ShaderModule vsModule;
367     wgpu::ShaderModule fsModule;
368 };
369 
370 // Test compilation and usage of the fixture
TEST_P(DepthStencilStateTest,Basic)371 TEST_P(DepthStencilStateTest, Basic) {
372     wgpu::StencilFaceState stencilFace;
373     stencilFace.compare = wgpu::CompareFunction::Always;
374     stencilFace.failOp = wgpu::StencilOperation::Keep;
375     stencilFace.depthFailOp = wgpu::StencilOperation::Keep;
376     stencilFace.passOp = wgpu::StencilOperation::Keep;
377 
378     wgpu::DepthStencilState state;
379     state.depthWriteEnabled = false;
380     state.depthCompare = wgpu::CompareFunction::Always;
381     state.stencilBack = stencilFace;
382     state.stencilFront = stencilFace;
383     state.stencilReadMask = 0xff;
384     state.stencilWriteMask = 0xff;
385 
386     DoTest(
387         {
388             {state, RGBA8(0, 255, 0, 255), 0.5f, 0u},
389         },
390         RGBA8(0, 255, 0, 255));
391 }
392 
393 // Test defaults: depth and stencil tests disabled
TEST_P(DepthStencilStateTest,DepthStencilDisabled)394 TEST_P(DepthStencilStateTest, DepthStencilDisabled) {
395     wgpu::StencilFaceState stencilFace;
396     stencilFace.compare = wgpu::CompareFunction::Always;
397     stencilFace.failOp = wgpu::StencilOperation::Keep;
398     stencilFace.depthFailOp = wgpu::StencilOperation::Keep;
399     stencilFace.passOp = wgpu::StencilOperation::Keep;
400 
401     wgpu::DepthStencilState state;
402     state.depthWriteEnabled = false;
403     state.depthCompare = wgpu::CompareFunction::Always;
404     state.stencilBack = stencilFace;
405     state.stencilFront = stencilFace;
406     state.stencilReadMask = 0xff;
407     state.stencilWriteMask = 0xff;
408 
409     TestSpec specs[3] = {
410         {state, RGBA8(255, 0, 0, 255), 0.0f, 0u},
411         {state, RGBA8(0, 255, 0, 255), 0.5f, 0u},
412         {state, RGBA8(0, 0, 255, 255), 1.0f, 0u},
413     };
414 
415     // Test that for all combinations, the last triangle drawn is the one visible
416     // We check against three triangles because the stencil test may modify results
417     for (uint32_t last = 0; last < 3; ++last) {
418         uint32_t i = (last + 1) % 3;
419         uint32_t j = (last + 2) % 3;
420         DoTest({specs[i], specs[j], specs[last]}, specs[last].color);
421         DoTest({specs[j], specs[i], specs[last]}, specs[last].color);
422     }
423 }
424 
425 // The following tests check that each depth comparison function works
TEST_P(DepthStencilStateTest,DepthAlways)426 TEST_P(DepthStencilStateTest, DepthAlways) {
427     CheckDepthCompareFunction(wgpu::CompareFunction::Always, true, true, true);
428 }
429 
TEST_P(DepthStencilStateTest,DepthEqual)430 TEST_P(DepthStencilStateTest, DepthEqual) {
431     CheckDepthCompareFunction(wgpu::CompareFunction::Equal, false, true, false);
432 }
433 
TEST_P(DepthStencilStateTest,DepthGreater)434 TEST_P(DepthStencilStateTest, DepthGreater) {
435     CheckDepthCompareFunction(wgpu::CompareFunction::Greater, false, false, true);
436 }
437 
TEST_P(DepthStencilStateTest,DepthGreaterEqual)438 TEST_P(DepthStencilStateTest, DepthGreaterEqual) {
439     CheckDepthCompareFunction(wgpu::CompareFunction::GreaterEqual, false, true, true);
440 }
441 
TEST_P(DepthStencilStateTest,DepthLess)442 TEST_P(DepthStencilStateTest, DepthLess) {
443     CheckDepthCompareFunction(wgpu::CompareFunction::Less, true, false, false);
444 }
445 
TEST_P(DepthStencilStateTest,DepthLessEqual)446 TEST_P(DepthStencilStateTest, DepthLessEqual) {
447     CheckDepthCompareFunction(wgpu::CompareFunction::LessEqual, true, true, false);
448 }
449 
TEST_P(DepthStencilStateTest,DepthNever)450 TEST_P(DepthStencilStateTest, DepthNever) {
451     CheckDepthCompareFunction(wgpu::CompareFunction::Never, false, false, false);
452 }
453 
TEST_P(DepthStencilStateTest,DepthNotEqual)454 TEST_P(DepthStencilStateTest, DepthNotEqual) {
455     CheckDepthCompareFunction(wgpu::CompareFunction::NotEqual, true, false, true);
456 }
457 
458 // Test that disabling depth writes works and leaves the depth buffer unchanged
TEST_P(DepthStencilStateTest,DepthWriteDisabled)459 TEST_P(DepthStencilStateTest, DepthWriteDisabled) {
460     wgpu::StencilFaceState stencilFace;
461     stencilFace.compare = wgpu::CompareFunction::Always;
462     stencilFace.failOp = wgpu::StencilOperation::Keep;
463     stencilFace.depthFailOp = wgpu::StencilOperation::Keep;
464     stencilFace.passOp = wgpu::StencilOperation::Keep;
465 
466     wgpu::DepthStencilState baseState;
467     baseState.depthWriteEnabled = true;
468     baseState.depthCompare = wgpu::CompareFunction::Always;
469     baseState.stencilBack = stencilFace;
470     baseState.stencilFront = stencilFace;
471     baseState.stencilReadMask = 0xff;
472     baseState.stencilWriteMask = 0xff;
473 
474     wgpu::DepthStencilState noDepthWrite;
475     noDepthWrite.depthWriteEnabled = false;
476     noDepthWrite.depthCompare = wgpu::CompareFunction::Always;
477     noDepthWrite.stencilBack = stencilFace;
478     noDepthWrite.stencilFront = stencilFace;
479     noDepthWrite.stencilReadMask = 0xff;
480     noDepthWrite.stencilWriteMask = 0xff;
481 
482     wgpu::DepthStencilState checkState;
483     checkState.depthWriteEnabled = false;
484     checkState.depthCompare = wgpu::CompareFunction::Equal;
485     checkState.stencilBack = stencilFace;
486     checkState.stencilFront = stencilFace;
487     checkState.stencilReadMask = 0xff;
488     checkState.stencilWriteMask = 0xff;
489 
490     DoTest(
491         {
492             {baseState, RGBA8(255, 255, 255, 255), 1.f,
493              0u},  // Draw a base triangle with depth enabled
494             {noDepthWrite, RGBA8(0, 0, 0, 255), 0.f,
495              0u},  // Draw a second triangle without depth enabled
496             {checkState, RGBA8(0, 255, 0, 255), 1.f,
497              0u},  // Draw a third triangle which should occlude the second even though it is behind
498                    // it
499         },
500         RGBA8(0, 255, 0, 255));
501 }
502 
503 // The following tests check that each stencil comparison function works
TEST_P(DepthStencilStateTest,StencilAlways)504 TEST_P(DepthStencilStateTest, StencilAlways) {
505     CheckStencilCompareFunction(wgpu::CompareFunction::Always, true, true, true);
506 }
507 
TEST_P(DepthStencilStateTest,StencilEqual)508 TEST_P(DepthStencilStateTest, StencilEqual) {
509     CheckStencilCompareFunction(wgpu::CompareFunction::Equal, false, true, false);
510 }
511 
TEST_P(DepthStencilStateTest,StencilGreater)512 TEST_P(DepthStencilStateTest, StencilGreater) {
513     CheckStencilCompareFunction(wgpu::CompareFunction::Greater, false, false, true);
514 }
515 
TEST_P(DepthStencilStateTest,StencilGreaterEqual)516 TEST_P(DepthStencilStateTest, StencilGreaterEqual) {
517     CheckStencilCompareFunction(wgpu::CompareFunction::GreaterEqual, false, true, true);
518 }
519 
TEST_P(DepthStencilStateTest,StencilLess)520 TEST_P(DepthStencilStateTest, StencilLess) {
521     CheckStencilCompareFunction(wgpu::CompareFunction::Less, true, false, false);
522 }
523 
TEST_P(DepthStencilStateTest,StencilLessEqual)524 TEST_P(DepthStencilStateTest, StencilLessEqual) {
525     CheckStencilCompareFunction(wgpu::CompareFunction::LessEqual, true, true, false);
526 }
527 
TEST_P(DepthStencilStateTest,StencilNever)528 TEST_P(DepthStencilStateTest, StencilNever) {
529     CheckStencilCompareFunction(wgpu::CompareFunction::Never, false, false, false);
530 }
531 
TEST_P(DepthStencilStateTest,StencilNotEqual)532 TEST_P(DepthStencilStateTest, StencilNotEqual) {
533     CheckStencilCompareFunction(wgpu::CompareFunction::NotEqual, true, false, true);
534 }
535 
536 // The following tests check that each stencil operation works
TEST_P(DepthStencilStateTest,StencilKeep)537 TEST_P(DepthStencilStateTest, StencilKeep) {
538     CheckStencilOperation(wgpu::StencilOperation::Keep, 1, 3, 1);
539 }
540 
TEST_P(DepthStencilStateTest,StencilZero)541 TEST_P(DepthStencilStateTest, StencilZero) {
542     CheckStencilOperation(wgpu::StencilOperation::Zero, 1, 3, 0);
543 }
544 
TEST_P(DepthStencilStateTest,StencilReplace)545 TEST_P(DepthStencilStateTest, StencilReplace) {
546     CheckStencilOperation(wgpu::StencilOperation::Replace, 1, 3, 3);
547 }
548 
TEST_P(DepthStencilStateTest,StencilInvert)549 TEST_P(DepthStencilStateTest, StencilInvert) {
550     CheckStencilOperation(wgpu::StencilOperation::Invert, 0xf0, 3, 0x0f);
551 }
552 
TEST_P(DepthStencilStateTest,StencilIncrementClamp)553 TEST_P(DepthStencilStateTest, StencilIncrementClamp) {
554     CheckStencilOperation(wgpu::StencilOperation::IncrementClamp, 1, 3, 2);
555     CheckStencilOperation(wgpu::StencilOperation::IncrementClamp, 0xff, 3, 0xff);
556 }
557 
TEST_P(DepthStencilStateTest,StencilIncrementWrap)558 TEST_P(DepthStencilStateTest, StencilIncrementWrap) {
559     CheckStencilOperation(wgpu::StencilOperation::IncrementWrap, 1, 3, 2);
560     CheckStencilOperation(wgpu::StencilOperation::IncrementWrap, 0xff, 3, 0);
561 }
562 
TEST_P(DepthStencilStateTest,StencilDecrementClamp)563 TEST_P(DepthStencilStateTest, StencilDecrementClamp) {
564     CheckStencilOperation(wgpu::StencilOperation::DecrementClamp, 1, 3, 0);
565     CheckStencilOperation(wgpu::StencilOperation::DecrementClamp, 0, 3, 0);
566 }
567 
TEST_P(DepthStencilStateTest,StencilDecrementWrap)568 TEST_P(DepthStencilStateTest, StencilDecrementWrap) {
569     CheckStencilOperation(wgpu::StencilOperation::DecrementWrap, 1, 3, 0);
570     CheckStencilOperation(wgpu::StencilOperation::DecrementWrap, 0, 3, 0xff);
571 }
572 
573 // Check that the setting a stencil read mask works
TEST_P(DepthStencilStateTest,StencilReadMask)574 TEST_P(DepthStencilStateTest, StencilReadMask) {
575     wgpu::StencilFaceState baseStencilFaceDescriptor;
576     baseStencilFaceDescriptor.compare = wgpu::CompareFunction::Always;
577     baseStencilFaceDescriptor.failOp = wgpu::StencilOperation::Keep;
578     baseStencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
579     baseStencilFaceDescriptor.passOp = wgpu::StencilOperation::Replace;
580     wgpu::DepthStencilState baseState;
581     baseState.depthWriteEnabled = false;
582     baseState.depthCompare = wgpu::CompareFunction::Always;
583     baseState.stencilBack = baseStencilFaceDescriptor;
584     baseState.stencilFront = baseStencilFaceDescriptor;
585     baseState.stencilReadMask = 0xff;
586     baseState.stencilWriteMask = 0xff;
587 
588     wgpu::StencilFaceState stencilFaceDescriptor;
589     stencilFaceDescriptor.compare = wgpu::CompareFunction::Equal;
590     stencilFaceDescriptor.failOp = wgpu::StencilOperation::Keep;
591     stencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
592     stencilFaceDescriptor.passOp = wgpu::StencilOperation::Keep;
593     wgpu::DepthStencilState state;
594     state.depthWriteEnabled = false;
595     state.depthCompare = wgpu::CompareFunction::Always;
596     state.stencilBack = stencilFaceDescriptor;
597     state.stencilFront = stencilFaceDescriptor;
598     state.stencilReadMask = 0x2;
599     state.stencilWriteMask = 0xff;
600 
601     RGBA8 baseColor = RGBA8(255, 255, 255, 255);
602     RGBA8 red = RGBA8(255, 0, 0, 255);
603     RGBA8 green = RGBA8(0, 255, 0, 255);
604 
605     TestSpec base = {baseState, baseColor, 0.5f, 3u};  // Base triangle to set the stencil to 3
606     DoTest({base, {state, red, 0.f, 1u}}, baseColor);  // Triangle with stencil reference 1 and read
607                                                        // mask 2 does not draw because (3 & 2 != 1)
608     DoTest({base, {state, green, 0.f, 2u}},
609            green);  // Triangle with stencil reference 2 and read mask 2 draws because (3 & 2 == 2)
610 }
611 
612 // Check that setting a stencil write mask works
TEST_P(DepthStencilStateTest,StencilWriteMask)613 TEST_P(DepthStencilStateTest, StencilWriteMask) {
614     wgpu::StencilFaceState baseStencilFaceDescriptor;
615     baseStencilFaceDescriptor.compare = wgpu::CompareFunction::Always;
616     baseStencilFaceDescriptor.failOp = wgpu::StencilOperation::Keep;
617     baseStencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
618     baseStencilFaceDescriptor.passOp = wgpu::StencilOperation::Replace;
619     wgpu::DepthStencilState baseState;
620     baseState.depthWriteEnabled = false;
621     baseState.depthCompare = wgpu::CompareFunction::Always;
622     baseState.stencilBack = baseStencilFaceDescriptor;
623     baseState.stencilFront = baseStencilFaceDescriptor;
624     baseState.stencilReadMask = 0xff;
625     baseState.stencilWriteMask = 0x1;
626 
627     wgpu::StencilFaceState stencilFaceDescriptor;
628     stencilFaceDescriptor.compare = wgpu::CompareFunction::Equal;
629     stencilFaceDescriptor.failOp = wgpu::StencilOperation::Keep;
630     stencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
631     stencilFaceDescriptor.passOp = wgpu::StencilOperation::Keep;
632     wgpu::DepthStencilState state;
633     state.depthWriteEnabled = false;
634     state.depthCompare = wgpu::CompareFunction::Always;
635     state.stencilBack = stencilFaceDescriptor;
636     state.stencilFront = stencilFaceDescriptor;
637     state.stencilReadMask = 0xff;
638     state.stencilWriteMask = 0xff;
639 
640     RGBA8 baseColor = RGBA8(255, 255, 255, 255);
641     RGBA8 green = RGBA8(0, 255, 0, 255);
642 
643     TestSpec base = {baseState, baseColor, 0.5f,
644                      3u};  // Base triangle with stencil reference 3 and mask 1 to set the stencil 1
645     DoTest({base, {state, green, 0.f, 2u}},
646            baseColor);  // Triangle with stencil reference 2 does not draw because 2 != (3 & 1)
647     DoTest({base, {state, green, 0.f, 1u}},
648            green);  // Triangle with stencil reference 1 draws because 1 == (3 & 1)
649 }
650 
651 // Test that the stencil operation is executed on stencil fail
TEST_P(DepthStencilStateTest,StencilFail)652 TEST_P(DepthStencilStateTest, StencilFail) {
653     wgpu::StencilFaceState baseStencilFaceDescriptor;
654     baseStencilFaceDescriptor.compare = wgpu::CompareFunction::Always;
655     baseStencilFaceDescriptor.failOp = wgpu::StencilOperation::Keep;
656     baseStencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
657     baseStencilFaceDescriptor.passOp = wgpu::StencilOperation::Replace;
658     wgpu::DepthStencilState baseState;
659     baseState.depthWriteEnabled = false;
660     baseState.depthCompare = wgpu::CompareFunction::Always;
661     baseState.stencilBack = baseStencilFaceDescriptor;
662     baseState.stencilFront = baseStencilFaceDescriptor;
663     baseState.stencilReadMask = 0xff;
664     baseState.stencilWriteMask = 0xff;
665 
666     wgpu::StencilFaceState stencilFaceDescriptor;
667     stencilFaceDescriptor.compare = wgpu::CompareFunction::Less;
668     stencilFaceDescriptor.failOp = wgpu::StencilOperation::Replace;
669     stencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
670     stencilFaceDescriptor.passOp = wgpu::StencilOperation::Keep;
671     wgpu::DepthStencilState state;
672     state.depthWriteEnabled = false;
673     state.depthCompare = wgpu::CompareFunction::Always;
674     state.stencilBack = stencilFaceDescriptor;
675     state.stencilFront = stencilFaceDescriptor;
676     state.stencilReadMask = 0xff;
677     state.stencilWriteMask = 0xff;
678 
679     CheckStencil(
680         {
681             {baseState, RGBA8(255, 255, 255, 255), 1.f, 1},  // Triangle to set stencil value to 1
682             {state, RGBA8(0, 0, 0, 255), 0.f,
683              2}  // Triangle with stencil reference 2 fails the Less comparison function
684         },
685         2);  // Replace the stencil on failure, so it should be 2
686 }
687 
688 // Test that the stencil operation is executed on stencil pass, depth fail
TEST_P(DepthStencilStateTest,StencilDepthFail)689 TEST_P(DepthStencilStateTest, StencilDepthFail) {
690     wgpu::StencilFaceState baseStencilFaceDescriptor;
691     baseStencilFaceDescriptor.compare = wgpu::CompareFunction::Always;
692     baseStencilFaceDescriptor.failOp = wgpu::StencilOperation::Keep;
693     baseStencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
694     baseStencilFaceDescriptor.passOp = wgpu::StencilOperation::Replace;
695     wgpu::DepthStencilState baseState;
696     baseState.depthWriteEnabled = true;
697     baseState.depthCompare = wgpu::CompareFunction::Always;
698     baseState.stencilBack = baseStencilFaceDescriptor;
699     baseState.stencilFront = baseStencilFaceDescriptor;
700     baseState.stencilReadMask = 0xff;
701     baseState.stencilWriteMask = 0xff;
702 
703     wgpu::StencilFaceState stencilFaceDescriptor;
704     stencilFaceDescriptor.compare = wgpu::CompareFunction::Greater;
705     stencilFaceDescriptor.failOp = wgpu::StencilOperation::Keep;
706     stencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Replace;
707     stencilFaceDescriptor.passOp = wgpu::StencilOperation::Keep;
708     wgpu::DepthStencilState state;
709     state.depthWriteEnabled = true;
710     state.depthCompare = wgpu::CompareFunction::Less;
711     state.stencilBack = stencilFaceDescriptor;
712     state.stencilFront = stencilFaceDescriptor;
713     state.stencilReadMask = 0xff;
714     state.stencilWriteMask = 0xff;
715 
716     CheckStencil({{baseState, RGBA8(255, 255, 255, 255), 0.f,
717                    1},  // Triangle to set stencil value to 1. Depth is 0
718                   {state, RGBA8(0, 0, 0, 255), 1.f,
719                    2}},  // Triangle with stencil reference 2 passes the Greater comparison
720                          // function. At depth 1, it fails the Less depth test
721                  2);     // Replace the stencil on stencil pass, depth failure, so it should be 2
722 }
723 
724 // Test that the stencil operation is executed on stencil pass, depth pass
TEST_P(DepthStencilStateTest,StencilDepthPass)725 TEST_P(DepthStencilStateTest, StencilDepthPass) {
726     wgpu::StencilFaceState baseStencilFaceDescriptor;
727     baseStencilFaceDescriptor.compare = wgpu::CompareFunction::Always;
728     baseStencilFaceDescriptor.failOp = wgpu::StencilOperation::Keep;
729     baseStencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
730     baseStencilFaceDescriptor.passOp = wgpu::StencilOperation::Replace;
731     wgpu::DepthStencilState baseState;
732     baseState.depthWriteEnabled = true;
733     baseState.depthCompare = wgpu::CompareFunction::Always;
734     baseState.stencilBack = baseStencilFaceDescriptor;
735     baseState.stencilFront = baseStencilFaceDescriptor;
736     baseState.stencilReadMask = 0xff;
737     baseState.stencilWriteMask = 0xff;
738 
739     wgpu::StencilFaceState stencilFaceDescriptor;
740     stencilFaceDescriptor.compare = wgpu::CompareFunction::Greater;
741     stencilFaceDescriptor.failOp = wgpu::StencilOperation::Keep;
742     stencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
743     stencilFaceDescriptor.passOp = wgpu::StencilOperation::Replace;
744     wgpu::DepthStencilState state;
745     state.depthWriteEnabled = true;
746     state.depthCompare = wgpu::CompareFunction::Less;
747     state.stencilBack = stencilFaceDescriptor;
748     state.stencilFront = stencilFaceDescriptor;
749     state.stencilReadMask = 0xff;
750     state.stencilWriteMask = 0xff;
751 
752     CheckStencil({{baseState, RGBA8(255, 255, 255, 255), 1.f,
753                    1},  // Triangle to set stencil value to 1. Depth is 0
754                   {state, RGBA8(0, 0, 0, 255), 0.f,
755                    2}},  // Triangle with stencil reference 2 passes the Greater comparison
756                          // function. At depth 0, it pass the Less depth test
757                  2);     // Replace the stencil on stencil pass, depth pass, so it should be 2
758 }
759 
760 // Test that creating a render pipeline works with for all depth and combined formats
TEST_P(DepthStencilStateTest,CreatePipelineWithAllFormats)761 TEST_P(DepthStencilStateTest, CreatePipelineWithAllFormats) {
762     constexpr wgpu::TextureFormat kDepthStencilFormats[] = {
763         wgpu::TextureFormat::Depth32Float,
764         wgpu::TextureFormat::Depth24PlusStencil8,
765         wgpu::TextureFormat::Depth24Plus,
766         wgpu::TextureFormat::Depth16Unorm,
767     };
768 
769     for (wgpu::TextureFormat depthStencilFormat : kDepthStencilFormats) {
770         utils::ComboRenderPipelineDescriptor descriptor;
771         descriptor.vertex.module = vsModule;
772         descriptor.cFragment.module = fsModule;
773         descriptor.EnableDepthStencil(depthStencilFormat);
774 
775         device.CreateRenderPipeline(&descriptor);
776     }
777 }
778 
779 // Test that the front and back stencil states are set correctly (and take frontFace into account)
TEST_P(DepthStencilStateTest,StencilFrontAndBackFace)780 TEST_P(DepthStencilStateTest, StencilFrontAndBackFace) {
781     wgpu::DepthStencilState state;
782     state.stencilFront.compare = wgpu::CompareFunction::Always;
783     state.stencilBack.compare = wgpu::CompareFunction::Never;
784 
785     // The front facing triangle passes the stencil comparison but the back facing one doesn't.
786     DoTest({{state, RGBA8::kRed, 0.f, 0u, wgpu::FrontFace::CCW}}, RGBA8::kRed, RGBA8::kZero);
787     DoTest({{state, RGBA8::kRed, 0.f, 0u, wgpu::FrontFace::CW}}, RGBA8::kZero, RGBA8::kRed);
788 }
789 
790 // Test that the depth reference of a new render pass is initialized to default value 0
TEST_P(DepthStencilStateTest,StencilReferenceInitialized)791 TEST_P(DepthStencilStateTest, StencilReferenceInitialized) {
792     wgpu::DepthStencilState stencilAlwaysReplaceState;
793     stencilAlwaysReplaceState.stencilFront.compare = wgpu::CompareFunction::Always;
794     stencilAlwaysReplaceState.stencilFront.passOp = wgpu::StencilOperation::Replace;
795     stencilAlwaysReplaceState.stencilBack.compare = wgpu::CompareFunction::Always;
796     stencilAlwaysReplaceState.stencilBack.passOp = wgpu::StencilOperation::Replace;
797 
798     wgpu::DepthStencilState stencilEqualKeepState;
799     stencilEqualKeepState.stencilFront.compare = wgpu::CompareFunction::Equal;
800     stencilEqualKeepState.stencilFront.passOp = wgpu::StencilOperation::Keep;
801     stencilEqualKeepState.stencilBack.compare = wgpu::CompareFunction::Equal;
802     stencilEqualKeepState.stencilBack.passOp = wgpu::StencilOperation::Keep;
803 
804     // Test that stencil reference is not inherited
805     {
806         // First pass sets the stencil to 0x1, and the second pass tests the stencil
807         // Only set the stencil reference in the first pass, and test that for other pass it should
808         // be default value rather than inherited
809         std::vector<TestSpec> testParams = {
810             {stencilAlwaysReplaceState, RGBA8::kRed, 0.f, 0x1, wgpu::FrontFace::CCW, true},
811             {stencilEqualKeepState, RGBA8::kGreen, 0.f, 0x0, wgpu::FrontFace::CCW, false}};
812 
813         // Since the stencil reference is not inherited, second draw won't pass the stencil test
814         std::pair<RGBA8, RGBA8> expectation = {RGBA8::kZero, RGBA8::kZero};
815 
816         DoTest(testParams, expectation.first, expectation.second, true);
817     }
818 
819     // Test that stencil reference is initialized as zero for new render pass
820     {
821         // First pass sets the stencil to 0x1, the second pass sets the stencil to its default
822         // value, and the third pass tests if the stencil is zero
823         std::vector<TestSpec> testParams = {
824             {stencilAlwaysReplaceState, RGBA8::kRed, 0.f, 0x1, wgpu::FrontFace::CCW, true},
825             {stencilAlwaysReplaceState, RGBA8::kGreen, 0.f, 0x1, wgpu::FrontFace::CCW, false},
826             {stencilEqualKeepState, RGBA8::kBlue, 0.f, 0x0, wgpu::FrontFace::CCW, true}};
827 
828         // The third draw should pass the stencil test since the second pass set it to default zero
829         std::pair<RGBA8, RGBA8> expectation = {RGBA8::kBlue, RGBA8::kBlue};
830 
831         DoTest(testParams, expectation.first, expectation.second, true);
832     }
833 }
834 
835 DAWN_INSTANTIATE_TEST(DepthStencilStateTest,
836                       D3D12Backend(),
837                       MetalBackend(),
838                       OpenGLBackend(),
839                       OpenGLESBackend(),
840                       VulkanBackend({"vulkan_use_d32s8"}, {}),
841                       VulkanBackend({}, {"vulkan_use_d32s8"}));
842