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