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 
getInteger(const glw::Functions & gl,deUint32 pname)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>
getInteger(const glw::Functions & gl)66 static int getInteger (const glw::Functions& gl)
67 {
68 	return getInteger(gl, Pname);
69 }
70 
getVectorsFromComps(const glw::Functions & gl,deUint32 pname)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>
getVectorsFromComps(const glw::Functions & gl)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 
ShaderBuiltinConstantCase(Context & context,const char * name,const char * desc,const char * varName,GetConstantValueFunc getValue,glu::ShaderType shaderType)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 
~ShaderBuiltinConstantCase(void)110 ShaderBuiltinConstantCase::~ShaderBuiltinConstantCase (void)
111 {
112 }
113 
createGetConstantExecutor(const glu::RenderContext & renderCtx,glu::ShaderType shaderType,const std::string & varName)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 
iterate(void)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 {
DepthRangeParamsdeqp::gles3::Functional::__anon1eeffb4d0111::DepthRangeParams165 	DepthRangeParams (void)
166 		: zNear	(0.0f)
167 		, zFar	(1.0f)
168 	{
169 	}
170 
DepthRangeParamsdeqp::gles3::Functional::__anon1eeffb4d0111::DepthRangeParams171 	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:
DepthRangeEvaluator(const DepthRangeParams & params)184 	DepthRangeEvaluator (const DepthRangeParams& params)
185 		: m_params(params)
186 	{
187 	}
188 
evaluate(gls::ShaderEvalContext & c)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:
ShaderDepthRangeTest(Context & context,const char * name,const char * desc,bool isVertexCase)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 
init(void)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 
iterate(void)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:
FragCoordXYZCase(Context & context)288 	FragCoordXYZCase (Context& context)
289 		: TestCase(context, "fragcoord_xyz", "gl_FragCoord.xyz Test")
290 	{
291 	}
292 
iterate(void)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 
projectedTriInterpolate(const tcu::Vec3 & s,const tcu::Vec3 & w,float nx,float ny)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:
FragCoordWCase(Context & context)385 	FragCoordWCase (Context& context)
386 		: TestCase(context, "fragcoord_w", "gl_FragCoord.w Test")
387 	{
388 	}
389 
iterate(void)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:
PointCoordCase(Context & context)475 	PointCoordCase (Context& context)
476 		: TestCase(context, "pointcoord", "gl_PointCoord Test")
477 	{
478 	}
479 
iterate(void)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:
FrontFacingCase(Context & context)595 	FrontFacingCase (Context& context)
596 		: TestCase(context, "frontfacing", "gl_FrontFacing Test")
597 	{
598 	}
599 
iterate(void)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 
VertexIDCase(Context & context)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 
~VertexIDCase(void)754 VertexIDCase::~VertexIDCase (void)
755 {
756 	VertexIDCase::deinit();
757 }
758 
init(void)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 
deinit(void)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 
VertexIDReferenceShader()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 
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const924 	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 
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const941 	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 
renderReference(const tcu::PixelBufferAccess & dst,const int numVertices,const deUint16 * const indices,const tcu::Vec4 * const positions,const tcu::Vec4 * const colors)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 
iterate(void)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 
ShaderBuiltinVarTests(Context & context)1095 ShaderBuiltinVarTests::ShaderBuiltinVarTests (Context& context)
1096 	: TestCaseGroup(context, "builtin_variable", "Built-in Variable Tests")
1097 {
1098 }
1099 
~ShaderBuiltinVarTests(void)1100 ShaderBuiltinVarTests::~ShaderBuiltinVarTests (void)
1101 {
1102 }
1103 
init(void)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