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