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