• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 2.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 "es2fShaderBuiltinVarTests.hpp"
25 #include "glsShaderRenderCase.hpp"
26 #include "deRandom.hpp"
27 #include "deString.h"
28 #include "deMath.h"
29 #include "deStringUtil.hpp"
30 #include "tcuTestLog.hpp"
31 #include "tcuTestCase.hpp"
32 #include "tcuTextureUtil.hpp"
33 #include "tcuRenderTarget.hpp"
34 #include "tcuImageCompare.hpp"
35 #include "gluPixelTransfer.hpp"
36 #include "gluDrawUtil.hpp"
37 
38 #include "glwEnums.hpp"
39 #include "glwFunctions.hpp"
40 
41 using std::string;
42 using std::vector;
43 using tcu::TestLog;
44 
45 namespace deqp
46 {
47 namespace gles2
48 {
49 namespace Functional
50 {
51 
52 const float builtinConstScale = 4.0f;
53 
evalBuiltinConstant(gls::ShaderEvalContext & c)54 void evalBuiltinConstant (gls::ShaderEvalContext& c)
55 {
56 	bool isOk = 0 == (int)(deFloatFloor(c.coords.x() * builtinConstScale) + 0.05f);
57 	c.color = isOk ? tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f) : tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
58 }
59 
60 class ShaderBuiltinConstantCase : public gls::ShaderRenderCase
61 {
62 public:
63 						ShaderBuiltinConstantCase				(Context& context, const char* name, const char* desc, const char* varName, deUint32 paramName, bool isVertexCase);
64 						~ShaderBuiltinConstantCase				(void);
65 
66 	void				init									(void);
67 
68 private:
69 	std::string			m_varName;
70 	deUint32			m_paramName;
71 };
72 
ShaderBuiltinConstantCase(Context & context,const char * name,const char * desc,const char * varName,deUint32 paramName,bool isVertexCase)73 ShaderBuiltinConstantCase::ShaderBuiltinConstantCase (Context& context, const char* name, const char* desc, const char* varName, deUint32 paramName, bool isVertexCase)
74 	: ShaderRenderCase	(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, desc, isVertexCase, evalBuiltinConstant)
75 	, m_varName			(varName)
76 	, m_paramName		(paramName)
77 {
78 }
79 
~ShaderBuiltinConstantCase(void)80 ShaderBuiltinConstantCase::~ShaderBuiltinConstantCase (void)
81 {
82 }
83 
getConstRefValue(const char * varName)84 static int getConstRefValue (const char* varName)
85 {
86 	if (deStringEqual(varName, "gl_MaxDrawBuffers"))
87 		return 1;
88 	else
89 	{
90 		DE_ASSERT(DE_FALSE);
91 		return 0;
92 	}
93 }
94 
init(void)95 void ShaderBuiltinConstantCase::init (void)
96 {
97 	int refValue = m_paramName != GL_NONE ? m_ctxInfo.getInt(m_paramName) : getConstRefValue(m_varName.c_str());
98 	m_testCtx.getLog() << tcu::TestLog::Message << m_varName << " = " << refValue << tcu::TestLog::EndMessage;
99 
100 	static const char* defaultVertSrc =
101 		"attribute highp vec4 a_position;\n"
102 		"attribute highp vec4 a_coords;\n"
103 		"varying mediump vec4 v_coords;\n\n"
104 		"void main (void)\n"
105 		"{\n"
106 		"	v_coords = a_coords;\n"
107 		"	gl_Position = a_position;\n"
108 		"}\n";
109 	static const char* defaultFragSrc =
110 		"varying mediump vec4 v_color;\n\n"
111 		"void main (void)\n"
112 		"{\n"
113 		"	gl_FragColor = v_color;\n"
114 		"}\n";
115 
116 	// Construct shader.
117 	std::ostringstream src;
118 	if (m_isVertexCase)
119 	{
120 		src << "attribute highp vec4 a_position;\n"
121 			<< "attribute highp vec4 a_coords;\n"
122 			<< "varying mediump vec4 v_color;\n";
123 	}
124 	else
125 		src << "varying mediump vec4 v_coords;\n";
126 
127 	src << "void main (void)\n{\n";
128 
129 	src << "\tbool isOk = " << m_varName << " == (" << refValue << " + int(floor(" << (m_isVertexCase ? "a_coords" : "v_coords") << ".x * " << de::floatToString(builtinConstScale, 1) << ") + 0.05));\n";
130 	src << "\t" << (m_isVertexCase ? "v_color" : "gl_FragColor") << " = isOk ? vec4(0.0, 1.0, 0.0, 1.0) : vec4(1.0, 0.0, 0.0, 1.0);\n";
131 
132 	if (m_isVertexCase)
133 		src << "\tgl_Position = a_position;\n";
134 
135 	src << "}\n";
136 
137 	m_vertShaderSource		= m_isVertexCase ? src.str()		: defaultVertSrc;
138 	m_fragShaderSource		= m_isVertexCase ? defaultFragSrc	: src.str();
139 
140 	gls::ShaderRenderCase::init();
141 }
142 
143 namespace
144 {
145 
146 struct DepthRangeParams
147 {
DepthRangeParamsdeqp::gles2::Functional::__anone95c6a420111::DepthRangeParams148 	DepthRangeParams (void)
149 		: zNear	(0.0f)
150 		, zFar	(1.0f)
151 	{
152 	}
153 
DepthRangeParamsdeqp::gles2::Functional::__anone95c6a420111::DepthRangeParams154 	DepthRangeParams (float zNear_, float zFar_)
155 		: zNear	(zNear_)
156 		, zFar	(zFar_)
157 	{
158 	}
159 
160 	float	zNear;
161 	float	zFar;
162 };
163 
164 class DepthRangeEvaluator : public gls::ShaderEvaluator
165 {
166 public:
DepthRangeEvaluator(const DepthRangeParams & params)167 	DepthRangeEvaluator (const DepthRangeParams& params)
168 		: m_params(params)
169 	{
170 	}
171 
evaluate(gls::ShaderEvalContext & c)172 	void evaluate (gls::ShaderEvalContext& c)
173 	{
174 		float zNear	= deFloatClamp(m_params.zNear, 0.0f, 1.0f);
175 		float zFar	= deFloatClamp(m_params.zFar, 0.0f, 1.0f);
176 		float diff	= zFar - zNear;
177 		c.color.xyz() = tcu::Vec3(zNear, zFar, diff*0.5f + 0.5f);
178 	}
179 
180 private:
181 	const DepthRangeParams& m_params;
182 };
183 
184 } // anonymous
185 
186 class ShaderDepthRangeTest : public gls::ShaderRenderCase
187 {
188 public:
ShaderDepthRangeTest(Context & context,const char * name,const char * desc,bool isVertexCase)189 	ShaderDepthRangeTest (Context& context, const char* name, const char* desc, bool isVertexCase)
190 		: ShaderRenderCase	(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, desc, isVertexCase, m_evaluator)
191 		, m_evaluator		(m_depthRange)
192 		, m_iterNdx			(0)
193 	{
194 	}
195 
init(void)196 	void init (void)
197 	{
198 		static const char* defaultVertSrc =
199 			"attribute highp vec4 a_position;\n"
200 			"void main (void)\n"
201 			"{\n"
202 			"	gl_Position = a_position;\n"
203 			"}\n";
204 		static const char* defaultFragSrc =
205 			"varying mediump vec4 v_color;\n\n"
206 			"void main (void)\n"
207 			"{\n"
208 			"	gl_FragColor = v_color;\n"
209 			"}\n";
210 
211 		// Construct shader.
212 		std::ostringstream src;
213 		if (m_isVertexCase)
214 			src << "attribute highp vec4 a_position;\n"
215 				<< "varying mediump vec4 v_color;\n";
216 
217 		src << "void main (void)\n{\n";
218 		src << "\t" << (m_isVertexCase ? "v_color" : "gl_FragColor") << " = vec4(gl_DepthRange.near, gl_DepthRange.far, gl_DepthRange.diff*0.5 + 0.5, 1.0);\n";
219 
220 		if (m_isVertexCase)
221 			src << "\tgl_Position = a_position;\n";
222 
223 		src << "}\n";
224 
225 		m_vertShaderSource		= m_isVertexCase ? src.str()		: defaultVertSrc;
226 		m_fragShaderSource		= m_isVertexCase ? defaultFragSrc	: src.str();
227 
228 		gls::ShaderRenderCase::init();
229 	}
230 
iterate(void)231 	IterateResult iterate (void)
232 	{
233 		const glw::Functions& gl = m_renderCtx.getFunctions();
234 
235 		const DepthRangeParams cases[] =
236 		{
237 			DepthRangeParams(0.0f,  1.0f),
238 			DepthRangeParams(1.5f, -1.0f),
239 			DepthRangeParams(0.7f,  0.3f)
240 		};
241 
242 		m_depthRange = cases[m_iterNdx];
243 		m_testCtx.getLog() << tcu::TestLog::Message << "glDepthRangef(" << m_depthRange.zNear << ", " << m_depthRange.zFar << ")" << tcu::TestLog::EndMessage;
244 		gl.depthRangef(m_depthRange.zNear, m_depthRange.zFar);
245 		GLU_EXPECT_NO_ERROR(gl.getError(), "glDepthRangef()");
246 
247 		gls::ShaderRenderCase::iterate();
248 		m_iterNdx += 1;
249 
250 		if (m_iterNdx == DE_LENGTH_OF_ARRAY(cases) || m_testCtx.getTestResult() != QP_TEST_RESULT_PASS)
251 			return STOP;
252 		else
253 			return CONTINUE;
254 	}
255 
256 private:
257 	DepthRangeParams		m_depthRange;
258 	DepthRangeEvaluator		m_evaluator;
259 	int						m_iterNdx;
260 };
261 
262 class FragCoordXYZCase : public TestCase
263 {
264 public:
FragCoordXYZCase(Context & context)265 	FragCoordXYZCase (Context& context)
266 		: TestCase(context, "fragcoord_xyz", "gl_FragCoord.xyz Test")
267 	{
268 	}
269 
iterate(void)270 	IterateResult iterate (void)
271 	{
272 		TestLog&				log			= m_testCtx.getLog();
273 		const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
274 		const int				width		= m_context.getRenderTarget().getWidth();
275 		const int				height		= m_context.getRenderTarget().getHeight();
276 		const tcu::RGBA			threshold	= tcu::RGBA(1,1,1,1) + m_context.getRenderTarget().getPixelFormat().getColorThreshold();
277 		const tcu::Vec3			scale		(1.f / float(width), 1.f / float(height), 1.0f);
278 
279 		tcu::Surface			testImg		(width, height);
280 		tcu::Surface			refImg		(width, height);
281 
282 		const glu::ShaderProgram program(m_context.getRenderContext(), glu::makeVtxFragSources(
283 			"attribute highp vec4 a_position;\n"
284 			"void main (void)\n"
285 			"{\n"
286 			"	gl_Position = a_position;\n"
287 			"}\n",
288 
289 			"uniform mediump vec3 u_scale;\n"
290 			"void main (void)\n"
291 			"{\n"
292 			"	gl_FragColor = vec4(gl_FragCoord.xyz*u_scale, 1.0);\n"
293 			"}\n"));
294 
295 		log << program;
296 
297 		if (!program.isOk())
298 			throw tcu::TestError("Compile failed");
299 
300 		// Draw with GL.
301 		{
302 			const float positions[] =
303 			{
304 				-1.0f,  1.0f, -1.0f, 1.0f,
305 				-1.0f, -1.0f,  0.0f, 1.0f,
306 				 1.0f,  1.0f,  0.0f, 1.0f,
307 				 1.0f, -1.0f,  1.0f, 1.0f
308 			};
309 			const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 };
310 
311 			const int				scaleLoc	= gl.getUniformLocation(program.getProgram(), "u_scale");
312 			glu::VertexArrayBinding	posBinding	= glu::va::Float("a_position", 4, 4, 0, &positions[0]);
313 
314 			gl.useProgram(program.getProgram());
315 			gl.uniform3fv(scaleLoc, 1, scale.getPtr());
316 
317 			glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
318 					  glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
319 
320 			glu::readPixels(m_context.getRenderContext(), 0, 0, testImg.getAccess());
321 			GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
322 		}
323 
324 		// Draw reference
325 		for (int y = 0; y < refImg.getHeight(); y++)
326 		{
327 			for (int x = 0; x < refImg.getWidth(); x++)
328 			{
329 				const float			xf			= (float(x)+.5f) / float(refImg.getWidth());
330 				const float			yf			= (float(refImg.getHeight()-y-1)+.5f) / float(refImg.getHeight());
331 				const float			z			= (xf + yf) / 2.0f;
332 				const tcu::Vec3		fragCoord	(float(x)+.5f, float(y)+.5f, z);
333 				const tcu::Vec3		scaledFC	= fragCoord*scale;
334 				const tcu::Vec4		color		(scaledFC.x(), scaledFC.y(), scaledFC.z(), 1.0f);
335 
336 				refImg.setPixel(x, y, tcu::RGBA(color));
337 			}
338 		}
339 
340 		// Compare
341 		{
342 			bool isOk = tcu::pixelThresholdCompare(log, "Result", "Image comparison result", refImg, testImg, threshold, tcu::COMPARE_LOG_RESULT);
343 			m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
344 									isOk ? "Pass"				: "Image comparison failed");
345 		}
346 
347 		return STOP;
348 	}
349 };
350 
projectedTriInterpolate(const tcu::Vec3 & s,const tcu::Vec3 & w,float nx,float ny)351 static inline float projectedTriInterpolate (const tcu::Vec3& s, const tcu::Vec3& w, float nx, float ny)
352 {
353 	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]);
354 }
355 
356 class FragCoordWCase : public TestCase
357 {
358 public:
FragCoordWCase(Context & context)359 	FragCoordWCase (Context& context)
360 		: TestCase(context, "fragcoord_w", "gl_FragCoord.w Test")
361 	{
362 	}
363 
iterate(void)364 	IterateResult iterate (void)
365 	{
366 		TestLog&				log			= m_testCtx.getLog();
367 		const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
368 		const int				width		= m_context.getRenderTarget().getWidth();
369 		const int				height		= m_context.getRenderTarget().getHeight();
370 		const tcu::RGBA			threshold	= tcu::RGBA(1,1,1,1) + m_context.getRenderTarget().getPixelFormat().getColorThreshold();
371 
372 		tcu::Surface			testImg		(width, height);
373 		tcu::Surface			refImg		(width, height);
374 
375 		const float				w[4]		= { 1.7f, 2.0f, 1.2f, 1.0f };
376 
377 		const glu::ShaderProgram program(m_context.getRenderContext(), glu::makeVtxFragSources(
378 			"attribute highp vec4 a_position;\n"
379 			"void main (void)\n"
380 			"{\n"
381 			"	gl_Position = a_position;\n"
382 			"}\n",
383 
384 			"void main (void)\n"
385 			"{\n"
386 			"	gl_FragColor = vec4(0.0, 1.0/gl_FragCoord.w - 1.0, 0.0, 1.0);\n"
387 			"}\n"));
388 
389 		log << program;
390 
391 		if (!program.isOk())
392 			throw tcu::TestError("Compile failed");
393 
394 		// Draw with GL.
395 		{
396 			const float positions[] =
397 			{
398 				-w[0],  w[0], 0.0f, w[0],
399 				-w[1], -w[1], 0.0f, w[1],
400 				 w[2],  w[2], 0.0f, w[2],
401 				 w[3], -w[3], 0.0f, w[3]
402 			};
403 			const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 };
404 
405 			glu::VertexArrayBinding	posBinding	= glu::va::Float("a_position", 4, 4, 0, &positions[0]);
406 
407 			gl.useProgram(program.getProgram());
408 
409 			glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
410 					  glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
411 
412 			glu::readPixels(m_context.getRenderContext(), 0, 0, testImg.getAccess());
413 			GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
414 		}
415 
416 		// Draw reference
417 		for (int y = 0; y < refImg.getHeight(); y++)
418 		{
419 			for (int x = 0; x < refImg.getWidth(); x++)
420 			{
421 				const float			xf			= (float(x)+.5f) / float(refImg.getWidth());
422 				const float			yf			= (float(refImg.getHeight()-y-1)+.5f) / float(refImg.getHeight());
423 				const float			oow			= ((xf + yf) < 1.0f)
424 												? projectedTriInterpolate(tcu::Vec3(w[0], w[1], w[2]), tcu::Vec3(w[0], w[1], w[2]), xf, yf)
425 												: projectedTriInterpolate(tcu::Vec3(w[3], w[2], w[1]), tcu::Vec3(w[3], w[2], w[1]), 1.0f-xf, 1.0f-yf);
426 				const tcu::Vec4		color		(0.0f, oow - 1.0f, 0.0f, 1.0f);
427 
428 				refImg.setPixel(x, y, tcu::RGBA(color));
429 			}
430 		}
431 
432 		// Compare
433 		{
434 			bool isOk = tcu::pixelThresholdCompare(log, "Result", "Image comparison result", refImg, testImg, threshold, tcu::COMPARE_LOG_RESULT);
435 			m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
436 									isOk ? "Pass"				: "Image comparison failed");
437 		}
438 
439 		return STOP;
440 	}
441 };
442 
443 class PointCoordCase : public TestCase
444 {
445 public:
PointCoordCase(Context & context)446 	PointCoordCase (Context& context)
447 		: TestCase(context, "pointcoord", "gl_PointCoord Test")
448 	{
449 	}
450 
iterate(void)451 	IterateResult iterate (void)
452 	{
453 		TestLog&				log			= m_testCtx.getLog();
454 		const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
455 		const int				width		= de::min(256, m_context.getRenderTarget().getWidth());
456 		const int				height		= de::min(256, m_context.getRenderTarget().getHeight());
457 		const float				threshold	= 0.02f;
458 
459 		const int				numPoints	= 8;
460 
461 		vector<tcu::Vec3>		coords		(numPoints);
462 		float					pointSizeRange[2]	= { 0.0f, 0.0f };
463 
464 		de::Random				rnd			(0x145fa);
465 		tcu::Surface			testImg		(width, height);
466 		tcu::Surface			refImg		(width, height);
467 
468 		gl.getFloatv(GL_ALIASED_POINT_SIZE_RANGE, &pointSizeRange[0]);
469 		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE)");
470 
471 		if (pointSizeRange[0] <= 0.0f || pointSizeRange[1] <= 0.0f || pointSizeRange[1] < pointSizeRange[0])
472 			throw tcu::TestError("Invalid GL_ALIASED_POINT_SIZE_RANGE");
473 
474 		// Compute coordinates.
475 		{
476 
477 			for (vector<tcu::Vec3>::iterator coord = coords.begin(); coord != coords.end(); ++coord)
478 			{
479 				coord->x() = rnd.getFloat(-0.9f, 0.9f);
480 				coord->y() = rnd.getFloat(-0.9f, 0.9f);
481 				coord->z() = rnd.getFloat(pointSizeRange[0], pointSizeRange[1]);
482 			}
483 		}
484 
485 		const glu::ShaderProgram program(m_context.getRenderContext(), glu::makeVtxFragSources(
486 			"attribute highp vec3 a_positionSize;\n"
487 			"void main (void)\n"
488 			"{\n"
489 			"	gl_Position = vec4(a_positionSize.xy, 0.0, 1.0);\n"
490 			"	gl_PointSize = a_positionSize.z;\n"
491 			"}\n",
492 
493 			"void main (void)\n"
494 			"{\n"
495 			"	gl_FragColor = vec4(gl_PointCoord, 0.0, 1.0);\n"
496 			"}\n"));
497 
498 		log << program;
499 
500 		if (!program.isOk())
501 			throw tcu::TestError("Compile failed");
502 
503 		// Draw with GL.
504 		{
505 			glu::VertexArrayBinding	posBinding	= glu::va::Float("a_positionSize", 3, (int)coords.size(), 0, (const float*)&coords[0]);
506 			const int				viewportX	= rnd.getInt(0, m_context.getRenderTarget().getWidth()-width);
507 			const int				viewportY	= rnd.getInt(0, m_context.getRenderTarget().getHeight()-height);
508 
509 			gl.viewport(viewportX, viewportY, width, height);
510 			gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
511 			gl.clear(GL_COLOR_BUFFER_BIT);
512 
513 			gl.useProgram(program.getProgram());
514 
515 			glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
516 					  glu::pr::Points((int)coords.size()));
517 
518 			glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, testImg.getAccess());
519 			GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
520 		}
521 
522 		// Draw reference
523 		tcu::clear(refImg.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
524 		for (vector<tcu::Vec3>::const_iterator pointIter = coords.begin(); pointIter != coords.end(); ++pointIter)
525 		{
526 			const int	x0		= deRoundFloatToInt32(float(width) *(pointIter->x()*0.5f + 0.5f) - pointIter->z()*0.5f);
527 			const int	y0		= deRoundFloatToInt32(float(height)*(pointIter->y()*0.5f + 0.5f) - pointIter->z()*0.5f);
528 			const int	x1		= deRoundFloatToInt32(float(width) *(pointIter->x()*0.5f + 0.5f) + pointIter->z()*0.5f);
529 			const int	y1		= deRoundFloatToInt32(float(height)*(pointIter->y()*0.5f + 0.5f) + pointIter->z()*0.5f);
530 			const int	w		= x1-x0;
531 			const int	h		= y1-y0;
532 
533 			for (int yo = 0; yo < h; yo++)
534 			{
535 				for (int xo = 0; xo < w; xo++)
536 				{
537 					const float			xf		= float(xo+0.5f) / float(w);
538 					const float			yf		= float((h-yo-1)+0.5f) / float(h);
539 					const tcu::Vec4		color	(xf, yf, 0.0f, 1.0f);
540 					const int			dx		= x0+xo;
541 					const int			dy		= y0+yo;
542 
543 					if (de::inBounds(dx, 0, refImg.getWidth()) && de::inBounds(dy, 0, refImg.getHeight()))
544 						refImg.setPixel(dx, dy, tcu::RGBA(color));
545 				}
546 			}
547 		}
548 
549 		// Compare
550 		{
551 			bool isOk = tcu::fuzzyCompare(log, "Result", "Image comparison result", refImg, testImg, threshold, tcu::COMPARE_LOG_RESULT);
552 			m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
553 									isOk ? "Pass"				: "Image comparison failed");
554 		}
555 
556 		return STOP;
557 	}
558 };
559 
560 class FrontFacingCase : public TestCase
561 {
562 public:
FrontFacingCase(Context & context)563 	FrontFacingCase (Context& context)
564 		: TestCase(context, "frontfacing", "gl_FrontFacing Test")
565 	{
566 	}
567 
iterate(void)568 	IterateResult iterate (void)
569 	{
570 		// Test case renders two adjecent quads, where left is has front-facing
571 		// triagles and right back-facing. Color is selected based on gl_FrontFacing
572 		// value.
573 
574 		TestLog&				log			= m_testCtx.getLog();
575 		const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
576 		de::Random				rnd			(0x89f2c);
577 		const int				width		= de::min(64, m_context.getRenderTarget().getWidth());
578 		const int				height		= de::min(64, m_context.getRenderTarget().getHeight());
579 		const int				viewportX	= rnd.getInt(0, m_context.getRenderTarget().getWidth()-width);
580 		const int				viewportY	= rnd.getInt(0, m_context.getRenderTarget().getHeight()-height);
581 		const tcu::RGBA			threshold	= tcu::RGBA(1,1,1,1) + m_context.getRenderTarget().getPixelFormat().getColorThreshold();
582 
583 		tcu::Surface			testImg		(width, height);
584 		tcu::Surface			refImg		(width, height);
585 
586 		const glu::ShaderProgram program(m_context.getRenderContext(), glu::makeVtxFragSources(
587 			"attribute highp vec4 a_position;\n"
588 			"void main (void)\n"
589 			"{\n"
590 			"	gl_Position = a_position;\n"
591 			"}\n",
592 
593 			"void main (void)\n"
594 			"{\n"
595 			"	if (gl_FrontFacing)\n"
596 			"		gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
597 			"	else\n"
598 			"		gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
599 			"}\n"));
600 
601 		log << program;
602 
603 		if (!program.isOk())
604 			throw tcu::TestError("Compile failed");
605 
606 		// Draw with GL.
607 		{
608 			const float positions[] =
609 			{
610 				-1.0f,  1.0f, 0.0f, 1.0f,
611 				-1.0f, -1.0f, 0.0f, 1.0f,
612 				 1.0f,  1.0f, 0.0f, 1.0f,
613 				 1.0f, -1.0f, 0.0f, 1.0f
614 			};
615 			const deUint16 indicesCCW[]	= { 0, 1, 2, 2, 1, 3 };
616 			const deUint16 indicesCW[]	= { 2, 1, 0, 3, 1, 2 };
617 
618 			glu::VertexArrayBinding	posBinding	= glu::va::Float("a_position", 4, 4, 0, &positions[0]);
619 
620 			gl.useProgram(program.getProgram());
621 
622 			gl.viewport(viewportX, viewportY, width/2, height);
623 			glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
624 					  glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indicesCCW), &indicesCCW[0]));
625 
626 			gl.viewport(viewportX + width/2, viewportY, width-width/2, height);
627 			glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
628 					  glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indicesCW), &indicesCW[0]));
629 
630 			glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, testImg.getAccess());
631 			GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
632 		}
633 
634 		// Draw reference
635 		for (int y = 0; y < refImg.getHeight(); y++)
636 		{
637 			for (int x = 0; x < refImg.getWidth()/2; x++)
638 				refImg.setPixel(x, y, tcu::RGBA::green);
639 
640 			for (int x = refImg.getWidth()/2; x < refImg.getWidth(); x++)
641 				refImg.setPixel(x, y, tcu::RGBA::blue);
642 		}
643 
644 		// Compare
645 		{
646 			bool isOk = tcu::pixelThresholdCompare(log, "Result", "Image comparison result", refImg, testImg, threshold, tcu::COMPARE_LOG_RESULT);
647 			m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
648 									isOk ? "Pass"				: "Image comparison failed");
649 		}
650 
651 		return STOP;
652 	}
653 };
654 
ShaderBuiltinVarTests(Context & context)655 ShaderBuiltinVarTests::ShaderBuiltinVarTests (Context& context)
656 	: TestCaseGroup(context, "builtin_variable", "Built-in Variable Tests")
657 {
658 }
659 
~ShaderBuiltinVarTests(void)660 ShaderBuiltinVarTests::~ShaderBuiltinVarTests (void)
661 {
662 }
663 
init(void)664 void ShaderBuiltinVarTests::init (void)
665 {
666 	// Builtin constants.
667 
668 	static const struct
669 	{
670 		const char*		caseName;
671 		const char*		varName;
672 		deUint32		paramName;
673 	} builtinConstants[] =
674 	{
675 		{ "max_vertex_attribs",					"gl_MaxVertexAttribs",				GL_MAX_VERTEX_ATTRIBS },
676 		{ "max_vertex_uniform_vectors",			"gl_MaxVertexUniformVectors",		GL_MAX_VERTEX_UNIFORM_VECTORS },
677 		{ "max_fragment_uniform_vectors",		"gl_MaxFragmentUniformVectors",		GL_MAX_FRAGMENT_UNIFORM_VECTORS },
678 		{ "max_varying_vectors",				"gl_MaxVaryingVectors",				GL_MAX_VARYING_VECTORS },
679 		{ "max_texture_image_units",			"gl_MaxTextureImageUnits",			GL_MAX_TEXTURE_IMAGE_UNITS },
680 		{ "max_vertex_texture_image_units",		"gl_MaxVertexTextureImageUnits",	GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS },
681 		{ "max_combined_texture_image_units",	"gl_MaxCombinedTextureImageUnits",	GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS },
682 		{ "max_draw_buffers",					"gl_MaxDrawBuffers",				GL_NONE }
683 	};
684 
685 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(builtinConstants); ndx++)
686 	{
687 		const char*		caseName	= builtinConstants[ndx].caseName;
688 		const char*		varName		= builtinConstants[ndx].varName;
689 		deUint32		paramName	= builtinConstants[ndx].paramName;
690 
691 		addChild(new ShaderBuiltinConstantCase(m_context, (string(caseName) + "_vertex").c_str(),	varName, varName, paramName, true));
692 		addChild(new ShaderBuiltinConstantCase(m_context, (string(caseName) + "_fragment").c_str(),	varName, varName, paramName, false));
693 	}
694 
695 	addChild(new ShaderDepthRangeTest(m_context, "depth_range_vertex",		"gl_DepthRange", true));
696 	addChild(new ShaderDepthRangeTest(m_context, "depth_range_fragment",	"gl_DepthRange", false));
697 
698 	// Fragment shader builtin variables.
699 
700 	addChild(new FragCoordXYZCase	(m_context));
701 	addChild(new FragCoordWCase		(m_context));
702 	addChild(new PointCoordCase		(m_context));
703 	addChild(new FrontFacingCase	(m_context));
704 }
705 
706 } // Functional
707 } // gles2
708 } // deqp
709