Home | History | Annotate | Download | only in shaderexecutor
      1 /*------------------------------------------------------------------------
      2  * Vulkan Conformance Tests
      3  * ------------------------
      4  *
      5  * Copyright (c) 2015 The Khronos Group Inc.
      6  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
      7  * Copyright (c) 2016 The Android Open Source Project
      8  *
      9  * Licensed under the Apache License, Version 2.0 (the "License");
     10  * you may not use this file except in compliance with the License.
     11  * You may obtain a copy of the License at
     12  *
     13  *      http://www.apache.org/licenses/LICENSE-2.0
     14  *
     15  * Unless required by applicable law or agreed to in writing, software
     16  * distributed under the License is distributed on an "AS IS" BASIS,
     17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     18  * See the License for the specific language governing permissions and
     19  * limitations under the License.
     20  *
     21  *//*!
     22  * \file
     23  * \brief Opaque type (sampler, buffer, atomic counter, ...) indexing tests.
     24  *//*--------------------------------------------------------------------*/
     25 
     26 #include "vktOpaqueTypeIndexingTests.hpp"
     27 
     28 #include "tcuTexture.hpp"
     29 #include "tcuTestLog.hpp"
     30 #include "tcuVectorUtil.hpp"
     31 #include "tcuTextureUtil.hpp"
     32 
     33 #include "deStringUtil.hpp"
     34 #include "deRandom.hpp"
     35 
     36 #include "vktShaderExecutor.hpp"
     37 
     38 #include <sstream>
     39 
     40 namespace vkt
     41 {
     42 namespace shaderexecutor
     43 {
     44 
     45 namespace
     46 {
     47 
     48 enum IndexExprType
     49 {
     50 	INDEX_EXPR_TYPE_CONST_LITERAL	= 0,
     51 	INDEX_EXPR_TYPE_CONST_EXPRESSION,
     52 	INDEX_EXPR_TYPE_UNIFORM,
     53 	INDEX_EXPR_TYPE_DYNAMIC_UNIFORM,
     54 
     55 	INDEX_EXPR_TYPE_LAST
     56 };
     57 
     58 enum TextureType
     59 {
     60 	TEXTURE_TYPE_1D = 0,
     61 	TEXTURE_TYPE_2D,
     62 	TEXTURE_TYPE_CUBE,
     63 	TEXTURE_TYPE_2D_ARRAY,
     64 	TEXTURE_TYPE_3D,
     65 
     66 	TEXTURE_TYPE_LAST
     67 };
     68 
     69 class OpaqueTypeIndexingCase : public TestCase
     70 {
     71 public:
     72 										OpaqueTypeIndexingCase		(tcu::TestContext&			testCtx,
     73 																	 const char*				name,
     74 																	 const char*				description,
     75 																	 const glu::ShaderType		shaderType,
     76 																	 const IndexExprType		indexExprType);
     77 	virtual								~OpaqueTypeIndexingCase		(void);
     78 	virtual void						initPrograms				(vk::SourceCollections& programCollection) const
     79 										{
     80 											m_executor->setShaderSources(programCollection);
     81 										}
     82 	virtual TestInstance*				createInstance				(Context& context) const = 0;
     83 	void								init						(void);
     84 
     85 protected:
     86 	const char*							m_name;
     87 	const glu::ShaderType				m_shaderType;
     88 	const IndexExprType					m_indexExprType;
     89 	ShaderSpec							m_shaderSpec;
     90 	de::MovePtr<ShaderExecutor>			m_executor;
     91 	UniformSetup*						m_uniformSetup;
     92 };
     93 
     94 class OpaqueTypeIndexingTestInstance : public TestInstance
     95 {
     96 public:
     97 										OpaqueTypeIndexingTestInstance		(Context&					context,
     98 																			 const glu::ShaderType		shaderType,
     99 																			 const ShaderSpec&			shaderSpec,
    100 																			 ShaderExecutor&			executor,
    101 																			 const char*				name,
    102 																			 UniformSetup*				uniformSetup,
    103 																			 const IndexExprType		indexExprType);
    104 	virtual								~OpaqueTypeIndexingTestInstance		(void);
    105 
    106 	virtual tcu::TestStatus				iterate								(void) = 0;
    107 
    108 protected:
    109 	void								checkSupported						(const VkDescriptorType descriptorType);
    110 
    111 protected:
    112 	tcu::TestContext&					m_testCtx;
    113 	const glu::ShaderType				m_shaderType;
    114 	const ShaderSpec&					m_shaderSpec;
    115 	const char*							m_name;
    116 	const IndexExprType					m_indexExprType;
    117 	ShaderExecutor&						m_executor;
    118 	UniformSetup*						m_uniformSetup;
    119 };
    120 
    121 OpaqueTypeIndexingCase::OpaqueTypeIndexingCase (tcu::TestContext&			testCtx,
    122 												const char*					name,
    123 												const char*					description,
    124 												const glu::ShaderType		shaderType,
    125 												const IndexExprType			indexExprType)
    126 	: TestCase			(testCtx, name, description)
    127 	, m_name			(name)
    128 	, m_shaderType		(shaderType)
    129 	, m_indexExprType	(indexExprType)
    130 	, m_executor		(DE_NULL)
    131 	, m_uniformSetup	(new UniformSetup())
    132 {
    133 }
    134 
    135 OpaqueTypeIndexingCase::~OpaqueTypeIndexingCase (void)
    136 {
    137 }
    138 
    139 void OpaqueTypeIndexingCase::init (void)
    140 {
    141 	DE_ASSERT(!m_executor);
    142 
    143 	m_executor = de::MovePtr<ShaderExecutor>(createExecutor(m_shaderType, m_shaderSpec));
    144 	m_testCtx.getLog() << *m_executor;
    145 }
    146 
    147 OpaqueTypeIndexingTestInstance::OpaqueTypeIndexingTestInstance (Context&					context,
    148 																const glu::ShaderType		shaderType,
    149 																const ShaderSpec&			shaderSpec,
    150 																ShaderExecutor&				executor,
    151 																const char*					name,
    152 																UniformSetup*				uniformSetup,
    153 																const IndexExprType			indexExprType)
    154 	: TestInstance		(context)
    155 	, m_testCtx			(context.getTestContext())
    156 	, m_shaderType		(shaderType)
    157 	, m_shaderSpec		(shaderSpec)
    158 	, m_name			(name)
    159 	, m_indexExprType	(indexExprType)
    160 	, m_executor		(executor)
    161 	, m_uniformSetup	(uniformSetup)
    162 {
    163 }
    164 
    165 OpaqueTypeIndexingTestInstance::~OpaqueTypeIndexingTestInstance (void)
    166 {
    167 }
    168 
    169 void OpaqueTypeIndexingTestInstance::checkSupported (const VkDescriptorType descriptorType)
    170 {
    171 	const VkPhysicalDeviceFeatures& deviceFeatures = m_context.getDeviceFeatures();
    172 
    173 	if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL && m_indexExprType != INDEX_EXPR_TYPE_CONST_EXPRESSION)
    174 	{
    175 		switch (descriptorType)
    176 		{
    177 			case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
    178 				if (!deviceFeatures.shaderSampledImageArrayDynamicIndexing)
    179 					TCU_THROW(NotSupportedError, "Dynamic indexing of sampler arrays is not supported");
    180 				break;
    181 
    182 			case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
    183 				if (!deviceFeatures.shaderUniformBufferArrayDynamicIndexing)
    184 					TCU_THROW(NotSupportedError, "Dynamic indexing of uniform buffer arrays is not supported");
    185 				break;
    186 
    187 			case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
    188 				if (!deviceFeatures.shaderStorageBufferArrayDynamicIndexing)
    189 					TCU_THROW(NotSupportedError, "Dynamic indexing of storage buffer arrays is not supported");
    190 				break;
    191 
    192 			default:
    193 				break;
    194 		}
    195 	}
    196 }
    197 
    198 static deUint32 getFirstFreeBindingLocation (const glu::ShaderType shaderType)
    199 {
    200 	deUint32 location;
    201 
    202 	switch (shaderType)
    203 	{
    204 		case glu::SHADERTYPE_TESSELLATION_CONTROL:
    205 		case glu::SHADERTYPE_TESSELLATION_EVALUATION:
    206 		case glu::SHADERTYPE_COMPUTE:
    207 			// 0 - input buffer
    208 			// 1 - output buffer
    209 			location = 2u;
    210 			break;
    211 
    212 		default:
    213 			location = 0u;
    214 			break;
    215 	}
    216 
    217 	return location;
    218 }
    219 
    220 static void declareUniformIndexVars (std::ostream& str, const char* varPrefix, int numVars, deUint32& bindingLocation)
    221 {
    222 	for (int varNdx = 0; varNdx < numVars; varNdx++)
    223 		str << "layout(set = 0, binding = " << bindingLocation++ << ") uniform buf" << varNdx << " { highp int " << varPrefix << varNdx << "; }" << ";\n";
    224 }
    225 
    226 static void uploadUniformIndices (UniformSetup* uniformSetup, int numIndices, const int* indices, deUint32& bindingLocation)
    227 {
    228 	for (int varNdx = 0; varNdx < numIndices; varNdx++)
    229 		uniformSetup->addData(new UniformData<int>(bindingLocation++, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, indices[varNdx]));
    230 }
    231 
    232 static TextureType getTextureType (glu::DataType samplerType)
    233 {
    234 	switch (samplerType)
    235 	{
    236 		case glu::TYPE_SAMPLER_1D:
    237 		case glu::TYPE_INT_SAMPLER_1D:
    238 		case glu::TYPE_UINT_SAMPLER_1D:
    239 		case glu::TYPE_SAMPLER_1D_SHADOW:
    240 			return TEXTURE_TYPE_1D;
    241 
    242 		case glu::TYPE_SAMPLER_2D:
    243 		case glu::TYPE_INT_SAMPLER_2D:
    244 		case glu::TYPE_UINT_SAMPLER_2D:
    245 		case glu::TYPE_SAMPLER_2D_SHADOW:
    246 			return TEXTURE_TYPE_2D;
    247 
    248 		case glu::TYPE_SAMPLER_CUBE:
    249 		case glu::TYPE_INT_SAMPLER_CUBE:
    250 		case glu::TYPE_UINT_SAMPLER_CUBE:
    251 		case glu::TYPE_SAMPLER_CUBE_SHADOW:
    252 			return TEXTURE_TYPE_CUBE;
    253 
    254 		case glu::TYPE_SAMPLER_2D_ARRAY:
    255 		case glu::TYPE_INT_SAMPLER_2D_ARRAY:
    256 		case glu::TYPE_UINT_SAMPLER_2D_ARRAY:
    257 		case glu::TYPE_SAMPLER_2D_ARRAY_SHADOW:
    258 			return TEXTURE_TYPE_2D_ARRAY;
    259 
    260 		case glu::TYPE_SAMPLER_3D:
    261 		case glu::TYPE_INT_SAMPLER_3D:
    262 		case glu::TYPE_UINT_SAMPLER_3D:
    263 			return TEXTURE_TYPE_3D;
    264 
    265 		default:
    266 			throw tcu::InternalError("Invalid sampler type");
    267 	}
    268 }
    269 
    270 static bool isShadowSampler (glu::DataType samplerType)
    271 {
    272 	return samplerType == glu::TYPE_SAMPLER_1D_SHADOW		||
    273 		   samplerType == glu::TYPE_SAMPLER_2D_SHADOW		||
    274 		   samplerType == glu::TYPE_SAMPLER_2D_ARRAY_SHADOW	||
    275 		   samplerType == glu::TYPE_SAMPLER_CUBE_SHADOW;
    276 }
    277 
    278 static glu::DataType getSamplerOutputType (glu::DataType samplerType)
    279 {
    280 	switch (samplerType)
    281 	{
    282 		case glu::TYPE_SAMPLER_1D:
    283 		case glu::TYPE_SAMPLER_2D:
    284 		case glu::TYPE_SAMPLER_CUBE:
    285 		case glu::TYPE_SAMPLER_2D_ARRAY:
    286 		case glu::TYPE_SAMPLER_3D:
    287 			return glu::TYPE_FLOAT_VEC4;
    288 
    289 		case glu::TYPE_SAMPLER_1D_SHADOW:
    290 		case glu::TYPE_SAMPLER_2D_SHADOW:
    291 		case glu::TYPE_SAMPLER_CUBE_SHADOW:
    292 		case glu::TYPE_SAMPLER_2D_ARRAY_SHADOW:
    293 			return glu::TYPE_FLOAT;
    294 
    295 		case glu::TYPE_INT_SAMPLER_1D:
    296 		case glu::TYPE_INT_SAMPLER_2D:
    297 		case glu::TYPE_INT_SAMPLER_CUBE:
    298 		case glu::TYPE_INT_SAMPLER_2D_ARRAY:
    299 		case glu::TYPE_INT_SAMPLER_3D:
    300 			return glu::TYPE_INT_VEC4;
    301 
    302 		case glu::TYPE_UINT_SAMPLER_1D:
    303 		case glu::TYPE_UINT_SAMPLER_2D:
    304 		case glu::TYPE_UINT_SAMPLER_CUBE:
    305 		case glu::TYPE_UINT_SAMPLER_2D_ARRAY:
    306 		case glu::TYPE_UINT_SAMPLER_3D:
    307 			return glu::TYPE_UINT_VEC4;
    308 
    309 		default:
    310 			throw tcu::InternalError("Invalid sampler type");
    311 	}
    312 }
    313 
    314 static tcu::TextureFormat getSamplerTextureFormat (glu::DataType samplerType)
    315 {
    316 	const glu::DataType		outType			= getSamplerOutputType(samplerType);
    317 	const glu::DataType		outScalarType	= glu::getDataTypeScalarType(outType);
    318 
    319 	switch (outScalarType)
    320 	{
    321 		case glu::TYPE_FLOAT:
    322 			if (isShadowSampler(samplerType))
    323 				return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT16);
    324 			else
    325 				return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
    326 
    327 		case glu::TYPE_INT:		return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT8);
    328 		case glu::TYPE_UINT:	return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT8);
    329 
    330 		default:
    331 			throw tcu::InternalError("Invalid sampler type");
    332 	}
    333 }
    334 
    335 static glu::DataType getSamplerCoordType (glu::DataType samplerType)
    336 {
    337 	const TextureType	texType		= getTextureType(samplerType);
    338 	int					numCoords	= 0;
    339 
    340 	switch (texType)
    341 	{
    342 		case TEXTURE_TYPE_1D:		numCoords = 1;	break;
    343 		case TEXTURE_TYPE_2D:		numCoords = 2;	break;
    344 		case TEXTURE_TYPE_2D_ARRAY:	numCoords = 3;	break;
    345 		case TEXTURE_TYPE_CUBE:		numCoords = 3;	break;
    346 		case TEXTURE_TYPE_3D:		numCoords = 3;	break;
    347 		default:
    348 			DE_ASSERT(false);
    349 	}
    350 
    351 	if (isShadowSampler(samplerType))
    352 		numCoords += 1;
    353 
    354 	DE_ASSERT(de::inRange(numCoords, 1, 4));
    355 
    356 	return numCoords == 1 ? glu::TYPE_FLOAT : glu::getDataTypeFloatVec(numCoords);
    357 }
    358 
    359 static void fillTextureData (const tcu::PixelBufferAccess& access, de::Random& rnd)
    360 {
    361 	DE_ASSERT(access.getHeight() == 1 && access.getDepth() == 1);
    362 
    363 	if (access.getFormat().order == tcu::TextureFormat::D)
    364 	{
    365 		// \note Texture uses odd values, lookup even values to avoid precision issues.
    366 		const float values[] = { 0.1f, 0.3f, 0.5f, 0.7f, 0.9f };
    367 
    368 		for (int ndx = 0; ndx < access.getWidth(); ndx++)
    369 			access.setPixDepth(rnd.choose<float>(DE_ARRAY_BEGIN(values), DE_ARRAY_END(values)), ndx, 0);
    370 	}
    371 	else
    372 	{
    373 		TCU_CHECK_INTERNAL(access.getFormat().order == tcu::TextureFormat::RGBA && access.getFormat().getPixelSize() == 4);
    374 
    375 		for (int ndx = 0; ndx < access.getWidth(); ndx++)
    376 			*((deUint32*)access.getDataPtr() + ndx) = rnd.getUint32();
    377 	}
    378 }
    379 
    380 static vk::VkImageType getVkImageType (TextureType texType)
    381 {
    382 	switch (texType)
    383 	{
    384 		case TEXTURE_TYPE_1D:			return vk::VK_IMAGE_TYPE_1D;
    385 		case TEXTURE_TYPE_2D:
    386 		case TEXTURE_TYPE_2D_ARRAY:		return vk::VK_IMAGE_TYPE_2D;
    387 		case TEXTURE_TYPE_CUBE:			return vk::VK_IMAGE_TYPE_2D;
    388 		case TEXTURE_TYPE_3D:			return vk::VK_IMAGE_TYPE_3D;
    389 		default:
    390 			DE_FATAL("Impossible");
    391 			return (vk::VkImageType)0;
    392 	}
    393 }
    394 
    395 static vk::VkImageViewType getVkImageViewType (TextureType texType)
    396 {
    397 	switch (texType)
    398 	{
    399 		case TEXTURE_TYPE_1D:			return vk::VK_IMAGE_VIEW_TYPE_1D;
    400 		case TEXTURE_TYPE_2D:			return vk::VK_IMAGE_VIEW_TYPE_2D;
    401 		case TEXTURE_TYPE_2D_ARRAY:		return vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY;
    402 		case TEXTURE_TYPE_CUBE:			return vk::VK_IMAGE_VIEW_TYPE_CUBE;
    403 		case TEXTURE_TYPE_3D:			return vk::VK_IMAGE_VIEW_TYPE_3D;
    404 		default:
    405 			DE_FATAL("Impossible");
    406 			return (vk::VkImageViewType)0;
    407 	}
    408 }
    409 
    410 // SamplerIndexingCaseInstance
    411 
    412 class SamplerIndexingCaseInstance : public OpaqueTypeIndexingTestInstance
    413 {
    414 public:
    415 	enum
    416 	{
    417 		NUM_INVOCATIONS		= 64,
    418 		NUM_SAMPLERS		= 8,
    419 		NUM_LOOKUPS			= 4
    420 	};
    421 
    422 								SamplerIndexingCaseInstance		(Context&					context,
    423 																 const glu::ShaderType		shaderType,
    424 																 const ShaderSpec&			shaderSpec,
    425 																 ShaderExecutor&			executor,
    426 																 const char*				name,
    427 																 glu::DataType				samplerType,
    428 																 const IndexExprType		indexExprType,
    429 																 UniformSetup*				uniformSetup,
    430 																 const std::vector<int>&	lookupIndices);
    431 	virtual						~SamplerIndexingCaseInstance	(void);
    432 
    433 	virtual tcu::TestStatus		iterate							(void);
    434 
    435 protected:
    436 	const glu::DataType			m_samplerType;
    437 	const std::vector<int>&		m_lookupIndices;
    438 };
    439 
    440 SamplerIndexingCaseInstance::SamplerIndexingCaseInstance (Context&						context,
    441 														  const glu::ShaderType			shaderType,
    442 														  const ShaderSpec&				shaderSpec,
    443 														  ShaderExecutor&				executor,
    444 														  const char*					name,
    445 														  glu::DataType					samplerType,
    446 														  const IndexExprType			indexExprType,
    447 														  UniformSetup*					uniformSetup,
    448 														  const std::vector<int>&		lookupIndices)
    449 	: OpaqueTypeIndexingTestInstance	(context, shaderType, shaderSpec, executor, name, uniformSetup, indexExprType)
    450 	, m_samplerType						(samplerType)
    451 	, m_lookupIndices					(lookupIndices)
    452 {
    453 }
    454 
    455 SamplerIndexingCaseInstance::~SamplerIndexingCaseInstance (void)
    456 {
    457 }
    458 
    459 bool isIntegerFormat (const tcu::TextureFormat& format)
    460 {
    461 	const tcu::TextureChannelClass	chnClass	= tcu::getTextureChannelClass(format.type);
    462 
    463 	return chnClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER ||
    464 		   chnClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER;
    465 }
    466 
    467 tcu::TestStatus SamplerIndexingCaseInstance::iterate (void)
    468 {
    469 	const int						numInvocations		= SamplerIndexingCaseInstance::NUM_INVOCATIONS;
    470 	const int						numSamplers			= SamplerIndexingCaseInstance::NUM_SAMPLERS;
    471 	const int						numLookups			= SamplerIndexingCaseInstance::NUM_LOOKUPS;
    472 	const glu::DataType				coordType			= getSamplerCoordType(m_samplerType);
    473 	const glu::DataType				outputType			= getSamplerOutputType(m_samplerType);
    474 	const tcu::TextureFormat		texFormat			= getSamplerTextureFormat(m_samplerType);
    475 	const int						outLookupStride		= numInvocations*getDataTypeScalarSize(outputType);
    476 	std::vector<float>				coords;
    477 	std::vector<deUint32>			outData;
    478 	std::vector<deUint8>			texData				(numSamplers * texFormat.getPixelSize());
    479 	const tcu::PixelBufferAccess	refTexAccess		(texFormat, numSamplers, 1, 1, &texData[0]);
    480 	de::Random						rnd					(deInt32Hash(m_samplerType) ^ deInt32Hash(m_shaderType) ^ deInt32Hash(m_indexExprType));
    481 	const TextureType				texType				= getTextureType(m_samplerType);
    482 	const vk::VkImageType			imageType			= getVkImageType(texType);
    483 	const vk::VkImageViewType		imageViewType		= getVkImageViewType(texType);
    484 	const tcu::Sampler::FilterMode	filterMode			= (isShadowSampler(m_samplerType) || isIntegerFormat(texFormat)) ? tcu::Sampler::NEAREST : tcu::Sampler::LINEAR;
    485 	const tcu::Sampler				refSampler			= isShadowSampler(m_samplerType)
    486 																? tcu::Sampler(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
    487 																				filterMode, filterMode, 0.0f, false /* non-normalized */,
    488 																				tcu::Sampler::COMPAREMODE_LESS)
    489 																: tcu::Sampler(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
    490 																				filterMode, filterMode);
    491 
    492 	checkSupported(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
    493 
    494 	coords.resize(numInvocations * getDataTypeScalarSize(coordType));
    495 
    496 	if (texType == TEXTURE_TYPE_CUBE)
    497 	{
    498 		if (isShadowSampler(m_samplerType))
    499 		{
    500 			for (size_t i = 0; i < coords.size() / 4; i++)
    501 			{
    502 				coords[4 * i] = 1.0f;
    503 				coords[4 * i + 1] = coords[4 * i + 2] = coords[4 * i + 3] = 0.0f;
    504 			}
    505 		}
    506 		else
    507 		{
    508 			for (size_t i = 0; i < coords.size() / 3; i++)
    509 			{
    510 				coords[3 * i] = 1.0f;
    511 				coords[3 * i + 1] = coords[3 * i + 2] = 0.0f;
    512 			}
    513 		}
    514 	}
    515 
    516 	if (isShadowSampler(m_samplerType))
    517 	{
    518 		// Use different comparison value per invocation.
    519 		// \note Texture uses odd values, comparison even values.
    520 		const int	numCoordComps	= getDataTypeScalarSize(coordType);
    521 		const float	cmpValues[]		= { 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f };
    522 
    523 		for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++)
    524 			coords[invocationNdx*numCoordComps + (numCoordComps-1)] = rnd.choose<float>(DE_ARRAY_BEGIN(cmpValues), DE_ARRAY_END(cmpValues));
    525 	}
    526 
    527 	fillTextureData(refTexAccess, rnd);
    528 
    529 	outData.resize(numLookups*outLookupStride);
    530 
    531 	{
    532 		std::vector<void*>		inputs;
    533 		std::vector<void*>		outputs;
    534 		std::vector<int>		expandedIndices;
    535 		deUint32				bindingLocation		= getFirstFreeBindingLocation(m_shaderType);
    536 
    537 		inputs.push_back(&coords[0]);
    538 
    539 		m_uniformSetup->addData(new SamplerUniformData(bindingLocation++, (deUint32)numSamplers, refSampler, texFormat, tcu::IVec3(1, 1, 1), imageType, imageViewType, &texData[0]));
    540 
    541 		if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM)
    542 		{
    543 			expandedIndices.resize(numInvocations * m_lookupIndices.size());
    544 			for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
    545 			{
    546 				for (int invNdx = 0; invNdx < numInvocations; invNdx++)
    547 					expandedIndices[lookupNdx*numInvocations + invNdx] = m_lookupIndices[lookupNdx];
    548 			}
    549 
    550 			for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
    551 				inputs.push_back(&expandedIndices[lookupNdx*numInvocations]);
    552 		}
    553 		else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM)
    554 			uploadUniformIndices(m_uniformSetup, numLookups, &m_lookupIndices[0], bindingLocation);
    555 
    556 		for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
    557 			outputs.push_back(&outData[outLookupStride*lookupNdx]);
    558 
    559 		m_executor.setUniforms(m_uniformSetup);
    560 
    561 		m_executor.execute(m_context, numInvocations, &inputs[0], &outputs[0]);
    562 	}
    563 
    564 	{
    565 		tcu::TestLog&		log				= m_context.getTestContext().getLog();
    566 		tcu::TestStatus		testResult		= tcu::TestStatus::pass("Pass");
    567 
    568 		if (isShadowSampler(m_samplerType))
    569 		{
    570 			const int			numCoordComps	= getDataTypeScalarSize(coordType);
    571 
    572 			TCU_CHECK_INTERNAL(getDataTypeScalarSize(outputType) == 1);
    573 
    574 			// Each invocation may have different results.
    575 			for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++)
    576 			{
    577 				const float	coord	= coords[invocationNdx*numCoordComps + (numCoordComps-1)];
    578 
    579 				for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
    580 				{
    581 					const int		texNdx		= m_lookupIndices[lookupNdx];
    582 					const float		result		= *((const float*)(const deUint8*)&outData[lookupNdx*outLookupStride + invocationNdx]);
    583 					const float		reference	= refTexAccess.sample2DCompare(refSampler, tcu::Sampler::NEAREST, coord, (float)texNdx, 0.0f, tcu::IVec3(0));
    584 
    585 					if (de::abs(result-reference) > 0.005f)
    586 					{
    587 						log << tcu::TestLog::Message << "ERROR: at invocation " << invocationNdx << ", lookup " << lookupNdx << ": expected "
    588 							<< reference << ", got " << result
    589 							<< tcu::TestLog::EndMessage;
    590 
    591 						if (testResult.getCode() == QP_TEST_RESULT_PASS)
    592 							testResult = tcu::TestStatus::fail("Got invalid lookup result");
    593 					}
    594 				}
    595 			}
    596 		}
    597 		else
    598 		{
    599 			TCU_CHECK_INTERNAL(getDataTypeScalarSize(outputType) == 4);
    600 
    601 			// Validate results from first invocation
    602 			for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
    603 			{
    604 				const int		texNdx	= m_lookupIndices[lookupNdx];
    605 				const deUint8*	resPtr	= (const deUint8*)&outData[lookupNdx*outLookupStride];
    606 				bool			isOk;
    607 
    608 				if (outputType == glu::TYPE_FLOAT_VEC4)
    609 				{
    610 					const float			threshold		= 1.0f / 256.0f;
    611 					const tcu::Vec4		reference		= refTexAccess.getPixel(texNdx, 0);
    612 					const float*		floatPtr		= (const float*)resPtr;
    613 					const tcu::Vec4		result			(floatPtr[0], floatPtr[1], floatPtr[2], floatPtr[3]);
    614 
    615 					isOk = boolAll(lessThanEqual(abs(reference-result), tcu::Vec4(threshold)));
    616 
    617 					if (!isOk)
    618 					{
    619 						log << tcu::TestLog::Message << "ERROR: at lookup " << lookupNdx << ": expected "
    620 							<< reference << ", got " << result
    621 							<< tcu::TestLog::EndMessage;
    622 					}
    623 				}
    624 				else
    625 				{
    626 					const tcu::UVec4	reference		= refTexAccess.getPixelUint(texNdx, 0);
    627 					const deUint32*		uintPtr			= (const deUint32*)resPtr;
    628 					const tcu::UVec4	result			(uintPtr[0], uintPtr[1], uintPtr[2], uintPtr[3]);
    629 
    630 					isOk = boolAll(equal(reference, result));
    631 
    632 					if (!isOk)
    633 					{
    634 						log << tcu::TestLog::Message << "ERROR: at lookup " << lookupNdx << ": expected "
    635 							<< reference << ", got " << result
    636 							<< tcu::TestLog::EndMessage;
    637 					}
    638 				}
    639 
    640 				if (!isOk && testResult.getCode() == QP_TEST_RESULT_PASS)
    641 					testResult = tcu::TestStatus::fail("Got invalid lookup result");
    642 			}
    643 
    644 			// Check results of other invocations against first one
    645 			for (int invocationNdx = 1; invocationNdx < numInvocations; invocationNdx++)
    646 			{
    647 				for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
    648 				{
    649 					const deUint32*		refPtr		= &outData[lookupNdx*outLookupStride];
    650 					const deUint32*		resPtr		= refPtr + invocationNdx*4;
    651 					bool				isOk		= true;
    652 
    653 					for (int ndx = 0; ndx < 4; ndx++)
    654 						isOk = isOk && (refPtr[ndx] == resPtr[ndx]);
    655 
    656 					if (!isOk)
    657 					{
    658 						log << tcu::TestLog::Message << "ERROR: invocation " << invocationNdx << " result "
    659 							<< tcu::formatArray(tcu::Format::HexIterator<deUint32>(resPtr), tcu::Format::HexIterator<deUint32>(resPtr+4))
    660 							<< " for lookup " << lookupNdx << " doesn't match result from first invocation "
    661 							<< tcu::formatArray(tcu::Format::HexIterator<deUint32>(refPtr), tcu::Format::HexIterator<deUint32>(refPtr+4))
    662 							<< tcu::TestLog::EndMessage;
    663 
    664 						if (testResult.getCode() == QP_TEST_RESULT_PASS)
    665 							testResult = tcu::TestStatus::fail("Inconsistent lookup results");
    666 					}
    667 				}
    668 			}
    669 		}
    670 
    671 		return testResult;
    672 	}
    673 }
    674 
    675 class SamplerIndexingCase : public OpaqueTypeIndexingCase
    676 {
    677 public:
    678 								SamplerIndexingCase			(tcu::TestContext&			testCtx,
    679 															 const char*				name,
    680 															 const char*				description,
    681 															 const glu::ShaderType		shaderType,
    682 															 glu::DataType				samplerType,
    683 															 IndexExprType				indexExprType);
    684 	virtual						~SamplerIndexingCase		(void);
    685 
    686 	virtual TestInstance*		createInstance				(Context& ctx) const;
    687 
    688 private:
    689 								SamplerIndexingCase			(const SamplerIndexingCase&);
    690 	SamplerIndexingCase&		operator=					(const SamplerIndexingCase&);
    691 
    692 	void						createShaderSpec			(void);
    693 
    694 	const glu::DataType			m_samplerType;
    695 	const int					m_numSamplers;
    696 	const int					m_numLookups;
    697 	std::vector<int>			m_lookupIndices;
    698 };
    699 
    700 SamplerIndexingCase::SamplerIndexingCase (tcu::TestContext&			testCtx,
    701 										  const char*				name,
    702 										  const char*				description,
    703 										  const glu::ShaderType		shaderType,
    704 										  glu::DataType				samplerType,
    705 										  IndexExprType				indexExprType)
    706 	: OpaqueTypeIndexingCase	(testCtx, name, description, shaderType, indexExprType)
    707 	, m_samplerType				(samplerType)
    708 	, m_numSamplers				(SamplerIndexingCaseInstance::NUM_SAMPLERS)
    709 	, m_numLookups				(SamplerIndexingCaseInstance::NUM_LOOKUPS)
    710 	, m_lookupIndices			(m_numLookups)
    711 {
    712 	createShaderSpec();
    713 	init();
    714 }
    715 
    716 SamplerIndexingCase::~SamplerIndexingCase (void)
    717 {
    718 }
    719 
    720 TestInstance* SamplerIndexingCase::createInstance (Context& ctx) const
    721 {
    722 	return new SamplerIndexingCaseInstance(ctx,
    723 										   m_shaderType,
    724 										   m_shaderSpec,
    725 										   *m_executor,
    726 										   m_name,
    727 										   m_samplerType,
    728 										   m_indexExprType,
    729 										   m_uniformSetup,
    730 										   m_lookupIndices);
    731 }
    732 
    733 void SamplerIndexingCase::createShaderSpec (void)
    734 {
    735 	de::Random			rnd				(deInt32Hash(m_samplerType) ^ deInt32Hash(m_shaderType) ^ deInt32Hash(m_indexExprType));
    736 	deUint32			binding			= getFirstFreeBindingLocation(m_shaderType);
    737 	const char*			samplersName	= "texSampler";
    738 	const char*			coordsName		= "coords";
    739 	const char*			indicesPrefix	= "index";
    740 	const char*			resultPrefix	= "result";
    741 	const glu::DataType	coordType		= getSamplerCoordType(m_samplerType);
    742 	const glu::DataType	outType			= getSamplerOutputType(m_samplerType);
    743 	std::ostringstream	global, code;
    744 
    745 	for (int ndx = 0; ndx < m_numLookups; ndx++)
    746 		m_lookupIndices[ndx] = rnd.getInt(0, m_numSamplers-1);
    747 
    748 	m_shaderSpec.inputs.push_back(Symbol(coordsName, glu::VarType(coordType, glu::PRECISION_HIGHP)));
    749 
    750 	if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL)
    751 		global << "#extension GL_EXT_gpu_shader5 : require\n";
    752 
    753 	if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
    754 		global << "const highp int indexBase = 1;\n";
    755 
    756 	global <<
    757 		"layout(set = 0, binding = " << binding++ << ") uniform highp " << getDataTypeName(m_samplerType) << " " << samplersName << "[" << m_numSamplers << "];\n";
    758 
    759 	if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM)
    760 	{
    761 		for (int lookupNdx = 0; lookupNdx < m_numLookups; lookupNdx++)
    762 		{
    763 			const std::string varName = indicesPrefix + de::toString(lookupNdx);
    764 			m_shaderSpec.inputs.push_back(Symbol(varName, glu::VarType(glu::TYPE_INT, glu::PRECISION_HIGHP)));
    765 		}
    766 	}
    767 	else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM)
    768 		declareUniformIndexVars(global, indicesPrefix, m_numLookups, binding);
    769 
    770 	for (int lookupNdx = 0; lookupNdx < m_numLookups; lookupNdx++)
    771 	{
    772 		const std::string varName = resultPrefix + de::toString(lookupNdx);
    773 		m_shaderSpec.outputs.push_back(Symbol(varName, glu::VarType(outType, glu::PRECISION_HIGHP)));
    774 	}
    775 
    776 	for (int lookupNdx = 0; lookupNdx < m_numLookups; lookupNdx++)
    777 	{
    778 		code << resultPrefix << "" << lookupNdx << " = texture(" << samplersName << "[";
    779 
    780 		if (m_indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL)
    781 			code << m_lookupIndices[lookupNdx];
    782 		else if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
    783 			code << "indexBase + " << (m_lookupIndices[lookupNdx]-1);
    784 		else
    785 			code << indicesPrefix << lookupNdx;
    786 
    787 		code << "], " << coordsName << ");\n";
    788 	}
    789 
    790 	m_shaderSpec.globalDeclarations	= global.str();
    791 	m_shaderSpec.source				= code.str();
    792 }
    793 
    794 enum BlockType
    795 {
    796 	BLOCKTYPE_UNIFORM = 0,
    797 	BLOCKTYPE_BUFFER,
    798 
    799 	BLOCKTYPE_LAST
    800 };
    801 
    802 class BlockArrayIndexingCaseInstance : public OpaqueTypeIndexingTestInstance
    803 {
    804 public:
    805 	enum
    806 	{
    807 		NUM_INVOCATIONS		= 32,
    808 		NUM_INSTANCES		= 4,
    809 		NUM_READS			= 4
    810 	};
    811 
    812 									BlockArrayIndexingCaseInstance	(Context&						context,
    813 																	 const glu::ShaderType			shaderType,
    814 																	 const ShaderSpec&				shaderSpec,
    815 																	 ShaderExecutor&				executor,
    816 																	 const char*					name,
    817 																	 BlockType						blockType,
    818 																	 const IndexExprType			indexExprType,
    819 																	 UniformSetup*					uniformSetup,
    820 																	 const std::vector<int>&		readIndices,
    821 																	 const std::vector<deUint32>&	inValues);
    822 	virtual							~BlockArrayIndexingCaseInstance	(void);
    823 
    824 	virtual tcu::TestStatus			iterate							(void);
    825 
    826 private:
    827 	const BlockType					m_blockType;
    828 	const std::vector<int>&			m_readIndices;
    829 	const std::vector<deUint32>&	m_inValues;
    830 };
    831 
    832 BlockArrayIndexingCaseInstance::BlockArrayIndexingCaseInstance (Context&						context,
    833 																const glu::ShaderType			shaderType,
    834 																const ShaderSpec&				shaderSpec,
    835 																ShaderExecutor&					executor,
    836 																const char*						name,
    837 																BlockType						blockType,
    838 																const IndexExprType				indexExprType,
    839 																UniformSetup*					uniformSetup,
    840 																const std::vector<int>&			readIndices,
    841 																const std::vector<deUint32>&	inValues)
    842 	: OpaqueTypeIndexingTestInstance	(context, shaderType, shaderSpec, executor, name, uniformSetup, indexExprType)
    843 	, m_blockType						(blockType)
    844 	, m_readIndices						(readIndices)
    845 	, m_inValues						(inValues)
    846 {
    847 }
    848 
    849 BlockArrayIndexingCaseInstance::~BlockArrayIndexingCaseInstance (void)
    850 {
    851 }
    852 
    853 tcu::TestStatus BlockArrayIndexingCaseInstance::iterate (void)
    854 {
    855 	const int					numInvocations		= NUM_INVOCATIONS;
    856 	const int					numReads			= NUM_READS;
    857 	std::vector<deUint32>		outValues			(numInvocations*numReads);
    858 
    859 	{
    860 		tcu::TestLog&			log					= m_context.getTestContext().getLog();
    861 		tcu::TestStatus			testResult			= tcu::TestStatus::pass("Pass");
    862 		std::vector<int>		expandedIndices;
    863 		std::vector<void*>		inputs;
    864 		std::vector<void*>		outputs;
    865 		deUint32				bindingLocation		= getFirstFreeBindingLocation(m_shaderType);
    866 		VkDescriptorType		descriptorType		= m_blockType == BLOCKTYPE_UNIFORM ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER : VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
    867 
    868 		checkSupported(descriptorType);
    869 
    870 		m_uniformSetup->addData(new UniformArrayData<deUint32>(bindingLocation++, descriptorType, m_inValues));
    871 
    872 		if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM)
    873 		{
    874 			expandedIndices.resize(numInvocations * m_readIndices.size());
    875 
    876 			for (int readNdx = 0; readNdx < numReads; readNdx++)
    877 			{
    878 				int* dst = &expandedIndices[numInvocations*readNdx];
    879 				std::fill(dst, dst+numInvocations, m_readIndices[readNdx]);
    880 			}
    881 
    882 			for (int readNdx = 0; readNdx < numReads; readNdx++)
    883 				inputs.push_back(&expandedIndices[readNdx*numInvocations]);
    884 		}
    885 		else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM)
    886 			uploadUniformIndices(m_uniformSetup, numReads, &m_readIndices[0], bindingLocation);
    887 
    888 		for (int readNdx = 0; readNdx < numReads; readNdx++)
    889 			outputs.push_back(&outValues[readNdx*numInvocations]);
    890 
    891 		m_executor.setUniforms(m_uniformSetup);
    892 
    893 		m_executor.execute(m_context, numInvocations, inputs.empty() ? DE_NULL : &inputs[0], &outputs[0]);
    894 
    895 		for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++)
    896 		{
    897 			for (int readNdx = 0; readNdx < numReads; readNdx++)
    898 			{
    899 				const deUint32	refValue	= m_inValues[m_readIndices[readNdx]];
    900 				const deUint32	resValue	= outValues[readNdx*numInvocations + invocationNdx];
    901 
    902 				if (refValue != resValue)
    903 				{
    904 					log << tcu::TestLog::Message << "ERROR: at invocation " << invocationNdx
    905 						<< ", read " << readNdx << ": expected "
    906 						<< tcu::toHex(refValue) << ", got " << tcu::toHex(resValue)
    907 						<< tcu::TestLog::EndMessage;
    908 
    909 					if (testResult.getCode() == QP_TEST_RESULT_PASS)
    910 						testResult = tcu::TestStatus::fail("Invalid result value");
    911 				}
    912 			}
    913 		}
    914 
    915 		return testResult;
    916 	}
    917 }
    918 
    919 class BlockArrayIndexingCase : public OpaqueTypeIndexingCase
    920 {
    921 public:
    922 								BlockArrayIndexingCase		(tcu::TestContext&			testCtx,
    923 															 const char*				name,
    924 															 const char*				description,
    925 															 BlockType					blockType,
    926 															 IndexExprType				indexExprType,
    927 															 const glu::ShaderType		shaderType);
    928 	virtual						~BlockArrayIndexingCase		(void);
    929 
    930 	virtual TestInstance*		createInstance				(Context& ctx) const;
    931 
    932 private:
    933 								BlockArrayIndexingCase		(const BlockArrayIndexingCase&);
    934 	BlockArrayIndexingCase&		operator=					(const BlockArrayIndexingCase&);
    935 
    936 	void						createShaderSpec			(void);
    937 
    938 	const BlockType				m_blockType;
    939 	std::vector<int>			m_readIndices;
    940 	std::vector<deUint32>		m_inValues;
    941 };
    942 
    943 BlockArrayIndexingCase::BlockArrayIndexingCase (tcu::TestContext&			testCtx,
    944 												const char*					name,
    945 												const char*					description,
    946 												BlockType					blockType,
    947 												IndexExprType				indexExprType,
    948 												const glu::ShaderType		shaderType)
    949 	: OpaqueTypeIndexingCase	(testCtx, name, description, shaderType, indexExprType)
    950 	, m_blockType				(blockType)
    951 	, m_readIndices				(BlockArrayIndexingCaseInstance::NUM_READS)
    952 	, m_inValues				(BlockArrayIndexingCaseInstance::NUM_INSTANCES)
    953 {
    954 	createShaderSpec();
    955 	init();
    956 }
    957 
    958 BlockArrayIndexingCase::~BlockArrayIndexingCase (void)
    959 {
    960 }
    961 
    962 TestInstance* BlockArrayIndexingCase::createInstance (Context& ctx) const
    963 {
    964 	return new BlockArrayIndexingCaseInstance(ctx,
    965 											  m_shaderType,
    966 											  m_shaderSpec,
    967 											  *m_executor,
    968 											  m_name,
    969 											  m_blockType,
    970 											  m_indexExprType,
    971 											  m_uniformSetup,
    972 											  m_readIndices,
    973 											  m_inValues);
    974 }
    975 
    976 void BlockArrayIndexingCase::createShaderSpec (void)
    977 {
    978 	const int			numInstances	= BlockArrayIndexingCaseInstance::NUM_INSTANCES;
    979 	const int			numReads		= BlockArrayIndexingCaseInstance::NUM_READS;
    980 	de::Random			rnd				(deInt32Hash(m_shaderType) ^ deInt32Hash(m_blockType) ^ deInt32Hash(m_indexExprType));
    981 	deUint32			binding			= getFirstFreeBindingLocation(m_shaderType);
    982 	const char*			blockName		= "Block";
    983 	const char*			instanceName	= "block";
    984 	const char*			indicesPrefix	= "index";
    985 	const char*			resultPrefix	= "result";
    986 	const char*			interfaceName	= m_blockType == BLOCKTYPE_UNIFORM ? "uniform" : "buffer";
    987 	std::ostringstream	global, code;
    988 
    989 	for (int readNdx = 0; readNdx < numReads; readNdx++)
    990 		m_readIndices[readNdx] = rnd.getInt(0, numInstances-1);
    991 
    992 	for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
    993 		m_inValues[instanceNdx] = rnd.getUint32();
    994 
    995 	if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL)
    996 		global << "#extension GL_EXT_gpu_shader5 : require\n";
    997 
    998 	if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
    999 		global << "const highp int indexBase = 1;\n";
   1000 
   1001 	global <<
   1002 		"layout(set = 0, binding = " << binding++ << ") " << interfaceName << " " << blockName << "\n"
   1003 		"{\n"
   1004 		"	highp uint value;\n"
   1005 		"} " << instanceName << "[" << numInstances << "];\n";
   1006 
   1007 	if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM)
   1008 	{
   1009 		for (int readNdx = 0; readNdx < numReads; readNdx++)
   1010 		{
   1011 			const std::string varName = indicesPrefix + de::toString(readNdx);
   1012 			m_shaderSpec.inputs.push_back(Symbol(varName, glu::VarType(glu::TYPE_INT, glu::PRECISION_HIGHP)));
   1013 		}
   1014 	}
   1015 	else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM)
   1016 		declareUniformIndexVars(global, indicesPrefix, numReads, binding);
   1017 
   1018 	for (int readNdx = 0; readNdx < numReads; readNdx++)
   1019 	{
   1020 		const std::string varName = resultPrefix + de::toString(readNdx);
   1021 		m_shaderSpec.outputs.push_back(Symbol(varName, glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
   1022 	}
   1023 
   1024 	for (int readNdx = 0; readNdx < numReads; readNdx++)
   1025 	{
   1026 		code << resultPrefix << readNdx << " = " << instanceName << "[";
   1027 
   1028 		if (m_indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL)
   1029 			code << m_readIndices[readNdx];
   1030 		else if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
   1031 			code << "indexBase + " << (m_readIndices[readNdx]-1);
   1032 		else
   1033 			code << indicesPrefix << readNdx;
   1034 
   1035 		code << "].value;\n";
   1036 	}
   1037 
   1038 	m_shaderSpec.globalDeclarations	= global.str();
   1039 	m_shaderSpec.source				= code.str();
   1040 }
   1041 
   1042 class AtomicCounterIndexingCaseInstance : public OpaqueTypeIndexingTestInstance
   1043 {
   1044 public:
   1045 	enum
   1046 	{
   1047 		NUM_INVOCATIONS		= 32,
   1048 		NUM_COUNTERS		= 4,
   1049 		NUM_OPS				= 4
   1050 	};
   1051 
   1052 								AtomicCounterIndexingCaseInstance	(Context&					context,
   1053 																	 const glu::ShaderType		shaderType,
   1054 																	 const ShaderSpec&			shaderSpec,
   1055 																	 ShaderExecutor&			executor,
   1056 																	 const char*				name,
   1057 																	 UniformSetup*				uniformSetup,
   1058 																	 const std::vector<int>&	opIndices,
   1059 																	 const IndexExprType		indexExprType);
   1060 	virtual						~AtomicCounterIndexingCaseInstance	(void);
   1061 
   1062 	virtual	tcu::TestStatus		iterate								(void);
   1063 
   1064 private:
   1065 	const std::vector<int>&		m_opIndices;
   1066 };
   1067 
   1068 AtomicCounterIndexingCaseInstance::AtomicCounterIndexingCaseInstance (Context&					context,
   1069 																	  const glu::ShaderType		shaderType,
   1070 																	  const ShaderSpec&			shaderSpec,
   1071 																	  ShaderExecutor&			executor,
   1072 																	  const char*				name,
   1073 																	  UniformSetup*				uniformSetup,
   1074 																	  const std::vector<int>&	opIndices,
   1075 																	  const IndexExprType		indexExprType)
   1076 	: OpaqueTypeIndexingTestInstance	(context, shaderType, shaderSpec, executor, name, uniformSetup, indexExprType)
   1077 	, m_opIndices						(opIndices)
   1078 {
   1079 }
   1080 
   1081 AtomicCounterIndexingCaseInstance::~AtomicCounterIndexingCaseInstance (void)
   1082 {
   1083 }
   1084 
   1085 tcu::TestStatus AtomicCounterIndexingCaseInstance::iterate (void)
   1086 {
   1087 	// \todo [2015-12-02 elecro] Add vertexPipelineStoresAndAtomics feature check.
   1088 	const int					numInvocations		= NUM_INVOCATIONS;
   1089 	const int					numCounters			= NUM_COUNTERS;
   1090 	const int					numOps				= NUM_OPS;
   1091 	std::vector<int>			expandedIndices;
   1092 	std::vector<void*>			inputs;
   1093 	std::vector<void*>			outputs;
   1094 	std::vector<deUint32>		outValues			(numInvocations*numOps);
   1095 	deUint32					bindingLocation		= getFirstFreeBindingLocation(m_shaderType);
   1096 
   1097 	const deUint32 atomicCounterLocation = bindingLocation++;
   1098 
   1099 	checkSupported(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
   1100 
   1101 	{
   1102 		DE_ASSERT(numCounters <= 4);
   1103 		// Add the atomic counters' base value, all zero.
   1104 		m_uniformSetup->addData(new UniformData<tcu::Mat4>(atomicCounterLocation, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, tcu::Mat4(0.0)));
   1105 
   1106 		if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM)
   1107 		{
   1108 			expandedIndices.resize(numInvocations * m_opIndices.size());
   1109 
   1110 			for (int opNdx = 0; opNdx < numOps; opNdx++)
   1111 			{
   1112 				int* dst = &expandedIndices[numInvocations*opNdx];
   1113 				std::fill(dst, dst+numInvocations, m_opIndices[opNdx]);
   1114 			}
   1115 
   1116 			for (int opNdx = 0; opNdx < numOps; opNdx++)
   1117 				inputs.push_back(&expandedIndices[opNdx*numInvocations]);
   1118 		}
   1119 		else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM)
   1120 			uploadUniformIndices(m_uniformSetup, numOps, &m_opIndices[0], bindingLocation);
   1121 
   1122 		for (int opNdx = 0; opNdx < numOps; opNdx++)
   1123 			outputs.push_back(&outValues[opNdx*numInvocations]);
   1124 
   1125 		m_executor.setUniforms(m_uniformSetup);
   1126 
   1127 		m_executor.execute(m_context, numInvocations, inputs.empty() ? DE_NULL : &inputs[0], &outputs[0]);
   1128 	}
   1129 
   1130 	{
   1131 		tcu::TestLog&					log				= m_context.getTestContext().getLog();
   1132 		tcu::TestStatus					testResult		= tcu::TestStatus::pass("Pass");
   1133 		std::vector<int>				numHits			(numCounters, 0);	// Number of hits per counter.
   1134 		std::vector<deUint32>			counterValues	(numCounters);
   1135 		std::vector<std::vector<bool> >	counterMasks	(numCounters);
   1136 
   1137 		for (int opNdx = 0; opNdx < numOps; opNdx++)
   1138 			numHits[m_opIndices[opNdx]] += 1;
   1139 
   1140 		// Read counter values
   1141 		{
   1142 			const void* mapPtr = m_executor.getBufferPtr(atomicCounterLocation);
   1143 			DE_ASSERT(mapPtr != DE_NULL);
   1144 			std::copy((const deUint32*)mapPtr, (const deUint32*)mapPtr + numCounters, &counterValues[0]);
   1145 		}
   1146 
   1147 		// Verify counter values
   1148 		for (int counterNdx = 0; counterNdx < numCounters; counterNdx++)
   1149 		{
   1150 			const deUint32		refCount	= (deUint32)(numHits[counterNdx]*numInvocations);
   1151 			const deUint32		resCount	= counterValues[counterNdx];
   1152 
   1153 			if (refCount != resCount)
   1154 			{
   1155 				log << tcu::TestLog::Message << "ERROR: atomic counter " << counterNdx << " has value " << resCount
   1156 					<< ", expected " << refCount
   1157 					<< tcu::TestLog::EndMessage;
   1158 
   1159 				if (testResult.getCode() == QP_TEST_RESULT_PASS)
   1160 					testResult = tcu::TestStatus::fail("Invalid atomic counter value");
   1161 			}
   1162 		}
   1163 
   1164 		// Allocate bitmasks - one bit per each valid result value
   1165 		for (int counterNdx = 0; counterNdx < numCounters; counterNdx++)
   1166 		{
   1167 			const int	counterValue	= numHits[counterNdx]*numInvocations;
   1168 			counterMasks[counterNdx].resize(counterValue, false);
   1169 		}
   1170 
   1171 		// Verify result values from shaders
   1172 		for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++)
   1173 		{
   1174 			for (int opNdx = 0; opNdx < numOps; opNdx++)
   1175 			{
   1176 				const int		counterNdx	= m_opIndices[opNdx];
   1177 				const deUint32	resValue	= outValues[opNdx*numInvocations + invocationNdx];
   1178 				const bool		rangeOk		= de::inBounds(resValue, 0u, (deUint32)counterMasks[counterNdx].size());
   1179 				const bool		notSeen		= rangeOk && !counterMasks[counterNdx][resValue];
   1180 				const bool		isOk		= rangeOk && notSeen;
   1181 
   1182 				if (!isOk)
   1183 				{
   1184 					log << tcu::TestLog::Message << "ERROR: at invocation " << invocationNdx
   1185 						<< ", op " << opNdx << ": got invalid result value "
   1186 						<< resValue
   1187 						<< tcu::TestLog::EndMessage;
   1188 
   1189 					if (testResult.getCode() == QP_TEST_RESULT_PASS)
   1190 						testResult = tcu::TestStatus::fail("Invalid result value");
   1191 				}
   1192 				else
   1193 				{
   1194 					// Mark as used - no other invocation should see this value from same counter.
   1195 					counterMasks[counterNdx][resValue] = true;
   1196 				}
   1197 			}
   1198 		}
   1199 
   1200 		if (testResult.getCode() == QP_TEST_RESULT_PASS)
   1201 		{
   1202 			// Consistency check - all masks should be 1 now
   1203 			for (int counterNdx = 0; counterNdx < numCounters; counterNdx++)
   1204 			{
   1205 				for (std::vector<bool>::const_iterator i = counterMasks[counterNdx].begin(); i != counterMasks[counterNdx].end(); i++)
   1206 					TCU_CHECK_INTERNAL(*i);
   1207 			}
   1208 		}
   1209 
   1210 		return testResult;
   1211 	}
   1212 }
   1213 
   1214 class AtomicCounterIndexingCase : public OpaqueTypeIndexingCase
   1215 {
   1216 public:
   1217 								AtomicCounterIndexingCase	(tcu::TestContext&			testCtx,
   1218 															 const char*				name,
   1219 															 const char*				description,
   1220 															 IndexExprType				indexExprType,
   1221 															 const glu::ShaderType		shaderType);
   1222 	virtual						~AtomicCounterIndexingCase	(void);
   1223 
   1224 	virtual TestInstance*		createInstance				(Context& ctx) const;
   1225 
   1226 private:
   1227 								AtomicCounterIndexingCase	(const BlockArrayIndexingCase&);
   1228 	AtomicCounterIndexingCase&	operator=					(const BlockArrayIndexingCase&);
   1229 
   1230 	void						createShaderSpec			(void);
   1231 
   1232 	std::vector<int>			m_opIndices;
   1233 };
   1234 
   1235 AtomicCounterIndexingCase::AtomicCounterIndexingCase (tcu::TestContext&			testCtx,
   1236 													  const char*				name,
   1237 													  const char*				description,
   1238 													  IndexExprType				indexExprType,
   1239 													  const glu::ShaderType		shaderType)
   1240 	: OpaqueTypeIndexingCase	(testCtx, name, description, shaderType, indexExprType)
   1241 	, m_opIndices				(AtomicCounterIndexingCaseInstance::NUM_OPS)
   1242 {
   1243 	createShaderSpec();
   1244 	init();
   1245 }
   1246 
   1247 AtomicCounterIndexingCase::~AtomicCounterIndexingCase (void)
   1248 {
   1249 }
   1250 
   1251 TestInstance* AtomicCounterIndexingCase::createInstance (Context& ctx) const
   1252 {
   1253 	return new AtomicCounterIndexingCaseInstance(ctx,
   1254 												 m_shaderType,
   1255 												 m_shaderSpec,
   1256 												 *m_executor,
   1257 												 m_name,
   1258 												 m_uniformSetup,
   1259 												 m_opIndices,
   1260 												 m_indexExprType);
   1261 }
   1262 
   1263 void AtomicCounterIndexingCase::createShaderSpec (void)
   1264 {
   1265 	const int				numCounters		= AtomicCounterIndexingCaseInstance::NUM_COUNTERS;
   1266 	const int				numOps			= AtomicCounterIndexingCaseInstance::NUM_OPS;
   1267 	deUint32				binding			= getFirstFreeBindingLocation(m_shaderType);
   1268 	de::Random				rnd				(deInt32Hash(m_shaderType) ^ deInt32Hash(m_indexExprType));
   1269 
   1270 	for (int opNdx = 0; opNdx < numOps; opNdx++)
   1271 		m_opIndices[opNdx] = rnd.getInt(0, numOps-1);
   1272 
   1273 	{
   1274 		const char*			indicesPrefix	= "index";
   1275 		const char*			resultPrefix	= "result";
   1276 		std::ostringstream	global, code;
   1277 
   1278 		if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL)
   1279 			global << "#extension GL_EXT_gpu_shader5 : require\n";
   1280 
   1281 		if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
   1282 			global << "const highp int indexBase = 1;\n";
   1283 
   1284 		global <<
   1285 			"layout(set = 0, binding = " << binding++ << ") buffer AtomicBuffer { highp uint counter[" << numCounters << "]; };\n";
   1286 
   1287 		if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM)
   1288 		{
   1289 			for (int opNdx = 0; opNdx < numOps; opNdx++)
   1290 			{
   1291 				const std::string varName = indicesPrefix + de::toString(opNdx);
   1292 				m_shaderSpec.inputs.push_back(Symbol(varName, glu::VarType(glu::TYPE_INT, glu::PRECISION_HIGHP)));
   1293 			}
   1294 		}
   1295 		else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM)
   1296 			declareUniformIndexVars(global, indicesPrefix, numOps, binding);
   1297 
   1298 		for (int opNdx = 0; opNdx < numOps; opNdx++)
   1299 		{
   1300 			const std::string varName = resultPrefix + de::toString(opNdx);
   1301 			m_shaderSpec.outputs.push_back(Symbol(varName, glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
   1302 		}
   1303 
   1304 		for (int opNdx = 0; opNdx < numOps; opNdx++)
   1305 		{
   1306 			code << resultPrefix << opNdx << " = atomicAdd(counter[";
   1307 
   1308 			if (m_indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL)
   1309 				code << m_opIndices[opNdx];
   1310 			else if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
   1311 				code << "indexBase + " << (m_opIndices[opNdx]-1);
   1312 			else
   1313 				code << indicesPrefix << opNdx;
   1314 
   1315 			code << "], uint(1));\n";
   1316 		}
   1317 
   1318 		m_shaderSpec.globalDeclarations	= global.str();
   1319 		m_shaderSpec.source				= code.str();
   1320 	}
   1321 }
   1322 
   1323 class OpaqueTypeIndexingTests : public tcu::TestCaseGroup
   1324 {
   1325 public:
   1326 								OpaqueTypeIndexingTests		(tcu::TestContext& testCtx);
   1327 	virtual						~OpaqueTypeIndexingTests	(void);
   1328 
   1329 	virtual void				init						(void);
   1330 
   1331 private:
   1332 								OpaqueTypeIndexingTests		(const OpaqueTypeIndexingTests&);
   1333 	OpaqueTypeIndexingTests&	operator=					(const OpaqueTypeIndexingTests&);
   1334 };
   1335 
   1336 OpaqueTypeIndexingTests::OpaqueTypeIndexingTests (tcu::TestContext& testCtx)
   1337 	: tcu::TestCaseGroup(testCtx, "opaque_type_indexing", "Opaque Type Indexing Tests")
   1338 {
   1339 }
   1340 
   1341 OpaqueTypeIndexingTests::~OpaqueTypeIndexingTests (void)
   1342 {
   1343 }
   1344 
   1345 void OpaqueTypeIndexingTests::init (void)
   1346 {
   1347 	static const struct
   1348 	{
   1349 		IndexExprType	type;
   1350 		const char*		name;
   1351 		const char*		description;
   1352 	} indexingTypes[] =
   1353 	{
   1354 		{ INDEX_EXPR_TYPE_CONST_LITERAL,	"const_literal",		"Indexing by constant literal"					},
   1355 		{ INDEX_EXPR_TYPE_CONST_EXPRESSION,	"const_expression",		"Indexing by constant expression"				},
   1356 		{ INDEX_EXPR_TYPE_UNIFORM,			"uniform",				"Indexing by uniform value"						},
   1357 		{ INDEX_EXPR_TYPE_DYNAMIC_UNIFORM,	"dynamically_uniform",	"Indexing by dynamically uniform expression"	}
   1358 	};
   1359 
   1360 	static const struct
   1361 	{
   1362 		glu::ShaderType	type;
   1363 		const char*		name;
   1364 	} shaderTypes[] =
   1365 	{
   1366 		{ glu::SHADERTYPE_VERTEX,		"vertex"	},
   1367 		{ glu::SHADERTYPE_FRAGMENT,		"fragment"	},
   1368 		{ glu::SHADERTYPE_COMPUTE,		"compute"	}
   1369 	};
   1370 
   1371 	// .sampler
   1372 	{
   1373 		static const glu::DataType samplerTypes[] =
   1374 		{
   1375 			// \note 1D images will be added by a later extension.
   1376 //			glu::TYPE_SAMPLER_1D,
   1377 			glu::TYPE_SAMPLER_2D,
   1378 			glu::TYPE_SAMPLER_CUBE,
   1379 			glu::TYPE_SAMPLER_2D_ARRAY,
   1380 			glu::TYPE_SAMPLER_3D,
   1381 //			glu::TYPE_SAMPLER_1D_SHADOW,
   1382 			glu::TYPE_SAMPLER_2D_SHADOW,
   1383 			glu::TYPE_SAMPLER_CUBE_SHADOW,
   1384 			glu::TYPE_SAMPLER_2D_ARRAY_SHADOW,
   1385 //			glu::TYPE_INT_SAMPLER_1D,
   1386 			glu::TYPE_INT_SAMPLER_2D,
   1387 			glu::TYPE_INT_SAMPLER_CUBE,
   1388 			glu::TYPE_INT_SAMPLER_2D_ARRAY,
   1389 			glu::TYPE_INT_SAMPLER_3D,
   1390 //			glu::TYPE_UINT_SAMPLER_1D,
   1391 			glu::TYPE_UINT_SAMPLER_2D,
   1392 			glu::TYPE_UINT_SAMPLER_CUBE,
   1393 			glu::TYPE_UINT_SAMPLER_2D_ARRAY,
   1394 			glu::TYPE_UINT_SAMPLER_3D,
   1395 		};
   1396 
   1397 		tcu::TestCaseGroup* const samplerGroup = new tcu::TestCaseGroup(m_testCtx, "sampler", "Sampler Array Indexing Tests");
   1398 		addChild(samplerGroup);
   1399 
   1400 		for (int indexTypeNdx = 0; indexTypeNdx < DE_LENGTH_OF_ARRAY(indexingTypes); indexTypeNdx++)
   1401 		{
   1402 			const IndexExprType			indexExprType	= indexingTypes[indexTypeNdx].type;
   1403 			tcu::TestCaseGroup* const	indexGroup		= new tcu::TestCaseGroup(m_testCtx, indexingTypes[indexTypeNdx].name, indexingTypes[indexTypeNdx].description);
   1404 			samplerGroup->addChild(indexGroup);
   1405 
   1406 			for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(shaderTypes); shaderTypeNdx++)
   1407 			{
   1408 				const glu::ShaderType		shaderType		= shaderTypes[shaderTypeNdx].type;
   1409 				tcu::TestCaseGroup* const	shaderGroup		= new tcu::TestCaseGroup(m_testCtx, shaderTypes[shaderTypeNdx].name, "");
   1410 				indexGroup->addChild(shaderGroup);
   1411 
   1412 				for (int samplerTypeNdx = 0; samplerTypeNdx < DE_LENGTH_OF_ARRAY(samplerTypes); samplerTypeNdx++)
   1413 				{
   1414 					const glu::DataType	samplerType	= samplerTypes[samplerTypeNdx];
   1415 					const char*			samplerName	= getDataTypeName(samplerType);
   1416 					const std::string	caseName	= de::toLower(samplerName);
   1417 
   1418 					shaderGroup->addChild(new SamplerIndexingCase(m_testCtx, caseName.c_str(), "", shaderType, samplerType, indexExprType));
   1419 				}
   1420 			}
   1421 		}
   1422 	}
   1423 
   1424 	// .ubo / .ssbo / .atomic_counter
   1425 	{
   1426 		tcu::TestCaseGroup* const	uboGroup	= new tcu::TestCaseGroup(m_testCtx, "ubo",				"Uniform Block Instance Array Indexing Tests");
   1427 		tcu::TestCaseGroup* const	ssboGroup	= new tcu::TestCaseGroup(m_testCtx, "ssbo",				"Buffer Block Instance Array Indexing Tests");
   1428 		tcu::TestCaseGroup* const	acGroup		= new tcu::TestCaseGroup(m_testCtx, "atomic_counter",	"Atomic Counter Array Indexing Tests");
   1429 		addChild(uboGroup);
   1430 		addChild(ssboGroup);
   1431 		addChild(acGroup);
   1432 
   1433 		for (int indexTypeNdx = 0; indexTypeNdx < DE_LENGTH_OF_ARRAY(indexingTypes); indexTypeNdx++)
   1434 		{
   1435 			const IndexExprType		indexExprType		= indexingTypes[indexTypeNdx].type;
   1436 			const char*				indexExprName		= indexingTypes[indexTypeNdx].name;
   1437 			const char*				indexExprDesc		= indexingTypes[indexTypeNdx].description;
   1438 
   1439 			for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(shaderTypes); shaderTypeNdx++)
   1440 			{
   1441 				const glu::ShaderType	shaderType		= shaderTypes[shaderTypeNdx].type;
   1442 				const std::string		name			= std::string(indexExprName) + "_" + shaderTypes[shaderTypeNdx].name;
   1443 
   1444 				uboGroup->addChild	(new BlockArrayIndexingCase		(m_testCtx, name.c_str(), indexExprDesc, BLOCKTYPE_UNIFORM,	indexExprType, shaderType));
   1445 				acGroup->addChild	(new AtomicCounterIndexingCase	(m_testCtx, name.c_str(), indexExprDesc, indexExprType, shaderType));
   1446 
   1447 				if (indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL || indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
   1448 					ssboGroup->addChild	(new BlockArrayIndexingCase	(m_testCtx, name.c_str(), indexExprDesc, BLOCKTYPE_BUFFER, indexExprType, shaderType));
   1449 			}
   1450 		}
   1451 	}
   1452 }
   1453 
   1454 } // anonymous
   1455 
   1456 tcu::TestCaseGroup* createOpaqueTypeIndexingTests (tcu::TestContext& testCtx)
   1457 {
   1458 	return new OpaqueTypeIndexingTests(testCtx);
   1459 }
   1460 
   1461 } // shaderexecutor
   1462 } // vkt
   1463