1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 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 Multisample interpolation tests
22 *//*--------------------------------------------------------------------*/
23
24#include "es31fShaderMultisampleInterpolationTests.hpp"
25#include "es31fMultisampleShaderRenderCase.hpp"
26#include "tcuTestLog.hpp"
27#include "tcuRGBA.hpp"
28#include "tcuSurface.hpp"
29#include "tcuStringTemplate.hpp"
30#include "tcuRenderTarget.hpp"
31#include "gluContextInfo.hpp"
32#include "gluShaderProgram.hpp"
33#include "gluRenderContext.hpp"
34#include "glwFunctions.hpp"
35#include "glwEnums.hpp"
36#include "deArrayUtil.hpp"
37#include "deStringUtil.hpp"
38#include "deMath.h"
39
40#include <map>
41
42namespace deqp
43{
44namespace gles31
45{
46namespace Functional
47{
48namespace
49{
50
51
52static bool verifyGreenImage (const tcu::Surface& image, tcu::TestLog& log)
53{
54	bool error = false;
55
56	log << tcu::TestLog::Message << "Verifying result image, expecting green." << tcu::TestLog::EndMessage;
57
58	// all pixels must be green
59
60	for (int y = 0; y < image.getHeight(); ++y)
61	for (int x = 0; x < image.getWidth(); ++x)
62	{
63		const tcu::RGBA color			= image.getPixel(x, y);
64		const int		greenThreshold	= 8;
65
66		if (color.getRed() > 0 || color.getGreen() < 255-greenThreshold || color.getBlue() > 0)
67			error = true;
68	}
69
70	if (error)
71		log	<< tcu::TestLog::Image("ResultImage", "Result Image", image.getAccess())
72			<< tcu::TestLog::Message
73			<< "Image verification failed."
74			<< tcu::TestLog::EndMessage;
75	else
76		log	<< tcu::TestLog::Image("ResultImage", "Result Image", image.getAccess())
77			<< tcu::TestLog::Message
78			<< "Image verification passed."
79			<< tcu::TestLog::EndMessage;
80
81	return !error;
82}
83
84class MultisampleShadeCountRenderCase : public MultisampleShaderRenderUtil::MultisampleRenderCase
85{
86public:
87						MultisampleShadeCountRenderCase		(Context& context, const char* name, const char* description, int numSamples, RenderTarget target);
88	virtual				~MultisampleShadeCountRenderCase	(void);
89
90	void				init								(void);
91
92private:
93	enum
94	{
95		RENDER_SIZE = 128
96	};
97
98	virtual std::string	getIterationDescription				(int iteration) const;
99	bool				verifyImage							(const tcu::Surface& resultImage);
100};
101
102MultisampleShadeCountRenderCase::MultisampleShadeCountRenderCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target)
103	: MultisampleShaderRenderUtil::MultisampleRenderCase(context, name, description, numSamples, target, RENDER_SIZE, MultisampleShaderRenderUtil::MultisampleRenderCase::FLAG_PER_ITERATION_SHADER)
104{
105	m_numIterations = -1; // must be set by deriving class
106}
107
108MultisampleShadeCountRenderCase::~MultisampleShadeCountRenderCase (void)
109{
110}
111
112void MultisampleShadeCountRenderCase::init (void)
113{
114	// requirements
115	if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation"))
116		TCU_THROW(NotSupportedError, "Test requires GL_OES_shader_multisample_interpolation extension");
117
118	MultisampleShaderRenderUtil::MultisampleRenderCase::init();
119}
120
121std::string	MultisampleShadeCountRenderCase::getIterationDescription (int iteration) const
122{
123	// must be overriden
124	DE_UNREF(iteration);
125	DE_ASSERT(false);
126	return "";
127}
128
129bool MultisampleShadeCountRenderCase::verifyImage (const tcu::Surface& resultImage)
130{
131	const bool				isSingleSampleTarget	= (m_renderTarget != TARGET_DEFAULT && m_numRequestedSamples == 0) || (m_renderTarget == TARGET_DEFAULT && m_context.getRenderTarget().getNumSamples() <= 1);
132	const int				numShadesRequired		= (isSingleSampleTarget) ? (2) : (m_numTargetSamples + 1);
133	const int				rareThreshold			= 100;
134	int						rareCount				= 0;
135	std::map<deUint32, int>	shadeFrequency;
136
137	m_testCtx.getLog()
138		<< tcu::TestLog::Image("ResultImage", "Result Image", resultImage.getAccess())
139		<< tcu::TestLog::Message
140		<< "Verifying image has (at least) " << numShadesRequired << " different shades.\n"
141		<< "Excluding pixels with no full coverage (pixels on the shared edge of the triangle pair)."
142		<< tcu::TestLog::EndMessage;
143
144	for (int y = 0; y < RENDER_SIZE; ++y)
145	for (int x = 0; x < RENDER_SIZE; ++x)
146	{
147		const tcu::RGBA	color	= resultImage.getPixel(x, y);
148		const deUint32	packed	= ((deUint32)color.getRed()) + ((deUint32)color.getGreen() << 8) + ((deUint32)color.getGreen() << 16);
149
150		// on the triangle edge, skip
151		if (x == y)
152			continue;
153
154		if (shadeFrequency.find(packed) == shadeFrequency.end())
155			shadeFrequency[packed] = 1;
156		else
157			shadeFrequency[packed] = shadeFrequency[packed] + 1;
158	}
159
160	for (std::map<deUint32, int>::const_iterator it = shadeFrequency.begin(); it != shadeFrequency.end(); ++it)
161		if (it->second < rareThreshold)
162			rareCount++;
163
164	m_testCtx.getLog()
165		<< tcu::TestLog::Message
166		<< "Found " << (int)shadeFrequency.size() << " different shades.\n"
167		<< "\tRare (less than " << rareThreshold << " pixels): " << rareCount << "\n"
168		<< "\tCommon: " << (int)shadeFrequency.size() - rareCount << "\n"
169		<< tcu::TestLog::EndMessage;
170
171	if ((int)shadeFrequency.size() < numShadesRequired)
172	{
173		m_testCtx.getLog() << tcu::TestLog::Message << "Image verification failed." << tcu::TestLog::EndMessage;
174		return false;
175	}
176	return true;
177}
178
179class SampleQualifierRenderCase : public MultisampleShadeCountRenderCase
180{
181public:
182				SampleQualifierRenderCase	(Context& context, const char* name, const char* description, int numSamples, RenderTarget target);
183				~SampleQualifierRenderCase	(void);
184
185	void		init						(void);
186
187private:
188	std::string	genVertexSource				(int numTargetSamples) const;
189	std::string	genFragmentSource			(int numTargetSamples) const;
190	std::string	getIterationDescription		(int iteration) const;
191};
192
193SampleQualifierRenderCase::SampleQualifierRenderCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target)
194	: MultisampleShadeCountRenderCase(context, name, description, numSamples, target)
195{
196	m_numIterations = 6; // float, vec2, .3, .4, array, struct
197}
198
199SampleQualifierRenderCase::~SampleQualifierRenderCase (void)
200{
201}
202
203void SampleQualifierRenderCase::init (void)
204{
205	const bool isSingleSampleTarget = (m_renderTarget != TARGET_DEFAULT && m_numRequestedSamples == 0) || (m_renderTarget == TARGET_DEFAULT && m_context.getRenderTarget().getNumSamples() <= 1);
206
207	// test purpose and expectations
208	if (isSingleSampleTarget)
209	{
210		m_testCtx.getLog()
211			<< tcu::TestLog::Message
212			<< "Verifying that a sample-qualified varying is given different values for different samples.\n"
213			<< "	Render high-frequency function, map result to black/white.\n"
214			<< "	=> Resulting image image should contain both black and white pixels.\n"
215			<< tcu::TestLog::EndMessage;
216	}
217	else
218	{
219		m_testCtx.getLog()
220			<< tcu::TestLog::Message
221			<< "Verifying that a sample-qualified varying is given different values for different samples.\n"
222			<< "	Render high-frequency function, map result to black/white.\n"
223			<< "	=> Resulting image should contain n+1 shades of gray, n = sample count.\n"
224			<< tcu::TestLog::EndMessage;
225	}
226
227	MultisampleShadeCountRenderCase::init();
228}
229
230std::string	SampleQualifierRenderCase::genVertexSource (int numTargetSamples) const
231{
232	DE_UNREF(numTargetSamples);
233
234	std::ostringstream buf;
235
236	buf <<	"#version 310 es\n"
237			"#extension GL_OES_shader_multisample_interpolation : require\n"
238			"in highp vec4 a_position;\n";
239
240	if (m_iteration == 0)
241		buf << "sample out highp float v_input;\n";
242	else if (m_iteration == 1)
243		buf << "sample out highp vec2 v_input;\n";
244	else if (m_iteration == 2)
245		buf << "sample out highp vec3 v_input;\n";
246	else if (m_iteration == 3)
247		buf << "sample out highp vec4 v_input;\n";
248	else if (m_iteration == 4)
249		buf << "sample out highp float[2] v_input;\n";
250	else if (m_iteration == 5)
251		buf << "struct VaryingStruct { highp float a; highp float b; };\n"
252			   "sample out VaryingStruct v_input;\n";
253	else
254		DE_ASSERT(false);
255
256	buf <<	"void main (void)\n"
257			"{\n"
258			"	gl_Position = a_position;\n";
259
260	if (m_iteration == 0)
261		buf << "	v_input = a_position.x + exp(a_position.y) + step(0.9, a_position.x)*step(a_position.y, -0.9)*8.0;\n";
262	else if (m_iteration == 1)
263		buf << "	v_input = a_position.xy;\n";
264	else if (m_iteration == 2)
265		buf << "	v_input = vec3(a_position.xy, a_position.x * 2.0 - a_position.y);\n";
266	else if (m_iteration == 3)
267		buf << "	v_input = vec4(a_position.xy, a_position.x * 2.0 - a_position.y, a_position.x*a_position.y);\n";
268	else if (m_iteration == 4)
269		buf << "	v_input[0] = a_position.x;\n"
270			   "	v_input[1] = a_position.y;\n";
271	else if (m_iteration == 5)
272		buf << "	v_input.a = a_position.x;\n"
273			   "	v_input.b = a_position.y;\n";
274	else
275		DE_ASSERT(false);
276
277	buf <<	"}";
278
279	return buf.str();
280}
281
282std::string	SampleQualifierRenderCase::genFragmentSource (int numTargetSamples) const
283{
284	DE_UNREF(numTargetSamples);
285
286	std::ostringstream buf;
287
288	buf <<	"#version 310 es\n"
289			"#extension GL_OES_shader_multisample_interpolation : require\n";
290
291	if (m_iteration == 0)
292		buf << "sample in highp float v_input;\n";
293	else if (m_iteration == 1)
294		buf << "sample in highp vec2 v_input;\n";
295	else if (m_iteration == 2)
296		buf << "sample in highp vec3 v_input;\n";
297	else if (m_iteration == 3)
298		buf << "sample in highp vec4 v_input;\n";
299	else if (m_iteration == 4)
300		buf << "sample in highp float[2] v_input;\n";
301	else if (m_iteration == 5)
302		buf << "struct VaryingStruct { highp float a; highp float b; };\n"
303			   "sample in VaryingStruct v_input;\n";
304	else
305		DE_ASSERT(false);
306
307	buf <<	"layout(location = 0) out mediump vec4 fragColor;\n"
308			"void main (void)\n"
309			"{\n";
310
311	if (m_iteration == 0)
312		buf << "	highp float field = exp(v_input) + v_input*v_input;\n";
313	else if (m_iteration == 1)
314		buf << "	highp float field = dot(v_input.xy, v_input.xy) + dot(21.0 * v_input.xx, sin(3.1 * v_input.xy));\n";
315	else if (m_iteration == 2)
316		buf << "	highp float field = dot(v_input.xy, v_input.xy) + dot(21.0 * v_input.zx, sin(3.1 * v_input.zy));\n";
317	else if (m_iteration == 3)
318		buf << "	highp float field = dot(v_input.xy, v_input.zw) + dot(21.0 * v_input.zy, sin(3.1 * v_input.zw));\n";
319	else if (m_iteration == 4)
320		buf << "	highp float field = dot(vec2(v_input[0], v_input[1]), vec2(v_input[0], v_input[1])) + dot(21.0 * vec2(v_input[0]), sin(3.1 * vec2(v_input[0], v_input[1])));\n";
321	else if (m_iteration == 5)
322		buf << "	highp float field = dot(vec2(v_input.a, v_input.b), vec2(v_input.a, v_input.b)) + dot(21.0 * vec2(v_input.a), sin(3.1 * vec2(v_input.a, v_input.b)));\n";
323	else
324		DE_ASSERT(false);
325
326	buf <<	"	fragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
327			"\n"
328			"	if (fract(field) > 0.5)\n"
329			"		fragColor = vec4(0.0, 0.0, 0.0, 1.0);\n"
330			"}";
331
332	return buf.str();
333}
334
335std::string	SampleQualifierRenderCase::getIterationDescription (int iteration) const
336{
337	if (iteration == 0)
338		return "Test with float varying";
339	else if (iteration == 1)
340		return "Test with vec2 varying";
341	else if (iteration == 2)
342		return "Test with vec3 varying";
343	else if (iteration == 3)
344		return "Test with vec4 varying";
345	else if (iteration == 4)
346		return "Test with array varying";
347	else if (iteration == 5)
348		return "Test with struct varying";
349
350	DE_ASSERT(false);
351	return "";
352}
353
354class InterpolateAtSampleRenderCase : public MultisampleShadeCountRenderCase
355{
356public:
357	enum IndexingMode
358	{
359		INDEXING_STATIC,
360		INDEXING_DYNAMIC,
361
362		INDEXING_LAST
363	};
364						InterpolateAtSampleRenderCase	(Context& context, const char* name, const char* description, int numSamples, RenderTarget target, IndexingMode mode);
365						~InterpolateAtSampleRenderCase	(void);
366
367	void				init							(void);
368	void				preDraw							(void);
369
370private:
371	std::string			genVertexSource					(int numTargetSamples) const;
372	std::string			genFragmentSource				(int numTargetSamples) const;
373	std::string			getIterationDescription			(int iteration) const;
374
375	const IndexingMode	m_indexMode;
376};
377
378InterpolateAtSampleRenderCase::InterpolateAtSampleRenderCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target, IndexingMode mode)
379	: MultisampleShadeCountRenderCase	(context, name, description, numSamples, target)
380	, m_indexMode						(mode)
381{
382	DE_ASSERT(mode < INDEXING_LAST);
383
384	m_numIterations = 5; // float, vec2, .3, .4, array
385}
386
387InterpolateAtSampleRenderCase::~InterpolateAtSampleRenderCase (void)
388{
389}
390
391void InterpolateAtSampleRenderCase::init (void)
392{
393	const bool isSingleSampleTarget = (m_renderTarget != TARGET_DEFAULT && m_numRequestedSamples == 0) || (m_renderTarget == TARGET_DEFAULT && m_context.getRenderTarget().getNumSamples() <= 1);
394
395	// test purpose and expectations
396	if (isSingleSampleTarget)
397	{
398		m_testCtx.getLog()
399			<< tcu::TestLog::Message
400			<< "Verifying that a interpolateAtSample returns different values for different samples.\n"
401			<< "	Render high-frequency function, map result to black/white.\n"
402			<< "	=> Resulting image image should contain both black and white pixels.\n"
403			<< tcu::TestLog::EndMessage;
404	}
405	else
406	{
407		m_testCtx.getLog()
408			<< tcu::TestLog::Message
409			<< "Verifying that a interpolateAtSample returns different values for different samples.\n"
410			<< "	Render high-frequency function, map result to black/white.\n"
411			<< "	=> Resulting image should contain n+1 shades of gray, n = sample count.\n"
412			<< tcu::TestLog::EndMessage;
413	}
414
415	MultisampleShadeCountRenderCase::init();
416}
417
418void InterpolateAtSampleRenderCase::preDraw (void)
419{
420	if (m_indexMode == INDEXING_DYNAMIC)
421	{
422		const deInt32			range		= m_numTargetSamples;
423		const deInt32			offset		= 1;
424		const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
425		const deInt32			offsetLoc	= gl.getUniformLocation(m_program->getProgram(), "u_offset");
426		const deInt32			rangeLoc	= gl.getUniformLocation(m_program->getProgram(), "u_range");
427
428		if (offsetLoc == -1)
429			throw tcu::TestError("Location of u_offset was -1");
430		if (rangeLoc == -1)
431			throw tcu::TestError("Location of u_range was -1");
432
433		gl.uniform1i(offsetLoc, 0);
434		gl.uniform1i(rangeLoc, m_numTargetSamples);
435		GLU_EXPECT_NO_ERROR(gl.getError(), "set uniforms");
436
437		m_testCtx.getLog()
438			<< tcu::TestLog::Message
439			<< "Set u_offset = " << offset << "\n"
440			<< "Set u_range = " << range
441			<< tcu::TestLog::EndMessage;
442	}
443}
444
445std::string InterpolateAtSampleRenderCase::genVertexSource (int numTargetSamples) const
446{
447	DE_UNREF(numTargetSamples);
448
449	std::ostringstream buf;
450
451	buf <<	"#version 310 es\n"
452			"in highp vec4 a_position;\n";
453
454	if (m_iteration == 0)
455		buf << "out highp float v_input;\n";
456	else if (m_iteration == 1)
457		buf << "out highp vec2 v_input;\n";
458	else if (m_iteration == 2)
459		buf << "out highp vec3 v_input;\n";
460	else if (m_iteration == 3)
461		buf << "out highp vec4 v_input;\n";
462	else if (m_iteration == 4)
463		buf << "out highp vec2[2] v_input;\n";
464	else
465		DE_ASSERT(false);
466
467	buf <<	"void main (void)\n"
468			"{\n"
469			"	gl_Position = a_position;\n";
470
471	if (m_iteration == 0)
472		buf << "	v_input = a_position.x + exp(a_position.y) + step(0.9, a_position.x)*step(a_position.y, -0.9)*8.0;\n";
473	else if (m_iteration == 1)
474		buf << "	v_input = a_position.xy;\n";
475	else if (m_iteration == 2)
476		buf << "	v_input = vec3(a_position.xy, a_position.x * 2.0 - a_position.y);\n";
477	else if (m_iteration == 3)
478		buf << "	v_input = vec4(a_position.xy, a_position.x * 2.0 - a_position.y, a_position.x*a_position.y);\n";
479	else if (m_iteration == 4)
480		buf << "	v_input[0] = a_position.yx + vec2(0.5, 0.5);\n"
481			   "	v_input[1] = a_position.xy;\n";
482	else
483		DE_ASSERT(false);
484
485	buf <<	"}";
486
487	return buf.str();
488}
489
490std::string InterpolateAtSampleRenderCase::genFragmentSource (int numTargetSamples) const
491{
492	std::ostringstream buf;
493
494	buf <<	"#version 310 es\n"
495			"#extension GL_OES_shader_multisample_interpolation : require\n";
496
497	if (m_iteration == 0)
498		buf << "in highp float v_input;\n";
499	else if (m_iteration == 1)
500		buf << "in highp vec2 v_input;\n";
501	else if (m_iteration == 2)
502		buf << "in highp vec3 v_input;\n";
503	else if (m_iteration == 3)
504		buf << "in highp vec4 v_input;\n";
505	else if (m_iteration == 4)
506		buf << "in highp vec2[2] v_input;\n";
507	else
508		DE_ASSERT(false);
509
510	buf << "layout(location = 0) out mediump vec4 fragColor;\n";
511
512	if (m_indexMode == INDEXING_DYNAMIC)
513		buf <<	"uniform highp int u_offset;\n"
514				"uniform highp int u_range;\n";
515
516	buf <<	"void main (void)\n"
517			"{\n"
518			"	mediump int coverage = 0;\n"
519			"\n";
520
521	if (m_indexMode == INDEXING_STATIC)
522	{
523		for (int ndx = 0; ndx < numTargetSamples; ++ndx)
524		{
525			if (m_iteration == 0)
526				buf <<	"	highp float sampleInput" << ndx << " = interpolateAtSample(v_input, " << ndx << ");\n";
527			else if (m_iteration == 1)
528				buf <<	"	highp vec2 sampleInput" << ndx << " = interpolateAtSample(v_input, " << ndx << ");\n";
529			else if (m_iteration == 2)
530				buf <<	"	highp vec3 sampleInput" << ndx << " = interpolateAtSample(v_input, " << ndx << ");\n";
531			else if (m_iteration == 3)
532				buf <<	"	highp vec4 sampleInput" << ndx << " = interpolateAtSample(v_input, " << ndx << ");\n";
533			else if (m_iteration == 4)
534				buf <<	"	highp vec2 sampleInput" << ndx << " = interpolateAtSample(v_input[1], " << ndx << ");\n";
535			else
536				DE_ASSERT(false);
537		}
538		buf <<	"\n";
539
540		for (int ndx = 0; ndx < numTargetSamples; ++ndx)
541		{
542			if (m_iteration == 0)
543				buf << "	highp float field" << ndx << " = exp(sampleInput" << ndx << ") + sampleInput" << ndx << "*sampleInput" << ndx << ";\n";
544			else if (m_iteration == 1 || m_iteration == 4)
545				buf << "	highp float field" << ndx << " = dot(sampleInput" << ndx << ", sampleInput" << ndx << ") + dot(21.0 * sampleInput" << ndx << ".xx, sin(3.1 * sampleInput" << ndx << "));\n";
546			else if (m_iteration == 2)
547				buf << "	highp float field" << ndx << " = dot(sampleInput" << ndx << ".xy, sampleInput" << ndx << ".xy) + dot(21.0 * sampleInput" << ndx << ".zx, sin(3.1 * sampleInput" << ndx << ".zy));\n";
548			else if (m_iteration == 3)
549				buf << "	highp float field" << ndx << " = dot(sampleInput" << ndx << ".xy, sampleInput" << ndx << ".zw) + dot(21.0 * sampleInput" << ndx << ".zy, sin(3.1 * sampleInput" << ndx << ".zw));\n";
550			else
551				DE_ASSERT(false);
552		}
553		buf <<	"\n";
554
555		for (int ndx = 0; ndx < numTargetSamples; ++ndx)
556			buf <<	"	if (fract(field" << ndx << ") <= 0.5)\n"
557					"		++coverage;\n";
558	}
559	else if (m_indexMode == INDEXING_DYNAMIC)
560	{
561		buf <<	"	for (int ndx = 0; ndx < " << numTargetSamples << "; ++ndx)\n"
562				"	{\n";
563
564		if (m_iteration == 0)
565			buf <<	"		highp float sampleInput = interpolateAtSample(v_input, (u_offset + ndx) % u_range);\n";
566		else if (m_iteration == 1)
567			buf <<	"		highp vec2 sampleInput = interpolateAtSample(v_input, (u_offset + ndx) % u_range);\n";
568		else if (m_iteration == 2)
569			buf <<	"		highp vec3 sampleInput = interpolateAtSample(v_input, (u_offset + ndx) % u_range);\n";
570		else if (m_iteration == 3)
571			buf <<	"		highp vec4 sampleInput = interpolateAtSample(v_input, (u_offset + ndx) % u_range);\n";
572		else if (m_iteration == 4)
573			buf <<	"		highp vec2 sampleInput = interpolateAtSample(v_input[1], (u_offset + ndx) % u_range);\n";
574		else
575			DE_ASSERT(false);
576
577		if (m_iteration == 0)
578			buf << "		highp float field = exp(sampleInput) + sampleInput*sampleInput;\n";
579		else if (m_iteration == 1 || m_iteration == 4)
580			buf << "		highp float field = dot(sampleInput, sampleInput) + dot(21.0 * sampleInput.xx, sin(3.1 * sampleInput));\n";
581		else if (m_iteration == 2)
582			buf << "		highp float field = dot(sampleInput.xy, sampleInput.xy) + dot(21.0 * sampleInput.zx, sin(3.1 * sampleInput.zy));\n";
583		else if (m_iteration == 3)
584			buf << "		highp float field = dot(sampleInput.xy, sampleInput.zw) + dot(21.0 * sampleInput.zy, sin(3.1 * sampleInput.zw));\n";
585		else
586			DE_ASSERT(false);
587
588		buf <<	"		if (fract(field) <= 0.5)\n"
589				"			++coverage;\n"
590				"	}\n";
591	}
592
593	buf <<	"	fragColor = vec4(vec3(float(coverage) / float(" << numTargetSamples << ")), 1.0);\n"
594			"}";
595
596	return buf.str();
597}
598
599std::string InterpolateAtSampleRenderCase::getIterationDescription (int iteration) const
600{
601	if (iteration == 0)
602		return "Test with float varying";
603	else if (iteration < 4)
604		return "Test with vec" + de::toString(iteration+1) + " varying";
605	else if (iteration == 4)
606		return "Test with array varying";
607
608	DE_ASSERT(false);
609	return "";
610}
611
612class SingleSampleInterpolateAtSampleCase : public MultisampleShaderRenderUtil::MultisampleRenderCase
613{
614public:
615	enum SampleCase
616	{
617		SAMPLE_0 = 0,
618		SAMPLE_N,
619
620		SAMPLE_LAST
621	};
622
623						SingleSampleInterpolateAtSampleCase		(Context& context, const char* name, const char* description, int numSamples, RenderTarget target, SampleCase sampleCase);
624	virtual				~SingleSampleInterpolateAtSampleCase	(void);
625
626	void				init									(void);
627
628private:
629	enum
630	{
631		RENDER_SIZE = 32
632	};
633
634	std::string			genVertexSource							(int numTargetSamples) const;
635	std::string			genFragmentSource						(int numTargetSamples) const;
636	bool				verifyImage								(const tcu::Surface& resultImage);
637
638	const SampleCase	m_sampleCase;
639};
640
641SingleSampleInterpolateAtSampleCase::SingleSampleInterpolateAtSampleCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target, SampleCase sampleCase)
642	: MultisampleShaderRenderUtil::MultisampleRenderCase	(context, name, description, numSamples, target, RENDER_SIZE)
643	, m_sampleCase											(sampleCase)
644{
645	DE_ASSERT(numSamples == 0);
646	DE_ASSERT(sampleCase < SAMPLE_LAST);
647}
648
649SingleSampleInterpolateAtSampleCase::~SingleSampleInterpolateAtSampleCase (void)
650{
651}
652
653void SingleSampleInterpolateAtSampleCase::init (void)
654{
655	// requirements
656	if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation"))
657		TCU_THROW(NotSupportedError, "Test requires GL_OES_shader_multisample_interpolation extension");
658	if (m_renderTarget == TARGET_DEFAULT && m_context.getRenderTarget().getNumSamples() > 1)
659		TCU_THROW(NotSupportedError, "Non-multisample framebuffer required");
660
661	// test purpose and expectations
662	m_testCtx.getLog()
663		<< tcu::TestLog::Message
664		<< "Verifying that using interpolateAtSample with multisample buffers not available returns sample evaluated at the center of the pixel.\n"
665		<< "	Interpolate varying containing screen space location.\n"
666		<< "	=> fract(screen space location) should be (about) (0.5, 0.5)\n"
667		<< tcu::TestLog::EndMessage;
668
669	MultisampleShaderRenderUtil::MultisampleRenderCase::init();
670}
671
672std::string SingleSampleInterpolateAtSampleCase::genVertexSource (int numTargetSamples) const
673{
674	DE_UNREF(numTargetSamples);
675
676	std::ostringstream buf;
677
678	buf <<	"#version 310 es\n"
679			"in highp vec4 a_position;\n"
680			"out highp vec2 v_position;\n"
681			"void main (void)\n"
682			"{\n"
683			"	gl_Position = a_position;\n"
684			"	v_position = (a_position.xy + vec2(1.0, 1.0)) / 2.0 * vec2(" << (int)RENDER_SIZE << ".0, " << (int)RENDER_SIZE << ".0);\n"
685			"}\n";
686
687	return buf.str();
688}
689
690std::string SingleSampleInterpolateAtSampleCase::genFragmentSource (int numTargetSamples) const
691{
692	DE_UNREF(numTargetSamples);
693
694	std::ostringstream buf;
695
696	buf <<	"#version 310 es\n"
697			"#extension GL_OES_shader_multisample_interpolation : require\n"
698			"in highp vec2 v_position;\n"
699			"layout(location = 0) out mediump vec4 fragColor;\n"
700			"void main (void)\n"
701			"{\n"
702			"	const highp float threshold = 0.15625; // 4 subpixel bits. Assume 3 accurate bits + 0.03125 for other errors\n"; // 0.03125 = mediump epsilon when value = 32 (RENDER_SIZE)
703
704	if (m_sampleCase == SAMPLE_0)
705	{
706		buf <<	"	highp vec2 samplePosition = interpolateAtSample(v_position, 0);\n"
707				"	highp vec2 positionInsideAPixel = fract(samplePosition);\n"
708				"\n"
709				"	if (abs(positionInsideAPixel.x - 0.5) <= threshold && abs(positionInsideAPixel.y - 0.5) <= threshold)\n"
710				"		fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
711				"	else\n"
712				"		fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
713				"}\n";
714	}
715	else if (m_sampleCase == SAMPLE_N)
716	{
717		buf <<	"	bool allOk = true;\n"
718				"	for (int sampleNdx = 159; sampleNdx < 163; ++sampleNdx)\n"
719				"	{\n"
720				"		highp vec2 samplePosition = interpolateAtSample(v_position, sampleNdx);\n"
721				"		highp vec2 positionInsideAPixel = fract(samplePosition);\n"
722				"		if (abs(positionInsideAPixel.x - 0.5) > threshold || abs(positionInsideAPixel.y - 0.5) > threshold)\n"
723				"			allOk = false;\n"
724				"	}\n"
725				"\n"
726				"	if (allOk)\n"
727				"		fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
728				"	else\n"
729				"		fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
730				"}\n";
731	}
732	else
733		DE_ASSERT(false);
734
735	return buf.str();
736}
737
738bool SingleSampleInterpolateAtSampleCase::verifyImage (const tcu::Surface& resultImage)
739{
740	return verifyGreenImage(resultImage, m_testCtx.getLog());
741}
742
743class CentroidRenderCase : public MultisampleShaderRenderUtil::MultisampleRenderCase
744{
745public:
746									CentroidRenderCase	(Context& context, const char* name, const char* description, int numSamples, RenderTarget target, int renderSize);
747	virtual							~CentroidRenderCase	(void);
748
749	void							init				(void);
750
751private:
752	void							setupRenderData		(void);
753};
754
755CentroidRenderCase::CentroidRenderCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target, int renderSize)
756	: MultisampleShaderRenderUtil::MultisampleRenderCase(context, name, description, numSamples, target, renderSize)
757{
758}
759
760CentroidRenderCase::~CentroidRenderCase (void)
761{
762}
763
764void CentroidRenderCase::init (void)
765{
766	// requirements
767	if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation"))
768		TCU_THROW(NotSupportedError, "Test requires GL_OES_shader_multisample_interpolation extension");
769
770	MultisampleShaderRenderUtil::MultisampleRenderCase::init();
771}
772
773void CentroidRenderCase::setupRenderData (void)
774{
775	const int				numTriangles	= 200;
776	const glw::Functions&	gl				= m_context.getRenderContext().getFunctions();
777	std::vector<tcu::Vec4>	data			(numTriangles * 3 * 3);
778
779	m_renderMode = GL_TRIANGLES;
780	m_renderCount = numTriangles * 3;
781	m_renderSceneDescription = "triangle fan of narrow triangles";
782
783	m_renderAttribs["a_position"].offset = 0;
784	m_renderAttribs["a_position"].stride = sizeof(float[4]) * 3;
785	m_renderAttribs["a_barycentricsA"].offset = sizeof(float[4]);
786	m_renderAttribs["a_barycentricsA"].stride = sizeof(float[4]) * 3;
787	m_renderAttribs["a_barycentricsB"].offset = sizeof(float[4]) * 2;
788	m_renderAttribs["a_barycentricsB"].stride = sizeof(float[4]) * 3;
789
790	for (int triangleNdx = 0; triangleNdx < numTriangles; ++triangleNdx)
791	{
792		const float angle		= ((float)triangleNdx) / numTriangles * 2.0f * DE_PI;
793		const float nextAngle	= ((float)triangleNdx + 1.0f) / numTriangles * 2.0f * DE_PI;
794
795		data[(triangleNdx * 3 + 0) * 3 + 0] = tcu::Vec4(0.2f, -0.3f, 0.0f, 1.0f);
796		data[(triangleNdx * 3 + 0) * 3 + 1] = tcu::Vec4(1.0f,  0.0f, 0.0f, 0.0f);
797		data[(triangleNdx * 3 + 0) * 3 + 2] = tcu::Vec4(1.0f,  0.0f, 0.0f, 0.0f);
798
799		data[(triangleNdx * 3 + 1) * 3 + 0] = tcu::Vec4(2.0f * cos(angle), 2.0f * sin(angle), 0.0f, 1.0f);
800		data[(triangleNdx * 3 + 1) * 3 + 1] = tcu::Vec4(0.0f,  1.0f, 0.0f, 0.0f);
801		data[(triangleNdx * 3 + 1) * 3 + 2] = tcu::Vec4(0.0f,  1.0f, 0.0f, 0.0f);
802
803		data[(triangleNdx * 3 + 2) * 3 + 0] = tcu::Vec4(2.0f * cos(nextAngle), 2.0f * sin(nextAngle), 0.0f, 1.0f);
804		data[(triangleNdx * 3 + 2) * 3 + 1] = tcu::Vec4(0.0f,  0.0f, 1.0f, 0.0f);
805		data[(triangleNdx * 3 + 2) * 3 + 2] = tcu::Vec4(0.0f,  0.0f, 1.0f, 0.0f);
806	}
807
808	gl.bindBuffer(GL_ARRAY_BUFFER, m_buffer);
809	gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(data.size() * sizeof(tcu::Vec4)), data[0].getPtr(), GL_STATIC_DRAW);
810}
811
812class CentroidQualifierAtSampleCase : public CentroidRenderCase
813{
814public:
815									CentroidQualifierAtSampleCase	(Context& context, const char* name, const char* description, int numSamples, RenderTarget target);
816	virtual							~CentroidQualifierAtSampleCase	(void);
817
818	void							init						(void);
819
820private:
821	enum
822	{
823		RENDER_SIZE = 128
824	};
825
826	std::string						genVertexSource				(int numTargetSamples) const;
827	std::string						genFragmentSource			(int numTargetSamples) const;
828	bool							verifyImage					(const tcu::Surface& resultImage);
829};
830
831CentroidQualifierAtSampleCase::CentroidQualifierAtSampleCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target)
832	: CentroidRenderCase(context, name, description, numSamples, target, RENDER_SIZE)
833{
834}
835
836CentroidQualifierAtSampleCase::~CentroidQualifierAtSampleCase (void)
837{
838}
839
840void CentroidQualifierAtSampleCase::init (void)
841{
842	// test purpose and expectations
843	m_testCtx.getLog()
844		<< tcu::TestLog::Message
845		<< "Verifying that interpolateAtSample ignores the centroid-qualifier.\n"
846		<< "	Draw a fan of narrow triangles (large number of pixels on the edges).\n"
847		<< "	Set varyings 'barycentricsA' and 'barycentricsB' to contain barycentric coordinates.\n"
848		<< "	Add centroid-qualifier for barycentricsB.\n"
849		<< "	=> interpolateAtSample(barycentricsB, N) ~= interpolateAtSample(barycentricsA, N)\n"
850		<< tcu::TestLog::EndMessage;
851
852	CentroidRenderCase::init();
853}
854
855std::string CentroidQualifierAtSampleCase::genVertexSource (int numTargetSamples) const
856{
857	DE_UNREF(numTargetSamples);
858
859	return	"#version 310 es\n"
860			"in highp vec4 a_position;\n"
861			"in highp vec4 a_barycentricsA;\n"
862			"in highp vec4 a_barycentricsB;\n"
863			"out highp vec3 v_barycentricsA;\n"
864			"centroid out highp vec3 v_barycentricsB;\n"
865			"void main (void)\n"
866			"{\n"
867			"	gl_Position = a_position;\n"
868			"	v_barycentricsA = a_barycentricsA.xyz;\n"
869			"	v_barycentricsB = a_barycentricsB.xyz;\n"
870			"}\n";
871}
872
873std::string CentroidQualifierAtSampleCase::genFragmentSource (int numTargetSamples) const
874{
875	DE_UNREF(numTargetSamples);
876
877	std::ostringstream buf;
878
879	buf <<	"#version 310 es\n"
880			"#extension GL_OES_shader_multisample_interpolation : require\n"
881			"in highp vec3 v_barycentricsA;\n"
882			"centroid in highp vec3 v_barycentricsB;\n"
883			"layout(location = 0) out mediump vec4 fragColor;\n"
884			"void main (void)\n"
885			"{\n"
886			"	const highp float threshold = 0.0005;\n"
887			"	bool allOk = true;\n"
888			"\n"
889			"	for (int sampleNdx = 0; sampleNdx < " << numTargetSamples << "; ++sampleNdx)\n"
890			"	{\n"
891			"		highp vec3 sampleA = interpolateAtSample(v_barycentricsA, sampleNdx);\n"
892			"		highp vec3 sampleB = interpolateAtSample(v_barycentricsB, sampleNdx);\n"
893			"		bool valuesEqual = all(lessThan(abs(sampleA - sampleB), vec3(threshold)));\n"
894			"		if (!valuesEqual)\n"
895			"			allOk = false;\n"
896			"	}\n"
897			"\n"
898			"	if (allOk)\n"
899			"		fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
900			"	else\n"
901			"		fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
902			"}\n";
903
904	return buf.str();
905}
906
907bool CentroidQualifierAtSampleCase::verifyImage (const tcu::Surface& resultImage)
908{
909	return verifyGreenImage(resultImage, m_testCtx.getLog());
910}
911
912class InterpolateAtSampleIDCase : public MultisampleShaderRenderUtil::MultisampleRenderCase
913{
914public:
915						InterpolateAtSampleIDCase	(Context& context, const char* name, const char* description, int numSamples, RenderTarget target);
916	virtual				~InterpolateAtSampleIDCase	(void);
917
918	void				init						(void);
919private:
920	enum
921	{
922		RENDER_SIZE = 32
923	};
924
925	std::string			genVertexSource				(int numTargetSamples) const;
926	std::string			genFragmentSource			(int numTargetSamples) const;
927	bool				verifyImage					(const tcu::Surface& resultImage);
928};
929
930InterpolateAtSampleIDCase::InterpolateAtSampleIDCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target)
931	: MultisampleShaderRenderUtil::MultisampleRenderCase(context, name, description, numSamples, target, RENDER_SIZE)
932{
933}
934
935InterpolateAtSampleIDCase::~InterpolateAtSampleIDCase (void)
936{
937}
938
939void InterpolateAtSampleIDCase::init (void)
940{
941	// requirements
942	if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation"))
943		TCU_THROW(NotSupportedError, "Test requires GL_OES_shader_multisample_interpolation extension");
944	if (!m_context.getContextInfo().isExtensionSupported("GL_OES_sample_variables"))
945		TCU_THROW(NotSupportedError, "Test requires GL_OES_sample_variables extension");
946
947	// test purpose and expectations
948	m_testCtx.getLog()
949		<< tcu::TestLog::Message
950		<< "Verifying that interpolateAtSample with the sample set to the current sampleID returns consistent values.\n"
951		<< "	Interpolate varying containing screen space location.\n"
952		<< "	=> interpolateAtSample(varying, sampleID) = varying"
953		<< tcu::TestLog::EndMessage;
954
955	MultisampleShaderRenderUtil::MultisampleRenderCase::init();
956}
957
958std::string InterpolateAtSampleIDCase::genVertexSource (int numTargetSamples) const
959{
960	DE_UNREF(numTargetSamples);
961
962	std::ostringstream buf;
963
964	buf <<	"#version 310 es\n"
965			"#extension GL_OES_shader_multisample_interpolation : require\n"
966			"in highp vec4 a_position;\n"
967			"sample out highp vec2 v_screenPosition;\n"
968			"void main (void)\n"
969			"{\n"
970			"	gl_Position = a_position;\n"
971			"	v_screenPosition = (a_position.xy + vec2(1.0, 1.0)) / 2.0 * vec2(" << (int)RENDER_SIZE << ".0, " << (int)RENDER_SIZE << ".0);\n"
972			"}\n";
973
974	return buf.str();
975}
976
977std::string InterpolateAtSampleIDCase::genFragmentSource (int numTargetSamples) const
978{
979	DE_UNREF(numTargetSamples);
980
981	return	"#version 310 es\n"
982			"#extension GL_OES_sample_variables : require\n"
983			"#extension GL_OES_shader_multisample_interpolation : require\n"
984			"sample in highp vec2 v_screenPosition;\n"
985			"layout(location = 0) out mediump vec4 fragColor;\n"
986			"void main (void)\n"
987			"{\n"
988			"	const highp float threshold = 0.15625; // 4 subpixel bits. Assume 3 accurate bits + 0.03125 for other errors\n" // 0.03125 = mediump epsilon when value = 32 (RENDER_SIZE)
989			"\n"
990			"	highp vec2 offsetValue = interpolateAtSample(v_screenPosition, gl_SampleID);\n"
991			"	highp vec2 refValue = v_screenPosition;\n"
992			"\n"
993			"	bool valuesEqual = all(lessThan(abs(offsetValue - refValue), vec2(threshold)));\n"
994			"	if (valuesEqual)\n"
995			"		fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
996			"	else\n"
997			"		fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
998			"}\n";
999}
1000
1001bool InterpolateAtSampleIDCase::verifyImage (const tcu::Surface& resultImage)
1002{
1003	return verifyGreenImage(resultImage, m_testCtx.getLog());
1004}
1005
1006class InterpolateAtCentroidCase : public CentroidRenderCase
1007{
1008public:
1009	enum TestType
1010	{
1011		TEST_CONSISTENCY = 0,
1012		TEST_ARRAY_ELEMENT,
1013
1014		TEST_LAST
1015	};
1016
1017									InterpolateAtCentroidCase	(Context& context, const char* name, const char* description, int numSamples, RenderTarget target, TestType type);
1018	virtual							~InterpolateAtCentroidCase	(void);
1019
1020	void							init						(void);
1021
1022private:
1023	enum
1024	{
1025		RENDER_SIZE = 128
1026	};
1027
1028	std::string						genVertexSource				(int numTargetSamples) const;
1029	std::string						genFragmentSource			(int numTargetSamples) const;
1030	bool							verifyImage					(const tcu::Surface& resultImage);
1031
1032	const TestType					m_type;
1033};
1034
1035InterpolateAtCentroidCase::InterpolateAtCentroidCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target, TestType type)
1036	: CentroidRenderCase	(context, name, description, numSamples, target, RENDER_SIZE)
1037	, m_type				(type)
1038{
1039}
1040
1041InterpolateAtCentroidCase::~InterpolateAtCentroidCase (void)
1042{
1043}
1044
1045void InterpolateAtCentroidCase::init (void)
1046{
1047	// test purpose and expectations
1048	if (m_type == TEST_CONSISTENCY)
1049	{
1050		m_testCtx.getLog()
1051			<< tcu::TestLog::Message
1052			<< "Verifying that interpolateAtCentroid does not return different values than a corresponding centroid-qualified varying.\n"
1053			<< "	Draw a fan of narrow triangles (large number of pixels on the edges).\n"
1054			<< "	Set varyings 'barycentricsA' and 'barycentricsB' to contain barycentric coordinates.\n"
1055			<< "	Add centroid-qualifier for barycentricsB.\n"
1056			<< "	=> interpolateAtCentroid(barycentricsA) ~= barycentricsB\n"
1057			<< tcu::TestLog::EndMessage;
1058	}
1059	else if (m_type == TEST_ARRAY_ELEMENT)
1060	{
1061		m_testCtx.getLog()
1062			<< tcu::TestLog::Message
1063			<< "Testing interpolateAtCentroid with element of array as an argument."
1064			<< tcu::TestLog::EndMessage;
1065	}
1066	else
1067		DE_ASSERT(false);
1068
1069	CentroidRenderCase::init();
1070}
1071
1072std::string InterpolateAtCentroidCase::genVertexSource (int numTargetSamples) const
1073{
1074	DE_UNREF(numTargetSamples);
1075
1076	if (m_type == TEST_CONSISTENCY)
1077		return	"#version 310 es\n"
1078				"in highp vec4 a_position;\n"
1079				"in highp vec4 a_barycentricsA;\n"
1080				"in highp vec4 a_barycentricsB;\n"
1081				"out highp vec3 v_barycentricsA;\n"
1082				"centroid out highp vec3 v_barycentricsB;\n"
1083				"void main (void)\n"
1084				"{\n"
1085				"	gl_Position = a_position;\n"
1086				"	v_barycentricsA = a_barycentricsA.xyz;\n"
1087				"	v_barycentricsB = a_barycentricsB.xyz;\n"
1088				"}\n";
1089	else if (m_type == TEST_ARRAY_ELEMENT)
1090		return	"#version 310 es\n"
1091				"in highp vec4 a_position;\n"
1092				"in highp vec4 a_barycentricsA;\n"
1093				"in highp vec4 a_barycentricsB;\n"
1094				"out highp vec3[2] v_barycentrics;\n"
1095				"void main (void)\n"
1096				"{\n"
1097				"	gl_Position = a_position;\n"
1098				"	v_barycentrics[0] = a_barycentricsA.xyz;\n"
1099				"	v_barycentrics[1] = a_barycentricsB.xyz;\n"
1100				"}\n";
1101
1102	DE_ASSERT(false);
1103	return "";
1104}
1105
1106std::string InterpolateAtCentroidCase::genFragmentSource (int numTargetSamples) const
1107{
1108	DE_UNREF(numTargetSamples);
1109
1110	if (m_type == TEST_CONSISTENCY)
1111		return	"#version 310 es\n"
1112				"#extension GL_OES_shader_multisample_interpolation : require\n"
1113				"in highp vec3 v_barycentricsA;\n"
1114				"centroid in highp vec3 v_barycentricsB;\n"
1115				"layout(location = 0) out highp vec4 fragColor;\n"
1116				"void main (void)\n"
1117				"{\n"
1118				"	const highp float threshold = 0.0005;\n"
1119				"\n"
1120				"	highp vec3 centroidASampled = interpolateAtCentroid(v_barycentricsA);\n"
1121				"	bool valuesEqual = all(lessThan(abs(centroidASampled - v_barycentricsB), vec3(threshold)));\n"
1122				"	bool centroidAIsInvalid = any(greaterThan(centroidASampled, vec3(1.0))) ||\n"
1123				"	                          any(lessThan(centroidASampled, vec3(0.0)));\n"
1124				"	bool centroidBIsInvalid = any(greaterThan(v_barycentricsB, vec3(1.0))) ||\n"
1125				"	                          any(lessThan(v_barycentricsB, vec3(0.0)));\n"
1126				"\n"
1127				"	if (valuesEqual && !centroidAIsInvalid && !centroidBIsInvalid)\n"
1128				"		fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
1129				"	else if (centroidAIsInvalid || centroidBIsInvalid)\n"
1130				"		fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
1131				"	else\n"
1132				"		fragColor = vec4(1.0, 1.0, 0.0, 1.0);\n"
1133				"}\n";
1134	else if (m_type == TEST_ARRAY_ELEMENT)
1135		return	"#version 310 es\n"
1136				"#extension GL_OES_shader_multisample_interpolation : require\n"
1137				"in highp vec3[2] v_barycentrics;\n"
1138				"layout(location = 0) out mediump vec4 fragColor;\n"
1139				"void main (void)\n"
1140				"{\n"
1141				"	const highp float threshold = 0.0005;\n"
1142				"\n"
1143				"	highp vec3 centroidInterpolated = interpolateAtCentroid(v_barycentrics[1]);\n"
1144				"	bool centroidIsInvalid = any(greaterThan(centroidInterpolated, vec3(1.0))) ||\n"
1145				"	                         any(lessThan(centroidInterpolated, vec3(0.0)));\n"
1146				"\n"
1147				"	if (!centroidIsInvalid)\n"
1148				"		fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
1149				"	else\n"
1150				"		fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
1151				"}\n";
1152
1153	DE_ASSERT(false);
1154	return "";
1155}
1156
1157bool InterpolateAtCentroidCase::verifyImage (const tcu::Surface& resultImage)
1158{
1159	return verifyGreenImage(resultImage, m_testCtx.getLog());
1160}
1161
1162class InterpolateAtOffsetCase : public MultisampleShaderRenderUtil::MultisampleRenderCase
1163{
1164public:
1165	enum TestType
1166	{
1167		TEST_QUALIFIER_NONE = 0,
1168		TEST_QUALIFIER_CENTROID,
1169		TEST_QUALIFIER_SAMPLE,
1170		TEST_ARRAY_ELEMENT,
1171
1172		TEST_LAST
1173	};
1174						InterpolateAtOffsetCase		(Context& context, const char* name, const char* description, int numSamples, RenderTarget target, TestType testType);
1175	virtual				~InterpolateAtOffsetCase	(void);
1176
1177	void				init						(void);
1178private:
1179	enum
1180	{
1181		RENDER_SIZE = 32
1182	};
1183
1184	std::string			genVertexSource				(int numTargetSamples) const;
1185	std::string			genFragmentSource			(int numTargetSamples) const;
1186	bool				verifyImage					(const tcu::Surface& resultImage);
1187
1188	const TestType		m_testType;
1189};
1190
1191InterpolateAtOffsetCase::InterpolateAtOffsetCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target, TestType testType)
1192	: MultisampleShaderRenderUtil::MultisampleRenderCase	(context, name, description, numSamples, target, RENDER_SIZE)
1193	, m_testType											(testType)
1194{
1195	DE_ASSERT(testType < TEST_LAST);
1196}
1197
1198InterpolateAtOffsetCase::~InterpolateAtOffsetCase (void)
1199{
1200}
1201
1202void InterpolateAtOffsetCase::init (void)
1203{
1204	// requirements
1205	if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation"))
1206		TCU_THROW(NotSupportedError, "Test requires GL_OES_shader_multisample_interpolation extension");
1207
1208	// test purpose and expectations
1209	m_testCtx.getLog()
1210		<< tcu::TestLog::Message
1211		<< "Verifying that interpolateAtOffset returns correct values.\n"
1212		<< "	Interpolate varying containing screen space location.\n"
1213		<< "	=> interpolateAtOffset(varying, offset) should be \"varying value at the pixel center\" + offset"
1214		<< tcu::TestLog::EndMessage;
1215
1216	MultisampleShaderRenderUtil::MultisampleRenderCase::init();
1217}
1218
1219std::string InterpolateAtOffsetCase::genVertexSource (int numTargetSamples) const
1220{
1221	DE_UNREF(numTargetSamples);
1222
1223	std::ostringstream buf;
1224	buf << "#version 310 es\n"
1225		<< "#extension GL_OES_shader_multisample_interpolation : require\n"
1226		<< "in highp vec4 a_position;\n";
1227
1228	if (m_testType == TEST_QUALIFIER_NONE || m_testType == TEST_QUALIFIER_CENTROID || m_testType == TEST_QUALIFIER_SAMPLE)
1229	{
1230		const char* const qualifier = (m_testType == TEST_QUALIFIER_CENTROID) ? ("centroid ") : (m_testType == TEST_QUALIFIER_SAMPLE) ? ("sample ") : ("");
1231		buf << qualifier << "out highp vec2 v_screenPosition;\n"
1232			<< qualifier << "out highp vec2 v_offset;\n";
1233	}
1234	else if (m_testType == TEST_ARRAY_ELEMENT)
1235	{
1236		buf << "out highp vec2[2] v_screenPosition;\n"
1237			<< "out highp vec2 v_offset;\n";
1238	}
1239	else
1240		DE_ASSERT(false);
1241
1242	buf	<< "void main (void)\n"
1243		<< "{\n"
1244		<< "	gl_Position = a_position;\n";
1245
1246	if (m_testType != TEST_ARRAY_ELEMENT)
1247		buf	<< "	v_screenPosition = (a_position.xy + vec2(1.0, 1.0)) / 2.0 * vec2(" << (int)RENDER_SIZE << ".0, " << (int)RENDER_SIZE << ".0);\n";
1248	else
1249		buf	<< "	v_screenPosition[0] = a_position.xy; // not used\n"
1250				"	v_screenPosition[1] = (a_position.xy + vec2(1.0, 1.0)) / 2.0 * vec2(" << (int)RENDER_SIZE << ".0, " << (int)RENDER_SIZE << ".0);\n";
1251
1252	buf	<< "	v_offset = a_position.xy * 0.5f;\n"
1253		<< "}\n";
1254
1255	return buf.str();
1256}
1257
1258std::string InterpolateAtOffsetCase::genFragmentSource (int numTargetSamples) const
1259{
1260	DE_UNREF(numTargetSamples);
1261
1262	const char* const	arrayIndexing = (m_testType == TEST_ARRAY_ELEMENT) ? ("[1]") : ("");
1263	std::ostringstream	buf;
1264
1265	buf <<	"#version 310 es\n"
1266			"#extension GL_OES_shader_multisample_interpolation : require\n";
1267
1268	if (m_testType == TEST_QUALIFIER_NONE || m_testType == TEST_QUALIFIER_CENTROID || m_testType == TEST_QUALIFIER_SAMPLE)
1269	{
1270		const char* const qualifier = (m_testType == TEST_QUALIFIER_CENTROID) ? ("centroid ") : (m_testType == TEST_QUALIFIER_SAMPLE) ? ("sample ") : ("");
1271		buf	<< qualifier << "in highp vec2 v_screenPosition;\n"
1272			<< qualifier << "in highp vec2 v_offset;\n";
1273	}
1274	else if (m_testType == TEST_ARRAY_ELEMENT)
1275	{
1276		buf << "in highp vec2[2] v_screenPosition;\n"
1277			<< "in highp vec2 v_offset;\n";
1278	}
1279	else
1280		DE_ASSERT(false);
1281
1282	buf	<<	"layout(location = 0) out mediump vec4 fragColor;\n"
1283			"void main (void)\n"
1284			"{\n"
1285			"	const highp float threshold = 0.15625; // 4 subpixel bits. Assume 3 accurate bits + 0.03125 for other errors\n" // 0.03125 = mediump epsilon when value = 32 (RENDER_SIZE)
1286			"\n"
1287			"	highp vec2 pixelCenter = floor(v_screenPosition" << arrayIndexing << ") + vec2(0.5, 0.5);\n"
1288			"	highp vec2 offsetValue = interpolateAtOffset(v_screenPosition" << arrayIndexing << ", v_offset);\n"
1289			"	highp vec2 refValue = pixelCenter + v_offset;\n"
1290			"\n"
1291			"	bool valuesEqual = all(lessThan(abs(offsetValue - refValue), vec2(threshold)));\n"
1292			"	if (valuesEqual)\n"
1293			"		fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
1294			"	else\n"
1295			"		fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
1296			"}\n";
1297
1298	return buf.str();
1299}
1300
1301bool InterpolateAtOffsetCase::verifyImage (const tcu::Surface& resultImage)
1302{
1303	return verifyGreenImage(resultImage, m_testCtx.getLog());
1304}
1305
1306class InterpolateAtSamplePositionCase : public MultisampleShaderRenderUtil::MultisampleRenderCase
1307{
1308public:
1309						InterpolateAtSamplePositionCase		(Context& context, const char* name, const char* description, int numSamples, RenderTarget target);
1310	virtual				~InterpolateAtSamplePositionCase	(void);
1311
1312	void				init								(void);
1313private:
1314	enum
1315	{
1316		RENDER_SIZE = 32
1317	};
1318
1319	std::string			genVertexSource						(int numTargetSamples) const;
1320	std::string			genFragmentSource					(int numTargetSamples) const;
1321	bool				verifyImage							(const tcu::Surface& resultImage);
1322};
1323
1324InterpolateAtSamplePositionCase::InterpolateAtSamplePositionCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target)
1325	: MultisampleShaderRenderUtil::MultisampleRenderCase(context, name, description, numSamples, target, RENDER_SIZE)
1326{
1327}
1328
1329InterpolateAtSamplePositionCase::~InterpolateAtSamplePositionCase (void)
1330{
1331}
1332
1333void InterpolateAtSamplePositionCase::init (void)
1334{
1335	// requirements
1336	if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation"))
1337		TCU_THROW(NotSupportedError, "Test requires GL_OES_shader_multisample_interpolation extension");
1338	if (!m_context.getContextInfo().isExtensionSupported("GL_OES_sample_variables"))
1339		TCU_THROW(NotSupportedError, "Test requires GL_OES_sample_variables extension");
1340
1341	// test purpose and expectations
1342	m_testCtx.getLog()
1343		<< tcu::TestLog::Message
1344		<< "Verifying that interpolateAtOffset with the offset of current sample position returns consistent values.\n"
1345		<< "	Interpolate varying containing screen space location.\n"
1346		<< "	=> interpolateAtOffset(varying, currentOffset) = varying"
1347		<< tcu::TestLog::EndMessage;
1348
1349	MultisampleShaderRenderUtil::MultisampleRenderCase::init();
1350}
1351
1352std::string InterpolateAtSamplePositionCase::genVertexSource (int numTargetSamples) const
1353{
1354	DE_UNREF(numTargetSamples);
1355
1356	std::ostringstream buf;
1357
1358	buf <<	"#version 310 es\n"
1359			"#extension GL_OES_shader_multisample_interpolation : require\n"
1360			"in highp vec4 a_position;\n"
1361			"sample out highp vec2 v_screenPosition;\n"
1362			"void main (void)\n"
1363			"{\n"
1364			"	gl_Position = a_position;\n"
1365			"	v_screenPosition = (a_position.xy + vec2(1.0, 1.0)) / 2.0 * vec2(" << (int)RENDER_SIZE << ".0, " << (int)RENDER_SIZE << ".0);\n"
1366			"}\n";
1367
1368	return buf.str();
1369}
1370
1371std::string InterpolateAtSamplePositionCase::genFragmentSource (int numTargetSamples) const
1372{
1373	DE_UNREF(numTargetSamples);
1374
1375	return	"#version 310 es\n"
1376			"#extension GL_OES_sample_variables : require\n"
1377			"#extension GL_OES_shader_multisample_interpolation : require\n"
1378			"sample in highp vec2 v_screenPosition;\n"
1379			"layout(location = 0) out mediump vec4 fragColor;\n"
1380			"void main (void)\n"
1381			"{\n"
1382			"	const highp float threshold = 0.15625; // 4 subpixel bits. Assume 3 accurate bits + 0.03125 for other errors\n" // 0.03125 = mediump epsilon when value = 32 (RENDER_SIZE)
1383			"\n"
1384			"	highp vec2 offset = gl_SamplePosition - vec2(0.5, 0.5);\n"
1385			"	highp vec2 offsetValue = interpolateAtOffset(v_screenPosition, offset);\n"
1386			"	highp vec2 refValue = v_screenPosition;\n"
1387			"\n"
1388			"	bool valuesEqual = all(lessThan(abs(offsetValue - refValue), vec2(threshold)));\n"
1389			"	if (valuesEqual)\n"
1390			"		fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
1391			"	else\n"
1392			"		fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
1393			"}\n";
1394}
1395
1396bool InterpolateAtSamplePositionCase::verifyImage (const tcu::Surface& resultImage)
1397{
1398	return verifyGreenImage(resultImage, m_testCtx.getLog());
1399}
1400
1401class NegativeCompileInterpolationCase : public TestCase
1402{
1403public:
1404	enum CaseType
1405	{
1406		CASE_VEC4_IDENTITY_SWIZZLE = 0,
1407		CASE_VEC4_CROP_SWIZZLE,
1408		CASE_VEC4_MIXED_SWIZZLE,
1409		CASE_INTERPOLATE_IVEC4,
1410		CASE_INTERPOLATE_UVEC4,
1411		CASE_INTERPOLATE_ARRAY,
1412		CASE_INTERPOLATE_STRUCT,
1413		CASE_INTERPOLATE_STRUCT_MEMBER,
1414		CASE_INTERPOLATE_LOCAL,
1415		CASE_INTERPOLATE_GLOBAL,
1416		CASE_INTERPOLATE_CONSTANT,
1417
1418		CASE_LAST
1419	};
1420	enum InterpolatorType
1421	{
1422		INTERPOLATE_AT_SAMPLE = 0,
1423		INTERPOLATE_AT_CENTROID,
1424		INTERPOLATE_AT_OFFSET,
1425
1426		INTERPOLATE_LAST
1427	};
1428
1429							NegativeCompileInterpolationCase	(Context& context, const char* name, const char* description, CaseType caseType, InterpolatorType interpolator);
1430
1431private:
1432	void					init								(void);
1433	IterateResult			iterate								(void);
1434
1435	std::string				genShaderSource						(void) const;
1436
1437	const CaseType			m_caseType;
1438	const InterpolatorType	m_interpolation;
1439};
1440
1441NegativeCompileInterpolationCase::NegativeCompileInterpolationCase (Context& context, const char* name, const char* description, CaseType caseType, InterpolatorType interpolator)
1442	: TestCase			(context, name, description)
1443	, m_caseType		(caseType)
1444	, m_interpolation	(interpolator)
1445{
1446	DE_ASSERT(m_caseType < CASE_LAST);
1447	DE_ASSERT(m_interpolation < INTERPOLATE_LAST);
1448}
1449
1450void NegativeCompileInterpolationCase::init (void)
1451{
1452	if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation"))
1453		TCU_THROW(NotSupportedError, "Test requires GL_OES_shader_multisample_interpolation extension");
1454
1455	m_testCtx.getLog() << tcu::TestLog::Message << "Trying to compile illegal shader, expecting compile to fail." << tcu::TestLog::EndMessage;
1456}
1457
1458NegativeCompileInterpolationCase::IterateResult NegativeCompileInterpolationCase::iterate (void)
1459{
1460	const std::string	source			= genShaderSource();
1461	glu::Shader			shader			(m_context.getRenderContext(), glu::SHADERTYPE_FRAGMENT);
1462	const char* const	sourceStrPtr	= source.c_str();
1463
1464	m_testCtx.getLog()	<< tcu::TestLog::Message
1465						<< "Fragment shader source:"
1466						<< tcu::TestLog::EndMessage
1467						<< tcu::TestLog::KernelSource(source);
1468
1469	shader.setSources(1, &sourceStrPtr, DE_NULL);
1470	shader.compile();
1471
1472	m_testCtx.getLog()	<< tcu::TestLog::Message
1473						<< "Info log:"
1474						<< tcu::TestLog::EndMessage
1475						<< tcu::TestLog::KernelSource(shader.getInfoLog());
1476
1477	if (shader.getCompileStatus())
1478	{
1479		m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: Illegal shader compiled successfully." << tcu::TestLog::EndMessage;
1480		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Unexpected compile status");
1481	}
1482	else
1483	{
1484		m_testCtx.getLog() << tcu::TestLog::Message << "Compile failed as expected." << tcu::TestLog::EndMessage;
1485		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1486	}
1487	return STOP;
1488}
1489
1490std::string NegativeCompileInterpolationCase::genShaderSource (void) const
1491{
1492	std::ostringstream	buf;
1493	std::string			interpolation;
1494	const char*			interpolationTemplate;
1495	const char*			description;
1496	const char*			globalDeclarations		= "";
1497	const char*			localDeclarations		= "";
1498	const char*			interpolationTarget		= "";
1499	const char*			postSelector			= "";
1500
1501	switch (m_caseType)
1502	{
1503		case CASE_VEC4_IDENTITY_SWIZZLE:
1504			globalDeclarations	= "in highp vec4 v_var;\n";
1505			interpolationTarget	= "v_var.xyzw";
1506			description			= "component selection is illegal";
1507			break;
1508
1509		case CASE_VEC4_CROP_SWIZZLE:
1510			globalDeclarations	= "in highp vec4 v_var;\n";
1511			interpolationTarget	= "v_var.xy";
1512			postSelector		= ".x";
1513			description			= "component selection is illegal";
1514			break;
1515
1516		case CASE_VEC4_MIXED_SWIZZLE:
1517			globalDeclarations	= "in highp vec4 v_var;\n";
1518			interpolationTarget	= "v_var.yzxw";
1519			description			= "component selection is illegal";
1520			break;
1521
1522		case CASE_INTERPOLATE_IVEC4:
1523			globalDeclarations	= "flat in highp ivec4 v_var;\n";
1524			interpolationTarget	= "v_var";
1525			description			= "no overload for ivec";
1526			break;
1527
1528		case CASE_INTERPOLATE_UVEC4:
1529			globalDeclarations	= "flat in highp uvec4 v_var;\n";
1530			interpolationTarget	= "v_var";
1531			description			= "no overload for uvec";
1532			break;
1533
1534		case CASE_INTERPOLATE_ARRAY:
1535			globalDeclarations	= "in highp float v_var[2];\n";
1536			interpolationTarget	= "v_var";
1537			postSelector		= "[1]";
1538			description			= "no overload for arrays";
1539			break;
1540
1541		case CASE_INTERPOLATE_STRUCT:
1542		case CASE_INTERPOLATE_STRUCT_MEMBER:
1543			globalDeclarations	=	"struct S\n"
1544									"{\n"
1545									"	highp float a;\n"
1546									"	highp float b;\n"
1547									"};\n"
1548									"in S v_var;\n";
1549
1550			interpolationTarget	= (m_caseType == CASE_INTERPOLATE_STRUCT) ? ("v_var")						: ("v_var.a");
1551			postSelector		= (m_caseType == CASE_INTERPOLATE_STRUCT) ? (".a")							: ("");
1552			description			= (m_caseType == CASE_INTERPOLATE_STRUCT) ? ("no overload for this type")	: ("<interpolant> is not an input variable (just a member of)");
1553			break;
1554
1555		case CASE_INTERPOLATE_LOCAL:
1556			localDeclarations	= "	highp vec4 local_var = gl_FragCoord;\n";
1557			interpolationTarget	= "local_var";
1558			description			= "<interpolant> is not an input variable";
1559			break;
1560
1561		case CASE_INTERPOLATE_GLOBAL:
1562			globalDeclarations	= "highp vec4 global_var;\n";
1563			localDeclarations	= "	global_var = gl_FragCoord;\n";
1564			interpolationTarget	= "global_var";
1565			description			= "<interpolant> is not an input variable";
1566			break;
1567
1568		case CASE_INTERPOLATE_CONSTANT:
1569			globalDeclarations	= "const highp vec4 const_var = vec4(0.2);\n";
1570			interpolationTarget	= "const_var";
1571			description			= "<interpolant> is not an input variable";
1572			break;
1573
1574		default:
1575			DE_ASSERT(false);
1576			return "";
1577	}
1578
1579	switch (m_interpolation)
1580	{
1581		case INTERPOLATE_AT_SAMPLE:
1582			interpolationTemplate = "interpolateAtSample(${TARGET}, 0)${POST_SELECTOR}";
1583			break;
1584
1585		case INTERPOLATE_AT_CENTROID:
1586			interpolationTemplate = "interpolateAtCentroid(${TARGET})${POST_SELECTOR}";
1587			break;
1588
1589		case INTERPOLATE_AT_OFFSET:
1590			interpolationTemplate = "interpolateAtOffset(${TARGET}, vec2(0.2, 0.2))${POST_SELECTOR}";
1591			break;
1592
1593		default:
1594			DE_ASSERT(false);
1595			return "";
1596	}
1597
1598	{
1599		std::map<std::string, std::string> args;
1600		args["TARGET"] = interpolationTarget;
1601		args["POST_SELECTOR"] = postSelector;
1602
1603		interpolation = tcu::StringTemplate(interpolationTemplate).specialize(args);
1604	}
1605
1606	buf <<	"#version 310 es\n"
1607			"#extension GL_OES_shader_multisample_interpolation : require\n"
1608		<<	globalDeclarations
1609		<<	"layout(location = 0) out mediump vec4 fragColor;\n"
1610			"void main (void)\n"
1611			"{\n"
1612		<<	localDeclarations
1613		<<	"	fragColor = vec4(" << interpolation << "); // " << description << "\n"
1614			"}\n";
1615
1616	return buf.str();
1617}
1618
1619} // anonymous
1620
1621ShaderMultisampleInterpolationTests::ShaderMultisampleInterpolationTests (Context& context)
1622	: TestCaseGroup(context, "multisample_interpolation", "Test multisample interpolation")
1623{
1624}
1625
1626ShaderMultisampleInterpolationTests::~ShaderMultisampleInterpolationTests (void)
1627{
1628}
1629
1630void ShaderMultisampleInterpolationTests::init (void)
1631{
1632	using namespace MultisampleShaderRenderUtil;
1633
1634	static const struct RenderTarget
1635	{
1636		const char*							name;
1637		const char*							desc;
1638		int									numSamples;
1639		MultisampleRenderCase::RenderTarget	target;
1640	} targets[] =
1641	{
1642		{ "default_framebuffer",		"Test with default framebuffer",	0,	MultisampleRenderCase::TARGET_DEFAULT		},
1643		{ "singlesample_texture",		"Test with singlesample texture",	0,	MultisampleRenderCase::TARGET_TEXTURE		},
1644		{ "multisample_texture_1",		"Test with multisample texture",	1,	MultisampleRenderCase::TARGET_TEXTURE		},
1645		{ "multisample_texture_2",		"Test with multisample texture",	2,	MultisampleRenderCase::TARGET_TEXTURE		},
1646		{ "multisample_texture_4",		"Test with multisample texture",	4,	MultisampleRenderCase::TARGET_TEXTURE		},
1647		{ "multisample_texture_8",		"Test with multisample texture",	8,	MultisampleRenderCase::TARGET_TEXTURE		},
1648		{ "multisample_texture_16",		"Test with multisample texture",	16,	MultisampleRenderCase::TARGET_TEXTURE		},
1649		{ "singlesample_rbo",			"Test with singlesample rbo",		0,	MultisampleRenderCase::TARGET_RENDERBUFFER	},
1650		{ "multisample_rbo_1",			"Test with multisample rbo",		1,	MultisampleRenderCase::TARGET_RENDERBUFFER	},
1651		{ "multisample_rbo_2",			"Test with multisample rbo",		2,	MultisampleRenderCase::TARGET_RENDERBUFFER	},
1652		{ "multisample_rbo_4",			"Test with multisample rbo",		4,	MultisampleRenderCase::TARGET_RENDERBUFFER	},
1653		{ "multisample_rbo_8",			"Test with multisample rbo",		8,	MultisampleRenderCase::TARGET_RENDERBUFFER	},
1654		{ "multisample_rbo_16",			"Test with multisample rbo",		16,	MultisampleRenderCase::TARGET_RENDERBUFFER	},
1655	};
1656
1657	static const struct
1658	{
1659		const char*									name;
1660		const char*									description;
1661		NegativeCompileInterpolationCase::CaseType	caseType;
1662	} negativeCompileCases[] =
1663	{
1664		{ "vec4_identity_swizzle",		"use identity swizzle",				NegativeCompileInterpolationCase::CASE_VEC4_IDENTITY_SWIZZLE		},
1665		{ "vec4_crop_swizzle",			"use cropped identity swizzle",		NegativeCompileInterpolationCase::CASE_VEC4_CROP_SWIZZLE			},
1666		{ "vec4_mixed_swizzle",			"use swizzle",						NegativeCompileInterpolationCase::CASE_VEC4_MIXED_SWIZZLE			},
1667		{ "interpolate_ivec4",			"interpolate integer variable",		NegativeCompileInterpolationCase::CASE_INTERPOLATE_IVEC4			},
1668		{ "interpolate_uvec4",			"interpolate integer variable",		NegativeCompileInterpolationCase::CASE_INTERPOLATE_UVEC4			},
1669		{ "interpolate_array",			"interpolate whole array",			NegativeCompileInterpolationCase::CASE_INTERPOLATE_ARRAY			},
1670		{ "interpolate_struct",			"interpolate whole struct",			NegativeCompileInterpolationCase::CASE_INTERPOLATE_STRUCT			},
1671		{ "interpolate_struct_member",	"interpolate struct member",		NegativeCompileInterpolationCase::CASE_INTERPOLATE_STRUCT_MEMBER	},
1672		{ "interpolate_local",			"interpolate local variable",		NegativeCompileInterpolationCase::CASE_INTERPOLATE_LOCAL			},
1673		{ "interpolate_global",			"interpolate global variable",		NegativeCompileInterpolationCase::CASE_INTERPOLATE_GLOBAL			},
1674		{ "interpolate_constant",		"interpolate constant variable",	NegativeCompileInterpolationCase::CASE_INTERPOLATE_CONSTANT			},
1675	};
1676
1677	// .sample_qualifier
1678	{
1679		tcu::TestCaseGroup* const sampleQualifierGroup = new tcu::TestCaseGroup(m_testCtx, "sample_qualifier", "Test sample qualifier");
1680		addChild(sampleQualifierGroup);
1681
1682		for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
1683			sampleQualifierGroup->addChild(new SampleQualifierRenderCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target));
1684	}
1685
1686	// .interpolate_at_sample
1687	{
1688		tcu::TestCaseGroup* const interpolateAtSampleGroup = new tcu::TestCaseGroup(m_testCtx, "interpolate_at_sample", "Test interpolateAtSample");
1689		addChild(interpolateAtSampleGroup);
1690
1691		// .static_sample_number
1692		{
1693			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "static_sample_number", "Test interpolateAtSample sample number");
1694			interpolateAtSampleGroup->addChild(group);
1695
1696			for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
1697				group->addChild(new InterpolateAtSampleRenderCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, InterpolateAtSampleRenderCase::INDEXING_STATIC));
1698		}
1699
1700		// .dynamic_sample_number
1701		{
1702			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "dynamic_sample_number", "Test interpolateAtSample sample number");
1703			interpolateAtSampleGroup->addChild(group);
1704
1705			for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
1706				group->addChild(new InterpolateAtSampleRenderCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, InterpolateAtSampleRenderCase::INDEXING_DYNAMIC));
1707		}
1708
1709		// .non_multisample_buffer
1710		{
1711			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "non_multisample_buffer", "Test interpolateAtSample with non-multisample buffers");
1712			interpolateAtSampleGroup->addChild(group);
1713
1714			for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
1715				if (targets[targetNdx].numSamples == 0)
1716					group->addChild(new SingleSampleInterpolateAtSampleCase(m_context, std::string("sample_0_").append(targets[targetNdx].name).c_str(), targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SingleSampleInterpolateAtSampleCase::SAMPLE_0));
1717
1718			for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
1719				if (targets[targetNdx].numSamples == 0)
1720					group->addChild(new SingleSampleInterpolateAtSampleCase(m_context, std::string("sample_n_").append(targets[targetNdx].name).c_str(), targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SingleSampleInterpolateAtSampleCase::SAMPLE_N));
1721		}
1722
1723		// .centroid_qualifier
1724		{
1725			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "centroid_qualified", "Test interpolateAtSample with centroid qualified varying");
1726			interpolateAtSampleGroup->addChild(group);
1727
1728			for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
1729				group->addChild(new CentroidQualifierAtSampleCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target));
1730		}
1731
1732		// .at_sample_id
1733		{
1734			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "at_sample_id", "Test interpolateAtSample at current sample id");
1735			interpolateAtSampleGroup->addChild(group);
1736
1737			for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
1738				group->addChild(new InterpolateAtSampleIDCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target));
1739		}
1740
1741		// .negative
1742		{
1743			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "negative", "interpolateAtSample negative tests");
1744			interpolateAtSampleGroup->addChild(group);
1745
1746			for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(negativeCompileCases); ++ndx)
1747				group->addChild(new NegativeCompileInterpolationCase(m_context,
1748																	 negativeCompileCases[ndx].name,
1749																	 negativeCompileCases[ndx].description,
1750																	 negativeCompileCases[ndx].caseType,
1751																	 NegativeCompileInterpolationCase::INTERPOLATE_AT_SAMPLE));
1752		}
1753	}
1754
1755	// .interpolate_at_centroid
1756	{
1757		tcu::TestCaseGroup* const methodGroup = new tcu::TestCaseGroup(m_testCtx, "interpolate_at_centroid", "Test interpolateAtCentroid");
1758		addChild(methodGroup);
1759
1760		// .consistency
1761		{
1762			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "consistency", "Test interpolateAtCentroid return value is consistent to centroid qualified value");
1763			methodGroup->addChild(group);
1764
1765			for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
1766				group->addChild(new InterpolateAtCentroidCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, InterpolateAtCentroidCase::TEST_CONSISTENCY));
1767		}
1768
1769		// .array_element
1770		{
1771			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "array_element", "Test interpolateAtCentroid with array element");
1772			methodGroup->addChild(group);
1773
1774			for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
1775				group->addChild(new InterpolateAtCentroidCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, InterpolateAtCentroidCase::TEST_ARRAY_ELEMENT));
1776		}
1777
1778		// .negative
1779		{
1780			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "negative", "interpolateAtCentroid negative tests");
1781			methodGroup->addChild(group);
1782
1783			for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(negativeCompileCases); ++ndx)
1784				group->addChild(new NegativeCompileInterpolationCase(m_context,
1785																	 negativeCompileCases[ndx].name,
1786																	 negativeCompileCases[ndx].description,
1787																	 negativeCompileCases[ndx].caseType,
1788																	 NegativeCompileInterpolationCase::INTERPOLATE_AT_CENTROID));
1789		}
1790	}
1791
1792	// .interpolate_at_offset
1793	{
1794		static const struct TestConfig
1795		{
1796			const char*							name;
1797			InterpolateAtOffsetCase::TestType	type;
1798		} configs[] =
1799		{
1800			{ "no_qualifiers",		InterpolateAtOffsetCase::TEST_QUALIFIER_NONE		},
1801			{ "centroid_qualifier",	InterpolateAtOffsetCase::TEST_QUALIFIER_CENTROID	},
1802			{ "sample_qualifier",	InterpolateAtOffsetCase::TEST_QUALIFIER_SAMPLE		},
1803		};
1804
1805		tcu::TestCaseGroup* const methodGroup = new tcu::TestCaseGroup(m_testCtx, "interpolate_at_offset", "Test interpolateAtOffset");
1806		addChild(methodGroup);
1807
1808		// .no_qualifiers
1809		// .centroid_qualifier
1810		// .sample_qualifier
1811		for (int configNdx = 0; configNdx < DE_LENGTH_OF_ARRAY(configs); ++configNdx)
1812		{
1813			tcu::TestCaseGroup* const qualifierGroup = new tcu::TestCaseGroup(m_testCtx, configs[configNdx].name, "Test interpolateAtOffset with qualified/non-qualified varying");
1814			methodGroup->addChild(qualifierGroup);
1815
1816			for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
1817				qualifierGroup->addChild(new InterpolateAtOffsetCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, configs[configNdx].type));
1818		}
1819
1820		// .at_sample_position
1821		{
1822			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "at_sample_position", "Test interpolateAtOffset at sample position");
1823			methodGroup->addChild(group);
1824
1825			for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
1826				group->addChild(new InterpolateAtSamplePositionCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target));
1827		}
1828
1829		// .array_element
1830		{
1831			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "array_element", "Test interpolateAtOffset with array element");
1832			methodGroup->addChild(group);
1833
1834			for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
1835				group->addChild(new InterpolateAtOffsetCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, InterpolateAtOffsetCase::TEST_ARRAY_ELEMENT));
1836		}
1837
1838		// .negative
1839		{
1840			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "negative", "interpolateAtOffset negative tests");
1841			methodGroup->addChild(group);
1842
1843			for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(negativeCompileCases); ++ndx)
1844				group->addChild(new NegativeCompileInterpolationCase(m_context,
1845																	 negativeCompileCases[ndx].name,
1846																	 negativeCompileCases[ndx].description,
1847																	 negativeCompileCases[ndx].caseType,
1848																	 NegativeCompileInterpolationCase::INTERPOLATE_AT_OFFSET));
1849		}
1850	}
1851}
1852
1853} // Functional
1854} // gles31
1855} // deqp
1856