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 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 
     46 using std::string;
     47 using std::vector;
     48 using tcu::TestLog;
     49 
     50 namespace deqp
     51 {
     52 namespace gles3
     53 {
     54 namespace Functional
     55 {
     56 
     57 static 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 
     65 template<deUint32 Pname>
     66 static int getInteger (const glw::Functions& gl)
     67 {
     68 	return getInteger(gl, Pname);
     69 }
     70 
     71 static 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 	// Accept truncated division. According to the spec, the number of vectors is number of components divided by four, plain and simple.
     77 	return value/4;
     78 }
     79 
     80 template<deUint32 Pname>
     81 static int getVectorsFromComps (const glw::Functions& gl)
     82 {
     83 	return getVectorsFromComps(gl, Pname);
     84 }
     85 
     86 class ShaderBuiltinConstantCase : public TestCase
     87 {
     88 public:
     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 
     96 private:
     97 	const std::string			m_varName;
     98 	const GetConstantValueFunc	m_getValue;
     99 	const glu::ShaderType		m_shaderType;
    100 };
    101 
    102 ShaderBuiltinConstantCase::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 
    110 ShaderBuiltinConstantCase::~ShaderBuiltinConstantCase (void)
    111 {
    112 }
    113 
    114 static 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 
    127 ShaderBuiltinConstantCase::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 
    160 namespace
    161 {
    162 
    163 struct 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 
    181 class DepthRangeEvaluator : public gls::ShaderEvaluator
    182 {
    183 public:
    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 
    197 private:
    198 	const DepthRangeParams& m_params;
    199 };
    200 
    201 } // anonymous
    202 
    203 class ShaderDepthRangeTest : public gls::ShaderRenderCase
    204 {
    205 public:
    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 
    279 private:
    280 	DepthRangeParams		m_depthRange;
    281 	DepthRangeEvaluator		m_evaluator;
    282 	int						m_iterNdx;
    283 };
    284 
    285 class FragCoordXYZCase : public TestCase
    286 {
    287 public:
    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 
    377 static 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 
    382 class FragCoordWCase : public TestCase
    383 {
    384 public:
    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 
    472 class PointCoordCase : public TestCase
    473 {
    474 public:
    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 
    592 class FrontFacingCase : public TestCase
    593 {
    594 public:
    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.frontFace(GL_CCW);
    658 
    659 			gl.viewport(viewportX, viewportY, width/2, height/2);
    660 			glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
    661 					  glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indicesCCW), &indicesCCW[0]));
    662 
    663 			gl.viewport(viewportX + width/2, viewportY, width-width/2, height/2);
    664 			glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
    665 					  glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indicesCW), &indicesCW[0]));
    666 
    667 			gl.frontFace(GL_CW);
    668 
    669 			gl.viewport(viewportX, viewportY + height/2, width/2, height-height/2);
    670 			glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
    671 					  glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indicesCCW), &indicesCCW[0]));
    672 
    673 			gl.viewport(viewportX + width/2, viewportY + height/2, width-width/2, height-height/2);
    674 			glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
    675 					  glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indicesCW), &indicesCW[0]));
    676 
    677 			glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, testImg.getAccess());
    678 			GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
    679 		}
    680 
    681 		// Draw reference
    682 		{
    683 			for(int y = 0; y < refImg.getHeight() / 2; y++)
    684 				for(int x = 0; x < refImg.getWidth() / 2; x++)
    685 					refImg.setPixel(x, y, tcu::RGBA::green());
    686 
    687 			for(int y = 0; y < refImg.getHeight() / 2; y++)
    688 				for(int x = refImg.getWidth() / 2; x < refImg.getWidth(); x++)
    689 					refImg.setPixel(x, y, tcu::RGBA::blue());
    690 
    691 			for(int y = refImg.getHeight() / 2; y < refImg.getHeight(); y++)
    692 				for(int x = 0; x < refImg.getWidth() / 2; x++)
    693 					refImg.setPixel(x, y, tcu::RGBA::blue());
    694 
    695 			for(int y = refImg.getHeight() / 2; y < refImg.getHeight(); y++)
    696 				for(int x = refImg.getWidth() / 2; x < refImg.getWidth(); x++)
    697 					refImg.setPixel(x, y, tcu::RGBA::green());
    698 		}
    699 
    700 		// Compare
    701 		{
    702 			bool isOk = tcu::pixelThresholdCompare(log, "Result", "Image comparison result", refImg, testImg, threshold, tcu::COMPARE_LOG_RESULT);
    703 			m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
    704 									isOk ? "Pass"				: "Image comparison failed");
    705 		}
    706 
    707 		return STOP;
    708 	}
    709 };
    710 
    711 // VertexIDCase
    712 
    713 class VertexIDCase : public TestCase
    714 {
    715 public:
    716 						VertexIDCase			(Context& context);
    717 						~VertexIDCase			(void);
    718 
    719 	void				init					(void);
    720 	void				deinit					(void);
    721 	IterateResult		iterate					(void);
    722 
    723 private:
    724 	enum
    725 	{
    726 		MAX_VERTICES = 8*3	//!< 8 triangles, totals 24 vertices
    727 	};
    728 
    729 	void				renderReference			(const tcu::PixelBufferAccess& dst, const int numVertices, const deUint16* const indices, const tcu::Vec4* const positions, const tcu::Vec4* const colors);
    730 
    731 	glu::ShaderProgram*	m_program;
    732 	deUint32			m_positionBuffer;
    733 	deUint32			m_elementBuffer;
    734 
    735 	vector<tcu::Vec4>	m_positions;
    736 	vector<tcu::Vec4>	m_colors;
    737 	int					m_viewportW;
    738 	int					m_viewportH;
    739 
    740 	int					m_iterNdx;
    741 };
    742 
    743 VertexIDCase::VertexIDCase (Context& context)
    744 	: TestCase			(context, "vertex_id",	"gl_VertexID Test")
    745 	, m_program			(DE_NULL)
    746 	, m_positionBuffer	(0)
    747 	, m_elementBuffer	(0)
    748 	, m_viewportW		(0)
    749 	, m_viewportH		(0)
    750 	, m_iterNdx			(0)
    751 {
    752 }
    753 
    754 VertexIDCase::~VertexIDCase (void)
    755 {
    756 	VertexIDCase::deinit();
    757 }
    758 
    759 void VertexIDCase::init (void)
    760 {
    761 	const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
    762 	const int				width		= m_context.getRenderTarget().getWidth();
    763 	const int				height		= m_context.getRenderTarget().getHeight();
    764 
    765 	const int				quadWidth	= 32;
    766 	const int				quadHeight	= 32;
    767 
    768 	if (width < quadWidth)
    769 		throw tcu::NotSupportedError("Too small render target");
    770 
    771 	const int				maxQuadsX	= width/quadWidth;
    772 	const int				numVertices	= MAX_VERTICES;
    773 
    774 	const int				numQuads	= numVertices/6 + (numVertices%6 != 0 ? 1 : 0);
    775 	const int				viewportW	= de::min(numQuads, maxQuadsX)*quadWidth;
    776 	const int				viewportH	= (numQuads/maxQuadsX + (numQuads%maxQuadsX != 0 ? 1 : 0))*quadHeight;
    777 
    778 	if (viewportH > height)
    779 		throw tcu::NotSupportedError("Too small render target");
    780 
    781 	DE_ASSERT(viewportW <= width && viewportH <= height);
    782 
    783 	DE_ASSERT(!m_program);
    784 	m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(
    785 		"#version 300 es\n"
    786 		"in highp vec4 a_position;\n"
    787 		"out mediump vec4 v_color;\n"
    788 		"uniform highp vec4 u_colors[24];\n"
    789 		"void main (void)\n"
    790 		"{\n"
    791 		"	gl_Position = a_position;\n"
    792 		"	v_color = u_colors[gl_VertexID];\n"
    793 		"}\n",
    794 
    795 		"#version 300 es\n"
    796 		"in mediump vec4 v_color;\n"
    797 		"layout(location = 0) out mediump vec4 o_color;\n"
    798 		"void main (void)\n"
    799 		"{\n"
    800 		"	o_color = v_color;\n"
    801 		"}\n"));
    802 
    803 	m_testCtx.getLog() << *m_program;
    804 
    805 	if (!m_program->isOk())
    806 	{
    807 		delete m_program;
    808 		m_program = DE_NULL;
    809 		throw tcu::TestError("Compile failed");
    810 	}
    811 
    812 	gl.genBuffers(1, &m_positionBuffer);
    813 	gl.genBuffers(1, &m_elementBuffer);
    814 
    815 	// Set colors (in dynamic memory to save static data space).
    816 	m_colors.resize(numVertices);
    817 	m_colors[ 0] = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
    818 	m_colors[ 1] = tcu::Vec4(0.5f, 1.0f, 0.5f, 1.0f);
    819 	m_colors[ 2] = tcu::Vec4(0.0f, 0.5f, 1.0f, 1.0f);
    820 	m_colors[ 3] = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
    821 	m_colors[ 4] = tcu::Vec4(0.0f, 1.0f, 1.0f, 1.0f);
    822 	m_colors[ 5] = tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f);
    823 	m_colors[ 6] = tcu::Vec4(0.5f, 0.0f, 1.0f, 1.0f);
    824 	m_colors[ 7] = tcu::Vec4(0.5f, 0.0f, 0.5f, 1.0f);
    825 	m_colors[ 8] = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
    826 	m_colors[ 9] = tcu::Vec4(0.5f, 1.0f, 0.0f, 1.0f);
    827 	m_colors[10] = tcu::Vec4(0.0f, 0.5f, 0.0f, 1.0f);
    828 	m_colors[11] = tcu::Vec4(0.5f, 1.0f, 1.0f, 1.0f);
    829 	m_colors[12] = tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
    830 	m_colors[13] = tcu::Vec4(1.0f, 0.0f, 0.5f, 1.0f);
    831 	m_colors[14] = tcu::Vec4(0.0f, 0.5f, 0.5f, 1.0f);
    832 	m_colors[15] = tcu::Vec4(1.0f, 1.0f, 0.5f, 1.0f);
    833 	m_colors[16] = tcu::Vec4(1.0f, 0.0f, 1.0f, 1.0f);
    834 	m_colors[17] = tcu::Vec4(1.0f, 0.5f, 0.0f, 1.0f);
    835 	m_colors[18] = tcu::Vec4(0.0f, 1.0f, 0.5f, 1.0f);
    836 	m_colors[19] = tcu::Vec4(1.0f, 0.5f, 1.0f, 1.0f);
    837 	m_colors[20] = tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
    838 	m_colors[21] = tcu::Vec4(1.0f, 0.5f, 0.5f, 1.0f);
    839 	m_colors[22] = tcu::Vec4(0.0f, 0.0f, 0.5f, 1.0f);
    840 	m_colors[23] = tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
    841 
    842 	// Compute positions.
    843 	m_positions.resize(numVertices);
    844 	DE_ASSERT(numVertices%3 == 0);
    845 	for (int vtxNdx = 0; vtxNdx < numVertices; vtxNdx += 3)
    846 	{
    847 		const float	h			= 2.0f * float(quadHeight)/float(viewportH);
    848 		const float	w			= 2.0f * float(quadWidth)/float(viewportW);
    849 
    850 		const int	triNdx		= vtxNdx/3;
    851 		const int	quadNdx		= triNdx/2;
    852 		const int	quadY		= quadNdx/maxQuadsX;
    853 		const int	quadX		= quadNdx%maxQuadsX;
    854 
    855 		const float	x0			= -1.0f + float(quadX)*w;
    856 		const float	y0			= -1.0f + float(quadY)*h;
    857 
    858 		if (triNdx%2 == 0)
    859 		{
    860 			m_positions[vtxNdx+0] = tcu::Vec4(x0,   y0,   0.0f, 1.0f);
    861 			m_positions[vtxNdx+1] = tcu::Vec4(x0+w, y0+h, 0.0f, 1.0f);
    862 			m_positions[vtxNdx+2] = tcu::Vec4(x0,   y0+h, 0.0f, 1.0f);
    863 		}
    864 		else
    865 		{
    866 			m_positions[vtxNdx+0] = tcu::Vec4(x0+w, y0+h, 0.0f, 1.0f);
    867 			m_positions[vtxNdx+1] = tcu::Vec4(x0,   y0,   0.0f, 1.0f);
    868 			m_positions[vtxNdx+2] = tcu::Vec4(x0+w, y0,   0.0f, 1.0f);
    869 		}
    870 	}
    871 
    872 	m_viewportW	= viewportW;
    873 	m_viewportH	= viewportH;
    874 	m_iterNdx	= 0;
    875 
    876 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    877 }
    878 
    879 void VertexIDCase::deinit (void)
    880 {
    881 	delete m_program;
    882 	m_program = DE_NULL;
    883 
    884 	if (m_positionBuffer)
    885 	{
    886 		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_positionBuffer);
    887 		m_positionBuffer = 0;
    888 	}
    889 
    890 	if (m_elementBuffer)
    891 	{
    892 		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_elementBuffer);
    893 		m_elementBuffer = 0;
    894 	}
    895 
    896 	m_positions.clear();
    897 	m_colors.clear();
    898 }
    899 
    900 class VertexIDReferenceShader : public rr::VertexShader, public rr::FragmentShader
    901 {
    902 public:
    903 	enum
    904 	{
    905 		VARYINGLOC_COLOR = 0
    906 	};
    907 
    908 	VertexIDReferenceShader ()
    909 		: rr::VertexShader	(2, 1)		// color and pos in => color out
    910 		, rr::FragmentShader(1, 1)		// color in => color out
    911 	{
    912 		this->rr::VertexShader::m_inputs[0].type		= rr::GENERICVECTYPE_FLOAT;
    913 		this->rr::VertexShader::m_inputs[1].type		= rr::GENERICVECTYPE_FLOAT;
    914 
    915 		this->rr::VertexShader::m_outputs[0].type		= rr::GENERICVECTYPE_FLOAT;
    916 		this->rr::VertexShader::m_outputs[0].flatshade	= false;
    917 
    918 		this->rr::FragmentShader::m_inputs[0].type		= rr::GENERICVECTYPE_FLOAT;
    919 		this->rr::FragmentShader::m_inputs[0].flatshade	= false;
    920 
    921 		this->rr::FragmentShader::m_outputs[0].type		= rr::GENERICVECTYPE_FLOAT;
    922 	}
    923 
    924 	void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
    925 	{
    926 		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
    927 		{
    928 			const int positionAttrLoc = 0;
    929 			const int colorAttrLoc = 1;
    930 
    931 			rr::VertexPacket& packet = *packets[packetNdx];
    932 
    933 			// Transform to position
    934 			packet.position = rr::readVertexAttribFloat(inputs[positionAttrLoc], packet.instanceNdx, packet.vertexNdx);
    935 
    936 			// Pass color to FS
    937 			packet.outputs[VARYINGLOC_COLOR] = rr::readVertexAttribFloat(inputs[colorAttrLoc], packet.instanceNdx, packet.vertexNdx);
    938 		}
    939 	}
    940 
    941 	void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
    942 	{
    943 		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
    944 		{
    945 			rr::FragmentPacket& packet = packets[packetNdx];
    946 
    947 			for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
    948 				rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packet, context, VARYINGLOC_COLOR, fragNdx));
    949 		}
    950 	}
    951 };
    952 
    953 void VertexIDCase::renderReference (const tcu::PixelBufferAccess& dst, const int numVertices, const deUint16* const indices, const tcu::Vec4* const positions, const tcu::Vec4* const colors)
    954 {
    955 	const rr::Renderer				referenceRenderer;
    956 	const rr::RenderState			referenceState		((rr::ViewportState)(rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(dst)));
    957 	const rr::RenderTarget			referenceTarget		(rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(dst));
    958 	const VertexIDReferenceShader	referenceShader;
    959 	      rr::VertexAttrib			attribs[2];
    960 
    961 	attribs[0].type				= rr::VERTEXATTRIBTYPE_FLOAT;
    962 	attribs[0].size				= 4;
    963 	attribs[0].stride			= 0;
    964 	attribs[0].instanceDivisor	= 0;
    965 	attribs[0].pointer			= positions;
    966 
    967 	attribs[1].type				= rr::VERTEXATTRIBTYPE_FLOAT;
    968 	attribs[1].size				= 4;
    969 	attribs[1].stride			= 0;
    970 	attribs[1].instanceDivisor	= 0;
    971 	attribs[1].pointer			= colors;
    972 
    973 	referenceRenderer.draw(
    974 		rr::DrawCommand(
    975 			referenceState,
    976 			referenceTarget,
    977 			rr::Program(&referenceShader, &referenceShader),
    978 			2,
    979 			attribs,
    980 			rr::PrimitiveList(rr::PRIMITIVETYPE_TRIANGLES, numVertices, rr::DrawIndices(indices))));
    981 }
    982 
    983 VertexIDCase::IterateResult VertexIDCase::iterate (void)
    984 {
    985 	const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
    986 	const int				width		= m_context.getRenderTarget().getWidth();
    987 	const int				height		= m_context.getRenderTarget().getHeight();
    988 	const int				viewportW	= m_viewportW;
    989 	const int				viewportH	= m_viewportH;
    990 
    991 	const float				threshold	= 0.02f;
    992 
    993 	de::Random				rnd			(0xcf23ab1 ^ deInt32Hash(m_iterNdx));
    994 	tcu::Surface			refImg		(viewportW, viewportH);
    995 	tcu::Surface			testImg		(viewportW, viewportH);
    996 
    997 	const int				viewportX	= rnd.getInt(0, width-viewportW);
    998 	const int				viewportY	= rnd.getInt(0, height-viewportH);
    999 
   1000 	const int				posLoc		= gl.getAttribLocation(m_program->getProgram(), "a_position");
   1001 	const int				colorsLoc	= gl.getUniformLocation(m_program->getProgram(), "u_colors[0]");
   1002 	const tcu::Vec4			clearColor	(0.0f, 0.0f, 0.0f, 1.0f);
   1003 
   1004 	// Setup common state.
   1005 	gl.viewport					(viewportX, viewportY, viewportW, viewportH);
   1006 	gl.useProgram				(m_program->getProgram());
   1007 	gl.bindBuffer				(GL_ARRAY_BUFFER, m_positionBuffer);
   1008 	gl.enableVertexAttribArray	(posLoc);
   1009 	gl.vertexAttribPointer		(posLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
   1010 	gl.uniform4fv				(colorsLoc, (int)m_colors.size(), (const float*)&m_colors[0]);
   1011 
   1012 	// Clear render target to black.
   1013 	gl.clearColor	(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
   1014 	gl.clear		(GL_COLOR_BUFFER_BIT);
   1015 
   1016 	tcu::clear(refImg.getAccess(), clearColor);
   1017 
   1018 	if (m_iterNdx == 0)
   1019 	{
   1020 		tcu::ScopedLogSection	logSection	(m_testCtx.getLog(), "Iter0", "glDrawArrays()");
   1021 		vector<deUint16>		indices		(m_positions.size());
   1022 
   1023 		gl.bufferData(GL_ARRAY_BUFFER, (int)(m_positions.size()*sizeof(tcu::Vec4)), &m_positions[0], GL_DYNAMIC_DRAW);
   1024 		gl.drawArrays(GL_TRIANGLES, 0, (int)m_positions.size());
   1025 
   1026 		glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, testImg.getAccess());
   1027 		GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
   1028 
   1029 		// Reference indices
   1030 		for (int ndx = 0; ndx < (int)indices.size(); ndx++)
   1031 			indices[ndx] = (deUint16)ndx;
   1032 
   1033 		renderReference(refImg.getAccess(), (int)m_positions.size(), &indices[0], &m_positions[0], &m_colors[0]);
   1034 	}
   1035 	else if (m_iterNdx == 1)
   1036 	{
   1037 		tcu::ScopedLogSection	logSection	(m_testCtx.getLog(), "Iter1", "glDrawElements(), indices in client-side array");
   1038 		vector<deUint16>		indices		(m_positions.size());
   1039 		vector<tcu::Vec4>		mappedPos	(m_positions.size());
   1040 
   1041 		// Compute initial indices and suffle
   1042 		for (int ndx = 0; ndx < (int)indices.size(); ndx++)
   1043 			indices[ndx] = (deUint16)ndx;
   1044 		rnd.shuffle(indices.begin(), indices.end());
   1045 
   1046 		// Use indices to re-map positions.
   1047 		for (int ndx = 0; ndx < (int)indices.size(); ndx++)
   1048 			mappedPos[indices[ndx]] = m_positions[ndx];
   1049 
   1050 		gl.bufferData(GL_ARRAY_BUFFER, (int)(m_positions.size()*sizeof(tcu::Vec4)), &mappedPos[0], GL_DYNAMIC_DRAW);
   1051 		gl.drawElements(GL_TRIANGLES, (int)indices.size(), GL_UNSIGNED_SHORT, &indices[0]);
   1052 
   1053 		glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, testImg.getAccess());
   1054 		GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
   1055 
   1056 		renderReference(refImg.getAccess(), (int)indices.size(), &indices[0], &mappedPos[0], &m_colors[0]);
   1057 	}
   1058 	else if (m_iterNdx == 2)
   1059 	{
   1060 		tcu::ScopedLogSection	logSection	(m_testCtx.getLog(), "Iter2", "glDrawElements(), indices in buffer");
   1061 		vector<deUint16>		indices		(m_positions.size());
   1062 		vector<tcu::Vec4>		mappedPos	(m_positions.size());
   1063 
   1064 		// Compute initial indices and suffle
   1065 		for (int ndx = 0; ndx < (int)indices.size(); ndx++)
   1066 			indices[ndx] = (deUint16)ndx;
   1067 		rnd.shuffle(indices.begin(), indices.end());
   1068 
   1069 		// Use indices to re-map positions.
   1070 		for (int ndx = 0; ndx < (int)indices.size(); ndx++)
   1071 			mappedPos[indices[ndx]] = m_positions[ndx];
   1072 
   1073 		gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementBuffer);
   1074 		gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (int)(indices.size()*sizeof(deUint16)), &indices[0], GL_DYNAMIC_DRAW);
   1075 
   1076 		gl.bufferData(GL_ARRAY_BUFFER, (int)(m_positions.size()*sizeof(tcu::Vec4)), &mappedPos[0], GL_DYNAMIC_DRAW);
   1077 		gl.drawElements(GL_TRIANGLES, (int)indices.size(), GL_UNSIGNED_SHORT, DE_NULL);
   1078 
   1079 		glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, testImg.getAccess());
   1080 		GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
   1081 
   1082 		tcu::clear(refImg.getAccess(), clearColor);
   1083 		renderReference(refImg.getAccess(), (int)indices.size(), &indices[0], &mappedPos[0], &m_colors[0]);
   1084 	}
   1085 	else
   1086 		DE_ASSERT(false);
   1087 
   1088 	if (!tcu::fuzzyCompare(m_testCtx.getLog(), "Result", "Image comparison result", refImg, testImg, threshold, tcu::COMPARE_LOG_RESULT))
   1089 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
   1090 
   1091 	m_iterNdx += 1;
   1092 	return (m_iterNdx < 3) ? CONTINUE : STOP;
   1093 }
   1094 
   1095 ShaderBuiltinVarTests::ShaderBuiltinVarTests (Context& context)
   1096 	: TestCaseGroup(context, "builtin_variable", "Built-in Variable Tests")
   1097 {
   1098 }
   1099 
   1100 ShaderBuiltinVarTests::~ShaderBuiltinVarTests (void)
   1101 {
   1102 }
   1103 
   1104 void ShaderBuiltinVarTests::init (void)
   1105 {
   1106 	// Builtin constants.
   1107 
   1108 	static const struct
   1109 	{
   1110 		const char*											caseName;
   1111 		const char*											varName;
   1112 		ShaderBuiltinConstantCase::GetConstantValueFunc		getValue;
   1113 	} builtinConstants[] =
   1114 	{
   1115 		// GLES 2.
   1116 
   1117 		{ "max_vertex_attribs",					"gl_MaxVertexAttribs",				getInteger<GL_MAX_VERTEX_ATTRIBS>						},
   1118 		{ "max_vertex_uniform_vectors",			"gl_MaxVertexUniformVectors",		getInteger<GL_MAX_VERTEX_UNIFORM_VECTORS>				},
   1119 		{ "max_fragment_uniform_vectors",		"gl_MaxFragmentUniformVectors",		getInteger<GL_MAX_FRAGMENT_UNIFORM_VECTORS>				},
   1120 		{ "max_texture_image_units",			"gl_MaxTextureImageUnits",			getInteger<GL_MAX_TEXTURE_IMAGE_UNITS>					},
   1121 		{ "max_vertex_texture_image_units",		"gl_MaxVertexTextureImageUnits",	getInteger<GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS>			},
   1122 		{ "max_combined_texture_image_units",	"gl_MaxCombinedTextureImageUnits",	getInteger<GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS>			},
   1123 		{ "max_draw_buffers",					"gl_MaxDrawBuffers",				getInteger<GL_MAX_DRAW_BUFFERS>							},
   1124 
   1125 		// GLES 3.
   1126 
   1127 		{ "max_vertex_output_vectors",			"gl_MaxVertexOutputVectors",		getVectorsFromComps<GL_MAX_VERTEX_OUTPUT_COMPONENTS>	},
   1128 		{ "max_fragment_input_vectors",			"gl_MaxFragmentInputVectors",		getVectorsFromComps<GL_MAX_FRAGMENT_INPUT_COMPONENTS>	},
   1129 		{ "min_program_texel_offset",			"gl_MinProgramTexelOffset",			getInteger<GL_MIN_PROGRAM_TEXEL_OFFSET>					},
   1130 		{ "max_program_texel_offset",			"gl_MaxProgramTexelOffset",			getInteger<GL_MAX_PROGRAM_TEXEL_OFFSET>					}
   1131 	};
   1132 
   1133 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(builtinConstants); ndx++)
   1134 	{
   1135 		const char* const										caseName	= builtinConstants[ndx].caseName;
   1136 		const char* const										varName		= builtinConstants[ndx].varName;
   1137 		const ShaderBuiltinConstantCase::GetConstantValueFunc	getValue	= builtinConstants[ndx].getValue;
   1138 
   1139 		addChild(new ShaderBuiltinConstantCase(m_context, (string(caseName) + "_vertex").c_str(),	varName, varName, getValue, glu::SHADERTYPE_VERTEX));
   1140 		addChild(new ShaderBuiltinConstantCase(m_context, (string(caseName) + "_fragment").c_str(),	varName, varName, getValue, glu::SHADERTYPE_FRAGMENT));
   1141 	}
   1142 
   1143 	addChild(new ShaderDepthRangeTest(m_context, "depth_range_vertex",		"gl_DepthRange", true));
   1144 	addChild(new ShaderDepthRangeTest(m_context, "depth_range_fragment",	"gl_DepthRange", false));
   1145 
   1146 	// Vertex shader builtin variables.
   1147 	addChild(new VertexIDCase		(m_context));
   1148 	// \todo [2013-03-20 pyry] gl_InstanceID -- tested in instancing tests quite thoroughly.
   1149 
   1150 	// Fragment shader builtin variables.
   1151 
   1152 	addChild(new FragCoordXYZCase	(m_context));
   1153 	addChild(new FragCoordWCase		(m_context));
   1154 	addChild(new PointCoordCase		(m_context));
   1155 	addChild(new FrontFacingCase	(m_context));
   1156 }
   1157 
   1158 } // Functional
   1159 } // gles3
   1160 } // deqp
   1161