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