Add new framebuffer fetch extension tests am: 2a609fb223
[platform/upstream/VK-GL-CTS.git] / modules / gles2 / functional / es2fDepthRangeTests.cpp
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 tcu::Vec2;
52 using tcu::Vec3;
53 using tcu::Vec4;
54 using tcu::TestLog;
55 using std::string;
56 using std::vector;
57
58 static const char* s_vertexShaderSrc =
59         "attribute highp vec4 a_position;\n"
60         "attribute highp vec2 a_coord;\n"
61         "void main (void)\n"
62         "{\n"
63         "       gl_Position = a_position;\n"
64         "}\n";
65 static const char* s_fragmentShaderSrc =
66         "uniform mediump vec4 u_color;\n"
67         "void main (void)\n"
68         "{\n"
69         "       gl_FragColor = u_color;\n"
70         "}\n";
71
72 template <typename T>
73 static inline bool compare (deUint32 func, T a, T b)
74 {
75         switch (func)
76         {
77                 case GL_NEVER:          return false;
78                 case GL_ALWAYS:         return true;
79                 case GL_LESS:           return a < b;
80                 case GL_LEQUAL:         return a <= b;
81                 case GL_EQUAL:          return a == b;
82                 case GL_NOTEQUAL:       return a != b;
83                 case GL_GEQUAL:         return a >= b;
84                 case GL_GREATER:        return a > b;
85                 default:
86                         DE_ASSERT(DE_FALSE);
87                         return false;
88         }
89 }
90
91 inline float triangleInterpolate (const float v0, const float v1, const float v2, const float x, const float y)
92 {
93         return v0 + (v2-v0)*x + (v1-v0)*y;
94 }
95
96 inline float triQuadInterpolate (const float x, const float y, const tcu::Vec4& quad)
97 {
98         // \note Top left fill rule.
99         if (x + y < 1.0f)
100                 return triangleInterpolate(quad.x(), quad.y(), quad.z(), x, y);
101         else
102                 return triangleInterpolate(quad.w(), quad.z(), quad.y(), 1.0f-x, 1.0f-y);
103 }
104
105 inline float depthRangeTransform (const float zd, const float zNear, const float zFar)
106 {
107         const float     cNear   = de::clamp(zNear, 0.0f, 1.0f);
108         const float     cFar    = de::clamp(zFar, 0.0f, 1.0f);
109         return ((cFar - cNear)/2.0f) * zd + (cNear + cFar)/2.0f;
110 }
111
112 class DepthRangeCompareCase : public TestCase
113 {
114 public:
115                                                         DepthRangeCompareCase   (Context& context, const char* name, const char* desc, const tcu::Vec4& depthCoord, const float zNear, const float zFar, const deUint32 compareFunc);
116                                                         ~DepthRangeCompareCase  (void);
117
118         IterateResult                   iterate                                 (void);
119
120 private:
121         const tcu::Vec4                 m_depthCoord;
122         const float                             m_zNear;
123         const float                             m_zFar;
124         const deUint32                  m_compareFunc;
125 };
126
127 DepthRangeCompareCase::DepthRangeCompareCase (Context& context, const char* name, const char* desc, const tcu::Vec4& depthCoord, const float zNear, const float zFar, const deUint32 compareFunc)
128         : TestCase                      (context, name, desc)
129         , m_depthCoord          (depthCoord)
130         , m_zNear                       (zNear)
131         , m_zFar                        (zFar)
132         , m_compareFunc         (compareFunc)
133 {
134 }
135
136 DepthRangeCompareCase::~DepthRangeCompareCase (void)
137 {
138 }
139
140 DepthRangeCompareCase::IterateResult DepthRangeCompareCase::iterate (void)
141 {
142         TestLog&                                        log                                     = m_testCtx.getLog();
143         de::Random                                      rnd                                     (deStringHash(getName()));
144         const tcu::RenderTarget&        renderTarget            = m_context.getRenderContext().getRenderTarget();
145         const int                                       viewportW                       = de::min(128, renderTarget.getWidth());
146         const int                                       viewportH                       = de::min(128, renderTarget.getHeight());
147         const int                                       viewportX                       = rnd.getInt(0, renderTarget.getWidth()-viewportW);
148         const int                                       viewportY                       = rnd.getInt(0, renderTarget.getHeight()-viewportH);
149         tcu::Surface                            renderedFrame           (viewportW, viewportH);
150         tcu::Surface                            referenceFrame          (viewportW, viewportH);
151         const float                                     constDepth                      = 0.1f;
152
153         if (renderTarget.getDepthBits() == 0)
154                 throw tcu::NotSupportedError("Depth buffer is required", "", __FILE__, __LINE__);
155
156         const glu::ShaderProgram        program                         (m_context.getRenderContext(), glu::makeVtxFragSources(s_vertexShaderSrc, s_fragmentShaderSrc));
157
158         if (!program.isOk())
159         {
160                 log << program;
161                 TCU_FAIL("Compile failed");
162         }
163
164         const int                                       colorLoc                        = glGetUniformLocation(program.getProgram(), "u_color");
165         const int                                       posLoc                          = glGetAttribLocation(program.getProgram(), "a_position");
166
167         m_testCtx.getLog() << TestLog::Message << "glDepthRangef(" << m_zNear << ", " << m_zFar << ")" << TestLog::EndMessage;
168
169         glViewport(viewportX, viewportY, viewportW, viewportH);
170         glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
171         glEnable(GL_DEPTH_TEST);
172         glUseProgram(program.getProgram());
173         glEnableVertexAttribArray(posLoc);
174
175         static const deUint16 quadIndices[] = { 0, 1, 2, 2, 1, 3 };
176
177         // Fill viewport with 2 quads - one with constant depth and another with d = [-1..1]
178         {
179                 static const float constDepthCoord[] =
180                 {
181                         -1.0f, -1.0f, constDepth, 1.0f,
182                         -1.0f, +1.0f, constDepth, 1.0f,
183                          0.0f, -1.0f, constDepth, 1.0f,
184                          0.0f, +1.0f, constDepth, 1.0f
185                 };
186                 static const float varyingDepthCoord[] =
187                 {
188                          0.0f, -1.0f, +1.0f, 1.0f,
189                          0.0f, +1.0f,  0.0f, 1.0f,
190                         +1.0f, -1.0f,  0.0f, 1.0f,
191                         +1.0f, +1.0f, -1.0f, 1.0f
192                 };
193
194                 glUniform4f(colorLoc, 0.0f, 0.0f, 1.0f, 1.0f);
195                 glDepthFunc(GL_ALWAYS);
196
197                 glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &constDepthCoord);
198                 glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(quadIndices), GL_UNSIGNED_SHORT, &quadIndices[0]);
199
200                 glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &varyingDepthCoord);
201                 glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(quadIndices), GL_UNSIGNED_SHORT, &quadIndices[0]);
202
203                 GLU_CHECK();
204         }
205
206         // Render with depth test.
207         {
208                 const float position[] =
209                 {
210                         -1.0f, -1.0f, m_depthCoord[0], 1.0f,
211                         -1.0f, +1.0f, m_depthCoord[1], 1.0f,
212                         +1.0f, -1.0f, m_depthCoord[2], 1.0f,
213                         +1.0f, +1.0f, m_depthCoord[3], 1.0f
214                 };
215
216                 glDepthRangef(m_zNear, m_zFar);
217                 glDepthFunc(m_compareFunc);
218                 glUniform4f(colorLoc, 0.0f, 1.0f, 0.0f, 1.0f);
219
220                 glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]);
221                 glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(quadIndices), GL_UNSIGNED_SHORT, &quadIndices[0]);
222
223                 GLU_CHECK();
224         }
225
226         glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, renderedFrame.getAccess());
227
228         // Render reference.
229         for (int y = 0; y < referenceFrame.getHeight(); y++)
230         {
231                 float   yf              = ((float)y + 0.5f) / (float)referenceFrame.getHeight();
232                 int             half    = de::clamp((int)((float)referenceFrame.getWidth()*0.5f + 0.5f), 0, referenceFrame.getWidth());
233
234                 // Fill left half - comparison to constant 0.5
235                 for (int x = 0; x < half; x++)
236                 {
237                         float   xf              = ((float)x + 0.5f) / (float)referenceFrame.getWidth();
238                         float   d               = depthRangeTransform(triQuadInterpolate(xf, yf, m_depthCoord), m_zNear, m_zFar);
239                         bool    dpass   = compare(m_compareFunc, d, constDepth*0.5f + 0.5f);
240
241                         referenceFrame.setPixel(x, y, dpass ? tcu::RGBA::green() : tcu::RGBA::blue());
242                 }
243
244                 // Fill right half - comparison to interpolated depth
245                 for (int x = half; x < referenceFrame.getWidth(); x++)
246                 {
247                         float   xf              = ((float)x + 0.5f) / (float)referenceFrame.getWidth();
248                         float   xh              = ((float)(x - half) + 0.5f) / (float)(referenceFrame.getWidth()-half);
249                         float   rd              = 1.0f - (xh + yf) * 0.5f;
250                         float   d               = depthRangeTransform(triQuadInterpolate(xf, yf, m_depthCoord), m_zNear, m_zFar);
251                         bool    dpass   = compare(m_compareFunc, d, rd);
252
253                         referenceFrame.setPixel(x, y, dpass ? tcu::RGBA::green() : tcu::RGBA::blue());
254                 }
255         }
256
257         bool isOk = tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame, renderedFrame, 0.05f, tcu::COMPARE_LOG_RESULT);
258         m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS      : QP_TEST_RESULT_FAIL,
259                                                         isOk ? "Pass"                           : "Fail");
260         return STOP;
261 }
262
263 class DepthRangeWriteCase : public TestCase
264 {
265 public:
266                                                         DepthRangeWriteCase             (Context& context, const char* name, const char* desc, const tcu::Vec4& depthCoord, const float zNear, const float zFar);
267                                                         ~DepthRangeWriteCase    (void);
268
269         IterateResult                   iterate                                 (void);
270
271 private:
272         const tcu::Vec4&                m_depthCoord;
273         const float                             m_zNear;
274         const float                             m_zFar;
275 };
276
277 DepthRangeWriteCase::DepthRangeWriteCase (Context& context, const char* name, const char* desc, const tcu::Vec4& depthCoord, const float zNear, const float zFar)
278         : TestCase                      (context, name, desc)
279         , m_depthCoord          (depthCoord)
280         , m_zNear                       (zNear)
281         , m_zFar                        (zFar)
282 {
283 }
284
285 DepthRangeWriteCase::~DepthRangeWriteCase (void)
286 {
287 }
288
289 DepthRangeWriteCase::IterateResult DepthRangeWriteCase::iterate (void)
290 {
291         TestLog&                                        log                             = m_testCtx.getLog();
292         de::Random                                      rnd                             (deStringHash(getName()));
293         const tcu::RenderTarget&        renderTarget    = m_context.getRenderContext().getRenderTarget();
294         const int                                       viewportW               = de::min(128, renderTarget.getWidth());
295         const int                                       viewportH               = de::min(128, renderTarget.getHeight());
296         const int                                       viewportX               = rnd.getInt(0, renderTarget.getWidth()-viewportW);
297         const int                                       viewportY               = rnd.getInt(0, renderTarget.getHeight()-viewportH);
298         tcu::Surface                            renderedFrame   (viewportW, viewportH);
299         tcu::Surface                            referenceFrame  (viewportW, viewportH);
300         const int                                       numDepthSteps   = VISUALIZE_DEPTH_STEPS;
301         const float                                     depthStep               = 1.0f/(float)(numDepthSteps-1);
302
303         if (renderTarget.getDepthBits() == 0)
304                 throw tcu::NotSupportedError("Depth buffer is required", "", __FILE__, __LINE__);
305
306         const glu::ShaderProgram        program                 (m_context.getRenderContext(), glu::makeVtxFragSources(s_vertexShaderSrc, s_fragmentShaderSrc));
307
308         if (!program.isOk())
309         {
310                 log << program;
311                 TCU_FAIL("Compile failed");
312         }
313
314         const int                                       colorLoc                = glGetUniformLocation(program.getProgram(), "u_color");
315         const int                                       posLoc                  = glGetAttribLocation(program.getProgram(), "a_position");
316
317         m_testCtx.getLog() << TestLog::Message << "glDepthRangef(" << m_zNear << ", " << m_zFar << ")" << 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 deUint16 quadIndices[] = { 0, 1, 2, 2, 1, 3 };
326
327         // Render with depth range.
328         {
329                 const float position[] =
330                 {
331                         -1.0f, -1.0f, m_depthCoord[0], 1.0f,
332                         -1.0f, +1.0f, m_depthCoord[1], 1.0f,
333                         +1.0f, -1.0f, m_depthCoord[2], 1.0f,
334                         +1.0f, +1.0f, m_depthCoord[3], 1.0f
335                 };
336
337                 glDepthFunc(GL_ALWAYS);
338                 glDepthRangef(m_zNear, m_zFar);
339                 glUniform4f(colorLoc, 0.0f, 1.0f, 0.0f, 1.0f);
340                 glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]);
341                 glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(quadIndices), GL_UNSIGNED_SHORT, &quadIndices[0]);
342                 GLU_CHECK();
343         }
344
345         // Visualize by rendering full-screen quads with increasing depth and color.
346         {
347                 glDepthFunc(GL_LEQUAL);
348                 glDepthMask(GL_FALSE);
349                 glDepthRangef(0.0f, 1.0f);
350
351                 for (int stepNdx = 0; stepNdx < numDepthSteps; stepNdx++)
352                 {
353                         float   f               = (float)stepNdx*depthStep;
354                         float   depth   = f*2.0f - 1.0f;
355                         Vec4    color   = Vec4(f, f, f, 1.0f);
356
357                         float position[] =
358                         {
359                                 -1.0f, -1.0f, depth, 1.0f,
360                                 -1.0f, +1.0f, depth, 1.0f,
361                                 +1.0f, -1.0f, depth, 1.0f,
362                                 +1.0f, +1.0f, depth, 1.0f
363                         };
364
365                         glUniform4fv(colorLoc, 1, color.getPtr());
366                         glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]);
367                         glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(quadIndices), GL_UNSIGNED_SHORT, &quadIndices[0]);
368                 }
369
370                 GLU_CHECK();
371         }
372
373         glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, renderedFrame.getAccess());
374
375         // Render reference.
376         for (int y = 0; y < referenceFrame.getHeight(); y++)
377         {
378                 for (int x = 0; x < referenceFrame.getWidth(); x++)
379                 {
380                         float   xf              = ((float)x + 0.5f) / (float)referenceFrame.getWidth();
381                         float   yf              = ((float)y + 0.5f) / (float)referenceFrame.getHeight();
382                         float   d               = depthRangeTransform(triQuadInterpolate(xf, yf, m_depthCoord), m_zNear, m_zFar);
383                         int             step    = (int)deFloatFloor(d / depthStep);
384                         int             col             = de::clamp(deRoundFloatToInt32((float)step*depthStep*255.0f), 0, 255);
385
386                         referenceFrame.setPixel(x, y, tcu::RGBA(col, col, col, 0xff));
387                 }
388         }
389
390         bool isOk = tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame, renderedFrame, 0.05f, tcu::COMPARE_LOG_RESULT);
391         m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS      : QP_TEST_RESULT_FAIL,
392                                                         isOk ? "Pass"                           : "Fail");
393         return STOP;
394 }
395
396 DepthRangeTests::DepthRangeTests (Context& context)
397         : TestCaseGroup(context, "depth_range", "glDepthRangef() tests")
398 {
399 }
400
401 DepthRangeTests::~DepthRangeTests (void)
402 {
403 }
404
405 void DepthRangeTests::init (void)
406 {
407         static const struct
408         {
409                 const char*                     name;
410                 const char*                     desc;
411                 const tcu::Vec4         depthCoord;
412                 const float                     zNear;
413                 const float                     zFar;
414         } cases[] =
415         {
416                 { "default",            "Default depth range",          tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),    0.0f,           1.0f },
417                 { "reverse",            "Reversed default range",       tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),    1.0f,           0.0f },
418                 { "zero_to_half",       "From 0 to 0.5",                        tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),    0.0f,           0.5f },
419                 { "half_to_one",        "From 0.5 to 1",                        tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),    0.5f,           1.0f },
420                 { "half_to_zero",       "From 0.5 to 0",                        tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),    0.5f,           0.0f },
421                 { "one_to_half",        "From 1 to 0.5",                        tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),    1.0f,           0.5f },
422                 { "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 },
423                 { "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 },
424                 { "zero_to_zero",       "From 0 to 0",                          tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),    0.0f,           0.0f },
425                 { "half_to_half",       "From 0.5 to 0.5",                      tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),    0.5f,           0.5f },
426                 { "one_to_one",         "From 1 to 1",                          tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),    1.0f,           1.0f },
427                 { "clamp_near",         "From -1 to 1",                         tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),    -1.0f,          1.0f },
428                 { "clamp_far",          "From 0 to 2",                          tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),    0.0f,           2.0 },
429                 { "clamp_both",         "From -1 to 2",                         tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),    -1.0,           2.0 }
430         };
431
432         // .write
433         tcu::TestCaseGroup* writeGroup = new tcu::TestCaseGroup(m_testCtx, "write", "gl_FragDepth write tests");
434         addChild(writeGroup);
435         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cases); ndx++)
436                 writeGroup->addChild(new DepthRangeWriteCase(m_context, cases[ndx].name, cases[ndx].desc, cases[ndx].depthCoord, cases[ndx].zNear, cases[ndx].zFar));
437
438         // .compare
439         tcu::TestCaseGroup* compareGroup = new tcu::TestCaseGroup(m_testCtx, "compare", "gl_FragDepth used with depth comparison");
440         addChild(compareGroup);
441         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cases); ndx++)
442                 compareGroup->addChild(new DepthRangeCompareCase(m_context, cases[ndx].name, cases[ndx].desc, cases[ndx].depthCoord, cases[ndx].zNear, cases[ndx].zFar, GL_LESS));
443 }
444
445 } // Functional
446 } // gles3
447 } // deqp