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 ¶ms,
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> ¶msInfo)
157 {
158 const DepthWriteVariationsTestParams ¶ms = 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