• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 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 "common/Constants.h"
16 #include "common/Math.h"
17 #include "tests/DawnTest.h"
18 #include "utils/ComboRenderPipelineDescriptor.h"
19 #include "utils/TextureUtils.h"
20 #include "utils/WGPUHelpers.h"
21 
22 constexpr static unsigned int kRTSize = 2;
23 
24 enum class QuadAngle { Flat, TiltedX };
25 
26 class DepthBiasTests : public DawnTest {
27   protected:
RunDepthBiasTest(wgpu::TextureFormat depthFormat,float depthClear,QuadAngle quadAngle,int32_t bias,float biasSlopeScale,float biasClamp)28     void RunDepthBiasTest(wgpu::TextureFormat depthFormat,
29                           float depthClear,
30                           QuadAngle quadAngle,
31                           int32_t bias,
32                           float biasSlopeScale,
33                           float biasClamp) {
34         const char* vertexSource = nullptr;
35         switch (quadAngle) {
36             case QuadAngle::Flat:
37                 // Draw a square at z = 0.25
38                 vertexSource = R"(
39     [[stage(vertex)]]
40     fn main([[builtin(vertex_index)]] VertexIndex : u32) -> [[builtin(position)]] vec4<f32> {
41         var pos = array<vec2<f32>, 6>(
42             vec2<f32>(-1.0, -1.0),
43             vec2<f32>( 1.0, -1.0),
44             vec2<f32>(-1.0,  1.0),
45             vec2<f32>(-1.0,  1.0),
46             vec2<f32>( 1.0, -1.0),
47             vec2<f32>( 1.0,  1.0));
48         return vec4<f32>(pos[VertexIndex], 0.25, 1.0);
49     })";
50                 break;
51 
52             case QuadAngle::TiltedX:
53                 // Draw a square ranging from 0 to 0.5, bottom to top
54                 vertexSource = R"(
55     [[stage(vertex)]]
56     fn main([[builtin(vertex_index)]] VertexIndex : u32) -> [[builtin(position)]] vec4<f32> {
57         var pos = array<vec3<f32>, 6>(
58             vec3<f32>(-1.0, -1.0, 0.0),
59             vec3<f32>( 1.0, -1.0, 0.0),
60             vec3<f32>(-1.0,  1.0, 0.5),
61             vec3<f32>(-1.0,  1.0, 0.5),
62             vec3<f32>( 1.0, -1.0, 0.0),
63             vec3<f32>( 1.0,  1.0, 0.5));
64         return vec4<f32>(pos[VertexIndex], 1.0);
65     })";
66                 break;
67         }
68 
69         wgpu::ShaderModule vertexModule = utils::CreateShaderModule(device, vertexSource);
70 
71         wgpu::ShaderModule fragmentModule = utils::CreateShaderModule(device, R"(
72     [[stage(fragment)]] fn main() -> [[location(0)]] vec4<f32> {
73         return vec4<f32>(1.0, 0.0, 0.0, 1.0);
74     })");
75 
76         {
77             wgpu::TextureDescriptor descriptor;
78             descriptor.size = {kRTSize, kRTSize, 1};
79             descriptor.format = depthFormat;
80             descriptor.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc;
81             mDepthTexture = device.CreateTexture(&descriptor);
82         }
83 
84         {
85             wgpu::TextureDescriptor descriptor;
86             descriptor.size = {kRTSize, kRTSize, 1};
87             descriptor.format = wgpu::TextureFormat::RGBA8Unorm;
88             descriptor.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc;
89             mRenderTarget = device.CreateTexture(&descriptor);
90         }
91 
92         // Create a render pass which clears depth to depthClear
93         utils::ComboRenderPassDescriptor renderPassDesc({mRenderTarget.CreateView()},
94                                                         mDepthTexture.CreateView());
95         renderPassDesc.cDepthStencilAttachmentInfo.clearDepth = depthClear;
96 
97         // Create a render pipeline to render the quad
98         utils::ComboRenderPipelineDescriptor renderPipelineDesc;
99 
100         renderPipelineDesc.vertex.module = vertexModule;
101         renderPipelineDesc.cFragment.module = fragmentModule;
102         wgpu::DepthStencilState* depthStencil = renderPipelineDesc.EnableDepthStencil(depthFormat);
103         depthStencil->depthWriteEnabled = true;
104         depthStencil->depthBias = bias;
105         depthStencil->depthBiasSlopeScale = biasSlopeScale;
106         depthStencil->depthBiasClamp = biasClamp;
107 
108         if (depthFormat != wgpu::TextureFormat::Depth32Float) {
109             depthStencil->depthCompare = wgpu::CompareFunction::Greater;
110         }
111 
112         wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&renderPipelineDesc);
113 
114         // Draw the quad (two triangles)
115         wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
116         wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPassDesc);
117         pass.SetPipeline(pipeline);
118         pass.Draw(6);
119         pass.EndPass();
120 
121         wgpu::CommandBuffer commands = commandEncoder.Finish();
122         queue.Submit(1, &commands);
123     }
124 
125     // Floating point depth buffers use the following formula to calculate bias
126     // bias = depthBias * 2 ** (exponent(max z of primitive) - number of bits in mantissa) +
127     //        slopeScale * maxSlope
128     // https://docs.microsoft.com/en-us/windows/win32/direct3d11/d3d10-graphics-programming-guide-output-merger-stage-depth-bias
129     // https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkCmdSetDepthBias.html
130     // https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1516269-setdepthbias
131     //
132     // To get a final bias of 0.25 for primitives with z = 0.25, we can use
133     // depthBias = 0.25 / (2 ** (-2 - 23)) = 8388608
134     static constexpr int32_t kPointTwoFiveBiasForPointTwoFiveZOnFloat = 8388608;
135 
136     wgpu::Texture mDepthTexture;
137     wgpu::Texture mRenderTarget;
138 };
139 
140 // Test adding positive bias to output
TEST_P(DepthBiasTests,PositiveBiasOnFloat)141 TEST_P(DepthBiasTests, PositiveBiasOnFloat) {
142     // NVIDIA GPUs under Vulkan seem to be using a different scale than everyone else.
143     DAWN_SUPPRESS_TEST_IF(IsVulkan() && IsNvidia());
144 
145     // OpenGL uses a different scale than the other APIs
146     DAWN_TEST_UNSUPPORTED_IF(IsOpenGL());
147     DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
148 
149     // Draw quad flat on z = 0.25 with 0.25 bias
150     RunDepthBiasTest(wgpu::TextureFormat::Depth32Float, 0, QuadAngle::Flat,
151                      kPointTwoFiveBiasForPointTwoFiveZOnFloat, 0, 0);
152 
153     // Quad at z = 0.25 + 0.25 bias = 0.5
154     std::vector<float> expected = {
155         0.5, 0.5,  //
156         0.5, 0.5,  //
157     };
158 
159     EXPECT_TEXTURE_EQ(expected.data(), mDepthTexture, {0, 0}, {kRTSize, kRTSize}, 0,
160                       wgpu::TextureAspect::DepthOnly);
161 }
162 
163 // Test adding positive bias to output with a clamp
TEST_P(DepthBiasTests,PositiveBiasOnFloatWithClamp)164 TEST_P(DepthBiasTests, PositiveBiasOnFloatWithClamp) {
165     // Clamping support in OpenGL is spotty
166     DAWN_TEST_UNSUPPORTED_IF(IsOpenGL());
167     DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
168 
169     // Draw quad flat on z = 0.25 with 0.25 bias clamped at 0.125.
170     RunDepthBiasTest(wgpu::TextureFormat::Depth32Float, 0, QuadAngle::Flat,
171                      kPointTwoFiveBiasForPointTwoFiveZOnFloat, 0, 0.125);
172 
173     // Quad at z = 0.25 + min(0.25 bias, 0.125 clamp) = 0.375
174     std::vector<float> expected = {
175         0.375, 0.375,  //
176         0.375, 0.375,  //
177     };
178 
179     EXPECT_TEXTURE_EQ(expected.data(), mDepthTexture, {0, 0}, {kRTSize, kRTSize}, 0,
180                       wgpu::TextureAspect::DepthOnly);
181 }
182 
183 // Test adding negative bias to output
TEST_P(DepthBiasTests,NegativeBiasOnFloat)184 TEST_P(DepthBiasTests, NegativeBiasOnFloat) {
185     // NVIDIA GPUs seems to be using a different scale than everyone else
186     DAWN_SUPPRESS_TEST_IF(IsVulkan() && IsNvidia());
187 
188     // OpenGL uses a different scale than the other APIs
189     DAWN_TEST_UNSUPPORTED_IF(IsOpenGL());
190 
191     // Draw quad flat on z = 0.25 with -0.25 bias, depth clear of 0.125
192     RunDepthBiasTest(wgpu::TextureFormat::Depth32Float, 0.125, QuadAngle::Flat,
193                      -kPointTwoFiveBiasForPointTwoFiveZOnFloat, 0, 0);
194 
195     // Quad at z = 0.25 - 0.25 bias = 0
196     std::vector<float> expected = {
197         0.0, 0.0,  //
198         0.0, 0.0,  //
199     };
200 
201     EXPECT_TEXTURE_EQ(expected.data(), mDepthTexture, {0, 0}, {kRTSize, kRTSize}, 0,
202                       wgpu::TextureAspect::DepthOnly);
203 }
204 
205 // Test adding negative bias to output with a clamp
TEST_P(DepthBiasTests,NegativeBiasOnFloatWithClamp)206 TEST_P(DepthBiasTests, NegativeBiasOnFloatWithClamp) {
207     // Clamping support in OpenGL is spotty
208     DAWN_TEST_UNSUPPORTED_IF(IsOpenGL());
209     DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
210 
211     // Draw quad flat on z = 0.25 with -0.25 bias clamped at -0.125.
212     RunDepthBiasTest(wgpu::TextureFormat::Depth32Float, 0, QuadAngle::Flat,
213                      -kPointTwoFiveBiasForPointTwoFiveZOnFloat, 0, -0.125);
214 
215     // Quad at z = 0.25 + max(-0.25 bias, -0.125 clamp) = 0.125
216     std::vector<float> expected = {
217         0.125, 0.125,  //
218         0.125, 0.125,  //
219     };
220 
221     EXPECT_TEXTURE_EQ(expected.data(), mDepthTexture, {0, 0}, {kRTSize, kRTSize}, 0,
222                       wgpu::TextureAspect::DepthOnly);
223 }
224 
225 // Test adding positive infinite slope bias to output
TEST_P(DepthBiasTests,PositiveInfinitySlopeBiasOnFloat)226 TEST_P(DepthBiasTests, PositiveInfinitySlopeBiasOnFloat) {
227     // NVIDIA GPUs do not clamp values to 1 when using Inf slope bias.
228     DAWN_SUPPRESS_TEST_IF(IsVulkan() && IsNvidia());
229 
230     // Draw quad with z from 0 to 0.5 with inf slope bias
231     RunDepthBiasTest(wgpu::TextureFormat::Depth32Float, 0.125, QuadAngle::TiltedX, 0,
232                      std::numeric_limits<float>::infinity(), 0);
233 
234     // Value at the center of the pixel + (0.25 slope * Inf slope bias) = 1 (clamped)
235     std::vector<float> expected = {
236         1.0, 1.0,  //
237         1.0, 1.0,  //
238     };
239 
240     EXPECT_TEXTURE_EQ(expected.data(), mDepthTexture, {0, 0}, {kRTSize, kRTSize}, 0,
241                       wgpu::TextureAspect::DepthOnly);
242 }
243 
244 // Test adding positive infinite slope bias to output
TEST_P(DepthBiasTests,NegativeInfinityBiasOnFloat)245 TEST_P(DepthBiasTests, NegativeInfinityBiasOnFloat) {
246     // NVIDIA GPUs do not clamp values to 0 when using -Inf slope bias.
247     DAWN_SUPPRESS_TEST_IF(IsVulkan() && IsNvidia());
248 
249     // Draw quad with z from 0 to 0.5 with -inf slope bias
250     RunDepthBiasTest(wgpu::TextureFormat::Depth32Float, 0.125, QuadAngle::TiltedX, 0,
251                      -std::numeric_limits<float>::infinity(), 0);
252 
253     // Value at the center of the pixel + (0.25 slope * -Inf slope bias) = 0 (clamped)
254     std::vector<float> expected = {
255         0.0, 0.0,  //
256         0.0, 0.0,  //
257     };
258 
259     EXPECT_TEXTURE_EQ(expected.data(), mDepthTexture, {0, 0}, {kRTSize, kRTSize}, 0,
260                       wgpu::TextureAspect::DepthOnly);
261 }
262 
263 // Test tiledX quad with no bias
TEST_P(DepthBiasTests,NoBiasTiltedXOnFloat)264 TEST_P(DepthBiasTests, NoBiasTiltedXOnFloat) {
265     // Draw quad with z from 0 to 0.5 with no bias
266     RunDepthBiasTest(wgpu::TextureFormat::Depth32Float, 0, QuadAngle::TiltedX, 0, 0, 0);
267 
268     // Depth values of TiltedX quad. Values at the center of the pixels.
269     std::vector<float> expected = {
270         0.375, 0.375,  //
271         0.125, 0.125,  //
272     };
273 
274     EXPECT_TEXTURE_EQ(expected.data(), mDepthTexture, {0, 0}, {kRTSize, kRTSize}, 0,
275                       wgpu::TextureAspect::DepthOnly);
276 }
277 
278 // Test adding positive slope bias to output
TEST_P(DepthBiasTests,PositiveSlopeBiasOnFloat)279 TEST_P(DepthBiasTests, PositiveSlopeBiasOnFloat) {
280     // Draw quad with z from 0 to 0.5 with a slope bias of 1
281     RunDepthBiasTest(wgpu::TextureFormat::Depth32Float, 0, QuadAngle::TiltedX, 0, 1, 0);
282 
283     // Value at the center of the pixel + (0.25 slope * 1.0 slope bias)
284     std::vector<float> expected = {
285         0.625, 0.625,  //
286         0.375, 0.375,  //
287     };
288 
289     EXPECT_TEXTURE_EQ(expected.data(), mDepthTexture, {0, 0}, {kRTSize, kRTSize}, 0,
290                       wgpu::TextureAspect::DepthOnly);
291 }
292 
293 // Test adding negative half slope bias to output
TEST_P(DepthBiasTests,NegativeHalfSlopeBiasOnFloat)294 TEST_P(DepthBiasTests, NegativeHalfSlopeBiasOnFloat) {
295     // Draw quad with z from 0 to 0.5 with a slope bias of -0.5
296     RunDepthBiasTest(wgpu::TextureFormat::Depth32Float, 0, QuadAngle::TiltedX, 0, -0.5, 0);
297 
298     // Value at the center of the pixel + (0.25 slope * -0.5 slope bias)
299     std::vector<float> expected = {
300         0.25, 0.25,  //
301         0.0, 0.0,    //
302     };
303 
304     EXPECT_TEXTURE_EQ(expected.data(), mDepthTexture, {0, 0}, {kRTSize, kRTSize}, 0,
305                       wgpu::TextureAspect::DepthOnly);
306 }
307 
308 // Test adding positive bias to output
TEST_P(DepthBiasTests,PositiveBiasOn24bit)309 TEST_P(DepthBiasTests, PositiveBiasOn24bit) {
310     // Draw quad flat on z = 0.25 with 0.25 bias
311     RunDepthBiasTest(wgpu::TextureFormat::Depth24PlusStencil8, 0.4f, QuadAngle::Flat,
312                      0.25f * (1 << 25), 0, 0);
313 
314     // Only the bottom left quad has colors. 0.5 quad > 0.4 clear.
315     // TODO(crbug.com/dawn/820): Switch to depth sampling once feature has been enabled.
316     std::vector<RGBA8> expected = {
317         RGBA8::kRed, RGBA8::kRed,  //
318         RGBA8::kRed, RGBA8::kRed,  //
319     };
320 
321     EXPECT_TEXTURE_EQ(expected.data(), mRenderTarget, {0, 0}, {kRTSize, kRTSize});
322 }
323 
324 // Test adding positive bias to output with a clamp
TEST_P(DepthBiasTests,PositiveBiasOn24bitWithClamp)325 TEST_P(DepthBiasTests, PositiveBiasOn24bitWithClamp) {
326     // Clamping support in OpenGL is spotty
327     DAWN_TEST_UNSUPPORTED_IF(IsOpenGL());
328     DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
329 
330     // Draw quad flat on z = 0.25 with 0.25 bias clamped at 0.125.
331     RunDepthBiasTest(wgpu::TextureFormat::Depth24PlusStencil8, 0.4f, QuadAngle::Flat,
332                      0.25f * (1 << 25), 0, 0.1f);
333 
334     // Since we cleared with a depth of 0.4 and clamped bias at 0.4, the depth test will fail. 0.25
335     // + 0.125 < 0.4 clear.
336     // TODO(crbug.com/dawn/820): Switch to depth sampling once feature has been enabled.
337     std::vector<RGBA8> zero = {
338         RGBA8::kZero, RGBA8::kZero,  //
339         RGBA8::kZero, RGBA8::kZero,  //
340     };
341 
342     EXPECT_TEXTURE_EQ(zero.data(), mRenderTarget, {0, 0}, {kRTSize, kRTSize});
343 }
344 
345 // Test adding positive bias to output
TEST_P(DepthBiasTests,PositiveSlopeBiasOn24bit)346 TEST_P(DepthBiasTests, PositiveSlopeBiasOn24bit) {
347     // Draw quad with z from 0 to 0.5 with a slope bias of 1
348     RunDepthBiasTest(wgpu::TextureFormat::Depth24PlusStencil8, 0.4f, QuadAngle::TiltedX, 0, 1, 0);
349 
350     // Only the top half of the quad has a depth > 0.4 clear
351     // TODO(crbug.com/dawn/820): Switch to depth sampling once feature has been enabled.
352     std::vector<RGBA8> expected = {
353         RGBA8::kRed, RGBA8::kRed,    //
354         RGBA8::kZero, RGBA8::kZero,  //
355     };
356 
357     EXPECT_TEXTURE_EQ(expected.data(), mRenderTarget, {0, 0}, {kRTSize, kRTSize});
358 }
359 
360 DAWN_INSTANTIATE_TEST(DepthBiasTests,
361                       D3D12Backend(),
362                       MetalBackend(),
363                       OpenGLBackend(),
364                       OpenGLESBackend(),
365                       VulkanBackend());
366