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
43namespace deqp
44{
45namespace gles3
46{
47namespace Functional
48{
49
50using tcu::Vec2;
51using tcu::Vec3;
52using tcu::Vec4;
53using tcu::TestLog;
54using std::string;
55using std::vector;
56
57typedef float (*EvalFragDepthFunc) (const Vec2& coord);
58
59static 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";
69static 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
78template <typename T>
79static 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
97class FragDepthCompareCase : public TestCase
98{
99public:
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
105private:
106	string					m_fragSrc;
107	EvalFragDepthFunc		m_evalFunc;
108	deUint32				m_compareFunc;
109};
110
111FragDepthCompareCase::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
119FragDepthCompareCase::~FragDepthCompareCase (void)
120{
121}
122
123FragDepthCompareCase::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
270class FragDepthWriteCase : public TestCase
271{
272public:
273							FragDepthWriteCase		(Context& context, const char* name, const char* desc, const char* fragSrc, EvalFragDepthFunc evalFunc);
274							~FragDepthWriteCase		(void);
275
276	IterateResult			iterate					(void);
277
278private:
279	string					m_fragSrc;
280	EvalFragDepthFunc		m_evalFunc;
281};
282
283FragDepthWriteCase::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
290FragDepthWriteCase::~FragDepthWriteCase (void)
291{
292}
293
294FragDepthWriteCase::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
422FragDepthTests::FragDepthTests (Context& context)
423	: TestCaseGroup(context, "fragdepth", "gl_FragDepth tests")
424{
425}
426
427FragDepthTests::~FragDepthTests (void)
428{
429}
430
431static float evalConstDepth		(const Vec2& coord)	{ DE_UNREF(coord); return 0.5f; }
432static float evalDynamicDepth	(const Vec2& coord)	{ return (coord.x()+coord.y())*0.5f; }
433static float evalNoWrite		(const Vec2& coord)	{ return 1.0f - (coord.x()+coord.y())*0.5f; }
434
435static 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
444void 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
592