xref: /aosp_15_r20/external/angle/src/tests/gl_tests/DepthWriteTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2023 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // The tests assert OpenGL behavior for all combinations of the following states
7 // - Depth Range
8 //   - Full (0, 1)
9 //   - Reduced
10 // - Depth Clamp
11 //   - Enabled (if supported)
12 //   - Disabled
13 // - Vertex Depth
14 //   - Inside clip volume
15 //   - Less than -1
16 //   - Greater than +1
17 // - gl_FragDepth
18 //   - Unused
19 //   - Passthrough (gl_FragCoord.z)
20 //   - Within the depth range
21 //   - Between 0 and near clipping plane
22 //   - Between 1 and far clipping plane
23 //   - Negative
24 //   - Greater than 1
25 // - Depth buffer format
26 //   - DEPTH_COMPONENT16
27 //   - DEPTH_COMPONENT32F (ES 3.x only)
28 
29 #include "test_utils/ANGLETest.h"
30 #include "test_utils/gl_raii.h"
31 
32 using namespace angle;
33 
34 namespace
35 {
36 
37 enum class DepthRange
38 {
39     Full,
40     Reduced,
41 };
42 
43 enum class VertexDepth
44 {
45     InsideClipVolume,
46     LessThanMinusOne,
47     GreaterThanOne,
48 };
49 
50 enum class FragmentDepth
51 {
52     Unused,
53     Passthrough,
54     WithinDepthRange,
55     BetweenZeroAndNearPlane,
56     BetweenFarPlaneAndOne,
57     Negative,
58     GreaterThanOne,
59 };
60 
61 // Variations corresponding to enums above.
62 using DepthWriteVariationsTestParams =
63     std::tuple<angle::PlatformParameters, DepthRange, bool, VertexDepth, FragmentDepth, GLenum>;
64 
operator <<(std::ostream & out,DepthRange depthRange)65 std::ostream &operator<<(std::ostream &out, DepthRange depthRange)
66 {
67     switch (depthRange)
68     {
69         case DepthRange::Full:
70             out << "Full";
71             break;
72         case DepthRange::Reduced:
73             out << "Reduced";
74             break;
75     }
76 
77     return out;
78 }
79 
operator <<(std::ostream & out,VertexDepth vertexDepth)80 std::ostream &operator<<(std::ostream &out, VertexDepth vertexDepth)
81 {
82     switch (vertexDepth)
83     {
84         case VertexDepth::InsideClipVolume:
85             out << "InsideClipVolume";
86             break;
87         case VertexDepth::LessThanMinusOne:
88             out << "LessThanMinusOne";
89             break;
90         case VertexDepth::GreaterThanOne:
91             out << "GreaterThanOne";
92             break;
93     }
94 
95     return out;
96 }
97 
operator <<(std::ostream & out,FragmentDepth fragmentDepth)98 std::ostream &operator<<(std::ostream &out, FragmentDepth fragmentDepth)
99 {
100     switch (fragmentDepth)
101     {
102         case FragmentDepth::Unused:
103             out << "Unused";
104             break;
105         case FragmentDepth::Passthrough:
106             out << "Passthrough";
107             break;
108         case FragmentDepth::WithinDepthRange:
109             out << "WithinDepthRange";
110             break;
111         case FragmentDepth::BetweenZeroAndNearPlane:
112             out << "BetweenZeroAndNearPlane";
113             break;
114         case FragmentDepth::BetweenFarPlaneAndOne:
115             out << "BetweenFarPlaneAndOne";
116             break;
117         case FragmentDepth::Negative:
118             out << "Negative";
119             break;
120         case FragmentDepth::GreaterThanOne:
121             out << "GreaterThanOne";
122             break;
123     }
124 
125     return out;
126 }
127 
BufferFormatToString(GLenum format)128 std::string BufferFormatToString(GLenum format)
129 {
130     switch (format)
131     {
132         case GL_DEPTH_COMPONENT16:
133             return "Depth16Unorm";
134         case GL_DEPTH_COMPONENT32F:
135             return "Depth32Float";
136         default:
137             return nullptr;
138     }
139 }
140 
ParseDepthWriteVariationsTestParams(const DepthWriteVariationsTestParams & params,DepthRange * depthRangeOut,bool * depthClampEnabledOut,VertexDepth * vertexDepthOut,FragmentDepth * fragmentDepthOut,GLenum * depthBufferFormatOut)141 void ParseDepthWriteVariationsTestParams(const DepthWriteVariationsTestParams &params,
142                                          DepthRange *depthRangeOut,
143                                          bool *depthClampEnabledOut,
144                                          VertexDepth *vertexDepthOut,
145                                          FragmentDepth *fragmentDepthOut,
146                                          GLenum *depthBufferFormatOut)
147 {
148     *depthRangeOut        = std::get<1>(params);
149     *depthClampEnabledOut = std::get<2>(params);
150     *vertexDepthOut       = std::get<3>(params);
151     *fragmentDepthOut     = std::get<4>(params);
152     *depthBufferFormatOut = std::get<5>(params);
153 }
154 
DepthWriteVariationsTestPrint(const::testing::TestParamInfo<DepthWriteVariationsTestParams> & paramsInfo)155 std::string DepthWriteVariationsTestPrint(
156     const ::testing::TestParamInfo<DepthWriteVariationsTestParams> &paramsInfo)
157 {
158     const DepthWriteVariationsTestParams &params = paramsInfo.param;
159     std::ostringstream out;
160 
161     out << std::get<0>(params);
162 
163     DepthRange depthRange;
164     bool depthClampEnabled;
165     VertexDepth vertexDepth;
166     FragmentDepth fragmentDepth;
167     GLenum depthBufferFormat;
168     ParseDepthWriteVariationsTestParams(params, &depthRange, &depthClampEnabled, &vertexDepth,
169                                         &fragmentDepth, &depthBufferFormat);
170 
171     out << "__"
172         << "DepthRange" << depthRange << "_" << (depthClampEnabled ? "Clamped" : "Clipped") << "_"
173         << "VertexDepth" << vertexDepth << "_"
174         << "FragmentDepth" << fragmentDepth << "_" << BufferFormatToString(depthBufferFormat);
175     return out.str();
176 }
177 
178 class DepthWriteTest : public ANGLETest<DepthWriteVariationsTestParams>
179 {};
180 
181 // Test correctness of depth writes
TEST_P(DepthWriteTest,Test)182 TEST_P(DepthWriteTest, Test)
183 {
184     if (getClientMajorVersion() < 3)
185     {
186         ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_depth_texture"));
187         ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_half_float"));
188     }
189     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_color_buffer_half_float") &&
190                        !IsGLExtensionEnabled("GL_EXT_color_buffer_float"));
191 
192     DepthRange depthRange;
193     bool depthClampEnabled;
194     VertexDepth vertexDepth;
195     FragmentDepth fragmentDepth;
196     GLenum depthBufferFormat;
197     ParseDepthWriteVariationsTestParams(GetParam(), &depthRange, &depthClampEnabled, &vertexDepth,
198                                         &fragmentDepth, &depthBufferFormat);
199 
200     if (getClientMajorVersion() < 3)
201     {
202         ANGLE_SKIP_TEST_IF(fragmentDepth != FragmentDepth::Unused &&
203                            !IsGLExtensionEnabled("GL_EXT_frag_depth"));
204         ANGLE_SKIP_TEST_IF(depthBufferFormat == GL_DEPTH_COMPONENT32F);
205     }
206     ANGLE_SKIP_TEST_IF(depthClampEnabled && !IsGLExtensionEnabled("GL_EXT_depth_clamp"));
207 
208     const float near = depthRange == DepthRange::Full ? 0.0 : 0.25;
209     const float far  = depthRange == DepthRange::Full ? 1.0 : 0.75;
210     glDepthRangef(near, far);
211 
212     if (depthClampEnabled)
213     {
214         glEnable(GL_DEPTH_CLAMP_EXT);
215     }
216 
217     float vertexDepthValue = 0.0;
218     switch (vertexDepth)
219     {
220         case VertexDepth::InsideClipVolume:
221             vertexDepthValue = 0.25;  // maps to 0.625
222             break;
223         case VertexDepth::LessThanMinusOne:
224             vertexDepthValue = -1.5;
225             break;
226         case VertexDepth::GreaterThanOne:
227             vertexDepthValue = 1.5;
228             break;
229     }
230 
231     float fragmentDepthValue = 0.0;
232     switch (fragmentDepth)
233     {
234         case FragmentDepth::Unused:
235         case FragmentDepth::Passthrough:
236             break;
237         case FragmentDepth::WithinDepthRange:
238             fragmentDepthValue = 0.375;
239             break;
240         case FragmentDepth::BetweenZeroAndNearPlane:
241             fragmentDepthValue = depthRange == DepthRange::Reduced ? 0.125 : 0.0;
242             break;
243         case FragmentDepth::BetweenFarPlaneAndOne:
244             fragmentDepthValue = depthRange == DepthRange::Reduced ? 0.875 : 1.0;
245             break;
246         case FragmentDepth::Negative:
247             fragmentDepthValue = -0.25;
248             break;
249         case FragmentDepth::GreaterThanOne:
250             fragmentDepthValue = 1.25;
251             break;
252     }
253 
254     glEnable(GL_DEPTH_TEST);
255     glDepthFunc(GL_ALWAYS);
256 
257     const int w = getWindowWidth();
258     const int h = getWindowHeight();
259 
260     const bool es2       = getClientMajorVersion() < 3;
261     const bool fragCoord = fragmentDepth == FragmentDepth::Passthrough;
262     std::stringstream fragmentSource;
263     fragmentSource << (es2 ? "#extension GL_EXT_frag_depth : require\n" : "#version 300 es\n")
264                    << (es2 ? "" : "out mediump vec4 fragColor;\n")
265                    << (fragCoord ? "" : "uniform mediump float u_depth;\n") << "void main()\n"
266                    << "{\n"
267                    << (es2 ? "    gl_FragColor" : "    fragColor")
268                    << " = vec4(1.0, 0.0, 0.0, 1.0);\n"
269                    << "    gl_FragDepth" << (es2 ? "EXT" : "")
270                    << (fragCoord ? " = gl_FragCoord.z;\n" : " = u_depth;\n") << "}";
271 
272     ANGLE_GL_PROGRAM(program, es2 ? essl1_shaders::vs::Simple() : essl3_shaders::vs::Simple(),
273                      fragmentDepth == FragmentDepth::Unused
274                          ? (es2 ? essl1_shaders::fs::Red() : essl3_shaders::fs::Red())
275                          : fragmentSource.str().c_str());
276     glUseProgram(program);
277     if (fragmentDepth != FragmentDepth::Unused && fragmentDepth != FragmentDepth::Passthrough)
278     {
279         glUniform1f(glGetUniformLocation(program, "u_depth"), fragmentDepthValue);
280     }
281     ASSERT_GL_NO_ERROR();
282 
283     GLFramebuffer fb;
284     glBindFramebuffer(GL_FRAMEBUFFER, fb);
285 
286     GLRenderbuffer rb;
287     glBindRenderbuffer(GL_RENDERBUFFER, rb);
288     glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB565, w, h);
289     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rb);
290 
291     GLTexture texDepth;
292     glBindTexture(GL_TEXTURE_2D, texDepth);
293     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
294     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
295     glTexImage2D(
296         GL_TEXTURE_2D, 0,
297         depthBufferFormat == GL_DEPTH_COMPONENT32F ? GL_DEPTH_COMPONENT32F : GL_DEPTH_COMPONENT, w,
298         h, 0, GL_DEPTH_COMPONENT,
299         depthBufferFormat == GL_DEPTH_COMPONENT32F ? GL_FLOAT : GL_UNSIGNED_SHORT, nullptr);
300     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, texDepth, 0);
301 
302     ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
303 
304     glEnable(GL_DEPTH_TEST);
305     glDepthFunc(GL_ALWAYS);
306 
307     glClearDepthf(0.33333333);
308     glClear(GL_DEPTH_BUFFER_BIT);
309 
310     drawQuad(program, essl1_shaders::PositionAttrib(), vertexDepthValue);
311     ASSERT_GL_NO_ERROR();
312 
313     auto getExpectedValue = [&]() {
314         auto clamp = [](float x, float min, float max) {
315             return x < min ? min : (x > max ? max : x);
316         };
317 
318         if (depthClampEnabled)
319         {
320             if (fragmentDepth != FragmentDepth::Unused &&
321                 fragmentDepth != FragmentDepth::Passthrough)
322             {
323                 // Fragment value clamped to the depth range
324                 return clamp(fragmentDepthValue, near, far);
325             }
326             else
327             {
328                 // Vertex value transformed to window coordinates and clamped to the depth range
329                 return clamp(0.5f * ((far - near) * vertexDepthValue + (far + near)), near, far);
330             }
331         }
332         else if (vertexDepthValue >= -1.0f && vertexDepthValue <= 1.0f)
333         {
334             if (fragmentDepth != FragmentDepth::Unused &&
335                 fragmentDepth != FragmentDepth::Passthrough)
336             {
337                 // Fragment value clamped to [0, 1]
338                 return clamp(fragmentDepthValue, 0.0f, 1.0f);
339             }
340             else
341             {
342                 // Vertex value transformed to window coordinates
343                 return 0.5f * ((far - near) * vertexDepthValue + (far + near));
344             }
345         }
346         return 0.33333333f;
347     };
348 
349     // Second pass to read written depth value
350     ANGLE_GL_PROGRAM(readProgram, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
351     glUseProgram(readProgram);
352     glUniform1i(glGetUniformLocation(readProgram, essl1_shaders::Texture2DUniform()), 0);
353     ASSERT_GL_NO_ERROR();
354 
355     GLFramebuffer readFb;
356     glBindFramebuffer(GL_FRAMEBUFFER, readFb);
357 
358     GLRenderbuffer readRb;
359     glBindRenderbuffer(GL_RENDERBUFFER, readRb);
360     glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA16F, w, h);
361     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, readRb);
362 
363     ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
364 
365     glClear(GL_COLOR_BUFFER_BIT);
366     drawQuad(readProgram, essl1_shaders::PositionAttrib(), 0.0f);
367 
368     float writtenValue[4] = {std::numeric_limits<float>::quiet_NaN()};
369     glReadPixels(0, 0, 1, 1, GL_RGBA, GL_FLOAT, writtenValue);
370     ASSERT_GL_NO_ERROR();
371 
372     EXPECT_NEAR(getExpectedValue(), writtenValue[0], 0.001);
373 }
374 
375 constexpr DepthRange kDepthRanges[] = {
376     DepthRange::Full,
377     DepthRange::Reduced,
378 };
379 constexpr VertexDepth kVertexDepths[] = {
380     VertexDepth::InsideClipVolume,
381     VertexDepth::LessThanMinusOne,
382     VertexDepth::GreaterThanOne,
383 };
384 constexpr FragmentDepth kFragmentDepths[] = {
385     FragmentDepth::Unused,
386     FragmentDepth::Passthrough,
387     FragmentDepth::WithinDepthRange,
388     FragmentDepth::BetweenZeroAndNearPlane,
389     FragmentDepth::BetweenFarPlaneAndOne,
390     FragmentDepth::Negative,
391     FragmentDepth::GreaterThanOne,
392 };
393 constexpr GLenum kDepthBufferFormats[] = {
394     GL_DEPTH_COMPONENT16,
395     GL_DEPTH_COMPONENT32F,
396 };
397 
398 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DepthWriteTest);
399 ANGLE_INSTANTIATE_TEST_COMBINE_5(DepthWriteTest,
400                                  DepthWriteVariationsTestPrint,
401                                  testing::ValuesIn(kDepthRanges),
402                                  testing::Bool(),
403                                  testing::ValuesIn(kVertexDepths),
404                                  testing::ValuesIn(kFragmentDepths),
405                                  testing::ValuesIn(kDepthBufferFormats),
406                                  ANGLE_ALL_TEST_PLATFORMS_ES2,
407                                  ANGLE_ALL_TEST_PLATFORMS_ES3);
408 
409 }  // anonymous namespace
410