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>
compare(deUint32 func,T a,T b)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 
FragDepthCompareCase(Context & context,const char * name,const char * desc,const char * fragSrc,EvalFragDepthFunc evalFunc,deUint32 compareFunc)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 
~FragDepthCompareCase(void)119 FragDepthCompareCase::~FragDepthCompareCase (void)
120 {
121 }
122 
iterate(void)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 
FragDepthWriteCase(Context & context,const char * name,const char * desc,const char * fragSrc,EvalFragDepthFunc evalFunc)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 
~FragDepthWriteCase(void)290 FragDepthWriteCase::~FragDepthWriteCase (void)
291 {
292 }
293 
iterate(void)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 
FragDepthTests(Context & context)422 FragDepthTests::FragDepthTests (Context& context)
423 	: TestCaseGroup(context, "fragdepth", "gl_FragDepth tests")
424 {
425 }
426 
~FragDepthTests(void)427 FragDepthTests::~FragDepthTests (void)
428 {
429 }
430 
evalConstDepth(const Vec2 & coord)431 static float evalConstDepth		(const Vec2& coord)	{ DE_UNREF(coord); return 0.5f; }
evalDynamicDepth(const Vec2 & coord)432 static float evalDynamicDepth	(const Vec2& coord)	{ return (coord.x()+coord.y())*0.5f; }
evalNoWrite(const Vec2 & coord)433 static float evalNoWrite		(const Vec2& coord)	{ return 1.0f - (coord.x()+coord.y())*0.5f; }
434 
evalDynamicConditionalDepth(const Vec2 & coord)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 
init(void)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
592