Home | History | Annotate | Download | only in functional
      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
    592