xref: /aosp_15_r20/external/deqp/modules/gles2/functional/es2fDepthRangeTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 2.0 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief glDepthRangef() tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es2fDepthRangeTests.hpp"
25 #include "tcuVector.hpp"
26 #include "tcuTestLog.hpp"
27 #include "tcuSurface.hpp"
28 #include "tcuImageCompare.hpp"
29 #include "tcuRenderTarget.hpp"
30 #include "gluPixelTransfer.hpp"
31 #include "gluShaderProgram.hpp"
32 #include "gluRenderContext.hpp"
33 #include "deRandom.hpp"
34 #include "deMath.h"
35 #include "deString.h"
36 
37 #include "glw.h"
38 
39 namespace deqp
40 {
41 namespace gles2
42 {
43 namespace Functional
44 {
45 
46 enum
47 {
48     VISUALIZE_DEPTH_STEPS = 32 //!< Number of depth steps in visualization
49 };
50 
51 using std::string;
52 using std::vector;
53 using tcu::TestLog;
54 using tcu::Vec2;
55 using tcu::Vec3;
56 using tcu::Vec4;
57 
58 static const char *s_vertexShaderSrc   = "attribute highp vec4 a_position;\n"
59                                          "attribute highp vec2 a_coord;\n"
60                                          "void main (void)\n"
61                                          "{\n"
62                                          "    gl_Position = a_position;\n"
63                                          "}\n";
64 static const char *s_fragmentShaderSrc = "uniform mediump vec4 u_color;\n"
65                                          "void main (void)\n"
66                                          "{\n"
67                                          "    gl_FragColor = u_color;\n"
68                                          "}\n";
69 
70 template <typename T>
compare(uint32_t func,T a,T b)71 static inline bool compare(uint32_t func, T a, T b)
72 {
73     switch (func)
74     {
75     case GL_NEVER:
76         return false;
77     case GL_ALWAYS:
78         return true;
79     case GL_LESS:
80         return a < b;
81     case GL_LEQUAL:
82         return a <= b;
83     case GL_EQUAL:
84         return a == b;
85     case GL_NOTEQUAL:
86         return a != b;
87     case GL_GEQUAL:
88         return a >= b;
89     case GL_GREATER:
90         return a > b;
91     default:
92         DE_ASSERT(false);
93         return false;
94     }
95 }
96 
triangleInterpolate(const float v0,const float v1,const float v2,const float x,const float y)97 inline float triangleInterpolate(const float v0, const float v1, const float v2, const float x, const float y)
98 {
99     return v0 + (v2 - v0) * x + (v1 - v0) * y;
100 }
101 
triQuadInterpolate(const float x,const float y,const tcu::Vec4 & quad)102 inline float triQuadInterpolate(const float x, const float y, const tcu::Vec4 &quad)
103 {
104     // \note Top left fill rule.
105     if (x + y < 1.0f)
106         return triangleInterpolate(quad.x(), quad.y(), quad.z(), x, y);
107     else
108         return triangleInterpolate(quad.w(), quad.z(), quad.y(), 1.0f - x, 1.0f - y);
109 }
110 
depthRangeTransform(const float zd,const float zNear,const float zFar)111 inline float depthRangeTransform(const float zd, const float zNear, const float zFar)
112 {
113     const float cNear = de::clamp(zNear, 0.0f, 1.0f);
114     const float cFar  = de::clamp(zFar, 0.0f, 1.0f);
115     return ((cFar - cNear) / 2.0f) * zd + (cNear + cFar) / 2.0f;
116 }
117 
118 class DepthRangeCompareCase : public TestCase
119 {
120 public:
121     DepthRangeCompareCase(Context &context, const char *name, const char *desc, const tcu::Vec4 &depthCoord,
122                           const float zNear, const float zFar, const uint32_t compareFunc);
123     ~DepthRangeCompareCase(void);
124 
125     IterateResult iterate(void);
126 
127 private:
128     const tcu::Vec4 m_depthCoord;
129     const float m_zNear;
130     const float m_zFar;
131     const uint32_t m_compareFunc;
132 };
133 
DepthRangeCompareCase(Context & context,const char * name,const char * desc,const tcu::Vec4 & depthCoord,const float zNear,const float zFar,const uint32_t compareFunc)134 DepthRangeCompareCase::DepthRangeCompareCase(Context &context, const char *name, const char *desc,
135                                              const tcu::Vec4 &depthCoord, const float zNear, const float zFar,
136                                              const uint32_t compareFunc)
137     : TestCase(context, name, desc)
138     , m_depthCoord(depthCoord)
139     , m_zNear(zNear)
140     , m_zFar(zFar)
141     , m_compareFunc(compareFunc)
142 {
143 }
144 
~DepthRangeCompareCase(void)145 DepthRangeCompareCase::~DepthRangeCompareCase(void)
146 {
147 }
148 
iterate(void)149 DepthRangeCompareCase::IterateResult DepthRangeCompareCase::iterate(void)
150 {
151     TestLog &log = m_testCtx.getLog();
152     de::Random rnd(deStringHash(getName()));
153     const tcu::RenderTarget &renderTarget = m_context.getRenderContext().getRenderTarget();
154     const int viewportW                   = de::min(128, renderTarget.getWidth());
155     const int viewportH                   = de::min(128, renderTarget.getHeight());
156     const int viewportX                   = rnd.getInt(0, renderTarget.getWidth() - viewportW);
157     const int viewportY                   = rnd.getInt(0, renderTarget.getHeight() - viewportH);
158     tcu::Surface renderedFrame(viewportW, viewportH);
159     tcu::Surface referenceFrame(viewportW, viewportH);
160     const float constDepth = 0.1f;
161 
162     if (renderTarget.getDepthBits() == 0)
163         throw tcu::NotSupportedError("Depth buffer is required", "", __FILE__, __LINE__);
164 
165     const glu::ShaderProgram program(m_context.getRenderContext(),
166                                      glu::makeVtxFragSources(s_vertexShaderSrc, s_fragmentShaderSrc));
167 
168     if (!program.isOk())
169     {
170         log << program;
171         TCU_FAIL("Compile failed");
172     }
173 
174     const int colorLoc = glGetUniformLocation(program.getProgram(), "u_color");
175     const int posLoc   = glGetAttribLocation(program.getProgram(), "a_position");
176 
177     m_testCtx.getLog() << TestLog::Message << "glDepthRangef(" << m_zNear << ", " << m_zFar << ")"
178                        << TestLog::EndMessage;
179 
180     glViewport(viewportX, viewportY, viewportW, viewportH);
181     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
182     glEnable(GL_DEPTH_TEST);
183     glUseProgram(program.getProgram());
184     glEnableVertexAttribArray(posLoc);
185 
186     static const uint16_t quadIndices[] = {0, 1, 2, 2, 1, 3};
187 
188     // Fill viewport with 2 quads - one with constant depth and another with d = [-1..1]
189     {
190         static const float constDepthCoord[]   = {-1.0f, -1.0f, constDepth, 1.0f, -1.0f, +1.0f, constDepth, 1.0f,
191                                                   0.0f,  -1.0f, constDepth, 1.0f, 0.0f,  +1.0f, constDepth, 1.0f};
192         static const float varyingDepthCoord[] = {0.0f,  -1.0f, +1.0f, 1.0f, 0.0f,  +1.0f, 0.0f,  1.0f,
193                                                   +1.0f, -1.0f, 0.0f,  1.0f, +1.0f, +1.0f, -1.0f, 1.0f};
194 
195         glUniform4f(colorLoc, 0.0f, 0.0f, 1.0f, 1.0f);
196         glDepthFunc(GL_ALWAYS);
197 
198         glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &constDepthCoord);
199         glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(quadIndices), GL_UNSIGNED_SHORT, &quadIndices[0]);
200 
201         glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &varyingDepthCoord);
202         glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(quadIndices), GL_UNSIGNED_SHORT, &quadIndices[0]);
203 
204         GLU_CHECK();
205     }
206 
207     // Render with depth test.
208     {
209         const float position[] = {-1.0f, -1.0f, m_depthCoord[0], 1.0f, -1.0f, +1.0f, m_depthCoord[1], 1.0f,
210                                   +1.0f, -1.0f, m_depthCoord[2], 1.0f, +1.0f, +1.0f, m_depthCoord[3], 1.0f};
211 
212         glDepthRangef(m_zNear, m_zFar);
213         glDepthFunc(m_compareFunc);
214         glUniform4f(colorLoc, 0.0f, 1.0f, 0.0f, 1.0f);
215 
216         glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]);
217         glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(quadIndices), GL_UNSIGNED_SHORT, &quadIndices[0]);
218 
219         GLU_CHECK();
220     }
221 
222     glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, renderedFrame.getAccess());
223 
224     // Render reference.
225     for (int y = 0; y < referenceFrame.getHeight(); y++)
226     {
227         float yf = ((float)y + 0.5f) / (float)referenceFrame.getHeight();
228         int half = de::clamp((int)((float)referenceFrame.getWidth() * 0.5f + 0.5f), 0, referenceFrame.getWidth());
229 
230         // Fill left half - comparison to constant 0.5
231         for (int x = 0; x < half; x++)
232         {
233             float xf   = ((float)x + 0.5f) / (float)referenceFrame.getWidth();
234             float d    = depthRangeTransform(triQuadInterpolate(xf, yf, m_depthCoord), m_zNear, m_zFar);
235             bool dpass = compare(m_compareFunc, d, constDepth * 0.5f + 0.5f);
236 
237             referenceFrame.setPixel(x, y, dpass ? tcu::RGBA::green() : tcu::RGBA::blue());
238         }
239 
240         // Fill right half - comparison to interpolated depth
241         for (int x = half; x < referenceFrame.getWidth(); x++)
242         {
243             float xf   = ((float)x + 0.5f) / (float)referenceFrame.getWidth();
244             float xh   = ((float)(x - half) + 0.5f) / (float)(referenceFrame.getWidth() - half);
245             float rd   = 1.0f - (xh + yf) * 0.5f;
246             float d    = depthRangeTransform(triQuadInterpolate(xf, yf, m_depthCoord), m_zNear, m_zFar);
247             bool dpass = compare(m_compareFunc, d, rd);
248 
249             referenceFrame.setPixel(x, y, dpass ? tcu::RGBA::green() : tcu::RGBA::blue());
250         }
251     }
252 
253     bool isOk = tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame, renderedFrame, 0.05f,
254                                   tcu::COMPARE_LOG_RESULT);
255     m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, isOk ? "Pass" : "Fail");
256     return STOP;
257 }
258 
259 class DepthRangeWriteCase : public TestCase
260 {
261 public:
262     DepthRangeWriteCase(Context &context, const char *name, const char *desc, const tcu::Vec4 &depthCoord,
263                         const float zNear, const float zFar);
264     ~DepthRangeWriteCase(void);
265 
266     IterateResult iterate(void);
267 
268 private:
269     const tcu::Vec4 &m_depthCoord;
270     const float m_zNear;
271     const float m_zFar;
272 };
273 
DepthRangeWriteCase(Context & context,const char * name,const char * desc,const tcu::Vec4 & depthCoord,const float zNear,const float zFar)274 DepthRangeWriteCase::DepthRangeWriteCase(Context &context, const char *name, const char *desc,
275                                          const tcu::Vec4 &depthCoord, const float zNear, const float zFar)
276     : TestCase(context, name, desc)
277     , m_depthCoord(depthCoord)
278     , m_zNear(zNear)
279     , m_zFar(zFar)
280 {
281 }
282 
~DepthRangeWriteCase(void)283 DepthRangeWriteCase::~DepthRangeWriteCase(void)
284 {
285 }
286 
iterate(void)287 DepthRangeWriteCase::IterateResult DepthRangeWriteCase::iterate(void)
288 {
289     TestLog &log = m_testCtx.getLog();
290     de::Random rnd(deStringHash(getName()));
291     const tcu::RenderTarget &renderTarget = m_context.getRenderContext().getRenderTarget();
292     const int viewportW                   = de::min(128, renderTarget.getWidth());
293     const int viewportH                   = de::min(128, renderTarget.getHeight());
294     const int viewportX                   = rnd.getInt(0, renderTarget.getWidth() - viewportW);
295     const int viewportY                   = rnd.getInt(0, renderTarget.getHeight() - viewportH);
296     tcu::Surface renderedFrame(viewportW, viewportH);
297     tcu::Surface referenceFrame(viewportW, viewportH);
298     const int numDepthSteps = VISUALIZE_DEPTH_STEPS;
299     const float depthStep   = 1.0f / (float)(numDepthSteps - 1);
300 
301     if (renderTarget.getDepthBits() == 0)
302         throw tcu::NotSupportedError("Depth buffer is required", "", __FILE__, __LINE__);
303 
304     const glu::ShaderProgram program(m_context.getRenderContext(),
305                                      glu::makeVtxFragSources(s_vertexShaderSrc, s_fragmentShaderSrc));
306 
307     if (!program.isOk())
308     {
309         log << program;
310         TCU_FAIL("Compile failed");
311     }
312 
313     const int colorLoc = glGetUniformLocation(program.getProgram(), "u_color");
314     const int posLoc   = glGetAttribLocation(program.getProgram(), "a_position");
315 
316     m_testCtx.getLog() << TestLog::Message << "glDepthRangef(" << m_zNear << ", " << m_zFar << ")"
317                        << TestLog::EndMessage;
318 
319     glViewport(viewportX, viewportY, viewportW, viewportH);
320     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
321     glEnable(GL_DEPTH_TEST);
322     glUseProgram(program.getProgram());
323     glEnableVertexAttribArray(posLoc);
324 
325     static const uint16_t quadIndices[] = {0, 1, 2, 2, 1, 3};
326 
327     // Render with depth range.
328     {
329         const float position[] = {-1.0f, -1.0f, m_depthCoord[0], 1.0f, -1.0f, +1.0f, m_depthCoord[1], 1.0f,
330                                   +1.0f, -1.0f, m_depthCoord[2], 1.0f, +1.0f, +1.0f, m_depthCoord[3], 1.0f};
331 
332         glDepthFunc(GL_ALWAYS);
333         glDepthRangef(m_zNear, m_zFar);
334         glUniform4f(colorLoc, 0.0f, 1.0f, 0.0f, 1.0f);
335         glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]);
336         glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(quadIndices), GL_UNSIGNED_SHORT, &quadIndices[0]);
337         GLU_CHECK();
338     }
339 
340     // Visualize by rendering full-screen quads with increasing depth and color.
341     {
342         glDepthFunc(GL_LEQUAL);
343         glDepthMask(GL_FALSE);
344         glDepthRangef(0.0f, 1.0f);
345 
346         for (int stepNdx = 0; stepNdx < numDepthSteps; stepNdx++)
347         {
348             float f     = (float)stepNdx * depthStep;
349             float depth = f * 2.0f - 1.0f;
350             Vec4 color  = Vec4(f, f, f, 1.0f);
351 
352             float position[] = {-1.0f, -1.0f, depth, 1.0f, -1.0f, +1.0f, depth, 1.0f,
353                                 +1.0f, -1.0f, depth, 1.0f, +1.0f, +1.0f, depth, 1.0f};
354 
355             glUniform4fv(colorLoc, 1, color.getPtr());
356             glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]);
357             glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(quadIndices), GL_UNSIGNED_SHORT, &quadIndices[0]);
358         }
359 
360         GLU_CHECK();
361     }
362 
363     glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, renderedFrame.getAccess());
364 
365     // Render reference.
366     for (int y = 0; y < referenceFrame.getHeight(); y++)
367     {
368         for (int x = 0; x < referenceFrame.getWidth(); x++)
369         {
370             float xf = ((float)x + 0.5f) / (float)referenceFrame.getWidth();
371             float yf = ((float)y + 0.5f) / (float)referenceFrame.getHeight();
372             float d  = depthRangeTransform(triQuadInterpolate(xf, yf, m_depthCoord), m_zNear, m_zFar);
373             int step = (int)deFloatFloor(d / depthStep);
374             int col  = de::clamp(deRoundFloatToInt32((float)step * depthStep * 255.0f), 0, 255);
375 
376             referenceFrame.setPixel(x, y, tcu::RGBA(col, col, col, 0xff));
377         }
378     }
379 
380     bool isOk = tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame, renderedFrame, 0.05f,
381                                   tcu::COMPARE_LOG_RESULT);
382     m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, isOk ? "Pass" : "Fail");
383     return STOP;
384 }
385 
DepthRangeTests(Context & context)386 DepthRangeTests::DepthRangeTests(Context &context) : TestCaseGroup(context, "depth_range", "glDepthRangef() tests")
387 {
388 }
389 
~DepthRangeTests(void)390 DepthRangeTests::~DepthRangeTests(void)
391 {
392 }
393 
init(void)394 void DepthRangeTests::init(void)
395 {
396     static const struct
397     {
398         const char *name;
399         const char *desc;
400         const tcu::Vec4 depthCoord;
401         const float zNear;
402         const float zFar;
403     } cases[] = {{"default", "Default depth range", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 0.0f, 1.0f},
404                  {"reverse", "Reversed default range", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 1.0f, 0.0f},
405                  {"zero_to_half", "From 0 to 0.5", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 0.0f, 0.5f},
406                  {"half_to_one", "From 0.5 to 1", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 0.5f, 1.0f},
407                  {"half_to_zero", "From 0.5 to 0", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 0.5f, 0.0f},
408                  {"one_to_half", "From 1 to 0.5", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 1.0f, 0.5f},
409                  {"third_to_0_8", "From 1/3 to 0.8", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 1.0f / 3.0f, 0.8f},
410                  {"0_8_to_third", "From 0.8 to 1/3", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 0.8f, 1.0f / 3.0f},
411                  {"zero_to_zero", "From 0 to 0", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 0.0f, 0.0f},
412                  {"half_to_half", "From 0.5 to 0.5", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 0.5f, 0.5f},
413                  {"one_to_one", "From 1 to 1", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 1.0f, 1.0f},
414                  {"clamp_near", "From -1 to 1", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), -1.0f, 1.0f},
415                  {"clamp_far", "From 0 to 2", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 0.0f, 2.0},
416                  {"clamp_both", "From -1 to 2", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), -1.0, 2.0}};
417 
418     // .write
419     tcu::TestCaseGroup *writeGroup = new tcu::TestCaseGroup(m_testCtx, "write", "gl_FragDepth write tests");
420     addChild(writeGroup);
421     for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cases); ndx++)
422         writeGroup->addChild(new DepthRangeWriteCase(m_context, cases[ndx].name, cases[ndx].desc, cases[ndx].depthCoord,
423                                                      cases[ndx].zNear, cases[ndx].zFar));
424 
425     // .compare
426     tcu::TestCaseGroup *compareGroup =
427         new tcu::TestCaseGroup(m_testCtx, "compare", "gl_FragDepth used with depth comparison");
428     addChild(compareGroup);
429     for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cases); ndx++)
430         compareGroup->addChild(new DepthRangeCompareCase(m_context, cases[ndx].name, cases[ndx].desc,
431                                                          cases[ndx].depthCoord, cases[ndx].zNear, cases[ndx].zFar,
432                                                          GL_LESS));
433 }
434 
435 } // namespace Functional
436 } // namespace gles2
437 } // namespace deqp
438