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