am 70413e6e: (-s ours) am e8efb729: Relax asin() precision requirements am: 1b358c43b7
[platform/upstream/VK-GL-CTS.git] / modules / gles3 / functional / es3fFragDepthTests.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.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 gl_FragDepth tests.
22  *//*--------------------------------------------------------------------*/
23
24 #include "es3fFragDepthTests.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 "gluDrawUtil.hpp"
33 #include "deRandom.hpp"
34 #include "deMath.h"
35 #include "deString.h"
36
37 // For setupDefaultUniforms()
38 #include "glsShaderRenderCase.hpp"
39
40 #include "glwEnums.hpp"
41 #include "glwFunctions.hpp"
42
43 namespace deqp
44 {
45 namespace gles3
46 {
47 namespace Functional
48 {
49
50 using tcu::Vec2;
51 using tcu::Vec3;
52 using tcu::Vec4;
53 using tcu::TestLog;
54 using std::string;
55 using std::vector;
56
57 typedef float (*EvalFragDepthFunc) (const Vec2& coord);
58
59 static const char* s_vertexShaderSrc =
60         "#version 300 es\n"
61         "in highp vec4 a_position;\n"
62         "in highp vec2 a_coord;\n"
63         "out highp vec2 v_coord;\n"
64         "void main (void)\n"
65         "{\n"
66         "       gl_Position = a_position;\n"
67         "       v_coord = a_coord;\n"
68         "}\n";
69 static const char* s_defaultFragmentShaderSrc =
70         "#version 300 es\n"
71         "uniform highp vec4 u_color;\n"
72         "layout(location = 0) out mediump vec4 o_color;\n"
73         "void main (void)\n"
74         "{\n"
75         "       o_color = u_color;\n"
76         "}\n";
77
78 template <typename T>
79 static inline bool compare (deUint32 func, T a, T b)
80 {
81         switch (func)
82         {
83                 case GL_NEVER:          return false;
84                 case GL_ALWAYS:         return true;
85                 case GL_LESS:           return a < b;
86                 case GL_LEQUAL:         return a <= b;
87                 case GL_EQUAL:          return a == b;
88                 case GL_NOTEQUAL:       return a != b;
89                 case GL_GEQUAL:         return a >= b;
90                 case GL_GREATER:        return a > b;
91                 default:
92                         DE_ASSERT(DE_FALSE);
93                         return false;
94         }
95 }
96
97 class FragDepthCompareCase : public TestCase
98 {
99 public:
100                                                         FragDepthCompareCase    (Context& context, const char* name, const char* desc, const char* fragSrc, EvalFragDepthFunc evalFunc, deUint32 compareFunc);
101                                                         ~FragDepthCompareCase   (void);
102
103         IterateResult                   iterate                                 (void);
104
105 private:
106         string                                  m_fragSrc;
107         EvalFragDepthFunc               m_evalFunc;
108         deUint32                                m_compareFunc;
109 };
110
111 FragDepthCompareCase::FragDepthCompareCase (Context& context, const char* name, const char* desc, const char* fragSrc, EvalFragDepthFunc evalFunc, deUint32 compareFunc)
112         : TestCase                      (context, name, desc)
113         , m_fragSrc                     (fragSrc)
114         , m_evalFunc            (evalFunc)
115         , m_compareFunc         (compareFunc)
116 {
117 }
118
119 FragDepthCompareCase::~FragDepthCompareCase (void)
120 {
121 }
122
123 FragDepthCompareCase::IterateResult FragDepthCompareCase::iterate (void)
124 {
125         TestLog&                                        log                             = m_testCtx.getLog();
126         const glw::Functions&           gl                              = m_context.getRenderContext().getFunctions();
127         de::Random                                      rnd                             (deStringHash(getName()));
128         const tcu::RenderTarget&        renderTarget    = m_context.getRenderContext().getRenderTarget();
129         int                                                     viewportW               = de::min(128, renderTarget.getWidth());
130         int                                                     viewportH               = de::min(128, renderTarget.getHeight());
131         int                                                     viewportX               = rnd.getInt(0, renderTarget.getWidth()-viewportW);
132         int                                                     viewportY               = rnd.getInt(0, renderTarget.getHeight()-viewportH);
133         tcu::Surface                            renderedFrame   (viewportW, viewportH);
134         tcu::Surface                            referenceFrame  (viewportW, viewportH);
135         const float                                     constDepth              = 0.1f;
136
137         if (renderTarget.getDepthBits() == 0)
138                 throw tcu::NotSupportedError("Depth buffer is required", "", __FILE__, __LINE__);
139
140         gl.viewport(viewportX, viewportY, viewportW, viewportH);
141         gl.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
142         gl.enable(GL_DEPTH_TEST);
143
144         static const deUint16 quadIndices[] = { 0, 1, 2, 2, 1, 3 };
145
146         // Fill viewport with 2 quads - one with constant depth and another with d = [-1..1]
147         {
148                 glu::ShaderProgram basicQuadProgram(m_context.getRenderContext(), glu::makeVtxFragSources(s_vertexShaderSrc, s_defaultFragmentShaderSrc));
149
150                 if (!basicQuadProgram.isOk())
151                 {
152                         log << basicQuadProgram;
153                         TCU_FAIL("Compile failed");
154                 }
155
156                 const float constDepthCoord[] =
157                 {
158                         -1.0f, -1.0f, constDepth, 1.0f,
159                         -1.0f, +1.0f, constDepth, 1.0f,
160                          0.0f, -1.0f, constDepth, 1.0f,
161                          0.0f, +1.0f, constDepth, 1.0f
162                 };
163                 const float varyingDepthCoord[] =
164                 {
165                          0.0f, -1.0f, +1.0f, 1.0f,
166                          0.0f, +1.0f,  0.0f, 1.0f,
167                         +1.0f, -1.0f,  0.0f, 1.0f,
168                         +1.0f, +1.0f, -1.0f, 1.0f
169                 };
170
171                 gl.useProgram(basicQuadProgram.getProgram());
172                 gl.uniform4f(gl.getUniformLocation(basicQuadProgram.getProgram(), "u_color"), 0.0f, 0.0f, 1.0f, 1.0f);
173                 gl.depthFunc(GL_ALWAYS);
174
175                 {
176                         glu::VertexArrayBinding posBinding = glu::va::Float("a_position", 4, 4, 0, &constDepthCoord[0]);
177                         glu::draw(m_context.getRenderContext(), basicQuadProgram.getProgram(), 1, &posBinding,
178                                           glu::pr::Triangles(DE_LENGTH_OF_ARRAY(quadIndices), &quadIndices[0]));
179                 }
180
181                 {
182                         glu::VertexArrayBinding posBinding = glu::va::Float("a_position", 4, 4, 0, &varyingDepthCoord[0]);
183                         glu::draw(m_context.getRenderContext(), basicQuadProgram.getProgram(), 1, &posBinding,
184                                           glu::pr::Triangles(DE_LENGTH_OF_ARRAY(quadIndices), &quadIndices[0]));
185                 }
186
187                 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw base quads");
188         }
189
190         // Render with depth test.
191         {
192                 glu::ShaderProgram program(m_context.getRenderContext(), glu::makeVtxFragSources(s_vertexShaderSrc, m_fragSrc.c_str()));
193                 log << program;
194
195                 if (!program.isOk())
196                         TCU_FAIL("Compile failed");
197
198                 const float coord[] =
199                 {
200                         0.0f, 0.0f,
201                         0.0f, 1.0f,
202                         1.0f, 0.0f,
203                         1.0f, 1.0f
204                 };
205                 const float position[] =
206                 {
207                         -1.0f, -1.0f, +1.0f, 1.0f,
208                         -1.0f, +1.0f,  0.0f, 1.0f,
209                         +1.0f, -1.0f,  0.0f, 1.0f,
210                         +1.0f, +1.0f, -1.0f, 1.0f
211                 };
212
213                 gl.useProgram(program.getProgram());
214                 gl.depthFunc(m_compareFunc);
215                 gl.uniform4f(gl.getUniformLocation(program.getProgram(), "u_color"), 0.0f, 1.0f, 0.0f, 1.0f);
216
217                 // Setup default helper uniforms.
218                 gls::setupDefaultUniforms(m_context.getRenderContext(), program.getProgram());
219
220                 {
221                         glu::VertexArrayBinding vertexArrays[] =
222                         {
223                                 glu::va::Float("a_position",    4, 4, 0, &position[0]),
224                                 glu::va::Float("a_coord",               2, 4, 0, &coord[0])
225                         };
226                         glu::draw(m_context.getRenderContext(), program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), &vertexArrays[0],
227                                           glu::pr::Triangles(DE_LENGTH_OF_ARRAY(quadIndices), &quadIndices[0]));
228                 }
229
230                 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw test quad");
231         }
232
233         glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, renderedFrame.getAccess());
234
235         // Render reference.
236         for (int y = 0; y < referenceFrame.getHeight(); y++)
237         {
238                 float   yf              = ((float)y + 0.5f) / (float)referenceFrame.getHeight();
239                 int             half    = de::clamp((int)((float)referenceFrame.getWidth()*0.5f + 0.5f), 0, referenceFrame.getWidth());
240
241                 // Fill left half - comparison to constant 0.5
242                 for (int x = 0; x < half; x++)
243                 {
244                         float   xf              = ((float)x + 0.5f) / (float)referenceFrame.getWidth();
245                         float   d               = m_evalFunc(Vec2(xf, yf));
246                         bool    dpass   = compare(m_compareFunc, d, constDepth*0.5f + 0.5f);
247
248                         referenceFrame.setPixel(x, y, dpass ? tcu::RGBA::green() : tcu::RGBA::blue());
249                 }
250
251                 // Fill right half - comparison to interpolated depth
252                 for (int x = half; x < referenceFrame.getWidth(); x++)
253                 {
254                         float   xf              = ((float)x + 0.5f) / (float)referenceFrame.getWidth();
255                         float   xh              = ((float)(x - half) + 0.5f) / (float)(referenceFrame.getWidth()-half);
256                         float   rd              = 1.0f - (xh + yf) * 0.5f;
257                         float   d               = m_evalFunc(Vec2(xf, yf));
258                         bool    dpass   = compare(m_compareFunc, d, rd);
259
260                         referenceFrame.setPixel(x, y, dpass ? tcu::RGBA::green() : tcu::RGBA::blue());
261                 }
262         }
263
264         bool isOk = tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame, renderedFrame, 0.05f, tcu::COMPARE_LOG_RESULT);
265         m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS      : QP_TEST_RESULT_FAIL,
266                                                         isOk ? "Pass"                           : "Fail");
267         return STOP;
268 }
269
270 class FragDepthWriteCase : public TestCase
271 {
272 public:
273                                                         FragDepthWriteCase              (Context& context, const char* name, const char* desc, const char* fragSrc, EvalFragDepthFunc evalFunc);
274                                                         ~FragDepthWriteCase             (void);
275
276         IterateResult                   iterate                                 (void);
277
278 private:
279         string                                  m_fragSrc;
280         EvalFragDepthFunc               m_evalFunc;
281 };
282
283 FragDepthWriteCase::FragDepthWriteCase (Context& context, const char* name, const char* desc, const char* fragSrc, EvalFragDepthFunc evalFunc)
284         : TestCase                      (context, name, desc)
285         , m_fragSrc                     (fragSrc)
286         , m_evalFunc            (evalFunc)
287 {
288 }
289
290 FragDepthWriteCase::~FragDepthWriteCase (void)
291 {
292 }
293
294 FragDepthWriteCase::IterateResult FragDepthWriteCase::iterate (void)
295 {
296         TestLog&                                        log                             = m_testCtx.getLog();
297         const glw::Functions&           gl                              = m_context.getRenderContext().getFunctions();
298         de::Random                                      rnd                             (deStringHash(getName()));
299         const tcu::RenderTarget&        renderTarget    = m_context.getRenderContext().getRenderTarget();
300         int                                                     viewportW               = de::min(128, renderTarget.getWidth());
301         int                                                     viewportH               = de::min(128, renderTarget.getHeight());
302         int                                                     viewportX               = rnd.getInt(0, renderTarget.getWidth()-viewportW);
303         int                                                     viewportY               = rnd.getInt(0, renderTarget.getHeight()-viewportH);
304         tcu::Surface                            renderedFrame   (viewportW, viewportH);
305         tcu::Surface                            referenceFrame  (viewportW, viewportH);
306         const int                                       numDepthSteps   = 16;
307         const float                                     depthStep               = 1.0f/(float)(numDepthSteps-1);
308
309         if (renderTarget.getDepthBits() == 0)
310                 throw tcu::NotSupportedError("Depth buffer is required", "", __FILE__, __LINE__);
311
312         gl.viewport(viewportX, viewportY, viewportW, viewportH);
313         gl.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
314         gl.enable(GL_DEPTH_TEST);
315         gl.depthFunc(GL_LESS);
316
317         static const deUint16 quadIndices[] = { 0, 1, 2, 2, 1, 3 };
318
319         // Render with given shader.
320         {
321                 glu::ShaderProgram program(m_context.getRenderContext(), glu::makeVtxFragSources(s_vertexShaderSrc, m_fragSrc.c_str()));
322                 log << program;
323
324                 if (!program.isOk())
325                         TCU_FAIL("Compile failed");
326
327                 const float coord[] =
328                 {
329                         0.0f, 0.0f,
330                         0.0f, 1.0f,
331                         1.0f, 0.0f,
332                         1.0f, 1.0f
333                 };
334                 const float position[] =
335                 {
336                         -1.0f, -1.0f, +1.0f, 1.0f,
337                         -1.0f, +1.0f,  0.0f, 1.0f,
338                         +1.0f, -1.0f,  0.0f, 1.0f,
339                         +1.0f, +1.0f, -1.0f, 1.0f
340                 };
341
342                 gl.useProgram(program.getProgram());
343                 gl.uniform4f(gl.getUniformLocation(program.getProgram(), "u_color"), 0.0f, 1.0f, 0.0f, 1.0f);
344
345                 // Setup default helper uniforms.
346                 gls::setupDefaultUniforms(m_context.getRenderContext(), program.getProgram());
347
348                 {
349                         glu::VertexArrayBinding vertexArrays[] =
350                         {
351                                 glu::va::Float("a_position",    4, 4, 0, &position[0]),
352                                 glu::va::Float("a_coord",               2, 4, 0, &coord[0])
353                         };
354                         glu::draw(m_context.getRenderContext(), program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), &vertexArrays[0],
355                                           glu::pr::Triangles(DE_LENGTH_OF_ARRAY(quadIndices), &quadIndices[0]));
356                 }
357
358                 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw test quad");
359         }
360
361         // Visualize by rendering full-screen quads with increasing depth and color.
362         {
363                 glu::ShaderProgram program (m_context.getRenderContext(), glu::makeVtxFragSources(s_vertexShaderSrc, s_defaultFragmentShaderSrc));
364                 if (!program.isOk())
365                 {
366                         log << program;
367                         TCU_FAIL("Compile failed");
368                 }
369
370                 int posLoc              = gl.getAttribLocation(program.getProgram(), "a_position");
371                 int colorLoc    = gl.getUniformLocation(program.getProgram(), "u_color");
372
373                 gl.useProgram(program.getProgram());
374                 gl.depthMask(GL_FALSE);
375
376                 for (int stepNdx = 0; stepNdx < numDepthSteps; stepNdx++)
377                 {
378                         float   f               = (float)stepNdx*depthStep;
379                         float   depth   = f*2.0f - 1.0f;
380                         Vec4    color   = Vec4(f, f, f, 1.0f);
381
382                         const float position[] =
383                         {
384                                 -1.0f, -1.0f, depth, 1.0f,
385                                 -1.0f, +1.0f, depth, 1.0f,
386                                 +1.0f, -1.0f, depth, 1.0f,
387                                 +1.0f, +1.0f, depth, 1.0f
388                         };
389                         glu::VertexArrayBinding posBinding = glu::va::Float(posLoc, 4, 4, 0, &position[0]);
390
391                         gl.uniform4fv(colorLoc, 1, color.getPtr());
392                         glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
393                                           glu::pr::Triangles(DE_LENGTH_OF_ARRAY(quadIndices), &quadIndices[0]));
394                 }
395
396                 GLU_EXPECT_NO_ERROR(gl.getError(), "Visualization draw");
397         }
398
399         glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, renderedFrame.getAccess());
400
401         // Render reference.
402         for (int y = 0; y < referenceFrame.getHeight(); y++)
403         {
404                 for (int x = 0; x < referenceFrame.getWidth(); x++)
405                 {
406                         float   xf              = ((float)x + 0.5f) / (float)referenceFrame.getWidth();
407                         float   yf              = ((float)y + 0.5f) / (float)referenceFrame.getHeight();
408                         float   d               = m_evalFunc(Vec2(xf, yf));
409                         int             step    = (int)deFloatFloor(d / depthStep);
410                         int             col             = de::clamp(deRoundFloatToInt32((float)step*depthStep*255.0f), 0, 255);
411
412                         referenceFrame.setPixel(x, y, tcu::RGBA(col, col, col, 0xff));
413                 }
414         }
415
416         bool isOk = tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame, renderedFrame, 0.05f, tcu::COMPARE_LOG_RESULT);
417         m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS      : QP_TEST_RESULT_FAIL,
418                                                         isOk ? "Pass"                           : "Fail");
419         return STOP;
420 }
421
422 FragDepthTests::FragDepthTests (Context& context)
423         : TestCaseGroup(context, "fragdepth", "gl_FragDepth tests")
424 {
425 }
426
427 FragDepthTests::~FragDepthTests (void)
428 {
429 }
430
431 static float evalConstDepth             (const Vec2& coord)     { DE_UNREF(coord); return 0.5f; }
432 static float evalDynamicDepth   (const Vec2& coord)     { return (coord.x()+coord.y())*0.5f; }
433 static float evalNoWrite                (const Vec2& coord)     { return 1.0f - (coord.x()+coord.y())*0.5f; }
434
435 static float evalDynamicConditionalDepth (const Vec2& coord)
436 {
437         float d = (coord.x()+coord.y())*0.5f;
438         if (coord.y() < 0.5f)
439                 return d;
440         else
441                 return 1.0f - d;
442 }
443
444 void FragDepthTests::init (void)
445 {
446         static const struct
447         {
448                 const char*                     name;
449                 const char*                     desc;
450                 EvalFragDepthFunc       evalFunc;
451                 const char*                     fragSrc;
452         } cases[] =
453         {
454                 {
455                         "no_write", "No gl_FragDepth write", evalNoWrite,
456                         "#version 300 es\n"
457                         "uniform highp vec4 u_color;\n"
458                         "layout(location = 0) out mediump vec4 o_color;\n"
459                         "void main (void)\n"
460                         "{\n"
461                         "       o_color = u_color;\n"
462                         "}\n"
463                 },
464                 {
465                         "const", "Const depth write", evalConstDepth,
466                         "#version 300 es\n"
467                         "uniform highp vec4 u_color;\n"
468                         "layout(location = 0) out mediump vec4 o_color;\n"
469                         "void main (void)\n"
470                         "{\n"
471                         "       o_color = u_color;\n"
472                         "       gl_FragDepth = 0.5;\n"
473                         "}\n"
474                 },
475                 {
476                         "uniform", "Uniform depth write", evalConstDepth,
477                         "#version 300 es\n"
478                         "uniform highp vec4 u_color;\n"
479                         "uniform highp float uf_half;\n"
480                         "layout(location = 0) out mediump vec4 o_color;\n"
481                         "void main (void)\n"
482                         "{\n"
483                         "       o_color = u_color;\n"
484                         "       gl_FragDepth = uf_half;\n"
485                         "}\n"
486                 },
487                 {
488                         "dynamic", "Dynamic depth write", evalDynamicDepth,
489                         "#version 300 es\n"
490                         "uniform highp vec4 u_color;\n"
491                         "in highp vec2 v_coord;\n"
492                         "layout(location = 0) out mediump vec4 o_color;\n"
493                         "void main (void)\n"
494                         "{\n"
495                         "       o_color = u_color;\n"
496                         "       gl_FragDepth = (v_coord.x+v_coord.y)*0.5;\n"
497                         "}\n"
498                 },
499                 {
500                         "fragcoord_z", "gl_FragDepth write from gl_FragCoord.z", evalNoWrite,
501                         "#version 300 es\n"
502                         "uniform highp vec4 u_color;\n"
503                         "layout(location = 0) out mediump vec4 o_color;\n"
504                         "void main (void)\n"
505                         "{\n"
506                         "       o_color = u_color;\n"
507                         "       gl_FragDepth = gl_FragCoord.z;\n"
508                         "}\n"
509                 },
510                 {
511                         "uniform_conditional_write", "Uniform conditional write", evalDynamicDepth,
512                         "#version 300 es\n"
513                         "uniform highp vec4 u_color;\n"
514                         "uniform bool ub_true;\n"
515                         "in highp vec2 v_coord;\n"
516                         "layout(location = 0) out mediump vec4 o_color;\n"
517                         "void main (void)\n"
518                         "{\n"
519                         "       o_color = u_color;\n"
520                         "       if (ub_true)\n"
521                         "               gl_FragDepth = (v_coord.x+v_coord.y)*0.5;\n"
522                         "}\n"
523                 },
524                 {
525                         "dynamic_conditional_write", "Uniform conditional write", evalDynamicConditionalDepth,
526                         "#version 300 es\n"
527                         "uniform highp vec4 u_color;\n"
528                         "uniform bool ub_true;\n"
529                         "in highp vec2 v_coord;\n"
530                         "layout(location = 0) out mediump vec4 o_color;\n"
531                         "void main (void)\n"
532                         "{\n"
533                         "       o_color = u_color;\n"
534                         "       mediump float d = (v_coord.x+v_coord.y)*0.5f;\n"
535                         "       if (v_coord.y < 0.5)\n"
536                         "               gl_FragDepth = d;\n"
537                         "       else\n"
538                         "               gl_FragDepth = 1.0 - d;\n"
539                         "}\n"
540                 },
541                 {
542                         "uniform_loop_write", "Uniform loop write", evalConstDepth,
543                         "#version 300 es\n"
544                         "uniform highp vec4 u_color;\n"
545                         "uniform int ui_two;\n"
546                         "uniform highp float uf_fourth;\n"
547                         "in highp vec2 v_coord;\n"
548                         "layout(location = 0) out mediump vec4 o_color;\n"
549                         "void main (void)\n"
550                         "{\n"
551                         "       o_color = u_color;\n"
552                         "       gl_FragDepth = 0.0;\n"
553                         "       for (int i = 0; i < ui_two; i++)\n"
554                         "               gl_FragDepth += uf_fourth;\n"
555                         "}\n"
556                 },
557                 {
558                         "write_in_function", "Uniform loop write", evalDynamicDepth,
559                         "#version 300 es\n"
560                         "uniform highp vec4 u_color;\n"
561                         "uniform highp float uf_half;\n"
562                         "in highp vec2 v_coord;\n"
563                         "layout(location = 0) out mediump vec4 o_color;\n"
564                         "void myfunc (highp vec2 coord)\n"
565                         "{\n"
566                         "       gl_FragDepth = (coord.x+coord.y)*0.5;\n"
567                         "}\n"
568                         "void main (void)\n"
569                         "{\n"
570                         "       o_color = u_color;\n"
571                         "       myfunc(v_coord);\n"
572                         "}\n"
573                 }
574         };
575
576         // .write
577         tcu::TestCaseGroup* writeGroup = new tcu::TestCaseGroup(m_testCtx, "write", "gl_FragDepth write tests");
578         addChild(writeGroup);
579         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cases); ndx++)
580                 writeGroup->addChild(new FragDepthWriteCase(m_context, cases[ndx].name, cases[ndx].desc, cases[ndx].fragSrc, cases[ndx].evalFunc));
581
582         // .compare
583         tcu::TestCaseGroup* compareGroup = new tcu::TestCaseGroup(m_testCtx, "compare", "gl_FragDepth used with depth comparison");
584         addChild(compareGroup);
585         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cases); ndx++)
586                 compareGroup->addChild(new FragDepthCompareCase(m_context, cases[ndx].name, cases[ndx].desc, cases[ndx].fragSrc, cases[ndx].evalFunc, GL_LESS));
587 }
588
589 } // Functional
590 } // gles3
591 } // deqp