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
41using std::string;
42using std::vector;
43using tcu::TestLog;
44
45namespace deqp
46{
47namespace gles2
48{
49namespace Functional
50{
51
52const float builtinConstScale = 4.0f;
53
54void 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
60class ShaderBuiltinConstantCase : public gls::ShaderRenderCase
61{
62public:
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
68private:
69	std::string			m_varName;
70	deUint32			m_paramName;
71};
72
73ShaderBuiltinConstantCase::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
80ShaderBuiltinConstantCase::~ShaderBuiltinConstantCase (void)
81{
82}
83
84static 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
95void 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
143namespace
144{
145
146struct DepthRangeParams
147{
148	DepthRangeParams (void)
149		: zNear	(0.0f)
150		, zFar	(1.0f)
151	{
152	}
153
154	DepthRangeParams (float zNear_, float zFar_)
155		: zNear	(zNear_)
156		, zFar	(zFar_)
157	{
158	}
159
160	float	zNear;
161	float	zFar;
162};
163
164class DepthRangeEvaluator : public gls::ShaderEvaluator
165{
166public:
167	DepthRangeEvaluator (const DepthRangeParams& params)
168		: m_params(params)
169	{
170	}
171
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
180private:
181	const DepthRangeParams& m_params;
182};
183
184} // anonymous
185
186class ShaderDepthRangeTest : public gls::ShaderRenderCase
187{
188public:
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
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
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
256private:
257	DepthRangeParams		m_depthRange;
258	DepthRangeEvaluator		m_evaluator;
259	int						m_iterNdx;
260};
261
262class FragCoordXYZCase : public TestCase
263{
264public:
265	FragCoordXYZCase (Context& context)
266		: TestCase(context, "fragcoord_xyz", "gl_FragCoord.xyz Test")
267	{
268	}
269
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
351static 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
356class FragCoordWCase : public TestCase
357{
358public:
359	FragCoordWCase (Context& context)
360		: TestCase(context, "fragcoord_w", "gl_FragCoord.w Test")
361	{
362	}
363
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
443class PointCoordCase : public TestCase
444{
445public:
446	PointCoordCase (Context& context)
447		: TestCase(context, "pointcoord", "gl_PointCoord Test")
448	{
449	}
450
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
560class FrontFacingCase : public TestCase
561{
562public:
563	FrontFacingCase (Context& context)
564		: TestCase(context, "frontfacing", "gl_FrontFacing Test")
565	{
566	}
567
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
655ShaderBuiltinVarTests::ShaderBuiltinVarTests (Context& context)
656	: TestCaseGroup(context, "builtin_variable", "Built-in Variable Tests")
657{
658}
659
660ShaderBuiltinVarTests::~ShaderBuiltinVarTests (void)
661{
662}
663
664void 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