• 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/DawnHelpers.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             dawn::TextureDescriptor renderTargetDescriptor;
29             renderTargetDescriptor.dimension = dawn::TextureDimension::e2D;
30             renderTargetDescriptor.size.width = kRTSize;
31             renderTargetDescriptor.size.height = kRTSize;
32             renderTargetDescriptor.size.depth = 1;
33             renderTargetDescriptor.arrayLayerCount = 1;
34             renderTargetDescriptor.sampleCount = 1;
35             renderTargetDescriptor.format = dawn::TextureFormat::RGBA8Unorm;
36             renderTargetDescriptor.mipLevelCount = 1;
37             renderTargetDescriptor.usage =
38                 dawn::TextureUsageBit::OutputAttachment | dawn::TextureUsageBit::CopySrc;
39             renderTarget = device.CreateTexture(&renderTargetDescriptor);
40 
41             renderTargetView = renderTarget.CreateDefaultView();
42 
43             dawn::TextureDescriptor depthDescriptor;
44             depthDescriptor.dimension = dawn::TextureDimension::e2D;
45             depthDescriptor.size.width = kRTSize;
46             depthDescriptor.size.height = kRTSize;
47             depthDescriptor.size.depth = 1;
48             depthDescriptor.arrayLayerCount = 1;
49             depthDescriptor.sampleCount = 1;
50             depthDescriptor.format = dawn::TextureFormat::Depth24PlusStencil8;
51             depthDescriptor.mipLevelCount = 1;
52             depthDescriptor.usage = dawn::TextureUsageBit::OutputAttachment;
53             depthTexture = device.CreateTexture(&depthDescriptor);
54 
55             depthTextureView = depthTexture.CreateDefaultView();
56 
57             vsModule = utils::CreateShaderModule(device, utils::ShaderStage::Vertex, R"(
58                 #version 450
59                 layout(set = 0, binding = 0) uniform myBlock {
60                     vec3 color;
61                     float depth;
62                 } myUbo;
63                 void main() {
64                     const vec2 pos[6] = vec2[6](
65                         vec2(-1.f, 1.f), vec2(-1.f, -1.f), vec2(1.f, -1.f), // front-facing
66                         vec2(-1.f, 1.f), vec2(1.f, 1.f), vec2(1.f, -1.f)    // back-facing
67                     );
68                     gl_Position = vec4(pos[gl_VertexIndex], myUbo.depth, 1.f);
69                 }
70             )");
71 
72             fsModule = utils::CreateShaderModule(device, utils::ShaderStage::Fragment, R"(
73                 #version 450
74                 layout(set = 0, binding = 0) uniform myBlock {
75                     vec3 color;
76                     float depth;
77                 } myUbo;
78                 layout(location = 0) out vec4 fragColor;
79                 void main() {
80                     fragColor = vec4(myUbo.color, 1.f);
81                 }
82             )");
83 
84             bindGroupLayout = utils::MakeBindGroupLayout(
85                 device, {
86                             {0, dawn::ShaderStageBit::Vertex | dawn::ShaderStageBit::Fragment,
87                              dawn::BindingType::UniformBuffer},
88                         });
89 
90             pipelineLayout = utils::MakeBasicPipelineLayout(device, &bindGroupLayout);
91         }
92 
93         struct TestSpec {
94             const dawn::DepthStencilStateDescriptor& depthStencilState;
95             RGBA8 color;
96             float depth;
97             uint32_t stencil;
98         };
99 
100         // Check whether a depth comparison function works as expected
101         // The less, equal, greater booleans denote wether the respective triangle should be visible based on the comparison function
CheckDepthCompareFunction(dawn::CompareFunction compareFunction,bool less,bool equal,bool greater)102         void CheckDepthCompareFunction(dawn::CompareFunction compareFunction, bool less, bool equal, bool greater) {
103             dawn::StencilStateFaceDescriptor stencilFace;
104             stencilFace.compare = dawn::CompareFunction::Always;
105             stencilFace.failOp = dawn::StencilOperation::Keep;
106             stencilFace.depthFailOp = dawn::StencilOperation::Keep;
107             stencilFace.passOp = dawn::StencilOperation::Keep;
108 
109             dawn::DepthStencilStateDescriptor baseState;
110             baseState.depthWriteEnabled = true;
111             baseState.depthCompare = dawn::CompareFunction::Always;
112             baseState.stencilBack = stencilFace;
113             baseState.stencilFront = stencilFace;
114             baseState.stencilReadMask = 0xff;
115             baseState.stencilWriteMask = 0xff;
116 
117             dawn::DepthStencilStateDescriptor state;
118             state.depthWriteEnabled = true;
119             state.depthCompare = compareFunction;
120             state.stencilBack = stencilFace;
121             state.stencilFront = stencilFace;
122             state.stencilReadMask = 0xff;
123             state.stencilWriteMask = 0xff;
124 
125             RGBA8 baseColor = RGBA8(255, 255, 255, 255);
126             RGBA8 lessColor = RGBA8(255, 0, 0, 255);
127             RGBA8 equalColor = RGBA8(0, 255, 0, 255);
128             RGBA8 greaterColor = RGBA8(0, 0, 255, 255);
129 
130             // Base triangle at depth 0.5, depth always, depth write enabled
131             TestSpec base = { baseState, baseColor, 0.5f, 0u };
132 
133             // Draw the base triangle, then a triangle in stencilFront of the base triangle with the
134             // given depth comparison function
135             DoTest({ base, { state, lessColor, 0.f, 0u } }, less ? lessColor : baseColor);
136 
137             // Draw the base triangle, then a triangle in at the same depth as the base triangle with the given depth comparison function
138             DoTest({ base, { state, equalColor, 0.5f, 0u } }, equal ? equalColor : baseColor);
139 
140             // Draw the base triangle, then a triangle behind the base triangle with the given depth comparison function
141             DoTest({ base, { state, greaterColor, 1.0f, 0u } }, greater ? greaterColor :  baseColor);
142         }
143 
144         // Check whether a stencil comparison function works as expected
145         // The less, equal, greater booleans denote wether the respective triangle should be visible based on the comparison function
CheckStencilCompareFunction(dawn::CompareFunction compareFunction,bool less,bool equal,bool greater)146         void CheckStencilCompareFunction(dawn::CompareFunction compareFunction, bool less, bool equal, bool greater) {
147             dawn::StencilStateFaceDescriptor baseStencilFaceDescriptor;
148             baseStencilFaceDescriptor.compare = dawn::CompareFunction::Always;
149             baseStencilFaceDescriptor.failOp = dawn::StencilOperation::Keep;
150             baseStencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Keep;
151             baseStencilFaceDescriptor.passOp = dawn::StencilOperation::Replace;
152             dawn::DepthStencilStateDescriptor baseState;
153             baseState.depthWriteEnabled = false;
154             baseState.depthCompare = dawn::CompareFunction::Always;
155             baseState.stencilBack = baseStencilFaceDescriptor;
156             baseState.stencilFront = baseStencilFaceDescriptor;
157             baseState.stencilReadMask = 0xff;
158             baseState.stencilWriteMask = 0xff;
159 
160             dawn::StencilStateFaceDescriptor stencilFaceDescriptor;
161             stencilFaceDescriptor.compare = compareFunction;
162             stencilFaceDescriptor.failOp = dawn::StencilOperation::Keep;
163             stencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Keep;
164             stencilFaceDescriptor.passOp = dawn::StencilOperation::Keep;
165             dawn::DepthStencilStateDescriptor state;
166             state.depthWriteEnabled = false;
167             state.depthCompare = dawn::CompareFunction::Always;
168             state.stencilBack = stencilFaceDescriptor;
169             state.stencilFront = stencilFaceDescriptor;
170             state.stencilReadMask = 0xff;
171             state.stencilWriteMask = 0xff;
172 
173             RGBA8 baseColor = RGBA8(255, 255, 255, 255);
174             RGBA8 lessColor = RGBA8(255, 0, 0, 255);
175             RGBA8 equalColor = RGBA8(0, 255, 0, 255);
176             RGBA8 greaterColor = RGBA8(0, 0, 255, 255);
177 
178             // Base triangle with stencil reference 1
179             TestSpec base = { baseState, baseColor, 0.0f, 1u };
180 
181             // Draw the base triangle, then a triangle with stencil reference 0 with the given stencil comparison function
182             DoTest({ base, { state, lessColor, 0.f, 0u } }, less ? lessColor : baseColor);
183 
184             // Draw the base triangle, then a triangle with stencil reference 1 with the given stencil comparison function
185             DoTest({ base, { state, equalColor, 0.f, 1u } }, equal ? equalColor : baseColor);
186 
187             // Draw the base triangle, then a triangle with stencil reference 2 with the given stencil comparison function
188             DoTest({ base, { state, greaterColor, 0.f, 2u } }, greater ? greaterColor : baseColor);
189         }
190 
191         // Given the provided `initialStencil` and `reference`, check that applying the `stencilOperation` produces the `expectedStencil`
CheckStencilOperation(dawn::StencilOperation stencilOperation,uint32_t initialStencil,uint32_t reference,uint32_t expectedStencil)192         void CheckStencilOperation(dawn::StencilOperation stencilOperation, uint32_t initialStencil, uint32_t reference, uint32_t expectedStencil) {
193             dawn::StencilStateFaceDescriptor baseStencilFaceDescriptor;
194             baseStencilFaceDescriptor.compare = dawn::CompareFunction::Always;
195             baseStencilFaceDescriptor.failOp = dawn::StencilOperation::Keep;
196             baseStencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Keep;
197             baseStencilFaceDescriptor.passOp = dawn::StencilOperation::Replace;
198             dawn::DepthStencilStateDescriptor baseState;
199             baseState.depthWriteEnabled = false;
200             baseState.depthCompare = dawn::CompareFunction::Always;
201             baseState.stencilBack = baseStencilFaceDescriptor;
202             baseState.stencilFront = baseStencilFaceDescriptor;
203             baseState.stencilReadMask = 0xff;
204             baseState.stencilWriteMask = 0xff;
205 
206             dawn::StencilStateFaceDescriptor stencilFaceDescriptor;
207             stencilFaceDescriptor.compare = dawn::CompareFunction::Always;
208             stencilFaceDescriptor.failOp = dawn::StencilOperation::Keep;
209             stencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Keep;
210             stencilFaceDescriptor.passOp = stencilOperation;
211             dawn::DepthStencilStateDescriptor state;
212             state.depthWriteEnabled = false;
213             state.depthCompare = dawn::CompareFunction::Always;
214             state.stencilBack = stencilFaceDescriptor;
215             state.stencilFront = stencilFaceDescriptor;
216             state.stencilReadMask = 0xff;
217             state.stencilWriteMask = 0xff;
218 
219             CheckStencil({
220                 // Wipe the stencil buffer with the initialStencil value
221                 { baseState, RGBA8(255, 255, 255, 255), 0.f, initialStencil },
222 
223                 // Draw a triangle with the provided stencil operation and reference
224                 { state, RGBA8(255, 0, 0, 255), 0.f, reference },
225             }, expectedStencil);
226         }
227 
228         // 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)229         void CheckStencil(std::vector<TestSpec> testParams, uint32_t expectedStencil) {
230             dawn::StencilStateFaceDescriptor stencilFaceDescriptor;
231             stencilFaceDescriptor.compare = dawn::CompareFunction::Equal;
232             stencilFaceDescriptor.failOp = dawn::StencilOperation::Keep;
233             stencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Keep;
234             stencilFaceDescriptor.passOp = dawn::StencilOperation::Keep;
235             dawn::DepthStencilStateDescriptor state;
236             state.depthWriteEnabled = false;
237             state.depthCompare = dawn::CompareFunction::Always;
238             state.stencilBack = stencilFaceDescriptor;
239             state.stencilFront = stencilFaceDescriptor;
240             state.stencilReadMask = 0xff;
241             state.stencilWriteMask = 0xff;
242 
243             testParams.push_back({ state, RGBA8(0, 255, 0, 255), 0, expectedStencil });
244             DoTest(testParams, RGBA8(0, 255, 0, 255));
245         }
246 
247         // Each test param represents a pair of triangles with a color, depth, stencil value, and depthStencil state, one frontfacing, one backfacing
248         // Draw the triangles in order and check the expected colors for the frontfaces and backfaces
DoTest(const std::vector<TestSpec> & testParams,const RGBA8 & expectedFront,const RGBA8 & expectedBack)249         void DoTest(const std::vector<TestSpec> &testParams, const RGBA8& expectedFront, const RGBA8& expectedBack) {
250             dawn::CommandEncoder encoder = device.CreateCommandEncoder();
251 
252             struct TriangleData {
253                 float color[3];
254                 float depth;
255             };
256 
257             utils::ComboRenderPassDescriptor renderPass({renderTargetView}, depthTextureView);
258             dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
259 
260             for (size_t i = 0; i < testParams.size(); ++i) {
261                 const TestSpec& test = testParams[i];
262 
263                 TriangleData data = {
264                     {  static_cast<float>(test.color.r) / 255.f, static_cast<float>(test.color.g) / 255.f, static_cast<float>(test.color.b) / 255.f },
265                     test.depth,
266                 };
267                 // Upload a buffer for each triangle's depth and color data
268                 dawn::Buffer buffer = utils::CreateBufferFromData(device, &data, sizeof(TriangleData), dawn::BufferUsageBit::Uniform);
269 
270                 // Create a bind group for the data
271                 dawn::BindGroup bindGroup = utils::MakeBindGroup(device, bindGroupLayout, {{0, buffer, 0, sizeof(TriangleData)}});
272 
273                 // Create a pipeline for the triangles with the test spec's depth stencil state
274 
275                 utils::ComboRenderPipelineDescriptor descriptor(device);
276                 descriptor.layout = pipelineLayout;
277                 descriptor.cVertexStage.module = vsModule;
278                 descriptor.cFragmentStage.module = fsModule;
279                 descriptor.cDepthStencilState = test.depthStencilState;
280                 descriptor.cDepthStencilState.format = dawn::TextureFormat::Depth24PlusStencil8;
281                 descriptor.depthStencilState = &descriptor.cDepthStencilState;
282 
283                 dawn::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor);
284 
285                 pass.SetPipeline(pipeline);
286                 pass.SetStencilReference(test.stencil);  // Set the stencil reference
287                 pass.SetBindGroup(0, bindGroup, 0, nullptr);         // Set the bind group which contains color and depth data
288                 pass.Draw(6, 1, 0, 0);
289             }
290             pass.EndPass();
291 
292             dawn::CommandBuffer commands = encoder.Finish();
293             queue.Submit(1, &commands);
294 
295             EXPECT_PIXEL_RGBA8_EQ(expectedFront, renderTarget, kRTSize / 4, kRTSize / 2) << "Front face check failed";
296             EXPECT_PIXEL_RGBA8_EQ(expectedBack, renderTarget, 3 * kRTSize / 4, kRTSize / 2) << "Back face check failed";
297         }
298 
DoTest(const std::vector<TestSpec> & testParams,const RGBA8 & expected)299         void DoTest(const std::vector<TestSpec> &testParams, const RGBA8& expected) {
300             DoTest(testParams, expected, expected);
301         }
302 
303         dawn::Texture renderTarget;
304         dawn::Texture depthTexture;
305         dawn::TextureView renderTargetView;
306         dawn::TextureView depthTextureView;
307         dawn::ShaderModule vsModule;
308         dawn::ShaderModule fsModule;
309         dawn::BindGroupLayout bindGroupLayout;
310         dawn::PipelineLayout pipelineLayout;
311 };
312 
313 // Test compilation and usage of the fixture
TEST_P(DepthStencilStateTest,Basic)314 TEST_P(DepthStencilStateTest, Basic) {
315     dawn::StencilStateFaceDescriptor stencilFace;
316     stencilFace.compare = dawn::CompareFunction::Always;
317     stencilFace.failOp = dawn::StencilOperation::Keep;
318     stencilFace.depthFailOp = dawn::StencilOperation::Keep;
319     stencilFace.passOp = dawn::StencilOperation::Keep;
320 
321     dawn::DepthStencilStateDescriptor state;
322     state.depthWriteEnabled = false;
323     state.depthCompare = dawn::CompareFunction::Always;
324     state.stencilBack = stencilFace;
325     state.stencilFront = stencilFace;
326     state.stencilReadMask = 0xff;
327     state.stencilWriteMask = 0xff;
328 
329     DoTest({
330         { state, RGBA8(0, 255, 0, 255), 0.5f, 0u },
331     }, RGBA8(0, 255, 0, 255));
332 }
333 
334 // Test defaults: depth and stencil tests disabled
TEST_P(DepthStencilStateTest,DepthStencilDisabled)335 TEST_P(DepthStencilStateTest, DepthStencilDisabled) {
336     dawn::StencilStateFaceDescriptor stencilFace;
337     stencilFace.compare = dawn::CompareFunction::Always;
338     stencilFace.failOp = dawn::StencilOperation::Keep;
339     stencilFace.depthFailOp = dawn::StencilOperation::Keep;
340     stencilFace.passOp = dawn::StencilOperation::Keep;
341 
342     dawn::DepthStencilStateDescriptor state;
343     state.depthWriteEnabled = false;
344     state.depthCompare = dawn::CompareFunction::Always;
345     state.stencilBack = stencilFace;
346     state.stencilFront = stencilFace;
347     state.stencilReadMask = 0xff;
348     state.stencilWriteMask = 0xff;
349 
350     TestSpec specs[3] = {
351         { state, RGBA8(255, 0, 0, 255), 0.0f, 0u },
352         { state, RGBA8(0, 255, 0, 255), 0.5f, 0u },
353         { state, RGBA8(0, 0, 255, 255), 1.0f, 0u },
354     };
355 
356     // Test that for all combinations, the last triangle drawn is the one visible
357     // We check against three triangles because the stencil test may modify results
358     for (uint32_t last = 0; last < 3; ++last) {
359         uint32_t i = (last + 1) % 3;
360         uint32_t j = (last + 2) % 3;
361         DoTest({ specs[i], specs[j], specs[last] }, specs[last].color);
362         DoTest({ specs[j], specs[i], specs[last] }, specs[last].color);
363     }
364 }
365 
366 // The following tests check that each depth comparison function works
TEST_P(DepthStencilStateTest,DepthAlways)367 TEST_P(DepthStencilStateTest, DepthAlways) {
368     CheckDepthCompareFunction(dawn::CompareFunction::Always , true, true, true);
369 }
370 
TEST_P(DepthStencilStateTest,DepthEqual)371 TEST_P(DepthStencilStateTest, DepthEqual) {
372     CheckDepthCompareFunction(dawn::CompareFunction::Equal, false, true, false);
373 }
374 
TEST_P(DepthStencilStateTest,DepthGreater)375 TEST_P(DepthStencilStateTest, DepthGreater) {
376     CheckDepthCompareFunction(dawn::CompareFunction::Greater, false, false, true);
377 }
378 
TEST_P(DepthStencilStateTest,DepthGreaterEqual)379 TEST_P(DepthStencilStateTest, DepthGreaterEqual) {
380     CheckDepthCompareFunction(dawn::CompareFunction::GreaterEqual, false, true, true);
381 }
382 
TEST_P(DepthStencilStateTest,DepthLess)383 TEST_P(DepthStencilStateTest, DepthLess) {
384     CheckDepthCompareFunction(dawn::CompareFunction::Less, true, false, false);
385 }
386 
TEST_P(DepthStencilStateTest,DepthLessEqual)387 TEST_P(DepthStencilStateTest, DepthLessEqual) {
388     CheckDepthCompareFunction(dawn::CompareFunction::LessEqual, true, true, false);
389 }
390 
TEST_P(DepthStencilStateTest,DepthNever)391 TEST_P(DepthStencilStateTest, DepthNever) {
392     CheckDepthCompareFunction(dawn::CompareFunction::Never, false, false, false);
393 }
394 
TEST_P(DepthStencilStateTest,DepthNotEqual)395 TEST_P(DepthStencilStateTest, DepthNotEqual) {
396     CheckDepthCompareFunction(dawn::CompareFunction::NotEqual, true, false, true);
397 }
398 
399 // Test that disabling depth writes works and leaves the depth buffer unchanged
TEST_P(DepthStencilStateTest,DepthWriteDisabled)400 TEST_P(DepthStencilStateTest, DepthWriteDisabled) {
401     dawn::StencilStateFaceDescriptor stencilFace;
402     stencilFace.compare = dawn::CompareFunction::Always;
403     stencilFace.failOp = dawn::StencilOperation::Keep;
404     stencilFace.depthFailOp = dawn::StencilOperation::Keep;
405     stencilFace.passOp = dawn::StencilOperation::Keep;
406 
407     dawn::DepthStencilStateDescriptor baseState;
408     baseState.depthWriteEnabled = true;
409     baseState.depthCompare = dawn::CompareFunction::Always;
410     baseState.stencilBack = stencilFace;
411     baseState.stencilFront = stencilFace;
412     baseState.stencilReadMask = 0xff;
413     baseState.stencilWriteMask = 0xff;
414 
415     dawn::DepthStencilStateDescriptor noDepthWrite;
416     noDepthWrite.depthWriteEnabled = false;
417     noDepthWrite.depthCompare = dawn::CompareFunction::Always;
418     noDepthWrite.stencilBack = stencilFace;
419     noDepthWrite.stencilFront = stencilFace;
420     noDepthWrite.stencilReadMask = 0xff;
421     noDepthWrite.stencilWriteMask = 0xff;
422 
423     dawn::DepthStencilStateDescriptor checkState;
424     checkState.depthWriteEnabled = false;
425     checkState.depthCompare = dawn::CompareFunction::Equal;
426     checkState.stencilBack = stencilFace;
427     checkState.stencilFront = stencilFace;
428     checkState.stencilReadMask = 0xff;
429     checkState.stencilWriteMask = 0xff;
430 
431     DoTest({
432         { baseState, RGBA8(255, 255, 255, 255), 1.f, 0u }, // Draw a base triangle with depth enabled
433         { noDepthWrite, RGBA8(0, 0, 0, 255), 0.f, 0u }, // Draw a second triangle without depth enabled
434         { checkState, RGBA8(0, 255, 0, 255), 1.f, 0u }, // Draw a third triangle which should occlude the second even though it is behind it
435     }, RGBA8(0, 255, 0, 255));
436 }
437 
438 // The following tests check that each stencil comparison function works
TEST_P(DepthStencilStateTest,StencilAlways)439 TEST_P(DepthStencilStateTest, StencilAlways) {
440     CheckStencilCompareFunction(dawn::CompareFunction::Always, true, true, true);
441 }
442 
TEST_P(DepthStencilStateTest,StencilEqual)443 TEST_P(DepthStencilStateTest, StencilEqual) {
444     CheckStencilCompareFunction(dawn::CompareFunction::Equal, false, true, false);
445 }
446 
TEST_P(DepthStencilStateTest,StencilGreater)447 TEST_P(DepthStencilStateTest, StencilGreater) {
448     CheckStencilCompareFunction(dawn::CompareFunction::Greater, false, false, true);
449 }
450 
TEST_P(DepthStencilStateTest,StencilGreaterEqual)451 TEST_P(DepthStencilStateTest, StencilGreaterEqual) {
452     CheckStencilCompareFunction(dawn::CompareFunction::GreaterEqual, false, true, true);
453 }
454 
TEST_P(DepthStencilStateTest,StencilLess)455 TEST_P(DepthStencilStateTest, StencilLess) {
456     CheckStencilCompareFunction(dawn::CompareFunction::Less, true, false, false);
457 }
458 
TEST_P(DepthStencilStateTest,StencilLessEqual)459 TEST_P(DepthStencilStateTest, StencilLessEqual) {
460     CheckStencilCompareFunction(dawn::CompareFunction::LessEqual, true, true, false);
461 }
462 
TEST_P(DepthStencilStateTest,StencilNever)463 TEST_P(DepthStencilStateTest, StencilNever) {
464     CheckStencilCompareFunction(dawn::CompareFunction::Never, false, false, false);
465 }
466 
TEST_P(DepthStencilStateTest,StencilNotEqual)467 TEST_P(DepthStencilStateTest, StencilNotEqual) {
468     CheckStencilCompareFunction(dawn::CompareFunction::NotEqual, true, false, true);
469 }
470 
471 // The following tests check that each stencil operation works
TEST_P(DepthStencilStateTest,StencilKeep)472 TEST_P(DepthStencilStateTest, StencilKeep) {
473     CheckStencilOperation(dawn::StencilOperation::Keep, 1, 3, 1);
474 }
475 
TEST_P(DepthStencilStateTest,StencilZero)476 TEST_P(DepthStencilStateTest, StencilZero) {
477     CheckStencilOperation(dawn::StencilOperation::Zero, 1, 3, 0);
478 }
479 
TEST_P(DepthStencilStateTest,StencilReplace)480 TEST_P(DepthStencilStateTest, StencilReplace) {
481     CheckStencilOperation(dawn::StencilOperation::Replace, 1, 3, 3);
482 }
483 
TEST_P(DepthStencilStateTest,StencilInvert)484 TEST_P(DepthStencilStateTest, StencilInvert) {
485     CheckStencilOperation(dawn::StencilOperation::Invert, 0xf0, 3, 0x0f);
486 }
487 
TEST_P(DepthStencilStateTest,StencilIncrementClamp)488 TEST_P(DepthStencilStateTest, StencilIncrementClamp) {
489     CheckStencilOperation(dawn::StencilOperation::IncrementClamp, 1, 3, 2);
490     CheckStencilOperation(dawn::StencilOperation::IncrementClamp, 0xff, 3, 0xff);
491 }
492 
TEST_P(DepthStencilStateTest,StencilIncrementWrap)493 TEST_P(DepthStencilStateTest, StencilIncrementWrap) {
494     CheckStencilOperation(dawn::StencilOperation::IncrementWrap, 1, 3, 2);
495     CheckStencilOperation(dawn::StencilOperation::IncrementWrap, 0xff, 3, 0);
496 }
497 
TEST_P(DepthStencilStateTest,StencilDecrementClamp)498 TEST_P(DepthStencilStateTest, StencilDecrementClamp) {
499     CheckStencilOperation(dawn::StencilOperation::DecrementClamp, 1, 3, 0);
500     CheckStencilOperation(dawn::StencilOperation::DecrementClamp, 0, 3, 0);
501 }
502 
TEST_P(DepthStencilStateTest,StencilDecrementWrap)503 TEST_P(DepthStencilStateTest, StencilDecrementWrap) {
504     CheckStencilOperation(dawn::StencilOperation::DecrementWrap, 1, 3, 0);
505     CheckStencilOperation(dawn::StencilOperation::DecrementWrap, 0, 3, 0xff);
506 }
507 
508 // Check that the setting a stencil read mask works
TEST_P(DepthStencilStateTest,StencilReadMask)509 TEST_P(DepthStencilStateTest, StencilReadMask) {
510     dawn::StencilStateFaceDescriptor baseStencilFaceDescriptor;
511     baseStencilFaceDescriptor.compare = dawn::CompareFunction::Always;
512     baseStencilFaceDescriptor.failOp = dawn::StencilOperation::Keep;
513     baseStencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Keep;
514     baseStencilFaceDescriptor.passOp = dawn::StencilOperation::Replace;
515     dawn::DepthStencilStateDescriptor baseState;
516     baseState.depthWriteEnabled = false;
517     baseState.depthCompare = dawn::CompareFunction::Always;
518     baseState.stencilBack = baseStencilFaceDescriptor;
519     baseState.stencilFront = baseStencilFaceDescriptor;
520     baseState.stencilReadMask = 0xff;
521     baseState.stencilWriteMask = 0xff;
522 
523     dawn::StencilStateFaceDescriptor stencilFaceDescriptor;
524     stencilFaceDescriptor.compare = dawn::CompareFunction::Equal;
525     stencilFaceDescriptor.failOp = dawn::StencilOperation::Keep;
526     stencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Keep;
527     stencilFaceDescriptor.passOp = dawn::StencilOperation::Keep;
528     dawn::DepthStencilStateDescriptor state;
529     state.depthWriteEnabled = false;
530     state.depthCompare = dawn::CompareFunction::Always;
531     state.stencilBack = stencilFaceDescriptor;
532     state.stencilFront = stencilFaceDescriptor;
533     state.stencilReadMask = 0x2;
534     state.stencilWriteMask = 0xff;
535 
536     RGBA8 baseColor = RGBA8(255, 255, 255, 255);
537     RGBA8 red = RGBA8(255, 0, 0, 255);
538     RGBA8 green = RGBA8(0, 255, 0, 255);
539 
540     TestSpec base = { baseState, baseColor, 0.5f, 3u };     // Base triangle to set the stencil to 3
541     DoTest({ base, { state, red, 0.f, 1u } }, baseColor);   // Triangle with stencil reference 1 and read mask 2 does not draw because (3 & 2 != 1)
542     DoTest({ base, { state, green, 0.f, 2u } }, green);     // Triangle with stencil reference 2 and read mask 2 draws because (3 & 2 == 2)
543 }
544 
545 // Check that setting a stencil write mask works
TEST_P(DepthStencilStateTest,StencilWriteMask)546 TEST_P(DepthStencilStateTest, StencilWriteMask) {
547     dawn::StencilStateFaceDescriptor baseStencilFaceDescriptor;
548     baseStencilFaceDescriptor.compare = dawn::CompareFunction::Always;
549     baseStencilFaceDescriptor.failOp = dawn::StencilOperation::Keep;
550     baseStencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Keep;
551     baseStencilFaceDescriptor.passOp = dawn::StencilOperation::Replace;
552     dawn::DepthStencilStateDescriptor baseState;
553     baseState.depthWriteEnabled = false;
554     baseState.depthCompare = dawn::CompareFunction::Always;
555     baseState.stencilBack = baseStencilFaceDescriptor;
556     baseState.stencilFront = baseStencilFaceDescriptor;
557     baseState.stencilReadMask = 0xff;
558     baseState.stencilWriteMask = 0x1;
559 
560     dawn::StencilStateFaceDescriptor stencilFaceDescriptor;
561     stencilFaceDescriptor.compare = dawn::CompareFunction::Equal;
562     stencilFaceDescriptor.failOp = dawn::StencilOperation::Keep;
563     stencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Keep;
564     stencilFaceDescriptor.passOp = dawn::StencilOperation::Keep;
565     dawn::DepthStencilStateDescriptor state;
566     state.depthWriteEnabled = false;
567     state.depthCompare = dawn::CompareFunction::Always;
568     state.stencilBack = stencilFaceDescriptor;
569     state.stencilFront = stencilFaceDescriptor;
570     state.stencilReadMask = 0xff;
571     state.stencilWriteMask = 0xff;
572 
573     RGBA8 baseColor = RGBA8(255, 255, 255, 255);
574     RGBA8 green = RGBA8(0, 255, 0, 255);
575 
576     TestSpec base = { baseState, baseColor, 0.5f, 3u };         // Base triangle with stencil reference 3 and mask 1 to set the stencil 1
577     DoTest({ base, { state, green, 0.f, 2u } }, baseColor);     // Triangle with stencil reference 2 does not draw because 2 != (3 & 1)
578     DoTest({ base, { state, green, 0.f, 1u } }, green);         // Triangle with stencil reference 1 draws because 1 == (3 & 1)
579 }
580 
581 // Test that the stencil operation is executed on stencil fail
TEST_P(DepthStencilStateTest,StencilFail)582 TEST_P(DepthStencilStateTest, StencilFail) {
583     dawn::StencilStateFaceDescriptor baseStencilFaceDescriptor;
584     baseStencilFaceDescriptor.compare = dawn::CompareFunction::Always;
585     baseStencilFaceDescriptor.failOp = dawn::StencilOperation::Keep;
586     baseStencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Keep;
587     baseStencilFaceDescriptor.passOp = dawn::StencilOperation::Replace;
588     dawn::DepthStencilStateDescriptor baseState;
589     baseState.depthWriteEnabled = false;
590     baseState.depthCompare = dawn::CompareFunction::Always;
591     baseState.stencilBack = baseStencilFaceDescriptor;
592     baseState.stencilFront = baseStencilFaceDescriptor;
593     baseState.stencilReadMask = 0xff;
594     baseState.stencilWriteMask = 0xff;
595 
596     dawn::StencilStateFaceDescriptor stencilFaceDescriptor;
597     stencilFaceDescriptor.compare = dawn::CompareFunction::Less;
598     stencilFaceDescriptor.failOp = dawn::StencilOperation::Replace;
599     stencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Keep;
600     stencilFaceDescriptor.passOp = dawn::StencilOperation::Keep;
601     dawn::DepthStencilStateDescriptor state;
602     state.depthWriteEnabled = false;
603     state.depthCompare = dawn::CompareFunction::Always;
604     state.stencilBack = stencilFaceDescriptor;
605     state.stencilFront = stencilFaceDescriptor;
606     state.stencilReadMask = 0xff;
607     state.stencilWriteMask = 0xff;
608 
609     CheckStencil({
610         { baseState, RGBA8(255, 255, 255, 255), 1.f, 1 },   // Triangle to set stencil value to 1
611         { state, RGBA8(0, 0, 0, 255), 0.f, 2 }              // Triangle with stencil reference 2 fails the Less comparison function
612     }, 2);                                                  // Replace the stencil on failure, so it should be 2
613 }
614 
615 // Test that the stencil operation is executed on stencil pass, depth fail
TEST_P(DepthStencilStateTest,StencilDepthFail)616 TEST_P(DepthStencilStateTest, StencilDepthFail) {
617     dawn::StencilStateFaceDescriptor baseStencilFaceDescriptor;
618     baseStencilFaceDescriptor.compare = dawn::CompareFunction::Always;
619     baseStencilFaceDescriptor.failOp = dawn::StencilOperation::Keep;
620     baseStencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Keep;
621     baseStencilFaceDescriptor.passOp = dawn::StencilOperation::Replace;
622     dawn::DepthStencilStateDescriptor baseState;
623     baseState.depthWriteEnabled = true;
624     baseState.depthCompare = dawn::CompareFunction::Always;
625     baseState.stencilBack = baseStencilFaceDescriptor;
626     baseState.stencilFront = baseStencilFaceDescriptor;
627     baseState.stencilReadMask = 0xff;
628     baseState.stencilWriteMask = 0xff;
629 
630     dawn::StencilStateFaceDescriptor stencilFaceDescriptor;
631     stencilFaceDescriptor.compare = dawn::CompareFunction::Greater;
632     stencilFaceDescriptor.failOp = dawn::StencilOperation::Keep;
633     stencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Replace;
634     stencilFaceDescriptor.passOp = dawn::StencilOperation::Keep;
635     dawn::DepthStencilStateDescriptor state;
636     state.depthWriteEnabled = true;
637     state.depthCompare = dawn::CompareFunction::Less;
638     state.stencilBack = stencilFaceDescriptor;
639     state.stencilFront = stencilFaceDescriptor;
640     state.stencilReadMask = 0xff;
641     state.stencilWriteMask = 0xff;
642 
643     CheckStencil({
644         { baseState, RGBA8(255, 255, 255, 255), 0.f, 1 },   // Triangle to set stencil value to 1. Depth is 0
645         { state, RGBA8(0, 0, 0, 255), 1.f, 2 } },           // Triangle with stencil reference 2 passes the Greater comparison function. At depth 1, it fails the Less depth test
646     2);                                                     // Replace the stencil on stencil pass, depth failure, so it should be 2
647 }
648 
649 // Test that the stencil operation is executed on stencil pass, depth pass
TEST_P(DepthStencilStateTest,StencilDepthPass)650 TEST_P(DepthStencilStateTest, StencilDepthPass) {
651     dawn::StencilStateFaceDescriptor baseStencilFaceDescriptor;
652     baseStencilFaceDescriptor.compare = dawn::CompareFunction::Always;
653     baseStencilFaceDescriptor.failOp = dawn::StencilOperation::Keep;
654     baseStencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Keep;
655     baseStencilFaceDescriptor.passOp = dawn::StencilOperation::Replace;
656     dawn::DepthStencilStateDescriptor baseState;
657     baseState.depthWriteEnabled = true;
658     baseState.depthCompare = dawn::CompareFunction::Always;
659     baseState.stencilBack = baseStencilFaceDescriptor;
660     baseState.stencilFront = baseStencilFaceDescriptor;
661     baseState.stencilReadMask = 0xff;
662     baseState.stencilWriteMask = 0xff;
663 
664     dawn::StencilStateFaceDescriptor stencilFaceDescriptor;
665     stencilFaceDescriptor.compare = dawn::CompareFunction::Greater;
666     stencilFaceDescriptor.failOp = dawn::StencilOperation::Keep;
667     stencilFaceDescriptor.depthFailOp = dawn::StencilOperation::Keep;
668     stencilFaceDescriptor.passOp = dawn::StencilOperation::Replace;
669     dawn::DepthStencilStateDescriptor state;
670     state.depthWriteEnabled = true;
671     state.depthCompare = dawn::CompareFunction::Less;
672     state.stencilBack = stencilFaceDescriptor;
673     state.stencilFront = stencilFaceDescriptor;
674     state.stencilReadMask = 0xff;
675     state.stencilWriteMask = 0xff;
676 
677     CheckStencil({
678         { baseState, RGBA8(255, 255, 255, 255), 1.f, 1 },   // Triangle to set stencil value to 1. Depth is 0
679         { state, RGBA8(0, 0, 0, 255), 0.f, 2 } },           // Triangle with stencil reference 2 passes the Greater comparison function. At depth 0, it pass the Less depth test
680 2);                                                         // Replace the stencil on stencil pass, depth pass, so it should be 2
681 }
682 
683 DAWN_INSTANTIATE_TEST(DepthStencilStateTest,
684                      D3D12Backend,
685                      MetalBackend,
686                      OpenGLBackend,
687                      VulkanBackend);
688