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 Shader built-in variable tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es3fShaderBuiltinVarTests.hpp"
25#include "glsShaderRenderCase.hpp"
26#include "glsShaderExecUtil.hpp"
27#include "deRandom.hpp"
28#include "deString.h"
29#include "deMath.h"
30#include "deUniquePtr.hpp"
31#include "deStringUtil.hpp"
32#include "tcuTestLog.hpp"
33#include "tcuTestCase.hpp"
34#include "tcuTextureUtil.hpp"
35#include "tcuRenderTarget.hpp"
36#include "tcuImageCompare.hpp"
37#include "gluPixelTransfer.hpp"
38#include "gluDrawUtil.hpp"
39#include "gluStrUtil.hpp"
40#include "rrRenderer.hpp"
41#include "rrFragmentOperations.hpp"
42
43#include "glwEnums.hpp"
44#include "glwFunctions.hpp"
45
46using std::string;
47using std::vector;
48using tcu::TestLog;
49
50namespace deqp
51{
52namespace gles3
53{
54namespace Functional
55{
56
57static int getInteger (const glw::Functions& gl, deUint32 pname)
58{
59	int value = -1;
60	gl.getIntegerv(pname, &value);
61	GLU_EXPECT_NO_ERROR(gl.getError(), ("glGetIntegerv(" + glu::getGettableStateStr((int)pname).toString() + ")").c_str());
62	return value;
63}
64
65template<deUint32 Pname>
66static int getInteger (const glw::Functions& gl)
67{
68	return getInteger(gl, Pname);
69}
70
71static int getVectorsFromComps (const glw::Functions& gl, deUint32 pname)
72{
73	int value = -1;
74	gl.getIntegerv(pname, &value);
75	GLU_EXPECT_NO_ERROR(gl.getError(), ("glGetIntegerv(" + glu::getGettableStateStr((int)pname).toString() + ")").c_str());
76	TCU_CHECK_MSG(value%4 == 0, ("Expected " + glu::getGettableStateStr((int)pname).toString() + " to be divisible by 4").c_str());
77	return value/4;
78}
79
80template<deUint32 Pname>
81static int getVectorsFromComps (const glw::Functions& gl)
82{
83	return getVectorsFromComps(gl, Pname);
84}
85
86class ShaderBuiltinConstantCase : public TestCase
87{
88public:
89	typedef int (*GetConstantValueFunc) (const glw::Functions& gl);
90
91								ShaderBuiltinConstantCase	(Context& context, const char* name, const char* desc, const char* varName, GetConstantValueFunc getValue, glu::ShaderType shaderType);
92								~ShaderBuiltinConstantCase	(void);
93
94	IterateResult				iterate						(void);
95
96private:
97	const std::string			m_varName;
98	const GetConstantValueFunc	m_getValue;
99	const glu::ShaderType		m_shaderType;
100};
101
102ShaderBuiltinConstantCase::ShaderBuiltinConstantCase (Context& context, const char* name, const char* desc, const char* varName, GetConstantValueFunc getValue, glu::ShaderType shaderType)
103	: TestCase		(context, name, desc)
104	, m_varName		(varName)
105	, m_getValue	(getValue)
106	, m_shaderType	(shaderType)
107{
108}
109
110ShaderBuiltinConstantCase::~ShaderBuiltinConstantCase (void)
111{
112}
113
114static gls::ShaderExecUtil::ShaderExecutor* createGetConstantExecutor (const glu::RenderContext& renderCtx, glu::ShaderType shaderType, const std::string& varName)
115{
116	using namespace gls::ShaderExecUtil;
117
118	ShaderSpec	shaderSpec;
119
120	shaderSpec.version	= glu::GLSL_VERSION_300_ES;
121	shaderSpec.source	= string("result = ") + varName + ";\n";
122	shaderSpec.outputs.push_back(Symbol("result", glu::VarType(glu::TYPE_INT, glu::PRECISION_HIGHP)));
123
124	return createExecutor(renderCtx, shaderType, shaderSpec);
125}
126
127ShaderBuiltinConstantCase::IterateResult ShaderBuiltinConstantCase::iterate (void)
128{
129	using namespace gls::ShaderExecUtil;
130
131	const de::UniquePtr<ShaderExecutor>	shaderExecutor	(createGetConstantExecutor(m_context.getRenderContext(), m_shaderType, m_varName));
132	const int							reference		= m_getValue(m_context.getRenderContext().getFunctions());
133	int									result			= -1;
134	void* const							outputs			= &result;
135
136	if (!shaderExecutor->isOk())
137	{
138		shaderExecutor->log(m_testCtx.getLog());
139		TCU_FAIL("Compile failed");
140	}
141
142	shaderExecutor->useProgram();
143	shaderExecutor->execute(1, DE_NULL, &outputs);
144
145	m_testCtx.getLog() << TestLog::Integer(m_varName, m_varName, "", QP_KEY_TAG_NONE, result);
146
147	if (result != reference)
148	{
149		m_testCtx.getLog() << TestLog::Message << "ERROR: Expected " << m_varName << " = " << reference << TestLog::EndMessage
150						   << TestLog::Message << "Test shader:" << TestLog::EndMessage;
151		shaderExecutor->log(m_testCtx.getLog());
152		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid builtin constant value");
153	}
154	else
155		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
156
157	return STOP;
158}
159
160namespace
161{
162
163struct DepthRangeParams
164{
165	DepthRangeParams (void)
166		: zNear	(0.0f)
167		, zFar	(1.0f)
168	{
169	}
170
171	DepthRangeParams (float zNear_, float zFar_)
172		: zNear	(zNear_)
173		, zFar	(zFar_)
174	{
175	}
176
177	float	zNear;
178	float	zFar;
179};
180
181class DepthRangeEvaluator : public gls::ShaderEvaluator
182{
183public:
184	DepthRangeEvaluator (const DepthRangeParams& params)
185		: m_params(params)
186	{
187	}
188
189	void evaluate (gls::ShaderEvalContext& c)
190	{
191		float zNear	= deFloatClamp(m_params.zNear, 0.0f, 1.0f);
192		float zFar	= deFloatClamp(m_params.zFar, 0.0f, 1.0f);
193		float diff	= zFar - zNear;
194		c.color.xyz() = tcu::Vec3(zNear, zFar, diff*0.5f + 0.5f);
195	}
196
197private:
198	const DepthRangeParams& m_params;
199};
200
201} // anonymous
202
203class ShaderDepthRangeTest : public gls::ShaderRenderCase
204{
205public:
206	ShaderDepthRangeTest (Context& context, const char* name, const char* desc, bool isVertexCase)
207		: ShaderRenderCase	(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, desc, isVertexCase, m_evaluator)
208		, m_evaluator		(m_depthRange)
209		, m_iterNdx			(0)
210	{
211	}
212
213	void init (void)
214	{
215		static const char* defaultVertSrc =
216			"#version 300 es\n"
217			"in highp vec4 a_position;\n"
218			"void main (void)\n"
219			"{\n"
220			"	gl_Position = a_position;\n"
221			"}\n";
222		static const char* defaultFragSrc =
223			"#version 300 es\n"
224			"in mediump vec4 v_color;\n"
225			"layout(location = 0) out mediump vec4 o_color;\n\n"
226			"void main (void)\n"
227			"{\n"
228			"	o_color = v_color;\n"
229			"}\n";
230
231		// Construct shader.
232		std::ostringstream src;
233		src << "#version 300 es\n";
234		if (m_isVertexCase)
235			src << "in highp vec4 a_position;\n"
236				<< "out mediump vec4 v_color;\n";
237		else
238			src << "layout(location = 0) out mediump vec4 o_color;\n";
239
240		src << "void main (void)\n{\n";
241		src << "\t" << (m_isVertexCase ? "v_color" : "o_color") << " = vec4(gl_DepthRange.near, gl_DepthRange.far, gl_DepthRange.diff*0.5 + 0.5, 1.0);\n";
242
243		if (m_isVertexCase)
244			src << "\tgl_Position = a_position;\n";
245
246		src << "}\n";
247
248		m_vertShaderSource		= m_isVertexCase ? src.str()		: defaultVertSrc;
249		m_fragShaderSource		= m_isVertexCase ? defaultFragSrc	: src.str();
250
251		gls::ShaderRenderCase::init();
252	}
253
254	IterateResult iterate (void)
255	{
256		const glw::Functions& gl = m_renderCtx.getFunctions();
257
258		const DepthRangeParams cases[] =
259		{
260			DepthRangeParams(0.0f,  1.0f),
261			DepthRangeParams(1.5f, -1.0f),
262			DepthRangeParams(0.7f,  0.3f)
263		};
264
265		m_depthRange = cases[m_iterNdx];
266		m_testCtx.getLog() << tcu::TestLog::Message << "glDepthRangef(" << m_depthRange.zNear << ", " << m_depthRange.zFar << ")" << tcu::TestLog::EndMessage;
267		gl.depthRangef(m_depthRange.zNear, m_depthRange.zFar);
268		GLU_EXPECT_NO_ERROR(gl.getError(), "glDepthRangef()");
269
270		gls::ShaderRenderCase::iterate();
271		m_iterNdx += 1;
272
273		if (m_iterNdx == DE_LENGTH_OF_ARRAY(cases) || m_testCtx.getTestResult() != QP_TEST_RESULT_PASS)
274			return STOP;
275		else
276			return CONTINUE;
277	}
278
279private:
280	DepthRangeParams		m_depthRange;
281	DepthRangeEvaluator		m_evaluator;
282	int						m_iterNdx;
283};
284
285class FragCoordXYZCase : public TestCase
286{
287public:
288	FragCoordXYZCase (Context& context)
289		: TestCase(context, "fragcoord_xyz", "gl_FragCoord.xyz Test")
290	{
291	}
292
293	IterateResult iterate (void)
294	{
295		TestLog&				log			= m_testCtx.getLog();
296		const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
297		const int				width		= m_context.getRenderTarget().getWidth();
298		const int				height		= m_context.getRenderTarget().getHeight();
299		const tcu::RGBA			threshold	= tcu::RGBA(1,1,1,1) + m_context.getRenderTarget().getPixelFormat().getColorThreshold();
300		const tcu::Vec3			scale		(1.f / float(width), 1.f / float(height), 1.0f);
301
302		tcu::Surface			testImg		(width, height);
303		tcu::Surface			refImg		(width, height);
304
305		const glu::ShaderProgram program(m_context.getRenderContext(), glu::makeVtxFragSources(
306			"#version 300 es\n"
307			"in highp vec4 a_position;\n"
308			"void main (void)\n"
309			"{\n"
310			"	gl_Position = a_position;\n"
311			"}\n",
312
313			"#version 300 es\n"
314			"uniform highp vec3 u_scale;\n"
315			"layout(location = 0) out mediump vec4 o_color;\n"
316			"void main (void)\n"
317			"{\n"
318			"	o_color = vec4(gl_FragCoord.xyz*u_scale, 1.0);\n"
319			"}\n"));
320
321		log << program;
322
323		if (!program.isOk())
324			throw tcu::TestError("Compile failed");
325
326		// Draw with GL.
327		{
328			const float positions[] =
329			{
330				-1.0f,  1.0f, -1.0f, 1.0f,
331				-1.0f, -1.0f,  0.0f, 1.0f,
332				 1.0f,  1.0f,  0.0f, 1.0f,
333				 1.0f, -1.0f,  1.0f, 1.0f
334			};
335			const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 };
336
337			const int				scaleLoc	= gl.getUniformLocation(program.getProgram(), "u_scale");
338			glu::VertexArrayBinding	posBinding	= glu::va::Float("a_position", 4, 4, 0, &positions[0]);
339
340			gl.useProgram(program.getProgram());
341			gl.uniform3fv(scaleLoc, 1, scale.getPtr());
342
343			glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
344					  glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
345
346			glu::readPixels(m_context.getRenderContext(), 0, 0, testImg.getAccess());
347			GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
348		}
349
350		// Draw reference
351		for (int y = 0; y < refImg.getHeight(); y++)
352		{
353			for (int x = 0; x < refImg.getWidth(); x++)
354			{
355				const float			xf			= (float(x)+.5f) / float(refImg.getWidth());
356				const float			yf			= (float(refImg.getHeight()-y-1)+.5f) / float(refImg.getHeight());
357				const float			z			= (xf + yf) / 2.0f;
358				const tcu::Vec3		fragCoord	(float(x)+.5f, float(y)+.5f, z);
359				const tcu::Vec3		scaledFC	= fragCoord*scale;
360				const tcu::Vec4		color		(scaledFC.x(), scaledFC.y(), scaledFC.z(), 1.0f);
361
362				refImg.setPixel(x, y, tcu::RGBA(color));
363			}
364		}
365
366		// Compare
367		{
368			bool isOk = tcu::pixelThresholdCompare(log, "Result", "Image comparison result", refImg, testImg, threshold, tcu::COMPARE_LOG_RESULT);
369			m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
370									isOk ? "Pass"				: "Image comparison failed");
371		}
372
373		return STOP;
374	}
375};
376
377static inline float projectedTriInterpolate (const tcu::Vec3& s, const tcu::Vec3& w, float nx, float ny)
378{
379	return (s[0]*(1.0f-nx-ny)/w[0] + s[1]*ny/w[1] + s[2]*nx/w[2]) / ((1.0f-nx-ny)/w[0] + ny/w[1] + nx/w[2]);
380}
381
382class FragCoordWCase : public TestCase
383{
384public:
385	FragCoordWCase (Context& context)
386		: TestCase(context, "fragcoord_w", "gl_FragCoord.w Test")
387	{
388	}
389
390	IterateResult iterate (void)
391	{
392		TestLog&				log			= m_testCtx.getLog();
393		const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
394		const int				width		= m_context.getRenderTarget().getWidth();
395		const int				height		= m_context.getRenderTarget().getHeight();
396		const tcu::RGBA			threshold	= tcu::RGBA(1,1,1,1) + m_context.getRenderTarget().getPixelFormat().getColorThreshold();
397
398		tcu::Surface			testImg		(width, height);
399		tcu::Surface			refImg		(width, height);
400
401		const float				w[4]		= { 1.7f, 2.0f, 1.2f, 1.0f };
402
403		const glu::ShaderProgram program(m_context.getRenderContext(), glu::makeVtxFragSources(
404			"#version 300 es\n"
405			"in highp vec4 a_position;\n"
406			"void main (void)\n"
407			"{\n"
408			"	gl_Position = a_position;\n"
409			"}\n",
410
411			"#version 300 es\n"
412			"layout(location = 0) out mediump vec4 o_color;\n"
413			"void main (void)\n"
414			"{\n"
415			"	o_color = vec4(0.0, 1.0/gl_FragCoord.w - 1.0, 0.0, 1.0);\n"
416			"}\n"));
417
418		log << program;
419
420		if (!program.isOk())
421			throw tcu::TestError("Compile failed");
422
423		// Draw with GL.
424		{
425			const float positions[] =
426			{
427				-w[0],  w[0], 0.0f, w[0],
428				-w[1], -w[1], 0.0f, w[1],
429				 w[2],  w[2], 0.0f, w[2],
430				 w[3], -w[3], 0.0f, w[3]
431			};
432			const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 };
433
434			glu::VertexArrayBinding	posBinding	= glu::va::Float("a_position", 4, 4, 0, &positions[0]);
435
436			gl.useProgram(program.getProgram());
437
438			glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
439					  glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
440
441			glu::readPixels(m_context.getRenderContext(), 0, 0, testImg.getAccess());
442			GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
443		}
444
445		// Draw reference
446		for (int y = 0; y < refImg.getHeight(); y++)
447		{
448			for (int x = 0; x < refImg.getWidth(); x++)
449			{
450				const float			xf			= (float(x)+.5f) / float(refImg.getWidth());
451				const float			yf			= (float(refImg.getHeight()-y-1)+.5f) / float(refImg.getHeight());
452				const float			oow			= ((xf + yf) < 1.0f)
453												? projectedTriInterpolate(tcu::Vec3(w[0], w[1], w[2]), tcu::Vec3(w[0], w[1], w[2]), xf, yf)
454												: projectedTriInterpolate(tcu::Vec3(w[3], w[2], w[1]), tcu::Vec3(w[3], w[2], w[1]), 1.0f-xf, 1.0f-yf);
455				const tcu::Vec4		color		(0.0f, oow - 1.0f, 0.0f, 1.0f);
456
457				refImg.setPixel(x, y, tcu::RGBA(color));
458			}
459		}
460
461		// Compare
462		{
463			bool isOk = tcu::pixelThresholdCompare(log, "Result", "Image comparison result", refImg, testImg, threshold, tcu::COMPARE_LOG_RESULT);
464			m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
465									isOk ? "Pass"				: "Image comparison failed");
466		}
467
468		return STOP;
469	}
470};
471
472class PointCoordCase : public TestCase
473{
474public:
475	PointCoordCase (Context& context)
476		: TestCase(context, "pointcoord", "gl_PointCoord Test")
477	{
478	}
479
480	IterateResult iterate (void)
481	{
482		TestLog&				log			= m_testCtx.getLog();
483		const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
484		const int				width		= de::min(256, m_context.getRenderTarget().getWidth());
485		const int				height		= de::min(256, m_context.getRenderTarget().getHeight());
486		const float				threshold	= 0.02f;
487
488		const int				numPoints	= 8;
489
490		vector<tcu::Vec3>		coords		(numPoints);
491		float					pointSizeRange[2]	= { 0.0f, 0.0f };
492
493		de::Random				rnd			(0x145fa);
494		tcu::Surface			testImg		(width, height);
495		tcu::Surface			refImg		(width, height);
496
497		gl.getFloatv(GL_ALIASED_POINT_SIZE_RANGE, &pointSizeRange[0]);
498		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE)");
499
500		if (pointSizeRange[0] <= 0.0f || pointSizeRange[1] <= 0.0f || pointSizeRange[1] < pointSizeRange[0])
501			throw tcu::TestError("Invalid GL_ALIASED_POINT_SIZE_RANGE");
502
503		// Compute coordinates.
504		{
505
506			for (vector<tcu::Vec3>::iterator coord = coords.begin(); coord != coords.end(); ++coord)
507			{
508				coord->x() = rnd.getFloat(-0.9f, 0.9f);
509				coord->y() = rnd.getFloat(-0.9f, 0.9f);
510				coord->z() = rnd.getFloat(pointSizeRange[0], pointSizeRange[1]);
511			}
512		}
513
514		const glu::ShaderProgram program(m_context.getRenderContext(), glu::makeVtxFragSources(
515			"#version 300 es\n"
516			"in highp vec3 a_positionSize;\n"
517			"void main (void)\n"
518			"{\n"
519			"	gl_Position = vec4(a_positionSize.xy, 0.0, 1.0);\n"
520			"	gl_PointSize = a_positionSize.z;\n"
521			"}\n",
522
523			"#version 300 es\n"
524			"layout(location = 0) out mediump vec4 o_color;\n"
525			"void main (void)\n"
526			"{\n"
527			"	o_color = vec4(gl_PointCoord, 0.0, 1.0);\n"
528			"}\n"));
529
530		log << program;
531
532		if (!program.isOk())
533			throw tcu::TestError("Compile failed");
534
535		// Draw with GL.
536		{
537			glu::VertexArrayBinding	posBinding	= glu::va::Float("a_positionSize", 3, (int)coords.size(), 0, (const float*)&coords[0]);
538			const int				viewportX	= rnd.getInt(0, m_context.getRenderTarget().getWidth()-width);
539			const int				viewportY	= rnd.getInt(0, m_context.getRenderTarget().getHeight()-height);
540
541			gl.viewport(viewportX, viewportY, width, height);
542			gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
543			gl.clear(GL_COLOR_BUFFER_BIT);
544
545			gl.useProgram(program.getProgram());
546
547			glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
548					  glu::pr::Points((int)coords.size()));
549
550			glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, testImg.getAccess());
551			GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
552		}
553
554		// Draw reference
555		tcu::clear(refImg.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
556		for (vector<tcu::Vec3>::const_iterator pointIter = coords.begin(); pointIter != coords.end(); ++pointIter)
557		{
558			const int	x0		= deRoundFloatToInt32(float(width) *(pointIter->x()*0.5f + 0.5f) - pointIter->z()*0.5f);
559			const int	y0		= deRoundFloatToInt32(float(height)*(pointIter->y()*0.5f + 0.5f) - pointIter->z()*0.5f);
560			const int	x1		= deRoundFloatToInt32(float(width) *(pointIter->x()*0.5f + 0.5f) + pointIter->z()*0.5f);
561			const int	y1		= deRoundFloatToInt32(float(height)*(pointIter->y()*0.5f + 0.5f) + pointIter->z()*0.5f);
562			const int	w		= x1-x0;
563			const int	h		= y1-y0;
564
565			for (int yo = 0; yo < h; yo++)
566			{
567				for (int xo = 0; xo < w; xo++)
568				{
569					const float			xf		= float(xo+0.5f) / float(w);
570					const float			yf		= float((h-yo-1)+0.5f) / float(h);
571					const tcu::Vec4		color	(xf, yf, 0.0f, 1.0f);
572					const int			dx		= x0+xo;
573					const int			dy		= y0+yo;
574
575					if (de::inBounds(dx, 0, refImg.getWidth()) && de::inBounds(dy, 0, refImg.getHeight()))
576						refImg.setPixel(dx, dy, tcu::RGBA(color));
577				}
578			}
579		}
580
581		// Compare
582		{
583			bool isOk = tcu::fuzzyCompare(log, "Result", "Image comparison result", refImg, testImg, threshold, tcu::COMPARE_LOG_RESULT);
584			m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
585									isOk ? "Pass"				: "Image comparison failed");
586		}
587
588		return STOP;
589	}
590};
591
592class FrontFacingCase : public TestCase
593{
594public:
595	FrontFacingCase (Context& context)
596		: TestCase(context, "frontfacing", "gl_FrontFacing Test")
597	{
598	}
599
600	IterateResult iterate (void)
601	{
602		// Test case renders two adjecent quads, where left is has front-facing
603		// triagles and right back-facing. Color is selected based on gl_FrontFacing
604		// value.
605
606		TestLog&				log			= m_testCtx.getLog();
607		const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
608		de::Random				rnd			(0x89f2c);
609		const int				width		= de::min(64, m_context.getRenderTarget().getWidth());
610		const int				height		= de::min(64, m_context.getRenderTarget().getHeight());
611		const int				viewportX	= rnd.getInt(0, m_context.getRenderTarget().getWidth()-width);
612		const int				viewportY	= rnd.getInt(0, m_context.getRenderTarget().getHeight()-height);
613		const tcu::RGBA			threshold	= tcu::RGBA(1,1,1,1) + m_context.getRenderTarget().getPixelFormat().getColorThreshold();
614
615		tcu::Surface			testImg		(width, height);
616		tcu::Surface			refImg		(width, height);
617
618		const glu::ShaderProgram program(m_context.getRenderContext(), glu::makeVtxFragSources(
619			"#version 300 es\n"
620			"in highp vec4 a_position;\n"
621			"void main (void)\n"
622			"{\n"
623			"	gl_Position = a_position;\n"
624			"}\n",
625
626			"#version 300 es\n"
627			"layout(location = 0) out mediump vec4 o_color;\n"
628			"void main (void)\n"
629			"{\n"
630			"	if (gl_FrontFacing)\n"
631			"		o_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
632			"	else\n"
633			"		o_color = vec4(0.0, 0.0, 1.0, 1.0);\n"
634			"}\n"));
635
636		log << program;
637
638		if (!program.isOk())
639			throw tcu::TestError("Compile failed");
640
641		// Draw with GL.
642		{
643			const float positions[] =
644			{
645				-1.0f,  1.0f, 0.0f, 1.0f,
646				-1.0f, -1.0f, 0.0f, 1.0f,
647				 1.0f,  1.0f, 0.0f, 1.0f,
648				 1.0f, -1.0f, 0.0f, 1.0f
649			};
650			const deUint16 indicesCCW[]	= { 0, 1, 2, 2, 1, 3 };
651			const deUint16 indicesCW[]	= { 2, 1, 0, 3, 1, 2 };
652
653			glu::VertexArrayBinding	posBinding	= glu::va::Float("a_position", 4, 4, 0, &positions[0]);
654
655			gl.useProgram(program.getProgram());
656
657			gl.viewport(viewportX, viewportY, width/2, height);
658			glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
659					  glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indicesCCW), &indicesCCW[0]));
660
661			gl.viewport(viewportX + width/2, viewportY, width-width/2, height);
662			glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
663					  glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indicesCW), &indicesCW[0]));
664
665			glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, testImg.getAccess());
666			GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
667		}
668
669		// Draw reference
670		for (int y = 0; y < refImg.getHeight(); y++)
671		{
672			for (int x = 0; x < refImg.getWidth()/2; x++)
673				refImg.setPixel(x, y, tcu::RGBA::green);
674
675			for (int x = refImg.getWidth()/2; x < refImg.getWidth(); x++)
676				refImg.setPixel(x, y, tcu::RGBA::blue);
677		}
678
679		// Compare
680		{
681			bool isOk = tcu::pixelThresholdCompare(log, "Result", "Image comparison result", refImg, testImg, threshold, tcu::COMPARE_LOG_RESULT);
682			m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
683									isOk ? "Pass"				: "Image comparison failed");
684		}
685
686		return STOP;
687	}
688};
689
690// VertexIDCase
691
692class VertexIDCase : public TestCase
693{
694public:
695						VertexIDCase			(Context& context);
696						~VertexIDCase			(void);
697
698	void				init					(void);
699	void				deinit					(void);
700	IterateResult		iterate					(void);
701
702private:
703	enum
704	{
705		MAX_VERTICES = 8*3	//!< 8 triangles, totals 24 vertices
706	};
707
708	void				renderReference			(const tcu::PixelBufferAccess& dst, const int numVertices, const deUint16* const indices, const tcu::Vec4* const positions, const tcu::Vec4* const colors);
709
710	glu::ShaderProgram*	m_program;
711	deUint32			m_positionBuffer;
712	deUint32			m_elementBuffer;
713
714	vector<tcu::Vec4>	m_positions;
715	vector<tcu::Vec4>	m_colors;
716	int					m_viewportW;
717	int					m_viewportH;
718
719	int					m_iterNdx;
720};
721
722VertexIDCase::VertexIDCase (Context& context)
723	: TestCase			(context, "vertex_id",	"gl_VertexID Test")
724	, m_program			(DE_NULL)
725	, m_positionBuffer	(0)
726	, m_elementBuffer	(0)
727	, m_viewportW		(0)
728	, m_viewportH		(0)
729	, m_iterNdx			(0)
730{
731}
732
733VertexIDCase::~VertexIDCase (void)
734{
735	VertexIDCase::deinit();
736}
737
738void VertexIDCase::init (void)
739{
740	const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
741	const int				width		= m_context.getRenderTarget().getWidth();
742	const int				height		= m_context.getRenderTarget().getHeight();
743
744	const int				quadWidth	= 32;
745	const int				quadHeight	= 32;
746
747	if (width < quadWidth)
748		throw tcu::NotSupportedError("Too small render target");
749
750	const int				maxQuadsX	= width/quadWidth;
751	const int				numVertices	= MAX_VERTICES;
752
753	const int				numQuads	= numVertices/6 + (numVertices%6 != 0 ? 1 : 0);
754	const int				viewportW	= de::min(numQuads, maxQuadsX)*quadWidth;
755	const int				viewportH	= (numQuads/maxQuadsX + (numQuads%maxQuadsX != 0 ? 1 : 0))*quadHeight;
756
757	if (viewportH > height)
758		throw tcu::NotSupportedError("Too small render target");
759
760	DE_ASSERT(viewportW <= width && viewportH <= height);
761
762	DE_ASSERT(!m_program);
763	m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(
764		"#version 300 es\n"
765		"in highp vec4 a_position;\n"
766		"out mediump vec4 v_color;\n"
767		"uniform highp vec4 u_colors[24];\n"
768		"void main (void)\n"
769		"{\n"
770		"	gl_Position = a_position;\n"
771		"	v_color = u_colors[gl_VertexID];\n"
772		"}\n",
773
774		"#version 300 es\n"
775		"in mediump vec4 v_color;\n"
776		"layout(location = 0) out mediump vec4 o_color;\n"
777		"void main (void)\n"
778		"{\n"
779		"	o_color = v_color;\n"
780		"}\n"));
781
782	m_testCtx.getLog() << *m_program;
783
784	if (!m_program->isOk())
785	{
786		delete m_program;
787		m_program = DE_NULL;
788		throw tcu::TestError("Compile failed");
789	}
790
791	gl.genBuffers(1, &m_positionBuffer);
792	gl.genBuffers(1, &m_elementBuffer);
793
794	// Set colors (in dynamic memory to save static data space).
795	m_colors.resize(numVertices);
796	m_colors[ 0] = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
797	m_colors[ 1] = tcu::Vec4(0.5f, 1.0f, 0.5f, 1.0f);
798	m_colors[ 2] = tcu::Vec4(0.0f, 0.5f, 1.0f, 1.0f);
799	m_colors[ 3] = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
800	m_colors[ 4] = tcu::Vec4(0.0f, 1.0f, 1.0f, 1.0f);
801	m_colors[ 5] = tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f);
802	m_colors[ 6] = tcu::Vec4(0.5f, 0.0f, 1.0f, 1.0f);
803	m_colors[ 7] = tcu::Vec4(0.5f, 0.0f, 0.5f, 1.0f);
804	m_colors[ 8] = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
805	m_colors[ 9] = tcu::Vec4(0.5f, 1.0f, 0.0f, 1.0f);
806	m_colors[10] = tcu::Vec4(0.0f, 0.5f, 0.0f, 1.0f);
807	m_colors[11] = tcu::Vec4(0.5f, 1.0f, 1.0f, 1.0f);
808	m_colors[12] = tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
809	m_colors[13] = tcu::Vec4(1.0f, 0.0f, 0.5f, 1.0f);
810	m_colors[14] = tcu::Vec4(0.0f, 0.5f, 0.5f, 1.0f);
811	m_colors[15] = tcu::Vec4(1.0f, 1.0f, 0.5f, 1.0f);
812	m_colors[16] = tcu::Vec4(1.0f, 0.0f, 1.0f, 1.0f);
813	m_colors[17] = tcu::Vec4(1.0f, 0.5f, 0.0f, 1.0f);
814	m_colors[18] = tcu::Vec4(0.0f, 1.0f, 0.5f, 1.0f);
815	m_colors[19] = tcu::Vec4(1.0f, 0.5f, 1.0f, 1.0f);
816	m_colors[20] = tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
817	m_colors[21] = tcu::Vec4(1.0f, 0.5f, 0.5f, 1.0f);
818	m_colors[22] = tcu::Vec4(0.0f, 0.0f, 0.5f, 1.0f);
819	m_colors[23] = tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
820
821	// Compute positions.
822	m_positions.resize(numVertices);
823	DE_ASSERT(numVertices%3 == 0);
824	for (int vtxNdx = 0; vtxNdx < numVertices; vtxNdx += 3)
825	{
826		const float	h			= 2.0f * float(quadHeight)/float(viewportH);
827		const float	w			= 2.0f * float(quadWidth)/float(viewportW);
828
829		const int	triNdx		= vtxNdx/3;
830		const int	quadNdx		= triNdx/2;
831		const int	quadY		= quadNdx/maxQuadsX;
832		const int	quadX		= quadNdx%maxQuadsX;
833
834		const float	x0			= -1.0f + quadX*w;
835		const float	y0			= -1.0f + quadY*h;
836
837		if (triNdx%2 == 0)
838		{
839			m_positions[vtxNdx+0] = tcu::Vec4(x0,   y0,   0.0f, 1.0f);
840			m_positions[vtxNdx+1] = tcu::Vec4(x0+w, y0+h, 0.0f, 1.0f);
841			m_positions[vtxNdx+2] = tcu::Vec4(x0,   y0+h, 0.0f, 1.0f);
842		}
843		else
844		{
845			m_positions[vtxNdx+0] = tcu::Vec4(x0+w, y0+h, 0.0f, 1.0f);
846			m_positions[vtxNdx+1] = tcu::Vec4(x0,   y0,   0.0f, 1.0f);
847			m_positions[vtxNdx+2] = tcu::Vec4(x0+w, y0,   0.0f, 1.0f);
848		}
849	}
850
851	m_viewportW	= viewportW;
852	m_viewportH	= viewportH;
853	m_iterNdx	= 0;
854
855	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
856}
857
858void VertexIDCase::deinit (void)
859{
860	delete m_program;
861	m_program = DE_NULL;
862
863	if (m_positionBuffer)
864	{
865		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_positionBuffer);
866		m_positionBuffer = 0;
867	}
868
869	if (m_elementBuffer)
870	{
871		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_elementBuffer);
872		m_elementBuffer = 0;
873	}
874
875	m_positions.clear();
876	m_colors.clear();
877}
878
879class VertexIDReferenceShader : public rr::VertexShader, public rr::FragmentShader
880{
881public:
882	enum
883	{
884		VARYINGLOC_COLOR = 0
885	};
886
887	VertexIDReferenceShader ()
888		: rr::VertexShader	(2, 1)		// color and pos in => color out
889		, rr::FragmentShader(1, 1)		// color in => color out
890	{
891		this->rr::VertexShader::m_inputs[0].type		= rr::GENERICVECTYPE_FLOAT;
892		this->rr::VertexShader::m_inputs[1].type		= rr::GENERICVECTYPE_FLOAT;
893
894		this->rr::VertexShader::m_outputs[0].type		= rr::GENERICVECTYPE_FLOAT;
895		this->rr::VertexShader::m_outputs[0].flatshade	= false;
896
897		this->rr::FragmentShader::m_inputs[0].type		= rr::GENERICVECTYPE_FLOAT;
898		this->rr::FragmentShader::m_inputs[0].flatshade	= false;
899
900		this->rr::FragmentShader::m_outputs[0].type		= rr::GENERICVECTYPE_FLOAT;
901	}
902
903	void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
904	{
905		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
906		{
907			const int positionAttrLoc = 0;
908			const int colorAttrLoc = 1;
909
910			rr::VertexPacket& packet = *packets[packetNdx];
911
912			// Transform to position
913			packet.position = rr::readVertexAttribFloat(inputs[positionAttrLoc], packet.instanceNdx, packet.vertexNdx);
914
915			// Pass color to FS
916			packet.outputs[VARYINGLOC_COLOR] = rr::readVertexAttribFloat(inputs[colorAttrLoc], packet.instanceNdx, packet.vertexNdx);
917		}
918	}
919
920	void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
921	{
922		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
923		{
924			rr::FragmentPacket& packet = packets[packetNdx];
925
926			for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
927				rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packet, context, VARYINGLOC_COLOR, fragNdx));
928		}
929	}
930};
931
932void VertexIDCase::renderReference (const tcu::PixelBufferAccess& dst, const int numVertices, const deUint16* const indices, const tcu::Vec4* const positions, const tcu::Vec4* const colors)
933{
934	const rr::Renderer				referenceRenderer;
935	const rr::RenderState			referenceState		((rr::ViewportState)(rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(dst)));
936	const rr::RenderTarget			referenceTarget		(rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(dst));
937	const VertexIDReferenceShader	referenceShader;
938	      rr::VertexAttrib			attribs[2];
939
940	attribs[0].type				= rr::VERTEXATTRIBTYPE_FLOAT;
941	attribs[0].size				= 4;
942	attribs[0].stride			= 0;
943	attribs[0].instanceDivisor	= 0;
944	attribs[0].pointer			= positions;
945
946	attribs[1].type				= rr::VERTEXATTRIBTYPE_FLOAT;
947	attribs[1].size				= 4;
948	attribs[1].stride			= 0;
949	attribs[1].instanceDivisor	= 0;
950	attribs[1].pointer			= colors;
951
952	referenceRenderer.draw(
953		rr::DrawCommand(
954			referenceState,
955			referenceTarget,
956			rr::Program(&referenceShader, &referenceShader),
957			2,
958			attribs,
959			rr::PrimitiveList(rr::PRIMITIVETYPE_TRIANGLES, numVertices, rr::DrawIndices(indices))));
960}
961
962VertexIDCase::IterateResult VertexIDCase::iterate (void)
963{
964	const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
965	const int				width		= m_context.getRenderTarget().getWidth();
966	const int				height		= m_context.getRenderTarget().getHeight();
967	const int				viewportW	= m_viewportW;
968	const int				viewportH	= m_viewportH;
969
970	const float				threshold	= 0.02f;
971
972	de::Random				rnd			(0xcf23ab1 ^ deInt32Hash(m_iterNdx));
973	tcu::Surface			refImg		(viewportW, viewportH);
974	tcu::Surface			testImg		(viewportW, viewportH);
975
976	const int				viewportX	= rnd.getInt(0, width-viewportW);
977	const int				viewportY	= rnd.getInt(0, height-viewportH);
978
979	const int				posLoc		= gl.getAttribLocation(m_program->getProgram(), "a_position");
980	const int				colorsLoc	= gl.getUniformLocation(m_program->getProgram(), "u_colors[0]");
981	const tcu::Vec4			clearColor	(0.0f, 0.0f, 0.0f, 1.0f);
982
983	// Setup common state.
984	gl.viewport					(viewportX, viewportY, viewportW, viewportH);
985	gl.useProgram				(m_program->getProgram());
986	gl.bindBuffer				(GL_ARRAY_BUFFER, m_positionBuffer);
987	gl.enableVertexAttribArray	(posLoc);
988	gl.vertexAttribPointer		(posLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
989	gl.uniform4fv				(colorsLoc, (int)m_colors.size(), (const float*)&m_colors[0]);
990
991	// Clear render target to black.
992	gl.clearColor	(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
993	gl.clear		(GL_COLOR_BUFFER_BIT);
994
995	tcu::clear(refImg.getAccess(), clearColor);
996
997	if (m_iterNdx == 0)
998	{
999		tcu::ScopedLogSection	logSection	(m_testCtx.getLog(), "Iter0", "glDrawArrays()");
1000		vector<deUint16>		indices		(m_positions.size());
1001
1002		gl.bufferData(GL_ARRAY_BUFFER, (int)(m_positions.size()*sizeof(tcu::Vec4)), &m_positions[0], GL_DYNAMIC_DRAW);
1003		gl.drawArrays(GL_TRIANGLES, 0, (int)m_positions.size());
1004
1005		glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, testImg.getAccess());
1006		GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
1007
1008		// Reference indices
1009		for (int ndx = 0; ndx < (int)indices.size(); ndx++)
1010			indices[ndx] = (deUint16)ndx;
1011
1012		renderReference(refImg.getAccess(), (int)m_positions.size(), &indices[0], &m_positions[0], &m_colors[0]);
1013	}
1014	else if (m_iterNdx == 1)
1015	{
1016		tcu::ScopedLogSection	logSection	(m_testCtx.getLog(), "Iter1", "glDrawElements(), indices in client-side array");
1017		vector<deUint16>		indices		(m_positions.size());
1018		vector<tcu::Vec4>		mappedPos	(m_positions.size());
1019
1020		// Compute initial indices and suffle
1021		for (int ndx = 0; ndx < (int)indices.size(); ndx++)
1022			indices[ndx] = (deUint16)ndx;
1023		rnd.shuffle(indices.begin(), indices.end());
1024
1025		// Use indices to re-map positions.
1026		for (int ndx = 0; ndx < (int)indices.size(); ndx++)
1027			mappedPos[indices[ndx]] = m_positions[ndx];
1028
1029		gl.bufferData(GL_ARRAY_BUFFER, (int)(m_positions.size()*sizeof(tcu::Vec4)), &mappedPos[0], GL_DYNAMIC_DRAW);
1030		gl.drawElements(GL_TRIANGLES, (int)indices.size(), GL_UNSIGNED_SHORT, &indices[0]);
1031
1032		glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, testImg.getAccess());
1033		GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
1034
1035		renderReference(refImg.getAccess(), (int)indices.size(), &indices[0], &mappedPos[0], &m_colors[0]);
1036	}
1037	else if (m_iterNdx == 2)
1038	{
1039		tcu::ScopedLogSection	logSection	(m_testCtx.getLog(), "Iter2", "glDrawElements(), indices in buffer");
1040		vector<deUint16>		indices		(m_positions.size());
1041		vector<tcu::Vec4>		mappedPos	(m_positions.size());
1042
1043		// Compute initial indices and suffle
1044		for (int ndx = 0; ndx < (int)indices.size(); ndx++)
1045			indices[ndx] = (deUint16)ndx;
1046		rnd.shuffle(indices.begin(), indices.end());
1047
1048		// Use indices to re-map positions.
1049		for (int ndx = 0; ndx < (int)indices.size(); ndx++)
1050			mappedPos[indices[ndx]] = m_positions[ndx];
1051
1052		gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementBuffer);
1053		gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (int)(indices.size()*sizeof(deUint16)), &indices[0], GL_DYNAMIC_DRAW);
1054
1055		gl.bufferData(GL_ARRAY_BUFFER, (int)(m_positions.size()*sizeof(tcu::Vec4)), &mappedPos[0], GL_DYNAMIC_DRAW);
1056		gl.drawElements(GL_TRIANGLES, (int)indices.size(), GL_UNSIGNED_SHORT, DE_NULL);
1057
1058		glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, testImg.getAccess());
1059		GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
1060
1061		tcu::clear(refImg.getAccess(), clearColor);
1062		renderReference(refImg.getAccess(), (int)indices.size(), &indices[0], &mappedPos[0], &m_colors[0]);
1063	}
1064	else
1065		DE_ASSERT(false);
1066
1067	if (!tcu::fuzzyCompare(m_testCtx.getLog(), "Result", "Image comparison result", refImg, testImg, threshold, tcu::COMPARE_LOG_RESULT))
1068		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
1069
1070	m_iterNdx += 1;
1071	return (m_iterNdx < 3) ? CONTINUE : STOP;
1072}
1073
1074ShaderBuiltinVarTests::ShaderBuiltinVarTests (Context& context)
1075	: TestCaseGroup(context, "builtin_variable", "Built-in Variable Tests")
1076{
1077}
1078
1079ShaderBuiltinVarTests::~ShaderBuiltinVarTests (void)
1080{
1081}
1082
1083void ShaderBuiltinVarTests::init (void)
1084{
1085	// Builtin constants.
1086
1087	static const struct
1088	{
1089		const char*											caseName;
1090		const char*											varName;
1091		ShaderBuiltinConstantCase::GetConstantValueFunc		getValue;
1092	} builtinConstants[] =
1093	{
1094		// GLES 2.
1095
1096		{ "max_vertex_attribs",					"gl_MaxVertexAttribs",				getInteger<GL_MAX_VERTEX_ATTRIBS>						},
1097		{ "max_vertex_uniform_vectors",			"gl_MaxVertexUniformVectors",		getInteger<GL_MAX_VERTEX_UNIFORM_VECTORS>				},
1098		{ "max_fragment_uniform_vectors",		"gl_MaxFragmentUniformVectors",		getInteger<GL_MAX_FRAGMENT_UNIFORM_VECTORS>				},
1099		{ "max_texture_image_units",			"gl_MaxTextureImageUnits",			getInteger<GL_MAX_TEXTURE_IMAGE_UNITS>					},
1100		{ "max_vertex_texture_image_units",		"gl_MaxVertexTextureImageUnits",	getInteger<GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS>			},
1101		{ "max_combined_texture_image_units",	"gl_MaxCombinedTextureImageUnits",	getInteger<GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS>			},
1102		{ "max_draw_buffers",					"gl_MaxDrawBuffers",				getInteger<GL_MAX_DRAW_BUFFERS>							},
1103
1104		// GLES 3.
1105
1106		{ "max_vertex_output_vectors",			"gl_MaxVertexOutputVectors",		getVectorsFromComps<GL_MAX_VERTEX_OUTPUT_COMPONENTS>	},
1107		{ "max_fragment_input_vectors",			"gl_MaxFragmentInputVectors",		getVectorsFromComps<GL_MAX_FRAGMENT_INPUT_COMPONENTS>	},
1108		{ "min_program_texel_offset",			"gl_MinProgramTexelOffset",			getInteger<GL_MIN_PROGRAM_TEXEL_OFFSET>					},
1109		{ "max_program_texel_offset",			"gl_MaxProgramTexelOffset",			getInteger<GL_MAX_PROGRAM_TEXEL_OFFSET>					}
1110	};
1111
1112	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(builtinConstants); ndx++)
1113	{
1114		const char* const										caseName	= builtinConstants[ndx].caseName;
1115		const char* const										varName		= builtinConstants[ndx].varName;
1116		const ShaderBuiltinConstantCase::GetConstantValueFunc	getValue	= builtinConstants[ndx].getValue;
1117
1118		addChild(new ShaderBuiltinConstantCase(m_context, (string(caseName) + "_vertex").c_str(),	varName, varName, getValue, glu::SHADERTYPE_VERTEX));
1119		addChild(new ShaderBuiltinConstantCase(m_context, (string(caseName) + "_fragment").c_str(),	varName, varName, getValue, glu::SHADERTYPE_FRAGMENT));
1120	}
1121
1122	addChild(new ShaderDepthRangeTest(m_context, "depth_range_vertex",		"gl_DepthRange", true));
1123	addChild(new ShaderDepthRangeTest(m_context, "depth_range_fragment",	"gl_DepthRange", false));
1124
1125	// Vertex shader builtin variables.
1126	addChild(new VertexIDCase		(m_context));
1127	// \todo [2013-03-20 pyry] gl_InstanceID -- tested in instancing tests quite thoroughly.
1128
1129	// Fragment shader builtin variables.
1130
1131	addChild(new FragCoordXYZCase	(m_context));
1132	addChild(new FragCoordWCase		(m_context));
1133	addChild(new PointCoordCase		(m_context));
1134	addChild(new FrontFacingCase	(m_context));
1135}
1136
1137} // Functional
1138} // gles3
1139} // deqp
1140