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 Opaque type (sampler, buffer, atomic counter, ...) indexing tests.
     22  *
     23  * \todo [2014-03-05 pyry] Extend with following:
     24  *  + sampler: different filtering modes, multiple sizes, incomplete textures
     25  *  + SSBO: write, atomic op, unsized array .length()
     26  *//*--------------------------------------------------------------------*/
     27 
     28 #include "es31fOpaqueTypeIndexingTests.hpp"
     29 #include "tcuTexture.hpp"
     30 #include "tcuTestLog.hpp"
     31 #include "tcuFormatUtil.hpp"
     32 #include "tcuVectorUtil.hpp"
     33 #include "gluShaderUtil.hpp"
     34 #include "gluShaderProgram.hpp"
     35 #include "gluObjectWrapper.hpp"
     36 #include "gluTextureUtil.hpp"
     37 #include "gluRenderContext.hpp"
     38 #include "gluProgramInterfaceQuery.hpp"
     39 #include "gluContextInfo.hpp"
     40 #include "glsShaderExecUtil.hpp"
     41 #include "glwFunctions.hpp"
     42 #include "glwEnums.hpp"
     43 #include "deUniquePtr.hpp"
     44 #include "deStringUtil.hpp"
     45 #include "deRandom.hpp"
     46 
     47 #include <sstream>
     48 
     49 namespace deqp
     50 {
     51 namespace gles31
     52 {
     53 namespace Functional
     54 {
     55 
     56 namespace
     57 {
     58 
     59 using namespace gls::ShaderExecUtil;
     60 using namespace glu;
     61 using std::string;
     62 using std::vector;
     63 using tcu::TextureFormat;
     64 using tcu::TestLog;
     65 
     66 typedef de::UniquePtr<ShaderExecutor> ShaderExecutorPtr;
     67 
     68 enum IndexExprType
     69 {
     70 	INDEX_EXPR_TYPE_CONST_LITERAL	= 0,
     71 	INDEX_EXPR_TYPE_CONST_EXPRESSION,
     72 	INDEX_EXPR_TYPE_UNIFORM,
     73 	INDEX_EXPR_TYPE_DYNAMIC_UNIFORM,
     74 
     75 	INDEX_EXPR_TYPE_LAST
     76 };
     77 
     78 enum TextureType
     79 {
     80 	TEXTURE_TYPE_1D = 0,
     81 	TEXTURE_TYPE_2D,
     82 	TEXTURE_TYPE_CUBE,
     83 	TEXTURE_TYPE_2D_ARRAY,
     84 	TEXTURE_TYPE_3D,
     85 
     86 	TEXTURE_TYPE_LAST
     87 };
     88 
     89 static void declareUniformIndexVars (std::ostream& str, const char* varPrefix, int numVars)
     90 {
     91 	for (int varNdx = 0; varNdx < numVars; varNdx++)
     92 		str << "uniform highp int " << varPrefix << varNdx << ";\n";
     93 }
     94 
     95 static void uploadUniformIndices (const glw::Functions& gl, deUint32 program, const char* varPrefix, int numIndices, const int* indices)
     96 {
     97 	for (int varNdx = 0; varNdx < numIndices; varNdx++)
     98 	{
     99 		const string	varName		= varPrefix + de::toString(varNdx);
    100 		const int		loc			= gl.getUniformLocation(program, varName.c_str());
    101 		TCU_CHECK_MSG(loc >= 0, ("No location assigned for uniform '" + varName + "'").c_str());
    102 
    103 		gl.uniform1i(loc, indices[varNdx]);
    104 	}
    105 }
    106 
    107 template<typename T>
    108 static T maxElement (const std::vector<T>& elements)
    109 {
    110 	T maxElem = elements[0];
    111 
    112 	for (size_t ndx = 1; ndx < elements.size(); ndx++)
    113 		maxElem = de::max(maxElem, elements[ndx]);
    114 
    115 	return maxElem;
    116 }
    117 
    118 static TextureType getTextureType (glu::DataType samplerType)
    119 {
    120 	switch (samplerType)
    121 	{
    122 		case glu::TYPE_SAMPLER_1D:
    123 		case glu::TYPE_INT_SAMPLER_1D:
    124 		case glu::TYPE_UINT_SAMPLER_1D:
    125 		case glu::TYPE_SAMPLER_1D_SHADOW:
    126 			return TEXTURE_TYPE_1D;
    127 
    128 		case glu::TYPE_SAMPLER_2D:
    129 		case glu::TYPE_INT_SAMPLER_2D:
    130 		case glu::TYPE_UINT_SAMPLER_2D:
    131 		case glu::TYPE_SAMPLER_2D_SHADOW:
    132 			return TEXTURE_TYPE_2D;
    133 
    134 		case glu::TYPE_SAMPLER_CUBE:
    135 		case glu::TYPE_INT_SAMPLER_CUBE:
    136 		case glu::TYPE_UINT_SAMPLER_CUBE:
    137 		case glu::TYPE_SAMPLER_CUBE_SHADOW:
    138 			return TEXTURE_TYPE_CUBE;
    139 
    140 		case glu::TYPE_SAMPLER_2D_ARRAY:
    141 		case glu::TYPE_INT_SAMPLER_2D_ARRAY:
    142 		case glu::TYPE_UINT_SAMPLER_2D_ARRAY:
    143 		case glu::TYPE_SAMPLER_2D_ARRAY_SHADOW:
    144 			return TEXTURE_TYPE_2D_ARRAY;
    145 
    146 		case glu::TYPE_SAMPLER_3D:
    147 		case glu::TYPE_INT_SAMPLER_3D:
    148 		case glu::TYPE_UINT_SAMPLER_3D:
    149 			return TEXTURE_TYPE_3D;
    150 
    151 		default:
    152 			throw tcu::InternalError("Invalid sampler type");
    153 	}
    154 }
    155 
    156 static bool isShadowSampler (glu::DataType samplerType)
    157 {
    158 	return samplerType == glu::TYPE_SAMPLER_1D_SHADOW		||
    159 		   samplerType == glu::TYPE_SAMPLER_2D_SHADOW		||
    160 		   samplerType == glu::TYPE_SAMPLER_2D_ARRAY_SHADOW	||
    161 		   samplerType == glu::TYPE_SAMPLER_CUBE_SHADOW;
    162 }
    163 
    164 static glu::DataType getSamplerOutputType (glu::DataType samplerType)
    165 {
    166 	switch (samplerType)
    167 	{
    168 		case glu::TYPE_SAMPLER_1D:
    169 		case glu::TYPE_SAMPLER_2D:
    170 		case glu::TYPE_SAMPLER_CUBE:
    171 		case glu::TYPE_SAMPLER_2D_ARRAY:
    172 		case glu::TYPE_SAMPLER_3D:
    173 			return glu::TYPE_FLOAT_VEC4;
    174 
    175 		case glu::TYPE_SAMPLER_1D_SHADOW:
    176 		case glu::TYPE_SAMPLER_2D_SHADOW:
    177 		case glu::TYPE_SAMPLER_CUBE_SHADOW:
    178 		case glu::TYPE_SAMPLER_2D_ARRAY_SHADOW:
    179 			return glu::TYPE_FLOAT;
    180 
    181 		case glu::TYPE_INT_SAMPLER_1D:
    182 		case glu::TYPE_INT_SAMPLER_2D:
    183 		case glu::TYPE_INT_SAMPLER_CUBE:
    184 		case glu::TYPE_INT_SAMPLER_2D_ARRAY:
    185 		case glu::TYPE_INT_SAMPLER_3D:
    186 			return glu::TYPE_INT_VEC4;
    187 
    188 		case glu::TYPE_UINT_SAMPLER_1D:
    189 		case glu::TYPE_UINT_SAMPLER_2D:
    190 		case glu::TYPE_UINT_SAMPLER_CUBE:
    191 		case glu::TYPE_UINT_SAMPLER_2D_ARRAY:
    192 		case glu::TYPE_UINT_SAMPLER_3D:
    193 			return glu::TYPE_UINT_VEC4;
    194 
    195 		default:
    196 			throw tcu::InternalError("Invalid sampler type");
    197 	}
    198 }
    199 
    200 static tcu::TextureFormat getSamplerTextureFormat (glu::DataType samplerType)
    201 {
    202 	const glu::DataType		outType			= getSamplerOutputType(samplerType);
    203 	const glu::DataType		outScalarType	= glu::getDataTypeScalarType(outType);
    204 
    205 	switch (outScalarType)
    206 	{
    207 		case glu::TYPE_FLOAT:
    208 			if (isShadowSampler(samplerType))
    209 				return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT16);
    210 			else
    211 				return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
    212 
    213 		case glu::TYPE_INT:		return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT8);
    214 		case glu::TYPE_UINT:	return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT8);
    215 
    216 		default:
    217 			throw tcu::InternalError("Invalid sampler type");
    218 	}
    219 }
    220 
    221 static glu::DataType getSamplerCoordType (glu::DataType samplerType)
    222 {
    223 	const TextureType	texType		= getTextureType(samplerType);
    224 	int					numCoords	= 0;
    225 
    226 	switch (texType)
    227 	{
    228 		case TEXTURE_TYPE_1D:		numCoords = 1;	break;
    229 		case TEXTURE_TYPE_2D:		numCoords = 2;	break;
    230 		case TEXTURE_TYPE_2D_ARRAY:	numCoords = 3;	break;
    231 		case TEXTURE_TYPE_CUBE:		numCoords = 3;	break;
    232 		case TEXTURE_TYPE_3D:		numCoords = 3;	break;
    233 		default:
    234 			DE_ASSERT(false);
    235 	}
    236 
    237 	if (isShadowSampler(samplerType))
    238 		numCoords += 1;
    239 
    240 	DE_ASSERT(de::inRange(numCoords, 1, 4));
    241 
    242 	return numCoords == 1 ? glu::TYPE_FLOAT : glu::getDataTypeFloatVec(numCoords);
    243 }
    244 
    245 static deUint32 getGLTextureTarget (TextureType texType)
    246 {
    247 	switch (texType)
    248 	{
    249 		case TEXTURE_TYPE_1D:		return GL_TEXTURE_1D;
    250 		case TEXTURE_TYPE_2D:		return GL_TEXTURE_2D;
    251 		case TEXTURE_TYPE_2D_ARRAY:	return GL_TEXTURE_2D_ARRAY;
    252 		case TEXTURE_TYPE_CUBE:		return GL_TEXTURE_CUBE_MAP;
    253 		case TEXTURE_TYPE_3D:		return GL_TEXTURE_3D;
    254 		default:
    255 			DE_ASSERT(false);
    256 			return 0;
    257 	}
    258 }
    259 
    260 static void setupTexture (const glw::Functions&	gl,
    261 						  deUint32				texture,
    262 						  glu::DataType			samplerType,
    263 						  tcu::TextureFormat	texFormat,
    264 						  const void*			color)
    265 {
    266 	const TextureType			texType		= getTextureType(samplerType);
    267 	const deUint32				texTarget	= getGLTextureTarget(texType);
    268 	const deUint32				intFormat	= glu::getInternalFormat(texFormat);
    269 	const glu::TransferFormat	transferFmt	= glu::getTransferFormat(texFormat);
    270 
    271 	// \todo [2014-03-04 pyry] Use larger than 1x1 textures?
    272 
    273 	gl.bindTexture(texTarget, texture);
    274 
    275 	switch (texType)
    276 	{
    277 		case TEXTURE_TYPE_1D:
    278 			gl.texStorage1D(texTarget, 1, intFormat, 1);
    279 			gl.texSubImage1D(texTarget, 0, 0, 1, transferFmt.format, transferFmt.dataType, color);
    280 			break;
    281 
    282 		case TEXTURE_TYPE_2D:
    283 			gl.texStorage2D(texTarget, 1, intFormat, 1, 1);
    284 			gl.texSubImage2D(texTarget, 0, 0, 0, 1, 1, transferFmt.format, transferFmt.dataType, color);
    285 			break;
    286 
    287 		case TEXTURE_TYPE_2D_ARRAY:
    288 		case TEXTURE_TYPE_3D:
    289 			gl.texStorage3D(texTarget, 1, intFormat, 1, 1, 1);
    290 			gl.texSubImage3D(texTarget, 0, 0, 0, 0, 1, 1, 1, transferFmt.format, transferFmt.dataType, color);
    291 			break;
    292 
    293 		case TEXTURE_TYPE_CUBE:
    294 			gl.texStorage2D(texTarget, 1, intFormat, 1, 1);
    295 			for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
    296 				gl.texSubImage2D(glu::getGLCubeFace((tcu::CubeFace)face), 0, 0, 0, 1, 1, transferFmt.format, transferFmt.dataType, color);
    297 			break;
    298 
    299 		default:
    300 			DE_ASSERT(false);
    301 	}
    302 
    303 	gl.texParameteri(texTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    304 	gl.texParameteri(texTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    305 
    306 	if (isShadowSampler(samplerType))
    307 		gl.texParameteri(texTarget, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
    308 
    309 	GLU_EXPECT_NO_ERROR(gl.getError(), "Texture setup failed");
    310 }
    311 
    312 class SamplerIndexingCase : public TestCase
    313 {
    314 public:
    315 							SamplerIndexingCase			(Context& context, const char* name, const char* description, glu::ShaderType shaderType, glu::DataType samplerType, IndexExprType indexExprType);
    316 							~SamplerIndexingCase		(void);
    317 
    318 	void					init						(void);
    319 	IterateResult			iterate						(void);
    320 
    321 private:
    322 							SamplerIndexingCase			(const SamplerIndexingCase&);
    323 	SamplerIndexingCase&	operator=					(const SamplerIndexingCase&);
    324 
    325 	void					getShaderSpec				(ShaderSpec* spec, int numSamplers, int numLookups, const int* lookupIndices) const;
    326 
    327 	const glu::ShaderType	m_shaderType;
    328 	const glu::DataType		m_samplerType;
    329 	const IndexExprType		m_indexExprType;
    330 };
    331 
    332 SamplerIndexingCase::SamplerIndexingCase (Context& context, const char* name, const char* description, glu::ShaderType shaderType, glu::DataType samplerType, IndexExprType indexExprType)
    333 	: TestCase			(context, name, description)
    334 	, m_shaderType		(shaderType)
    335 	, m_samplerType		(samplerType)
    336 	, m_indexExprType	(indexExprType)
    337 {
    338 }
    339 
    340 SamplerIndexingCase::~SamplerIndexingCase (void)
    341 {
    342 }
    343 
    344 void SamplerIndexingCase::init (void)
    345 {
    346 	const char* extName = "GL_EXT_gpu_shader5";
    347 
    348 	if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL &&
    349 		!m_context.getContextInfo().isExtensionSupported(extName))
    350 		throw tcu::NotSupportedError(string(extName) + " extension is required for dynamic indexing of sampler arrays");
    351 }
    352 
    353 void SamplerIndexingCase::getShaderSpec (ShaderSpec* spec, int numSamplers, int numLookups, const int* lookupIndices) const
    354 {
    355 	const char*			samplersName	= "sampler";
    356 	const char*			coordsName		= "coords";
    357 	const char*			indicesPrefix	= "index";
    358 	const char*			resultPrefix	= "result";
    359 	const DataType		coordType		= getSamplerCoordType(m_samplerType);
    360 	const DataType		outType			= getSamplerOutputType(m_samplerType);
    361 	std::ostringstream	global, code;
    362 
    363 	spec->inputs.push_back(Symbol(coordsName, VarType(coordType, PRECISION_HIGHP)));
    364 
    365 	if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL)
    366 		global << "#extension GL_EXT_gpu_shader5 : require\n";
    367 
    368 	if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
    369 		global << "const highp int indexBase = 1;\n";
    370 
    371 	global <<
    372 		"uniform highp " << getDataTypeName(m_samplerType) << " " << samplersName << "[" << numSamplers << "];\n";
    373 
    374 	if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM)
    375 	{
    376 		for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
    377 		{
    378 			const string varName = indicesPrefix + de::toString(lookupNdx);
    379 			spec->inputs.push_back(Symbol(varName, VarType(TYPE_INT, PRECISION_HIGHP)));
    380 		}
    381 	}
    382 	else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM)
    383 		declareUniformIndexVars(global, indicesPrefix, numLookups);
    384 
    385 	for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
    386 	{
    387 		const string varName = resultPrefix + de::toString(lookupNdx);
    388 		spec->outputs.push_back(Symbol(varName, VarType(outType, PRECISION_HIGHP)));
    389 	}
    390 
    391 	for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
    392 	{
    393 		code << resultPrefix << "" << lookupNdx << " = texture(" << samplersName << "[";
    394 
    395 		if (m_indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL)
    396 			code << lookupIndices[lookupNdx];
    397 		else if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
    398 			code << "indexBase + " << (lookupIndices[lookupNdx]-1);
    399 		else
    400 			code << indicesPrefix << lookupNdx;
    401 
    402 		code << "], " << coordsName << ");\n";
    403 	}
    404 
    405 	spec->version				= GLSL_VERSION_310_ES;
    406 	spec->globalDeclarations	= global.str();
    407 	spec->source				= code.str();
    408 }
    409 
    410 static void fillTextureData (const tcu::PixelBufferAccess& access, de::Random& rnd)
    411 {
    412 	DE_ASSERT(access.getHeight() == 1 && access.getDepth() == 1);
    413 
    414 	if (access.getFormat().order == TextureFormat::D)
    415 	{
    416 		// \note Texture uses odd values, lookup even values to avoid precision issues.
    417 		const float values[] = { 0.1f, 0.3f, 0.5f, 0.7f, 0.9f };
    418 
    419 		for (int ndx = 0; ndx < access.getWidth(); ndx++)
    420 			access.setPixDepth(rnd.choose<float>(DE_ARRAY_BEGIN(values), DE_ARRAY_END(values)), ndx, 0);
    421 	}
    422 	else
    423 	{
    424 		TCU_CHECK_INTERNAL(access.getFormat().order == TextureFormat::RGBA && access.getFormat().getPixelSize() == 4);
    425 
    426 		for (int ndx = 0; ndx < access.getWidth(); ndx++)
    427 			*((deUint32*)access.getDataPtr() + ndx) = rnd.getUint32();
    428 	}
    429 }
    430 
    431 SamplerIndexingCase::IterateResult SamplerIndexingCase::iterate (void)
    432 {
    433 	const int						numInvocations		= 64;
    434 	const int						numSamplers			= 8;
    435 	const int						numLookups			= 4;
    436 	const DataType					coordType			= getSamplerCoordType(m_samplerType);
    437 	const DataType					outputType			= getSamplerOutputType(m_samplerType);
    438 	const TextureFormat				texFormat			= getSamplerTextureFormat(m_samplerType);
    439 	const int						outLookupStride		= numInvocations*getDataTypeScalarSize(outputType);
    440 	vector<int>						lookupIndices		(numLookups);
    441 	vector<float>					coords;
    442 	vector<deUint32>				outData;
    443 	vector<deUint8>					texData				(numSamplers * texFormat.getPixelSize());
    444 	const tcu::PixelBufferAccess	refTexAccess		(texFormat, numSamplers, 1, 1, &texData[0]);
    445 	ShaderSpec						shaderSpec;
    446 	de::Random						rnd					(deInt32Hash(m_samplerType) ^ deInt32Hash(m_shaderType) ^ deInt32Hash(m_indexExprType));
    447 
    448 	for (int ndx = 0; ndx < numLookups; ndx++)
    449 		lookupIndices[ndx] = rnd.getInt(0, numSamplers-1);
    450 
    451 	getShaderSpec(&shaderSpec, numSamplers, numLookups, &lookupIndices[0]);
    452 
    453 	coords.resize(numInvocations * getDataTypeScalarSize(coordType));
    454 
    455 	if (isShadowSampler(m_samplerType))
    456 	{
    457 		// Use different comparison value per invocation.
    458 		// \note Texture uses odd values, comparison even values.
    459 		const int	numCoordComps	= getDataTypeScalarSize(coordType);
    460 		const float	cmpValues[]		= { 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f };
    461 
    462 		for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++)
    463 			coords[invocationNdx*numCoordComps + (numCoordComps-1)] = rnd.choose<float>(DE_ARRAY_BEGIN(cmpValues), DE_ARRAY_END(cmpValues));
    464 	}
    465 
    466 	fillTextureData(refTexAccess, rnd);
    467 
    468 	outData.resize(numLookups*outLookupStride);
    469 
    470 	{
    471 		const RenderContext&	renderCtx		= m_context.getRenderContext();
    472 		const glw::Functions&	gl				= renderCtx.getFunctions();
    473 		ShaderExecutorPtr		executor		(createExecutor(m_context.getRenderContext(), m_shaderType, shaderSpec));
    474 		TextureVector			textures		(renderCtx, numSamplers);
    475 		vector<void*>			inputs;
    476 		vector<void*>			outputs;
    477 		vector<int>				expandedIndices;
    478 		const int				maxIndex		= maxElement(lookupIndices);
    479 
    480 		m_testCtx.getLog() << *executor;
    481 
    482 		if (!executor->isOk())
    483 			TCU_FAIL("Compile failed");
    484 
    485 		executor->useProgram();
    486 
    487 		// \todo [2014-03-05 pyry] Do we want to randomize tex unit assignments?
    488 		for (int samplerNdx = 0; samplerNdx < numSamplers; samplerNdx++)
    489 		{
    490 			const string	samplerName	= string("sampler[") + de::toString(samplerNdx) + "]";
    491 			const int		samplerLoc	= gl.getUniformLocation(executor->getProgram(), samplerName.c_str());
    492 
    493 			if (samplerNdx > maxIndex && samplerLoc < 0)
    494 				continue; // Unused uniform eliminated by compiler
    495 
    496 			TCU_CHECK_MSG(samplerLoc >= 0, (string("No location for uniform '") + samplerName + "' found").c_str());
    497 
    498 			gl.activeTexture(GL_TEXTURE0 + samplerNdx);
    499 			setupTexture(gl, textures[samplerNdx], m_samplerType, texFormat, &texData[samplerNdx*texFormat.getPixelSize()]);
    500 
    501 			gl.uniform1i(samplerLoc, samplerNdx);
    502 		}
    503 
    504 		inputs.push_back(&coords[0]);
    505 
    506 		if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM)
    507 		{
    508 			expandedIndices.resize(numInvocations * lookupIndices.size());
    509 			for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
    510 			{
    511 				for (int invNdx = 0; invNdx < numInvocations; invNdx++)
    512 					expandedIndices[lookupNdx*numInvocations + invNdx] = lookupIndices[lookupNdx];
    513 			}
    514 
    515 			for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
    516 				inputs.push_back(&expandedIndices[lookupNdx*numInvocations]);
    517 		}
    518 		else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM)
    519 			uploadUniformIndices(gl, executor->getProgram(), "index", numLookups, &lookupIndices[0]);
    520 
    521 		for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
    522 			outputs.push_back(&outData[outLookupStride*lookupNdx]);
    523 
    524 		GLU_EXPECT_NO_ERROR(gl.getError(), "Setup failed");
    525 
    526 		executor->execute(numInvocations, &inputs[0], &outputs[0]);
    527 	}
    528 
    529 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    530 
    531 	if (isShadowSampler(m_samplerType))
    532 	{
    533 		const tcu::Sampler	refSampler		(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
    534 											 tcu::Sampler::NEAREST, tcu::Sampler::NEAREST, 0.0f, false /* non-normalized */,
    535 											 tcu::Sampler::COMPAREMODE_LESS);
    536 		const int			numCoordComps	= getDataTypeScalarSize(coordType);
    537 
    538 		TCU_CHECK_INTERNAL(getDataTypeScalarSize(outputType) == 1);
    539 
    540 		// Each invocation may have different results.
    541 		for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++)
    542 		{
    543 			const float	coord	= coords[invocationNdx*numCoordComps + (numCoordComps-1)];
    544 
    545 			for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
    546 			{
    547 				const int		texNdx		= lookupIndices[lookupNdx];
    548 				const float		result		= *((const float*)(const deUint8*)&outData[lookupNdx*outLookupStride + invocationNdx]);
    549 				const float		reference	= refTexAccess.sample2DCompare(refSampler, tcu::Sampler::NEAREST, coord, (float)texNdx, 0.0f, tcu::IVec3(0));
    550 
    551 				if (de::abs(result-reference) > 0.005f)
    552 				{
    553 					m_testCtx.getLog() << TestLog::Message << "ERROR: at invocation " << invocationNdx << ", lookup " << lookupNdx << ": expected "
    554 														   << reference << ", got " << result
    555 									   << TestLog::EndMessage;
    556 
    557 					if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
    558 						m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid lookup result");
    559 				}
    560 			}
    561 		}
    562 	}
    563 	else
    564 	{
    565 		TCU_CHECK_INTERNAL(getDataTypeScalarSize(outputType) == 4);
    566 
    567 		// Validate results from first invocation
    568 		for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
    569 		{
    570 			const int		texNdx	= lookupIndices[lookupNdx];
    571 			const deUint8*	resPtr	= (const deUint8*)&outData[lookupNdx*outLookupStride];
    572 			bool			isOk;
    573 
    574 			if (outputType == TYPE_FLOAT_VEC4)
    575 			{
    576 				const float			threshold		= 1.0f / 256.0f;
    577 				const tcu::Vec4		reference		= refTexAccess.getPixel(texNdx, 0);
    578 				const float*		floatPtr		= (const float*)resPtr;
    579 				const tcu::Vec4		result			(floatPtr[0], floatPtr[1], floatPtr[2], floatPtr[3]);
    580 
    581 				isOk = boolAll(lessThanEqual(abs(reference-result), tcu::Vec4(threshold)));
    582 
    583 				if (!isOk)
    584 				{
    585 					m_testCtx.getLog() << TestLog::Message << "ERROR: at lookup " << lookupNdx << ": expected "
    586 														   << reference << ", got " << result
    587 									   << TestLog::EndMessage;
    588 				}
    589 			}
    590 			else
    591 			{
    592 				const tcu::UVec4	reference		= refTexAccess.getPixelUint(texNdx, 0);
    593 				const deUint32*		uintPtr			= (const deUint32*)resPtr;
    594 				const tcu::UVec4	result			(uintPtr[0], uintPtr[1], uintPtr[2], uintPtr[3]);
    595 
    596 				isOk = boolAll(equal(reference, result));
    597 
    598 				if (!isOk)
    599 				{
    600 					m_testCtx.getLog() << TestLog::Message << "ERROR: at lookup " << lookupNdx << ": expected "
    601 														   << reference << ", got " << result
    602 									   << TestLog::EndMessage;
    603 				}
    604 			}
    605 
    606 			if (!isOk && m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
    607 				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid lookup result");
    608 		}
    609 
    610 		// Check results of other invocations against first one
    611 		for (int invocationNdx = 1; invocationNdx < numInvocations; invocationNdx++)
    612 		{
    613 			for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
    614 			{
    615 				const deUint32*		refPtr		= &outData[lookupNdx*outLookupStride];
    616 				const deUint32*		resPtr		= refPtr + invocationNdx*4;
    617 				bool				isOk		= true;
    618 
    619 				for (int ndx = 0; ndx < 4; ndx++)
    620 					isOk = isOk && (refPtr[ndx] == resPtr[ndx]);
    621 
    622 				if (!isOk)
    623 				{
    624 					m_testCtx.getLog() << TestLog::Message << "ERROR: invocation " << invocationNdx << " result "
    625 														   << tcu::formatArray(tcu::Format::HexIterator<deUint32>(resPtr), tcu::Format::HexIterator<deUint32>(resPtr+4))
    626 														   << " for lookup " << lookupNdx << " doesn't match result from first invocation "
    627 														   << tcu::formatArray(tcu::Format::HexIterator<deUint32>(refPtr), tcu::Format::HexIterator<deUint32>(refPtr+4))
    628 									   << TestLog::EndMessage;
    629 
    630 					if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
    631 						m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Inconsistent lookup results");
    632 				}
    633 			}
    634 		}
    635 	}
    636 
    637 	return STOP;
    638 }
    639 
    640 class BlockArrayIndexingCase : public TestCase
    641 {
    642 public:
    643 	enum BlockType
    644 	{
    645 		BLOCKTYPE_UNIFORM = 0,
    646 		BLOCKTYPE_BUFFER,
    647 
    648 		BLOCKTYPE_LAST
    649 	};
    650 								BlockArrayIndexingCase		(Context& context, const char* name, const char* description, BlockType blockType, IndexExprType indexExprType, ShaderType shaderType);
    651 								~BlockArrayIndexingCase		(void);
    652 
    653 	void						init						(void);
    654 	IterateResult				iterate						(void);
    655 
    656 private:
    657 								BlockArrayIndexingCase		(const BlockArrayIndexingCase&);
    658 	BlockArrayIndexingCase&		operator=					(const BlockArrayIndexingCase&);
    659 
    660 	void						getShaderSpec				(ShaderSpec* spec, int numInstances, int numReads, const int* readIndices) const;
    661 
    662 	const BlockType				m_blockType;
    663 	const IndexExprType			m_indexExprType;
    664 	const ShaderType			m_shaderType;
    665 
    666 	const int					m_numInstances;
    667 };
    668 
    669 BlockArrayIndexingCase::BlockArrayIndexingCase (Context& context, const char* name, const char* description, BlockType blockType, IndexExprType indexExprType, ShaderType shaderType)
    670 	: TestCase			(context, name, description)
    671 	, m_blockType		(blockType)
    672 	, m_indexExprType	(indexExprType)
    673 	, m_shaderType		(shaderType)
    674 	, m_numInstances	(4)
    675 {
    676 }
    677 
    678 BlockArrayIndexingCase::~BlockArrayIndexingCase (void)
    679 {
    680 }
    681 
    682 void BlockArrayIndexingCase::init (void)
    683 {
    684 	const char* extName = "GL_EXT_gpu_shader5";
    685 
    686 	if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL &&
    687 		!m_context.getContextInfo().isExtensionSupported(extName))
    688 		throw tcu::NotSupportedError(string(extName) + " extension is required for dynamic indexing of interface blocks");
    689 
    690 	if (m_blockType == BLOCKTYPE_BUFFER)
    691 	{
    692 		const deUint32 limitPnames[] =
    693 		{
    694 			GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS,
    695 			GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS,
    696 			GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS,
    697 			GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS,
    698 			GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS,
    699 			GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS
    700 		};
    701 
    702 		const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
    703 		int						maxBlocks	= 0;
    704 
    705 		gl.getIntegerv(limitPnames[m_shaderType], &maxBlocks);
    706 		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv()");
    707 
    708 		if (maxBlocks < m_numInstances)
    709 			throw tcu::NotSupportedError("Not enough shader storage blocks supported for shader type");
    710 	}
    711 }
    712 
    713 void BlockArrayIndexingCase::getShaderSpec (ShaderSpec* spec, int numInstances, int numReads, const int* readIndices) const
    714 {
    715 	const int			binding			= 2;
    716 	const char*			blockName		= "Block";
    717 	const char*			instanceName	= "block";
    718 	const char*			indicesPrefix	= "index";
    719 	const char*			resultPrefix	= "result";
    720 	const char*			interfaceName	= m_blockType == BLOCKTYPE_UNIFORM ? "uniform" : "buffer";
    721 	const char*			layout			= m_blockType == BLOCKTYPE_UNIFORM ? "std140" : "std430";
    722 	std::ostringstream	global, code;
    723 
    724 	if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL)
    725 		global << "#extension GL_EXT_gpu_shader5 : require\n";
    726 
    727 	if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
    728 		global << "const highp int indexBase = 1;\n";
    729 
    730 	global <<
    731 		"layout(" << layout << ", binding = " << binding << ") " << interfaceName << " " << blockName << "\n"
    732 		"{\n"
    733 		"	uint value;\n"
    734 		"} " << instanceName << "[" << numInstances << "];\n";
    735 
    736 	if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM)
    737 	{
    738 		for (int readNdx = 0; readNdx < numReads; readNdx++)
    739 		{
    740 			const string varName = indicesPrefix + de::toString(readNdx);
    741 			spec->inputs.push_back(Symbol(varName, VarType(TYPE_INT, PRECISION_HIGHP)));
    742 		}
    743 	}
    744 	else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM)
    745 		declareUniformIndexVars(global, indicesPrefix, numReads);
    746 
    747 	for (int readNdx = 0; readNdx < numReads; readNdx++)
    748 	{
    749 		const string varName = resultPrefix + de::toString(readNdx);
    750 		spec->outputs.push_back(Symbol(varName, VarType(TYPE_UINT, PRECISION_HIGHP)));
    751 	}
    752 
    753 	for (int readNdx = 0; readNdx < numReads; readNdx++)
    754 	{
    755 		code << resultPrefix << readNdx << " = " << instanceName << "[";
    756 
    757 		if (m_indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL)
    758 			code << readIndices[readNdx];
    759 		else if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
    760 			code << "indexBase + " << (readIndices[readNdx]-1);
    761 		else
    762 			code << indicesPrefix << readNdx;
    763 
    764 		code << "].value;\n";
    765 	}
    766 
    767 	spec->version				= GLSL_VERSION_310_ES;
    768 	spec->globalDeclarations	= global.str();
    769 	spec->source				= code.str();
    770 }
    771 
    772 BlockArrayIndexingCase::IterateResult BlockArrayIndexingCase::iterate (void)
    773 {
    774 	const int			numInvocations		= 32;
    775 	const int			numInstances		= m_numInstances;
    776 	const int			numReads			= 4;
    777 	vector<int>			readIndices			(numReads);
    778 	vector<deUint32>	inValues			(numInstances);
    779 	vector<deUint32>	outValues			(numInvocations*numReads);
    780 	ShaderSpec			shaderSpec;
    781 	de::Random			rnd					(deInt32Hash(m_shaderType) ^ deInt32Hash(m_blockType) ^ deInt32Hash(m_indexExprType));
    782 
    783 	for (int readNdx = 0; readNdx < numReads; readNdx++)
    784 		readIndices[readNdx] = rnd.getInt(0, numInstances-1);
    785 
    786 	for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
    787 		inValues[instanceNdx] = rnd.getUint32();
    788 
    789 	getShaderSpec(&shaderSpec, numInstances, numReads, &readIndices[0]);
    790 
    791 	{
    792 		const RenderContext&	renderCtx		= m_context.getRenderContext();
    793 		const glw::Functions&	gl				= renderCtx.getFunctions();
    794 		const int				baseBinding		= 2;
    795 		const BufferVector		buffers			(renderCtx, numInstances);
    796 		const deUint32			bufTarget		= m_blockType == BLOCKTYPE_BUFFER ? GL_SHADER_STORAGE_BUFFER : GL_UNIFORM_BUFFER;
    797 		ShaderExecutorPtr		shaderExecutor	(createExecutor(renderCtx, m_shaderType, shaderSpec));
    798 		vector<int>				expandedIndices;
    799 		vector<void*>			inputs;
    800 		vector<void*>			outputs;
    801 
    802 		m_testCtx.getLog() << *shaderExecutor;
    803 
    804 		if (!shaderExecutor->isOk())
    805 			TCU_FAIL("Compile failed");
    806 
    807 		shaderExecutor->useProgram();
    808 
    809 		for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
    810 		{
    811 			gl.bindBuffer(bufTarget, buffers[instanceNdx]);
    812 			gl.bufferData(bufTarget, (glw::GLsizeiptr)sizeof(deUint32), &inValues[instanceNdx], GL_STATIC_DRAW);
    813 			gl.bindBufferBase(bufTarget, baseBinding+instanceNdx, buffers[instanceNdx]);
    814 		}
    815 
    816 		if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM)
    817 		{
    818 			expandedIndices.resize(numInvocations * readIndices.size());
    819 
    820 			for (int readNdx = 0; readNdx < numReads; readNdx++)
    821 			{
    822 				int* dst = &expandedIndices[numInvocations*readNdx];
    823 				std::fill(dst, dst+numInvocations, readIndices[readNdx]);
    824 			}
    825 
    826 			for (int readNdx = 0; readNdx < numReads; readNdx++)
    827 				inputs.push_back(&expandedIndices[readNdx*numInvocations]);
    828 		}
    829 		else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM)
    830 			uploadUniformIndices(gl, shaderExecutor->getProgram(), "index", numReads, &readIndices[0]);
    831 
    832 		for (int readNdx = 0; readNdx < numReads; readNdx++)
    833 			outputs.push_back(&outValues[readNdx*numInvocations]);
    834 
    835 		GLU_EXPECT_NO_ERROR(gl.getError(), "Setup failed");
    836 
    837 		shaderExecutor->execute(numInvocations, inputs.empty() ? DE_NULL : &inputs[0], &outputs[0]);
    838 	}
    839 
    840 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    841 
    842 	for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++)
    843 	{
    844 		for (int readNdx = 0; readNdx < numReads; readNdx++)
    845 		{
    846 			const deUint32	refValue	= inValues[readIndices[readNdx]];
    847 			const deUint32	resValue	= outValues[readNdx*numInvocations + invocationNdx];
    848 
    849 			if (refValue != resValue)
    850 			{
    851 				m_testCtx.getLog() << TestLog::Message << "ERROR: at invocation " << invocationNdx
    852 													   << ", read " << readNdx << ": expected "
    853 													   << tcu::toHex(refValue) << ", got " << tcu::toHex(resValue)
    854 								   << TestLog::EndMessage;
    855 
    856 				if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
    857 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid result value");
    858 			}
    859 		}
    860 	}
    861 
    862 	return STOP;
    863 }
    864 
    865 class AtomicCounterIndexingCase : public TestCase
    866 {
    867 public:
    868 								AtomicCounterIndexingCase		(Context& context, const char* name, const char* description, IndexExprType indexExprType, ShaderType shaderType);
    869 								~AtomicCounterIndexingCase		(void);
    870 
    871 	void						init							(void);
    872 	IterateResult				iterate							(void);
    873 
    874 private:
    875 								AtomicCounterIndexingCase		(const AtomicCounterIndexingCase&);
    876 	AtomicCounterIndexingCase&	operator=						(const AtomicCounterIndexingCase&);
    877 
    878 	void						getShaderSpec					(ShaderSpec* spec, int numCounters, int numOps, const int* opIndices) const;
    879 
    880 	const IndexExprType			m_indexExprType;
    881 	const glu::ShaderType		m_shaderType;
    882 };
    883 
    884 AtomicCounterIndexingCase::AtomicCounterIndexingCase (Context& context, const char* name, const char* description, IndexExprType indexExprType, ShaderType shaderType)
    885 	: TestCase			(context, name, description)
    886 	, m_indexExprType	(indexExprType)
    887 	, m_shaderType		(shaderType)
    888 {
    889 }
    890 
    891 AtomicCounterIndexingCase::~AtomicCounterIndexingCase (void)
    892 {
    893 }
    894 
    895 void AtomicCounterIndexingCase::init (void)
    896 {
    897 	const char* extName = "GL_EXT_gpu_shader5";
    898 
    899 	if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL &&
    900 		!m_context.getContextInfo().isExtensionSupported(extName))
    901 		throw tcu::NotSupportedError(string(extName) + " extension is required for dynamic indexing of atomic counters");
    902 
    903 	if (m_shaderType == glu::SHADERTYPE_VERTEX || m_shaderType == glu::SHADERTYPE_FRAGMENT)
    904 	{
    905 		int numAtomicCounterBuffers = 0;
    906 		m_context.getRenderContext().getFunctions().getIntegerv(m_shaderType == glu::SHADERTYPE_VERTEX ? GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS
    907 																									   : GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS,
    908 																&numAtomicCounterBuffers);
    909 
    910 		if (numAtomicCounterBuffers == 0)
    911 			throw tcu::NotSupportedError(string("Atomic counters not supported in ") + glu::getShaderTypeName(m_shaderType) + " shader");
    912 	}
    913 }
    914 
    915 void AtomicCounterIndexingCase::getShaderSpec (ShaderSpec* spec, int numCounters, int numOps, const int* opIndices) const
    916 {
    917 	const char*			indicesPrefix	= "index";
    918 	const char*			resultPrefix	= "result";
    919 	std::ostringstream	global, code;
    920 
    921 	if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL)
    922 		global << "#extension GL_EXT_gpu_shader5 : require\n";
    923 
    924 	if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
    925 		global << "const highp int indexBase = 1;\n";
    926 
    927 	global <<
    928 		"layout(binding = 0) uniform atomic_uint counter[" << numCounters << "];\n";
    929 
    930 	if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM)
    931 	{
    932 		for (int opNdx = 0; opNdx < numOps; opNdx++)
    933 		{
    934 			const string varName = indicesPrefix + de::toString(opNdx);
    935 			spec->inputs.push_back(Symbol(varName, VarType(TYPE_INT, PRECISION_HIGHP)));
    936 		}
    937 	}
    938 	else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM)
    939 		declareUniformIndexVars(global, indicesPrefix, numOps);
    940 
    941 	for (int opNdx = 0; opNdx < numOps; opNdx++)
    942 	{
    943 		const string varName = resultPrefix + de::toString(opNdx);
    944 		spec->outputs.push_back(Symbol(varName, VarType(TYPE_UINT, PRECISION_HIGHP)));
    945 	}
    946 
    947 	for (int opNdx = 0; opNdx < numOps; opNdx++)
    948 	{
    949 		code << resultPrefix << opNdx << " = atomicCounterIncrement(counter[";
    950 
    951 		if (m_indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL)
    952 			code << opIndices[opNdx];
    953 		else if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
    954 			code << "indexBase + " << (opIndices[opNdx]-1);
    955 		else
    956 			code << indicesPrefix << opNdx;
    957 
    958 		code << "]);\n";
    959 	}
    960 
    961 	spec->version				= GLSL_VERSION_310_ES;
    962 	spec->globalDeclarations	= global.str();
    963 	spec->source				= code.str();
    964 }
    965 
    966 AtomicCounterIndexingCase::IterateResult AtomicCounterIndexingCase::iterate (void)
    967 {
    968 	const RenderContext&	renderCtx			= m_context.getRenderContext();
    969 	const glw::Functions&	gl					= renderCtx.getFunctions();
    970 	const Buffer			counterBuffer		(renderCtx);
    971 
    972 	const int				numInvocations		= 32;
    973 	const int				numCounters			= 4;
    974 	const int				numOps				= 4;
    975 	vector<int>				opIndices			(numOps);
    976 	vector<deUint32>		outValues			(numInvocations*numOps);
    977 	ShaderSpec				shaderSpec;
    978 	de::Random				rnd					(deInt32Hash(m_shaderType) ^ deInt32Hash(m_indexExprType));
    979 
    980 	for (int opNdx = 0; opNdx < numOps; opNdx++)
    981 		opIndices[opNdx] = rnd.getInt(0, numOps-1);
    982 
    983 	getShaderSpec(&shaderSpec, numCounters, numOps, &opIndices[0]);
    984 
    985 	{
    986 		const BufferVector		buffers			(renderCtx, numCounters);
    987 		ShaderExecutorPtr		shaderExecutor	(createExecutor(renderCtx, m_shaderType, shaderSpec));
    988 		vector<int>				expandedIndices;
    989 		vector<void*>			inputs;
    990 		vector<void*>			outputs;
    991 
    992 		m_testCtx.getLog() << *shaderExecutor;
    993 
    994 		if (!shaderExecutor->isOk())
    995 			TCU_FAIL("Compile failed");
    996 
    997 		{
    998 			const int				bufSize		= getProgramResourceInt(gl, shaderExecutor->getProgram(), GL_ATOMIC_COUNTER_BUFFER, 0, GL_BUFFER_DATA_SIZE);
    999 			const int				maxNdx		= maxElement(opIndices);
   1000 			std::vector<deUint8>	emptyData	(numCounters*4, 0);
   1001 
   1002 			if (bufSize < (maxNdx+1)*4)
   1003 				TCU_FAIL((string("GL reported invalid buffer size " + de::toString(bufSize)).c_str()));
   1004 
   1005 			gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, *counterBuffer);
   1006 			gl.bufferData(GL_ATOMIC_COUNTER_BUFFER, (glw::GLsizeiptr)emptyData.size(), &emptyData[0], GL_STATIC_DRAW);
   1007 			gl.bindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, *counterBuffer);
   1008 			GLU_EXPECT_NO_ERROR(gl.getError(), "Atomic counter buffer initialization failed");
   1009 		}
   1010 
   1011 		shaderExecutor->useProgram();
   1012 
   1013 		if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM)
   1014 		{
   1015 			expandedIndices.resize(numInvocations * opIndices.size());
   1016 
   1017 			for (int opNdx = 0; opNdx < numOps; opNdx++)
   1018 			{
   1019 				int* dst = &expandedIndices[numInvocations*opNdx];
   1020 				std::fill(dst, dst+numInvocations, opIndices[opNdx]);
   1021 			}
   1022 
   1023 			for (int opNdx = 0; opNdx < numOps; opNdx++)
   1024 				inputs.push_back(&expandedIndices[opNdx*numInvocations]);
   1025 		}
   1026 		else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM)
   1027 			uploadUniformIndices(gl, shaderExecutor->getProgram(), "index", numOps, &opIndices[0]);
   1028 
   1029 		for (int opNdx = 0; opNdx < numOps; opNdx++)
   1030 			outputs.push_back(&outValues[opNdx*numInvocations]);
   1031 
   1032 		GLU_EXPECT_NO_ERROR(gl.getError(), "Setup failed");
   1033 
   1034 		shaderExecutor->execute(numInvocations, inputs.empty() ? DE_NULL : &inputs[0], &outputs[0]);
   1035 	}
   1036 
   1037 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
   1038 
   1039 	{
   1040 		vector<int>				numHits			(numCounters, 0);	// Number of hits per counter.
   1041 		vector<deUint32>		counterValues	(numCounters);
   1042 		vector<vector<bool> >	counterMasks	(numCounters);
   1043 
   1044 		for (int opNdx = 0; opNdx < numOps; opNdx++)
   1045 			numHits[opIndices[opNdx]] += 1;
   1046 
   1047 		// Read counter values
   1048 		{
   1049 			const void* mapPtr = DE_NULL;
   1050 
   1051 			try
   1052 			{
   1053 				mapPtr = gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, numCounters*4, GL_MAP_READ_BIT);
   1054 				GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER)");
   1055 				TCU_CHECK(mapPtr);
   1056 				std::copy((const deUint32*)mapPtr, (const deUint32*)mapPtr + numCounters, &counterValues[0]);
   1057 				gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
   1058 			}
   1059 			catch (...)
   1060 			{
   1061 				if (mapPtr)
   1062 					gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
   1063 				throw;
   1064 			}
   1065 		}
   1066 
   1067 		// Verify counter values
   1068 		for (int counterNdx = 0; counterNdx < numCounters; counterNdx++)
   1069 		{
   1070 			const deUint32		refCount	= (deUint32)(numHits[counterNdx]*numInvocations);
   1071 			const deUint32		resCount	= counterValues[counterNdx];
   1072 
   1073 			if (refCount != resCount)
   1074 			{
   1075 				m_testCtx.getLog() << TestLog::Message << "ERROR: atomic counter " << counterNdx << " has value " << resCount
   1076 													   << ", expected " << refCount
   1077 								   << TestLog::EndMessage;
   1078 
   1079 				if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
   1080 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid atomic counter value");
   1081 			}
   1082 		}
   1083 
   1084 		// Allocate bitmasks - one bit per each valid result value
   1085 		for (int counterNdx = 0; counterNdx < numCounters; counterNdx++)
   1086 		{
   1087 			const int	counterValue	= numHits[counterNdx]*numInvocations;
   1088 			counterMasks[counterNdx].resize(counterValue, false);
   1089 		}
   1090 
   1091 		// Verify result values from shaders
   1092 		for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++)
   1093 		{
   1094 			for (int opNdx = 0; opNdx < numOps; opNdx++)
   1095 			{
   1096 				const int		counterNdx	= opIndices[opNdx];
   1097 				const deUint32	resValue	= outValues[opNdx*numInvocations + invocationNdx];
   1098 				const bool		rangeOk		= de::inBounds(resValue, 0u, (deUint32)counterMasks[counterNdx].size());
   1099 				const bool		notSeen		= rangeOk && !counterMasks[counterNdx][resValue];
   1100 				const bool		isOk		= rangeOk && notSeen;
   1101 
   1102 				if (!isOk)
   1103 				{
   1104 					m_testCtx.getLog() << TestLog::Message << "ERROR: at invocation " << invocationNdx
   1105 														   << ", op " << opNdx << ": got invalid result value "
   1106 														   << resValue
   1107 									   << TestLog::EndMessage;
   1108 
   1109 					if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
   1110 						m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid result value");
   1111 				}
   1112 				else
   1113 				{
   1114 					// Mark as used - no other invocation should see this value from same counter.
   1115 					counterMasks[counterNdx][resValue] = true;
   1116 				}
   1117 			}
   1118 		}
   1119 
   1120 		if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
   1121 		{
   1122 			// Consistency check - all masks should be 1 now
   1123 			for (int counterNdx = 0; counterNdx < numCounters; counterNdx++)
   1124 			{
   1125 				for (vector<bool>::const_iterator i = counterMasks[counterNdx].begin(); i != counterMasks[counterNdx].end(); i++)
   1126 					TCU_CHECK_INTERNAL(*i);
   1127 			}
   1128 		}
   1129 	}
   1130 
   1131 	return STOP;
   1132 }
   1133 
   1134 } // anonymous
   1135 
   1136 OpaqueTypeIndexingTests::OpaqueTypeIndexingTests (Context& context)
   1137 	: TestCaseGroup(context, "opaque_type_indexing", "Opaque Type Indexing Tests")
   1138 {
   1139 }
   1140 
   1141 OpaqueTypeIndexingTests::~OpaqueTypeIndexingTests (void)
   1142 {
   1143 }
   1144 
   1145 void OpaqueTypeIndexingTests::init (void)
   1146 {
   1147 	static const struct
   1148 	{
   1149 		IndexExprType	type;
   1150 		const char*		name;
   1151 		const char*		description;
   1152 	} indexingTypes[] =
   1153 	{
   1154 		{ INDEX_EXPR_TYPE_CONST_LITERAL,	"const_literal",		"Indexing by constant literal"					},
   1155 		{ INDEX_EXPR_TYPE_CONST_EXPRESSION,	"const_expression",		"Indexing by constant expression"				},
   1156 		{ INDEX_EXPR_TYPE_UNIFORM,			"uniform",				"Indexing by uniform value"						},
   1157 		{ INDEX_EXPR_TYPE_DYNAMIC_UNIFORM,	"dynamically_uniform",	"Indexing by dynamically uniform expression"	}
   1158 	};
   1159 
   1160 	static const struct
   1161 	{
   1162 		ShaderType		type;
   1163 		const char*		name;
   1164 	} shaderTypes[] =
   1165 	{
   1166 		{ SHADERTYPE_VERTEX,		"vertex"	},
   1167 		{ SHADERTYPE_FRAGMENT,		"fragment"	},
   1168 		{ SHADERTYPE_COMPUTE,		"compute"	}
   1169 	};
   1170 
   1171 	// .sampler
   1172 	{
   1173 		static const DataType samplerTypes[] =
   1174 		{
   1175 			// \note 1D images will be added by a later extension.
   1176 //			TYPE_SAMPLER_1D,
   1177 			TYPE_SAMPLER_2D,
   1178 			TYPE_SAMPLER_CUBE,
   1179 			TYPE_SAMPLER_2D_ARRAY,
   1180 			TYPE_SAMPLER_3D,
   1181 //			TYPE_SAMPLER_1D_SHADOW,
   1182 			TYPE_SAMPLER_2D_SHADOW,
   1183 			TYPE_SAMPLER_CUBE_SHADOW,
   1184 			TYPE_SAMPLER_2D_ARRAY_SHADOW,
   1185 //			TYPE_INT_SAMPLER_1D,
   1186 			TYPE_INT_SAMPLER_2D,
   1187 			TYPE_INT_SAMPLER_CUBE,
   1188 			TYPE_INT_SAMPLER_2D_ARRAY,
   1189 			TYPE_INT_SAMPLER_3D,
   1190 //			TYPE_UINT_SAMPLER_1D,
   1191 			TYPE_UINT_SAMPLER_2D,
   1192 			TYPE_UINT_SAMPLER_CUBE,
   1193 			TYPE_UINT_SAMPLER_2D_ARRAY,
   1194 			TYPE_UINT_SAMPLER_3D,
   1195 		};
   1196 
   1197 		tcu::TestCaseGroup* const samplerGroup = new tcu::TestCaseGroup(m_testCtx, "sampler", "Sampler Array Indexing Tests");
   1198 		addChild(samplerGroup);
   1199 
   1200 		for (int indexTypeNdx = 0; indexTypeNdx < DE_LENGTH_OF_ARRAY(indexingTypes); indexTypeNdx++)
   1201 		{
   1202 			const IndexExprType			indexExprType	= indexingTypes[indexTypeNdx].type;
   1203 			tcu::TestCaseGroup* const	indexGroup		= new tcu::TestCaseGroup(m_testCtx, indexingTypes[indexTypeNdx].name, indexingTypes[indexTypeNdx].description);
   1204 			samplerGroup->addChild(indexGroup);
   1205 
   1206 			for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(shaderTypes); shaderTypeNdx++)
   1207 			{
   1208 				const ShaderType			shaderType		= shaderTypes[shaderTypeNdx].type;
   1209 				tcu::TestCaseGroup* const	shaderGroup		= new tcu::TestCaseGroup(m_testCtx, shaderTypes[shaderTypeNdx].name, "");
   1210 				indexGroup->addChild(shaderGroup);
   1211 
   1212 				for (int samplerTypeNdx = 0; samplerTypeNdx < DE_LENGTH_OF_ARRAY(samplerTypes); samplerTypeNdx++)
   1213 				{
   1214 					const DataType	samplerType	= samplerTypes[samplerTypeNdx];
   1215 					const char*		samplerName	= getDataTypeName(samplerType);
   1216 					const string	caseName	= de::toLower(samplerName);
   1217 
   1218 					shaderGroup->addChild(new SamplerIndexingCase(m_context, caseName.c_str(), "", shaderType, samplerType, indexExprType));
   1219 				}
   1220 			}
   1221 		}
   1222 	}
   1223 
   1224 	// .ubo / .ssbo / .atomic_counter
   1225 	{
   1226 		tcu::TestCaseGroup* const	uboGroup	= new tcu::TestCaseGroup(m_testCtx, "ubo",				"Uniform Block Instance Array Indexing Tests");
   1227 		tcu::TestCaseGroup* const	ssboGroup	= new tcu::TestCaseGroup(m_testCtx, "ssbo",				"Buffer Block Instance Array Indexing Tests");
   1228 		tcu::TestCaseGroup* const	acGroup		= new tcu::TestCaseGroup(m_testCtx, "atomic_counter",	"Atomic Counter Array Indexing Tests");
   1229 		addChild(uboGroup);
   1230 		addChild(ssboGroup);
   1231 		addChild(acGroup);
   1232 
   1233 		for (int indexTypeNdx = 0; indexTypeNdx < DE_LENGTH_OF_ARRAY(indexingTypes); indexTypeNdx++)
   1234 		{
   1235 			const IndexExprType		indexExprType		= indexingTypes[indexTypeNdx].type;
   1236 			const char*				indexExprName		= indexingTypes[indexTypeNdx].name;
   1237 			const char*				indexExprDesc		= indexingTypes[indexTypeNdx].description;
   1238 
   1239 			for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(shaderTypes); shaderTypeNdx++)
   1240 			{
   1241 				const ShaderType		shaderType		= shaderTypes[shaderTypeNdx].type;
   1242 				const string			name			= string(indexExprName) + "_" + shaderTypes[shaderTypeNdx].name;
   1243 
   1244 				uboGroup->addChild	(new BlockArrayIndexingCase		(m_context, name.c_str(), indexExprDesc, BlockArrayIndexingCase::BLOCKTYPE_UNIFORM,	indexExprType, shaderType));
   1245 				acGroup->addChild	(new AtomicCounterIndexingCase	(m_context, name.c_str(), indexExprDesc, indexExprType, shaderType));
   1246 
   1247 				if (indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL || indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
   1248 					ssboGroup->addChild	(new BlockArrayIndexingCase		(m_context, name.c_str(), indexExprDesc, BlockArrayIndexingCase::BLOCKTYPE_BUFFER,	indexExprType, shaderType));
   1249 			}
   1250 		}
   1251 	}
   1252 }
   1253 
   1254 } // Functional
   1255 } // gles31
   1256 } // deqp
   1257