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