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