Home | History | Annotate | Download | only in ssbo
      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 SSBO layout tests.
     24  *//*--------------------------------------------------------------------*/
     25 
     26 #include "vktSSBOLayoutTests.hpp"
     27 #include "vktSSBOLayoutCase.hpp"
     28 
     29 #include "deUniquePtr.hpp"
     30 #include "tcuCommandLine.hpp"
     31 #include "tcuTestLog.hpp"
     32 #include "deRandom.hpp"
     33 #include "deStringUtil.hpp"
     34 #include "deString.h"
     35 #include "vktTestCaseUtil.hpp"
     36 #include "vktTestGroupUtil.hpp"
     37 #include "vkRef.hpp"
     38 #include "vkRefUtil.hpp"
     39 #include "vkBuilderUtil.hpp"
     40 #include "vkPrograms.hpp"
     41 #include "vkQueryUtil.hpp"
     42 #include "vkMemUtil.hpp"
     43 #include "vkTypeUtil.hpp"
     44 
     45 namespace vkt
     46 {
     47 namespace ssbo
     48 {
     49 namespace
     50 {
     51 
     52 using std::string;
     53 using std::vector;
     54 using glu::VarType;
     55 using glu::StructType;
     56 using namespace vk;
     57 
     58 enum FeatureBits
     59 {
     60 	FEATURE_VECTORS				= (1<<0),
     61 	FEATURE_MATRICES			= (1<<1),
     62 	FEATURE_ARRAYS				= (1<<2),
     63 	FEATURE_STRUCTS				= (1<<3),
     64 	FEATURE_NESTED_STRUCTS		= (1<<4),
     65 	FEATURE_INSTANCE_ARRAYS		= (1<<5),
     66 	FEATURE_UNUSED_VARS			= (1<<6),
     67 	FEATURE_UNUSED_MEMBERS		= (1<<7),
     68 	FEATURE_STD140_LAYOUT		= (1<<8),
     69 	FEATURE_STD430_LAYOUT		= (1<<9),
     70 	FEATURE_MATRIX_LAYOUT		= (1<<10),	//!< Matrix layout flags.
     71 	FEATURE_UNSIZED_ARRAYS		= (1<<11),
     72 	FEATURE_ARRAYS_OF_ARRAYS	= (1<<12),
     73 	FEATURE_RELAXED_LAYOUT		= (1<<13)
     74 };
     75 
     76 class RandomSSBOLayoutCase : public SSBOLayoutCase
     77 {
     78 public:
     79 
     80 							RandomSSBOLayoutCase		(tcu::TestContext& testCtx, const char* name, const char* description, BufferMode bufferMode, deUint32 features, deUint32 seed);
     81 
     82 private:
     83 	void					generateBlock				(de::Random& rnd, deUint32 layoutFlags);
     84 	void					generateBufferVar			(de::Random& rnd, BufferBlock& block, bool isLastMember);
     85 	glu::VarType			generateType				(de::Random& rnd, int typeDepth, bool arrayOk, bool unusedArrayOk);
     86 
     87 	deUint32				m_features;
     88 	int						m_maxBlocks;
     89 	int						m_maxInstances;
     90 	int						m_maxArrayLength;
     91 	int						m_maxStructDepth;
     92 	int						m_maxBlockMembers;
     93 	int						m_maxStructMembers;
     94 	deUint32				m_seed;
     95 
     96 	int						m_blockNdx;
     97 	int						m_bufferVarNdx;
     98 	int						m_structNdx;
     99 };
    100 
    101 RandomSSBOLayoutCase::RandomSSBOLayoutCase (tcu::TestContext& testCtx, const char* name, const char* description, BufferMode bufferMode, deUint32 features, deUint32 seed)
    102 	: SSBOLayoutCase		(testCtx, name, description, bufferMode, LOAD_FULL_MATRIX)
    103 	, m_features			(features)
    104 	, m_maxBlocks			(4)
    105 	, m_maxInstances		((features & FEATURE_INSTANCE_ARRAYS)	? 3 : 0)
    106 	, m_maxArrayLength		((features & FEATURE_ARRAYS)			? 8 : 1)
    107 	, m_maxStructDepth		((features & FEATURE_STRUCTS)			? 2 : 0)
    108 	, m_maxBlockMembers		(5)
    109 	, m_maxStructMembers	(4)
    110 	, m_seed				(seed)
    111 	, m_blockNdx			(1)
    112 	, m_bufferVarNdx		(1)
    113 	, m_structNdx			(1)
    114 {
    115 	de::Random rnd(m_seed);
    116 
    117 	const int numBlocks = rnd.getInt(1, m_maxBlocks);
    118 
    119 	for (int ndx = 0; ndx < numBlocks; ndx++)
    120 		generateBlock(rnd, 0);
    121 
    122 	init();
    123 }
    124 
    125 void RandomSSBOLayoutCase::generateBlock (de::Random& rnd, deUint32 layoutFlags)
    126 {
    127 	DE_ASSERT(m_blockNdx <= 'z' - 'a');
    128 
    129 	const float		instanceArrayWeight	= 0.3f;
    130 	BufferBlock&	block				= m_interface.allocBlock((string("Block") + (char)('A' + m_blockNdx)).c_str());
    131 	int				numInstances		= (m_maxInstances > 0 && rnd.getFloat() < instanceArrayWeight) ? rnd.getInt(0, m_maxInstances) : 0;
    132 	int				numVars				= rnd.getInt(1, m_maxBlockMembers);
    133 
    134 	if (numInstances > 0)
    135 		block.setArraySize(numInstances);
    136 
    137 	if (numInstances > 0 || rnd.getBool())
    138 		block.setInstanceName((string("block") + (char)('A' + m_blockNdx)).c_str());
    139 
    140 	// Layout flag candidates.
    141 	vector<deUint32> layoutFlagCandidates;
    142 
    143 	if (m_features & FEATURE_STD430_LAYOUT)
    144 		layoutFlagCandidates.push_back(LAYOUT_STD430);
    145 
    146 	if (m_features & FEATURE_STD140_LAYOUT)
    147 		layoutFlagCandidates.push_back(LAYOUT_STD140);
    148 
    149 	if (m_features & FEATURE_RELAXED_LAYOUT)
    150 		layoutFlagCandidates.push_back(LAYOUT_RELAXED);
    151 
    152 	DE_ASSERT(!layoutFlagCandidates.empty());
    153 
    154 	layoutFlags |= rnd.choose<deUint32>(layoutFlagCandidates.begin(), layoutFlagCandidates.end());
    155 
    156 	if (m_features & FEATURE_MATRIX_LAYOUT)
    157 	{
    158 		static const deUint32 matrixCandidates[] = { 0, LAYOUT_ROW_MAJOR, LAYOUT_COLUMN_MAJOR };
    159 		layoutFlags |= rnd.choose<deUint32>(&matrixCandidates[0], &matrixCandidates[DE_LENGTH_OF_ARRAY(matrixCandidates)]);
    160 	}
    161 
    162 	block.setFlags(layoutFlags);
    163 
    164 	for (int ndx = 0; ndx < numVars; ndx++)
    165 		generateBufferVar(rnd, block, (ndx+1 == numVars));
    166 
    167 	if (numVars > 0)
    168 	{
    169 		const BufferVar&	lastVar			= *(block.end()-1);
    170 		const glu::VarType&	lastType		= lastVar.getType();
    171 		const bool			isUnsizedArr	= lastType.isArrayType() && (lastType.getArraySize() == glu::VarType::UNSIZED_ARRAY);
    172 
    173 		if (isUnsizedArr)
    174 		{
    175 			for (int instanceNdx = 0; instanceNdx < (numInstances ? numInstances : 1); instanceNdx++)
    176 			{
    177 				const int arrSize = rnd.getInt(1, m_maxArrayLength);
    178 				block.setLastUnsizedArraySize(instanceNdx, arrSize);
    179 			}
    180 		}
    181 	}
    182 
    183 	m_blockNdx += 1;
    184 }
    185 
    186 static std::string genName (char first, char last, int ndx)
    187 {
    188 	std::string	str			= "";
    189 	int			alphabetLen	= last - first + 1;
    190 
    191 	while (ndx > alphabetLen)
    192 	{
    193 		str.insert(str.begin(), (char)(first + ((ndx-1)%alphabetLen)));
    194 		ndx = ((ndx-1) / alphabetLen);
    195 	}
    196 
    197 	str.insert(str.begin(), (char)(first + (ndx%(alphabetLen+1)) - 1));
    198 
    199 	return str;
    200 }
    201 
    202 void RandomSSBOLayoutCase::generateBufferVar (de::Random& rnd, BufferBlock& block, bool isLastMember)
    203 {
    204 	const float			readWeight			= 0.7f;
    205 	const float			writeWeight			= 0.7f;
    206 	const float			accessWeight		= 0.85f;
    207 	const bool			unusedOk			= (m_features & FEATURE_UNUSED_VARS) != 0;
    208 	const std::string	name				= genName('a', 'z', m_bufferVarNdx);
    209 	const glu::VarType	type				= generateType(rnd, 0, true, isLastMember && (m_features & FEATURE_UNSIZED_ARRAYS));
    210 	const bool			access				= !unusedOk || (rnd.getFloat() < accessWeight);
    211 	const bool			read				= access ? (rnd.getFloat() < readWeight) : false;
    212 	const bool			write				= access ? (!read || (rnd.getFloat() < writeWeight)) : false;
    213 	const deUint32		flags				= (read ? ACCESS_READ : 0) | (write ? ACCESS_WRITE : 0);
    214 
    215 	block.addMember(BufferVar(name.c_str(), type, flags));
    216 
    217 	m_bufferVarNdx += 1;
    218 }
    219 
    220 glu::VarType RandomSSBOLayoutCase::generateType (de::Random& rnd, int typeDepth, bool arrayOk, bool unsizedArrayOk)
    221 {
    222 	const float structWeight		= 0.1f;
    223 	const float arrayWeight			= 0.1f;
    224 	const float	unsizedArrayWeight	= 0.8f;
    225 
    226 	DE_ASSERT(arrayOk || !unsizedArrayOk);
    227 
    228 	if (unsizedArrayOk && (rnd.getFloat() < unsizedArrayWeight))
    229 	{
    230 		const bool			childArrayOk	= (m_features & FEATURE_ARRAYS_OF_ARRAYS) != 0;
    231 		const glu::VarType	elementType		= generateType(rnd, typeDepth, childArrayOk, false);
    232 		return glu::VarType(elementType, glu::VarType::UNSIZED_ARRAY);
    233 	}
    234 	else if (typeDepth < m_maxStructDepth && rnd.getFloat() < structWeight)
    235 	{
    236 		vector<glu::VarType>	memberTypes;
    237 		int						numMembers = rnd.getInt(1, m_maxStructMembers);
    238 
    239 		// Generate members first so nested struct declarations are in correct order.
    240 		for (int ndx = 0; ndx < numMembers; ndx++)
    241 			memberTypes.push_back(generateType(rnd, typeDepth+1, true, false));
    242 
    243 		glu::StructType& structType = m_interface.allocStruct((string("s") + genName('A', 'Z', m_structNdx)).c_str());
    244 		m_structNdx += 1;
    245 
    246 		DE_ASSERT(numMembers <= 'Z' - 'A');
    247 		for (int ndx = 0; ndx < numMembers; ndx++)
    248 		{
    249 			structType.addMember((string("m") + (char)('A' + ndx)).c_str(), memberTypes[ndx]);
    250 		}
    251 
    252 		return glu::VarType(&structType);
    253 	}
    254 	else if (m_maxArrayLength > 0 && arrayOk && rnd.getFloat() < arrayWeight)
    255 	{
    256 		const int			arrayLength		= rnd.getInt(1, m_maxArrayLength);
    257 		const bool			childArrayOk	= (m_features & FEATURE_ARRAYS_OF_ARRAYS) != 0;
    258 		const glu::VarType	elementType		= generateType(rnd, typeDepth, childArrayOk, false);
    259 
    260 		return glu::VarType(elementType, arrayLength);
    261 	}
    262 	else
    263 	{
    264 		vector<glu::DataType> typeCandidates;
    265 
    266 		typeCandidates.push_back(glu::TYPE_FLOAT);
    267 		typeCandidates.push_back(glu::TYPE_INT);
    268 		typeCandidates.push_back(glu::TYPE_UINT);
    269 		typeCandidates.push_back(glu::TYPE_BOOL);
    270 
    271 		if (m_features & FEATURE_VECTORS)
    272 		{
    273 			typeCandidates.push_back(glu::TYPE_FLOAT_VEC2);
    274 			typeCandidates.push_back(glu::TYPE_FLOAT_VEC3);
    275 			typeCandidates.push_back(glu::TYPE_FLOAT_VEC4);
    276 			typeCandidates.push_back(glu::TYPE_INT_VEC2);
    277 			typeCandidates.push_back(glu::TYPE_INT_VEC3);
    278 			typeCandidates.push_back(glu::TYPE_INT_VEC4);
    279 			typeCandidates.push_back(glu::TYPE_UINT_VEC2);
    280 			typeCandidates.push_back(glu::TYPE_UINT_VEC3);
    281 			typeCandidates.push_back(glu::TYPE_UINT_VEC4);
    282 			typeCandidates.push_back(glu::TYPE_BOOL_VEC2);
    283 			typeCandidates.push_back(glu::TYPE_BOOL_VEC3);
    284 			typeCandidates.push_back(glu::TYPE_BOOL_VEC4);
    285 		}
    286 
    287 		if (m_features & FEATURE_MATRICES)
    288 		{
    289 			typeCandidates.push_back(glu::TYPE_FLOAT_MAT2);
    290 			typeCandidates.push_back(glu::TYPE_FLOAT_MAT2X3);
    291 			typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X2);
    292 			typeCandidates.push_back(glu::TYPE_FLOAT_MAT3);
    293 			typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X4);
    294 			typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X2);
    295 			typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X3);
    296 			typeCandidates.push_back(glu::TYPE_FLOAT_MAT4);
    297 		}
    298 
    299 		glu::DataType	type		= rnd.choose<glu::DataType>(typeCandidates.begin(), typeCandidates.end());
    300 		glu::Precision	precision;
    301 
    302 		if (!glu::isDataTypeBoolOrBVec(type))
    303 		{
    304 			// Precision.
    305 			static const glu::Precision precisionCandidates[] = { glu::PRECISION_LOWP, glu::PRECISION_MEDIUMP, glu::PRECISION_HIGHP };
    306 			precision = rnd.choose<glu::Precision>(&precisionCandidates[0], &precisionCandidates[DE_LENGTH_OF_ARRAY(precisionCandidates)]);
    307 		}
    308 		else
    309 			precision = glu::PRECISION_LAST;
    310 
    311 		return glu::VarType(type, precision);
    312 	}
    313 }
    314 
    315 class BlockBasicTypeCase : public SSBOLayoutCase
    316 {
    317 public:
    318 	BlockBasicTypeCase (tcu::TestContext& testCtx, const char* name, const char* description, const VarType& type, deUint32 layoutFlags, int numInstances, MatrixLoadFlags matrixLoadFlag)
    319 		: SSBOLayoutCase(testCtx, name, description, BUFFERMODE_PER_BLOCK, matrixLoadFlag)
    320 	{
    321 		BufferBlock& block = m_interface.allocBlock("Block");
    322 		block.addMember(BufferVar("var", type, ACCESS_READ|ACCESS_WRITE));
    323 		block.setFlags(layoutFlags);
    324 
    325 		if (numInstances > 0)
    326 		{
    327 			block.setArraySize(numInstances);
    328 			block.setInstanceName("block");
    329 		}
    330 
    331 		init();
    332 	}
    333 };
    334 
    335 class BlockBasicUnsizedArrayCase : public SSBOLayoutCase
    336 {
    337 public:
    338 	BlockBasicUnsizedArrayCase (tcu::TestContext& testCtx, const char* name, const char* description, const VarType& elementType, int arraySize, deUint32 layoutFlags, MatrixLoadFlags matrixLoadFlag)
    339 		: SSBOLayoutCase(testCtx, name, description, BUFFERMODE_PER_BLOCK, matrixLoadFlag)
    340 	{
    341 		BufferBlock& block = m_interface.allocBlock("Block");
    342 		block.addMember(BufferVar("var", VarType(elementType, VarType::UNSIZED_ARRAY), ACCESS_READ|ACCESS_WRITE));
    343 		block.setFlags(layoutFlags);
    344 
    345 		block.setLastUnsizedArraySize(0, arraySize);
    346 
    347 		init();
    348 	}
    349 };
    350 
    351 static void createRandomCaseGroup (tcu::TestCaseGroup* parentGroup, tcu::TestContext& testCtx, const char* groupName, const char* description, SSBOLayoutCase::BufferMode bufferMode, deUint32 features, int numCases, deUint32 baseSeed)
    352 {
    353 	tcu::TestCaseGroup* group = new tcu::TestCaseGroup(testCtx, groupName, description);
    354 	parentGroup->addChild(group);
    355 
    356 	baseSeed += (deUint32)testCtx.getCommandLine().getBaseSeed();
    357 
    358 	for (int ndx = 0; ndx < numCases; ndx++)
    359 		group->addChild(new RandomSSBOLayoutCase(testCtx, de::toString(ndx).c_str(), "", bufferMode, features, (deUint32)ndx+baseSeed));
    360 }
    361 
    362 class BlockSingleStructCase : public SSBOLayoutCase
    363 {
    364 public:
    365 	BlockSingleStructCase (tcu::TestContext& testCtx, const char* name, const char* description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag)
    366 		: SSBOLayoutCase	(testCtx, name, description, bufferMode, matrixLoadFlag)
    367 		, m_layoutFlags		(layoutFlags)
    368 		, m_numInstances	(numInstances)
    369 	{
    370 		StructType& typeS = m_interface.allocStruct("S");
    371 		typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, glu::PRECISION_HIGHP)); // \todo [pyry] First member is unused.
    372 		typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, glu::PRECISION_MEDIUMP), 4));
    373 		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP));
    374 
    375 		BufferBlock& block = m_interface.allocBlock("Block");
    376 		block.addMember(BufferVar("s", VarType(&typeS), ACCESS_READ|ACCESS_WRITE));
    377 		block.setFlags(m_layoutFlags);
    378 
    379 		if (m_numInstances > 0)
    380 		{
    381 			block.setInstanceName("block");
    382 			block.setArraySize(m_numInstances);
    383 		}
    384 
    385 		init();
    386 	}
    387 
    388 private:
    389 	deUint32	m_layoutFlags;
    390 	int			m_numInstances;
    391 };
    392 
    393 class BlockSingleStructArrayCase : public SSBOLayoutCase
    394 {
    395 public:
    396 	BlockSingleStructArrayCase (tcu::TestContext& testCtx, const char* name, const char* description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag)
    397 		: SSBOLayoutCase	(testCtx, name, description, bufferMode, matrixLoadFlag)
    398 		, m_layoutFlags		(layoutFlags)
    399 		, m_numInstances	(numInstances)
    400 	{
    401 		StructType& typeS = m_interface.allocStruct("S");
    402 		typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, glu::PRECISION_HIGHP)); // \todo [pyry] UNUSED
    403 		typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, glu::PRECISION_MEDIUMP), 4));
    404 		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP));
    405 
    406 		BufferBlock& block = m_interface.allocBlock("Block");
    407 		block.addMember(BufferVar("u", VarType(glu::TYPE_UINT, glu::PRECISION_LOWP), 0 /* no access */));
    408 		block.addMember(BufferVar("s", VarType(VarType(&typeS), 3), ACCESS_READ|ACCESS_WRITE));
    409 		block.addMember(BufferVar("v", VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_MEDIUMP), ACCESS_WRITE));
    410 		block.setFlags(m_layoutFlags);
    411 
    412 		if (m_numInstances > 0)
    413 		{
    414 			block.setInstanceName("block");
    415 			block.setArraySize(m_numInstances);
    416 		}
    417 
    418 		init();
    419 	}
    420 
    421 private:
    422 	deUint32	m_layoutFlags;
    423 	int			m_numInstances;
    424 };
    425 
    426 class BlockSingleNestedStructCase : public SSBOLayoutCase
    427 {
    428 public:
    429 	BlockSingleNestedStructCase (tcu::TestContext& testCtx, const char* name, const char* description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag)
    430 		: SSBOLayoutCase	(testCtx, name, description, bufferMode, matrixLoadFlag)
    431 		, m_layoutFlags		(layoutFlags)
    432 		, m_numInstances	(numInstances)
    433 	{
    434 		StructType& typeS = m_interface.allocStruct("S");
    435 		typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, glu::PRECISION_HIGHP));
    436 		typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, glu::PRECISION_MEDIUMP), 4));
    437 		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)); // \todo [pyry] UNUSED
    438 
    439 		StructType& typeT = m_interface.allocStruct("T");
    440 		typeT.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, glu::PRECISION_MEDIUMP));
    441 		typeT.addMember("b", VarType(&typeS));
    442 
    443 		BufferBlock& block = m_interface.allocBlock("Block");
    444 		block.addMember(BufferVar("s", VarType(&typeS), ACCESS_READ));
    445 		block.addMember(BufferVar("v", VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_LOWP), 0 /* no access */));
    446 		block.addMember(BufferVar("t", VarType(&typeT), ACCESS_READ|ACCESS_WRITE));
    447 		block.addMember(BufferVar("u", VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP), ACCESS_WRITE));
    448 		block.setFlags(m_layoutFlags);
    449 
    450 		if (m_numInstances > 0)
    451 		{
    452 			block.setInstanceName("block");
    453 			block.setArraySize(m_numInstances);
    454 		}
    455 
    456 		init();
    457 	}
    458 
    459 private:
    460 	deUint32	m_layoutFlags;
    461 	int			m_numInstances;
    462 };
    463 
    464 class BlockSingleNestedStructArrayCase : public SSBOLayoutCase
    465 {
    466 public:
    467 	BlockSingleNestedStructArrayCase (tcu::TestContext& testCtx, const char* name, const char* description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag)
    468 		: SSBOLayoutCase	(testCtx, name, description, bufferMode, matrixLoadFlag)
    469 		, m_layoutFlags		(layoutFlags)
    470 		, m_numInstances	(numInstances)
    471 	{
    472 		StructType& typeS = m_interface.allocStruct("S");
    473 		typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, glu::PRECISION_HIGHP));
    474 		typeS.addMember("b", VarType(VarType(glu::TYPE_INT_VEC2, glu::PRECISION_MEDIUMP), 4));
    475 		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)); // \todo [pyry] UNUSED
    476 
    477 		StructType& typeT = m_interface.allocStruct("T");
    478 		typeT.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, glu::PRECISION_MEDIUMP));
    479 		typeT.addMember("b", VarType(VarType(&typeS), 3));
    480 
    481 		BufferBlock& block = m_interface.allocBlock("Block");
    482 		block.addMember(BufferVar("s", VarType(&typeS), ACCESS_WRITE));
    483 		block.addMember(BufferVar("v", VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_LOWP), 0 /* no access */));
    484 		block.addMember(BufferVar("t", VarType(VarType(&typeT), 2), ACCESS_READ));
    485 		block.addMember(BufferVar("u", VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP), ACCESS_READ|ACCESS_WRITE));
    486 		block.setFlags(m_layoutFlags);
    487 
    488 		if (m_numInstances > 0)
    489 		{
    490 			block.setInstanceName("block");
    491 			block.setArraySize(m_numInstances);
    492 		}
    493 
    494 		init();
    495 	}
    496 
    497 private:
    498 	deUint32	m_layoutFlags;
    499 	int			m_numInstances;
    500 };
    501 
    502 class BlockUnsizedStructArrayCase : public SSBOLayoutCase
    503 {
    504 public:
    505 	BlockUnsizedStructArrayCase (tcu::TestContext& testCtx, const char* name, const char* description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag)
    506 		: SSBOLayoutCase	(testCtx, name, description, bufferMode, matrixLoadFlag)
    507 		, m_layoutFlags		(layoutFlags)
    508 		, m_numInstances	(numInstances)
    509 	{
    510 		StructType& typeS = m_interface.allocStruct("S");
    511 		typeS.addMember("a", VarType(glu::TYPE_UINT_VEC2, glu::PRECISION_HIGHP)); // \todo [pyry] UNUSED
    512 		typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT2X4, glu::PRECISION_MEDIUMP), 4));
    513 		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC3, glu::PRECISION_HIGHP));
    514 
    515 		BufferBlock& block = m_interface.allocBlock("Block");
    516 		block.addMember(BufferVar("u", VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_LOWP), 0 /* no access */));
    517 		block.addMember(BufferVar("v", VarType(glu::TYPE_UINT, glu::PRECISION_MEDIUMP), ACCESS_WRITE));
    518 		block.addMember(BufferVar("s", VarType(VarType(&typeS), VarType::UNSIZED_ARRAY), ACCESS_READ|ACCESS_WRITE));
    519 		block.setFlags(m_layoutFlags);
    520 
    521 		if (m_numInstances > 0)
    522 		{
    523 			block.setInstanceName("block");
    524 			block.setArraySize(m_numInstances);
    525 		}
    526 
    527 		{
    528 			de::Random rnd(246);
    529 			for (int ndx = 0; ndx < (m_numInstances ? m_numInstances : 1); ndx++)
    530 			{
    531 				const int lastArrayLen = rnd.getInt(1, 5);
    532 				block.setLastUnsizedArraySize(ndx, lastArrayLen);
    533 			}
    534 		}
    535 
    536 		init();
    537 	}
    538 
    539 private:
    540 	deUint32	m_layoutFlags;
    541 	int			m_numInstances;
    542 };
    543 
    544 class Block2LevelUnsizedStructArrayCase : public SSBOLayoutCase
    545 {
    546 public:
    547 	Block2LevelUnsizedStructArrayCase (tcu::TestContext& testCtx, const char* name, const char* description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag)
    548 		: SSBOLayoutCase	(testCtx, name, description, bufferMode, matrixLoadFlag)
    549 		, m_layoutFlags		(layoutFlags)
    550 		, m_numInstances	(numInstances)
    551 	{
    552 		StructType& typeS = m_interface.allocStruct("S");
    553 		typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, glu::PRECISION_HIGHP));
    554 		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP));
    555 
    556 		BufferBlock& block = m_interface.allocBlock("Block");
    557 		block.addMember(BufferVar("u", VarType(glu::TYPE_UINT, glu::PRECISION_LOWP), 0 /* no access */));
    558 		block.addMember(BufferVar("v", VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_MEDIUMP), ACCESS_WRITE));
    559 		block.addMember(BufferVar("s", VarType(VarType(VarType(&typeS), 2), VarType::UNSIZED_ARRAY), ACCESS_READ|ACCESS_WRITE));
    560 		block.setFlags(m_layoutFlags);
    561 
    562 		if (m_numInstances > 0)
    563 		{
    564 			block.setInstanceName("block");
    565 			block.setArraySize(m_numInstances);
    566 		}
    567 
    568 		{
    569 			de::Random rnd(2344);
    570 			for (int ndx = 0; ndx < (m_numInstances ? m_numInstances : 1); ndx++)
    571 			{
    572 				const int lastArrayLen = rnd.getInt(1, 5);
    573 				block.setLastUnsizedArraySize(ndx, lastArrayLen);
    574 			}
    575 		}
    576 
    577 		init();
    578 	}
    579 
    580 private:
    581 	deUint32	m_layoutFlags;
    582 	int			m_numInstances;
    583 };
    584 
    585 class BlockUnsizedNestedStructArrayCase : public SSBOLayoutCase
    586 {
    587 public:
    588 	BlockUnsizedNestedStructArrayCase (tcu::TestContext& testCtx, const char* name, const char* description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag)
    589 		: SSBOLayoutCase	(testCtx, name, description, bufferMode, matrixLoadFlag)
    590 		, m_layoutFlags		(layoutFlags)
    591 		, m_numInstances	(numInstances)
    592 	{
    593 		StructType& typeS = m_interface.allocStruct("S");
    594 		typeS.addMember("a", VarType(glu::TYPE_UINT_VEC3, glu::PRECISION_HIGHP));
    595 		typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_MEDIUMP), 4));
    596 		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)); // \todo [pyry] UNUSED
    597 
    598 		StructType& typeT = m_interface.allocStruct("T");
    599 		typeT.addMember("a", VarType(glu::TYPE_FLOAT_MAT4X3, glu::PRECISION_MEDIUMP));
    600 		typeT.addMember("b", VarType(VarType(&typeS), 3));
    601 		typeT.addMember("c", VarType(glu::TYPE_INT, glu::PRECISION_HIGHP));
    602 
    603 		BufferBlock& block = m_interface.allocBlock("Block");
    604 		block.addMember(BufferVar("s", VarType(&typeS), ACCESS_WRITE));
    605 		block.addMember(BufferVar("v", VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_LOWP), 0 /* no access */));
    606 		block.addMember(BufferVar("u", VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP), ACCESS_READ|ACCESS_WRITE));
    607 		block.addMember(BufferVar("t", VarType(VarType(&typeT), VarType::UNSIZED_ARRAY), ACCESS_READ));
    608 		block.setFlags(m_layoutFlags);
    609 
    610 		if (m_numInstances > 0)
    611 		{
    612 			block.setInstanceName("block");
    613 			block.setArraySize(m_numInstances);
    614 		}
    615 
    616 		{
    617 			de::Random rnd(7921);
    618 			for (int ndx = 0; ndx < (m_numInstances ? m_numInstances : 1); ndx++)
    619 			{
    620 				const int lastArrayLen = rnd.getInt(1, 5);
    621 				block.setLastUnsizedArraySize(ndx, lastArrayLen);
    622 			}
    623 		}
    624 
    625 		init();
    626 	}
    627 
    628 private:
    629 	deUint32	m_layoutFlags;
    630 	int			m_numInstances;
    631 };
    632 
    633 class BlockMultiBasicTypesCase : public SSBOLayoutCase
    634 {
    635 public:
    636 	BlockMultiBasicTypesCase	(tcu::TestContext& testCtx, const char* name, const char* description, deUint32 flagsA, deUint32 flagsB, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag)
    637 		: SSBOLayoutCase		(testCtx, name, description, bufferMode, matrixLoadFlag)
    638 		, m_flagsA				(flagsA)
    639 		, m_flagsB				(flagsB)
    640 		, m_numInstances		(numInstances)
    641 	{
    642 		BufferBlock& blockA = m_interface.allocBlock("BlockA");
    643 		blockA.addMember(BufferVar("a", VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP), ACCESS_READ|ACCESS_WRITE));
    644 		blockA.addMember(BufferVar("b", VarType(glu::TYPE_UINT_VEC3, glu::PRECISION_LOWP), 0 /* no access */));
    645 		blockA.addMember(BufferVar("c", VarType(glu::TYPE_FLOAT_MAT2, glu::PRECISION_MEDIUMP), ACCESS_READ));
    646 		blockA.setInstanceName("blockA");
    647 		blockA.setFlags(m_flagsA);
    648 
    649 		BufferBlock& blockB = m_interface.allocBlock("BlockB");
    650 		blockB.addMember(BufferVar("a", VarType(glu::TYPE_FLOAT_MAT3, glu::PRECISION_MEDIUMP), ACCESS_WRITE));
    651 		blockB.addMember(BufferVar("b", VarType(glu::TYPE_INT_VEC2, glu::PRECISION_LOWP), ACCESS_READ));
    652 		blockB.addMember(BufferVar("c", VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP), 0 /* no access */));
    653 		blockB.addMember(BufferVar("d", VarType(glu::TYPE_BOOL, glu::PRECISION_LAST), ACCESS_READ|ACCESS_WRITE));
    654 		blockB.setInstanceName("blockB");
    655 		blockB.setFlags(m_flagsB);
    656 
    657 		if (m_numInstances > 0)
    658 		{
    659 			blockA.setArraySize(m_numInstances);
    660 			blockB.setArraySize(m_numInstances);
    661 		}
    662 
    663 		init();
    664 	}
    665 
    666 private:
    667 	deUint32	m_flagsA;
    668 	deUint32	m_flagsB;
    669 	int			m_numInstances;
    670 };
    671 
    672 class BlockMultiNestedStructCase : public SSBOLayoutCase
    673 {
    674 public:
    675 	BlockMultiNestedStructCase (tcu::TestContext& testCtx, const char* name, const char* description, deUint32 flagsA, deUint32 flagsB, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag)
    676 		: SSBOLayoutCase	(testCtx, name, description, bufferMode, matrixLoadFlag)
    677 		, m_flagsA			(flagsA)
    678 		, m_flagsB			(flagsB)
    679 		, m_numInstances	(numInstances)
    680 	{
    681 		StructType& typeS = m_interface.allocStruct("S");
    682 		typeS.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, glu::PRECISION_LOWP));
    683 		typeS.addMember("b", VarType(VarType(glu::TYPE_INT_VEC2, glu::PRECISION_MEDIUMP), 4));
    684 		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP));
    685 
    686 		StructType& typeT = m_interface.allocStruct("T");
    687 		typeT.addMember("a", VarType(glu::TYPE_UINT, glu::PRECISION_MEDIUMP)); // \todo [pyry] UNUSED
    688 		typeT.addMember("b", VarType(&typeS));
    689 		typeT.addMember("c", VarType(glu::TYPE_BOOL_VEC4, glu::PRECISION_LAST));
    690 
    691 		BufferBlock& blockA = m_interface.allocBlock("BlockA");
    692 		blockA.addMember(BufferVar("a", VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP), ACCESS_READ|ACCESS_WRITE));
    693 		blockA.addMember(BufferVar("b", VarType(&typeS), ACCESS_WRITE));
    694 		blockA.addMember(BufferVar("c", VarType(glu::TYPE_UINT_VEC3, glu::PRECISION_LOWP), 0 /* no access */));
    695 		blockA.setInstanceName("blockA");
    696 		blockA.setFlags(m_flagsA);
    697 
    698 		BufferBlock& blockB = m_interface.allocBlock("BlockB");
    699 		blockB.addMember(BufferVar("a", VarType(glu::TYPE_FLOAT_MAT2, glu::PRECISION_MEDIUMP), ACCESS_WRITE));
    700 		blockB.addMember(BufferVar("b", VarType(&typeT), ACCESS_READ|ACCESS_WRITE));
    701 		blockB.addMember(BufferVar("c", VarType(glu::TYPE_BOOL_VEC4, glu::PRECISION_LAST), 0 /* no access */));
    702 		blockB.addMember(BufferVar("d", VarType(glu::TYPE_BOOL, glu::PRECISION_LAST), ACCESS_READ|ACCESS_WRITE));
    703 		blockB.setInstanceName("blockB");
    704 		blockB.setFlags(m_flagsB);
    705 
    706 		if (m_numInstances > 0)
    707 		{
    708 			blockA.setArraySize(m_numInstances);
    709 			blockB.setArraySize(m_numInstances);
    710 		}
    711 
    712 		init();
    713 	}
    714 
    715 private:
    716 	deUint32	m_flagsA;
    717 	deUint32	m_flagsB;
    718 	int			m_numInstances;
    719 };
    720 
    721 // unsized_array_length
    722 
    723 struct UnsizedArrayCaseParams
    724 {
    725 	int					elementSize;
    726 	vk::VkDeviceSize	bufferSize;
    727 	vk::VkDeviceSize	bufferBindOffset;
    728 	vk::VkDeviceSize	bufferBindLength;
    729 	const char*			name;
    730 };
    731 
    732 void createUnsizedArrayLengthProgs (SourceCollections& dst, UnsizedArrayCaseParams)
    733 {
    734 	dst.glslSources.add("comp") << glu::ComputeSource(
    735 		"#version 310 es\n"
    736 		"layout(set=0, binding=0, std430) readonly buffer x {\n"
    737 		"   int xs[];\n"
    738 		"};\n"
    739 		"layout(set=0, binding=1, std430) writeonly buffer y {\n"
    740 		"   int observed_size;\n"
    741 		"};\n"
    742 		"layout(local_size_x=1) in;\n"
    743 		"void main (void) {\n"
    744 		"   observed_size = xs.length();\n"
    745 		"}\n");
    746 }
    747 
    748 tcu::TestStatus ssboUnsizedArrayLengthTest (Context& context, UnsizedArrayCaseParams params)
    749 {
    750 	const DeviceInterface&					vk						= context.getDeviceInterface();
    751 	const VkDevice							device					= context.getDevice();
    752 	const VkQueue							queue					= context.getUniversalQueue();
    753 	Allocator&								allocator				= context.getDefaultAllocator();
    754 
    755 	DescriptorSetLayoutBuilder				builder;
    756 	builder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT);	// input buffer
    757 	builder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT);	// result buffer
    758 
    759 	const Unique<VkDescriptorSetLayout>		descriptorSetLayout		(builder.build(vk, device));
    760 	const Unique<VkDescriptorPool>			descriptorPool			(vk::DescriptorPoolBuilder()
    761 																	.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2u)
    762 																	.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1));
    763 
    764 	const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo		=
    765 	{
    766 		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
    767 		DE_NULL,
    768 		(VkPipelineLayoutCreateFlags)0,
    769 		1,															// setLayoutCount,
    770 		&descriptorSetLayout.get(),									// pSetLayouts
    771 		0,															// pushConstantRangeCount
    772 		DE_NULL,													// pPushConstantRanges
    773 	};
    774 	const Unique<VkPipelineLayout>			pipelineLayout			(createPipelineLayout(vk, device, &pipelineLayoutCreateInfo));
    775 
    776 	const Unique<VkShaderModule>			computeModule			(createShaderModule(vk, device, context.getBinaryCollection().get("comp"), (VkShaderModuleCreateFlags)0u));
    777 
    778 	const VkPipelineShaderStageCreateInfo	shaderCreateInfo		=
    779 	{
    780 		VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
    781 		DE_NULL,
    782 		(VkPipelineShaderStageCreateFlags)0,
    783 		VK_SHADER_STAGE_COMPUTE_BIT,								// stage
    784 		*computeModule,												// shader
    785 		"main",
    786 		DE_NULL,													// pSpecializationInfo
    787 	};
    788 
    789 	const VkComputePipelineCreateInfo		pipelineCreateInfo		=
    790 	{
    791 		VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
    792 		DE_NULL,
    793 		0u,															// flags
    794 		shaderCreateInfo,											// cs
    795 		*pipelineLayout,											// layout
    796 		(vk::VkPipeline)0,											// basePipelineHandle
    797 		0u,															// basePipelineIndex
    798 	};
    799 
    800 	const Unique<VkPipeline>				pipeline				(createComputePipeline(vk, device, (VkPipelineCache)0u, &pipelineCreateInfo));
    801 
    802 	// Input buffer
    803 	const VkBufferCreateInfo inputBufferCreateInfo =
    804 	{
    805 		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
    806 		DE_NULL,
    807 		0,															// flags
    808 		(VkDeviceSize) params.bufferSize,							// size
    809 		VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,							// usage TODO: also test _DYNAMIC case.
    810 		VK_SHARING_MODE_EXCLUSIVE,
    811 		0u,															// queueFamilyCount
    812 		DE_NULL,													// pQueueFamilyIndices
    813 	};
    814 	const Unique<VkBuffer>					inputBuffer				(createBuffer(vk, device, &inputBufferCreateInfo));
    815 	const VkMemoryRequirements				inputBufferRequirements	= getBufferMemoryRequirements(vk, device, *inputBuffer);
    816 	const de::MovePtr<Allocation>			inputBufferMemory		= allocator.allocate(inputBufferRequirements, MemoryRequirement::HostVisible);
    817 
    818 	VK_CHECK(vk.bindBufferMemory(device, *inputBuffer, inputBufferMemory->getMemory(), inputBufferMemory->getOffset()));
    819 	// Note: don't care about the contents of the input buffer -- we only determine a size.
    820 
    821 	// Output buffer
    822 	const VkBufferCreateInfo outputBufferCreateInfo =
    823 	{
    824 		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
    825 		DE_NULL,
    826 		0,
    827 		(VkDeviceSize) 4,
    828 		VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
    829 		VK_SHARING_MODE_EXCLUSIVE,
    830 		0u,
    831 		DE_NULL,
    832 	};
    833 	const Unique<VkBuffer>					outputBuffer			(createBuffer(vk, device, &outputBufferCreateInfo));
    834 	const VkMemoryRequirements				outputBufferRequirements= getBufferMemoryRequirements(vk, device, *outputBuffer);
    835 	const de::MovePtr<Allocation>			outputBufferMemory		= allocator.allocate(outputBufferRequirements, MemoryRequirement::HostVisible);
    836 
    837 	VK_CHECK(vk.bindBufferMemory(device, *outputBuffer, outputBufferMemory->getMemory(), outputBufferMemory->getOffset()));
    838 
    839 	// Initialize output buffer contents
    840 	const VkMappedMemoryRange	range			=
    841 	{
    842 		VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,	// sType
    843 		DE_NULL,								// pNext
    844 		outputBufferMemory->getMemory(),		// memory
    845 		0,										// offset
    846 		VK_WHOLE_SIZE,							// size
    847 	};
    848 	int *							outputBufferPtr			= (int *)outputBufferMemory->getHostPtr();
    849 	*outputBufferPtr = -1;
    850 	VK_CHECK(vk.flushMappedMemoryRanges(device, 1u, &range));
    851 
    852 	// Build descriptor set
    853 	const VkDescriptorBufferInfo			inputBufferDesc			= makeDescriptorBufferInfo(*inputBuffer, params.bufferBindOffset, params.bufferBindLength);
    854 	const VkDescriptorBufferInfo			outputBufferDesc		= makeDescriptorBufferInfo(*outputBuffer, 0u, VK_WHOLE_SIZE);
    855 
    856 	const VkDescriptorSetAllocateInfo		descAllocInfo			=
    857 	{
    858 		VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
    859 		DE_NULL,
    860 		*descriptorPool,											// pool
    861 		1u,															// setLayoutCount
    862 		&descriptorSetLayout.get(),									// pSetLayouts
    863 	};
    864 	const Unique<VkDescriptorSet>			descSet					(allocateDescriptorSet(vk, device, &descAllocInfo));
    865 
    866 	DescriptorSetUpdateBuilder()
    867 		.writeSingle(*descSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &inputBufferDesc)
    868 		.writeSingle(*descSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &outputBufferDesc)
    869 		.update(vk, device);
    870 
    871 	const VkCommandPoolCreateInfo			cmdPoolParams			=
    872 	{
    873 		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					// sType
    874 		DE_NULL,													// pNext
    875 		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,			// flags
    876 		context.getUniversalQueueFamilyIndex(),						// queueFamilyIndex
    877 	};
    878 	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, device, &cmdPoolParams));
    879 
    880 	// Command buffer
    881 	const VkCommandBufferAllocateInfo		cmdBufParams			=
    882 	{
    883 		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,			// sType
    884 		DE_NULL,												// pNext
    885 		*cmdPool,												// pool
    886 		VK_COMMAND_BUFFER_LEVEL_PRIMARY,						// level
    887 		1u,														// bufferCount
    888 	};
    889 	const Unique<VkCommandBuffer>			cmdBuf					(allocateCommandBuffer(vk, device, &cmdBufParams));
    890 
    891 	const VkCommandBufferBeginInfo			cmdBufBeginParams		=
    892 	{
    893 		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,			// sType
    894 		DE_NULL,												// pNext
    895 		0u,														// flags
    896 		(const VkCommandBufferInheritanceInfo*)DE_NULL,
    897 	};
    898 
    899 	// Record commands
    900 	VK_CHECK(vk.beginCommandBuffer(*cmdBuf, &cmdBufBeginParams));
    901 
    902 	vk.cmdBindPipeline(*cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
    903 	vk.cmdBindDescriptorSets(*cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descSet.get(), 0u, DE_NULL);
    904 	vk.cmdDispatch(*cmdBuf, 1, 1, 1);
    905 
    906 	const VkMemoryBarrier					barrier					=
    907 	{
    908 		VK_STRUCTURE_TYPE_MEMORY_BARRIER,	// sType
    909 		DE_NULL,							// pNext
    910 		VK_ACCESS_SHADER_WRITE_BIT,			// srcAccessMask
    911 		VK_ACCESS_HOST_READ_BIT,			// dstAccessMask
    912 	};
    913 	vk.cmdPipelineBarrier(*cmdBuf, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 1, &barrier, 0, DE_NULL, 0, DE_NULL);
    914 
    915 	VK_CHECK(vk.endCommandBuffer(*cmdBuf));
    916 
    917 	const VkSubmitInfo						submitInfo				=
    918 	{
    919 		VK_STRUCTURE_TYPE_SUBMIT_INFO,
    920 		DE_NULL,
    921 		0,														// waitSemaphoreCount
    922 		DE_NULL,												// pWaitSemaphores
    923 		DE_NULL,												// pWaitDstStageMask
    924 		1,														// commandBufferCount
    925 		&cmdBuf.get(),											// pCommandBuffers
    926 		0,														// signalSemaphoreCount
    927 		DE_NULL,												// pSignalSemaphores
    928 	};
    929 	VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, (vk::VkFence)0));
    930 
    931 	// Force all work to have completed
    932 	VK_CHECK(vk.deviceWaitIdle(device));
    933 
    934 	// Read back output buffer contents
    935 	VK_CHECK(vk.invalidateMappedMemoryRanges(device, 1, &range));
    936 
    937 	// Expected number of elements in array at end of storage buffer
    938 	const VkDeviceSize						boundLength				= params.bufferBindLength == VK_WHOLE_SIZE
    939 																	? params.bufferSize - params.bufferBindOffset
    940 																	: params.bufferBindLength;
    941 	const int								expectedResult			= (int)(boundLength / params.elementSize);
    942 	const int								actualResult			= *outputBufferPtr;
    943 
    944 	context.getTestContext().getLog()
    945 	<< tcu::TestLog::Message
    946 	<< "Buffer size " << params.bufferSize
    947 	<< " offset " << params.bufferBindOffset
    948 	<< " length " << params.bufferBindLength
    949 	<< " element size " << params.elementSize
    950 	<< " expected array size: " << expectedResult
    951 	<< " actual array size: " << actualResult
    952 	<< tcu::TestLog::EndMessage;
    953 
    954 	if (expectedResult == actualResult)
    955 		return tcu::TestStatus::pass("Got expected array size");
    956 	else
    957 		return tcu::TestStatus::fail("Mismatch array size");
    958 }
    959 
    960 class SSBOLayoutTests : public tcu::TestCaseGroup
    961 {
    962 public:
    963 							SSBOLayoutTests		(tcu::TestContext& testCtx);
    964 							~SSBOLayoutTests	(void);
    965 
    966 	void					init				(void);
    967 
    968 private:
    969 							SSBOLayoutTests		(const SSBOLayoutTests& other);
    970 	SSBOLayoutTests&		operator=			(const SSBOLayoutTests& other);
    971 };
    972 
    973 
    974 SSBOLayoutTests::SSBOLayoutTests (tcu::TestContext& testCtx)
    975 	: TestCaseGroup(testCtx, "layout", "SSBO Layout Tests")
    976 {
    977 }
    978 
    979 SSBOLayoutTests::~SSBOLayoutTests (void)
    980 {
    981 }
    982 
    983 void SSBOLayoutTests::init (void)
    984 {
    985 	static const glu::DataType basicTypes[] =
    986 	{
    987 		glu::TYPE_FLOAT,
    988 		glu::TYPE_FLOAT_VEC2,
    989 		glu::TYPE_FLOAT_VEC3,
    990 		glu::TYPE_FLOAT_VEC4,
    991 		glu::TYPE_INT,
    992 		glu::TYPE_INT_VEC2,
    993 		glu::TYPE_INT_VEC3,
    994 		glu::TYPE_INT_VEC4,
    995 		glu::TYPE_UINT,
    996 		glu::TYPE_UINT_VEC2,
    997 		glu::TYPE_UINT_VEC3,
    998 		glu::TYPE_UINT_VEC4,
    999 		glu::TYPE_BOOL,
   1000 		glu::TYPE_BOOL_VEC2,
   1001 		glu::TYPE_BOOL_VEC3,
   1002 		glu::TYPE_BOOL_VEC4,
   1003 		glu::TYPE_FLOAT_MAT2,
   1004 		glu::TYPE_FLOAT_MAT3,
   1005 		glu::TYPE_FLOAT_MAT4,
   1006 		glu::TYPE_FLOAT_MAT2X3,
   1007 		glu::TYPE_FLOAT_MAT2X4,
   1008 		glu::TYPE_FLOAT_MAT3X2,
   1009 		glu::TYPE_FLOAT_MAT3X4,
   1010 		glu::TYPE_FLOAT_MAT4X2,
   1011 		glu::TYPE_FLOAT_MAT4X3
   1012 	};
   1013 
   1014 	static const struct
   1015 	{
   1016 		const char*		name;
   1017 		deUint32		flags;
   1018 	} layoutFlags[] =
   1019 	{
   1020 		{ "std140",	LAYOUT_STD140 },
   1021 		{ "std430",	LAYOUT_STD430 },
   1022 	};
   1023 
   1024 	static const struct
   1025 	{
   1026 		const char*		name;
   1027 		deUint32		flags;
   1028 	} matrixFlags[] =
   1029 	{
   1030 		{ "row_major",		LAYOUT_ROW_MAJOR	},
   1031 		{ "column_major",	LAYOUT_COLUMN_MAJOR }
   1032 	};
   1033 
   1034 	static const struct
   1035 	{
   1036 		const char*							name;
   1037 		SSBOLayoutCase::BufferMode		mode;
   1038 	} bufferModes[] =
   1039 	{
   1040 		{ "per_block_buffer",	SSBOLayoutCase::BUFFERMODE_PER_BLOCK },
   1041 		{ "single_buffer",		SSBOLayoutCase::BUFFERMODE_SINGLE	}
   1042 	};
   1043 
   1044 	// ssbo.single_basic_type
   1045 	{
   1046 		tcu::TestCaseGroup* singleBasicTypeGroup = new tcu::TestCaseGroup(m_testCtx, "single_basic_type", "Single basic variable in single buffer");
   1047 		addChild(singleBasicTypeGroup);
   1048 
   1049 		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
   1050 		{
   1051 			tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
   1052 			singleBasicTypeGroup->addChild(layoutGroup);
   1053 
   1054 			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
   1055 			{
   1056 				glu::DataType	type		= basicTypes[basicTypeNdx];
   1057 				const char*		typeName	= glu::getDataTypeName(type);
   1058 
   1059 				if (glu::isDataTypeBoolOrBVec(type))
   1060 					layoutGroup->addChild(new BlockBasicTypeCase(m_testCtx, typeName, "", VarType(type, glu::PRECISION_LAST), layoutFlags[layoutFlagNdx].flags, 0, LOAD_FULL_MATRIX));
   1061 				else
   1062 				{
   1063 					for (int precNdx = 0; precNdx < glu::PRECISION_LAST; precNdx++)
   1064 					{
   1065 						const glu::Precision	precision	= glu::Precision(precNdx);
   1066 						const string			caseName	= string(glu::getPrecisionName(precision)) + "_" + typeName;
   1067 
   1068 						layoutGroup->addChild(new BlockBasicTypeCase(m_testCtx, caseName.c_str(), "", VarType(type, precision), layoutFlags[layoutFlagNdx].flags, 0, LOAD_FULL_MATRIX));
   1069 					}
   1070 				}
   1071 
   1072 				if (glu::isDataTypeMatrix(type))
   1073 				{
   1074 					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
   1075 					{
   1076 						for (int precNdx = 0; precNdx < glu::PRECISION_LAST; precNdx++)
   1077 						{
   1078 							const glu::Precision	precision	= glu::Precision(precNdx);
   1079 							const string			caseName	= string(matrixFlags[matFlagNdx].name) + "_" + string(glu::getPrecisionName(precision)) + "_" + typeName;
   1080 
   1081 							layoutGroup->addChild(new BlockBasicTypeCase(m_testCtx, caseName.c_str(),					 "", glu::VarType(type, precision), layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags, 0, LOAD_FULL_MATRIX));
   1082 							layoutGroup->addChild(new BlockBasicTypeCase(m_testCtx, (caseName + "_comp_access").c_str(), "", glu::VarType(type, precision), layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags, 0, LOAD_MATRIX_COMPONENTS));
   1083 						}
   1084 					}
   1085 				}
   1086 			}
   1087 		}
   1088 	}
   1089 
   1090 	// ssbo.single_basic_array
   1091 	{
   1092 		tcu::TestCaseGroup* singleBasicArrayGroup = new tcu::TestCaseGroup(m_testCtx, "single_basic_array", "Single basic array variable in single buffer");
   1093 		addChild(singleBasicArrayGroup);
   1094 
   1095 		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
   1096 		{
   1097 			tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
   1098 			singleBasicArrayGroup->addChild(layoutGroup);
   1099 
   1100 			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
   1101 			{
   1102 				glu::DataType	type		= basicTypes[basicTypeNdx];
   1103 				const char*		typeName	= glu::getDataTypeName(type);
   1104 				const int		arraySize	= 3;
   1105 
   1106 				layoutGroup->addChild(new BlockBasicTypeCase(m_testCtx, typeName, "",
   1107 															 VarType(VarType(type, glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_HIGHP), arraySize),
   1108 															 layoutFlags[layoutFlagNdx].flags, 0, LOAD_FULL_MATRIX));
   1109 
   1110 				if (glu::isDataTypeMatrix(type))
   1111 				{
   1112 					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
   1113 					{
   1114 						layoutGroup->addChild(new BlockBasicTypeCase(m_testCtx, (string(matrixFlags[matFlagNdx].name) + "_" + typeName).c_str(), "",
   1115 																	 VarType(VarType(type, glu::PRECISION_HIGHP), arraySize),
   1116 																	 layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags, 0, LOAD_FULL_MATRIX));
   1117 						layoutGroup->addChild(new BlockBasicTypeCase(m_testCtx, (string(matrixFlags[matFlagNdx].name) + "_" + typeName + "_comp_access").c_str(), "",
   1118 																	 VarType(VarType(type, glu::PRECISION_HIGHP), arraySize),
   1119 																	 layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags, 0, LOAD_MATRIX_COMPONENTS));
   1120 					}
   1121 				}
   1122 			}
   1123 		}
   1124 	}
   1125 
   1126 	// ssbo.basic_unsized_array
   1127 	{
   1128 		tcu::TestCaseGroup* basicUnsizedArray = new tcu::TestCaseGroup(m_testCtx, "basic_unsized_array", "Basic unsized array tests");
   1129 		addChild(basicUnsizedArray);
   1130 
   1131 		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
   1132 		{
   1133 			tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
   1134 			basicUnsizedArray->addChild(layoutGroup);
   1135 
   1136 			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
   1137 			{
   1138 				glu::DataType	type		= basicTypes[basicTypeNdx];
   1139 				const char*		typeName	= glu::getDataTypeName(type);
   1140 				const int		arraySize	= 19;
   1141 
   1142 				layoutGroup->addChild(new BlockBasicUnsizedArrayCase(m_testCtx, typeName, "",
   1143 																	 VarType(type, glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_HIGHP),
   1144 																	 arraySize, layoutFlags[layoutFlagNdx].flags, LOAD_FULL_MATRIX));
   1145 
   1146 				if (glu::isDataTypeMatrix(type))
   1147 				{
   1148 					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
   1149 					{
   1150 						layoutGroup->addChild(new BlockBasicUnsizedArrayCase(m_testCtx, (string(matrixFlags[matFlagNdx].name) + "_" + typeName).c_str(), "",
   1151 																			 VarType(type, glu::PRECISION_HIGHP), arraySize,
   1152 																			 layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags, LOAD_FULL_MATRIX));
   1153 						layoutGroup->addChild(new BlockBasicUnsizedArrayCase(m_testCtx, (string(matrixFlags[matFlagNdx].name) + "_" + typeName + "_comp_access").c_str(), "",
   1154 																			 VarType(type, glu::PRECISION_HIGHP), arraySize,
   1155 																			 layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags, LOAD_MATRIX_COMPONENTS));
   1156 					}
   1157 				}
   1158 			}
   1159 		}
   1160 	}
   1161 
   1162 	// ssbo.2_level_array
   1163 	{
   1164 		tcu::TestCaseGroup* nestedArrayGroup = new tcu::TestCaseGroup(m_testCtx, "2_level_array", "2-level nested array");
   1165 		addChild(nestedArrayGroup);
   1166 
   1167 		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
   1168 		{
   1169 			tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
   1170 			nestedArrayGroup->addChild(layoutGroup);
   1171 
   1172 			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
   1173 			{
   1174 				glu::DataType	type		= basicTypes[basicTypeNdx];
   1175 				const char*		typeName	= glu::getDataTypeName(type);
   1176 				const int		childSize	= 3;
   1177 				const int		parentSize	= 4;
   1178 				const VarType	childType	(VarType(type, glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_HIGHP), childSize);
   1179 				const VarType	fullType	(childType, parentSize);
   1180 
   1181 				layoutGroup->addChild(new BlockBasicTypeCase(m_testCtx, typeName, "", fullType, layoutFlags[layoutFlagNdx].flags, 0, LOAD_FULL_MATRIX));
   1182 
   1183 				if (glu::isDataTypeMatrix(type))
   1184 				{
   1185 					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
   1186 					{
   1187 						layoutGroup->addChild(new BlockBasicTypeCase(m_testCtx, (string(matrixFlags[matFlagNdx].name) + "_" + typeName).c_str(), "",
   1188 																	 fullType,
   1189 																	 layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags, 0, LOAD_FULL_MATRIX));
   1190 						layoutGroup->addChild(new BlockBasicTypeCase(m_testCtx, (string(matrixFlags[matFlagNdx].name) + "_" + typeName + "_comp_access").c_str(), "",
   1191 																	 fullType,
   1192 																	 layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags, 0, LOAD_MATRIX_COMPONENTS));
   1193 					}
   1194 				}
   1195 			}
   1196 		}
   1197 	}
   1198 
   1199 	// ssbo.3_level_array
   1200 	{
   1201 		tcu::TestCaseGroup* nestedArrayGroup = new tcu::TestCaseGroup(m_testCtx, "3_level_array", "3-level nested array");
   1202 		addChild(nestedArrayGroup);
   1203 
   1204 		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
   1205 		{
   1206 			tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
   1207 			nestedArrayGroup->addChild(layoutGroup);
   1208 
   1209 			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
   1210 			{
   1211 				glu::DataType	type		= basicTypes[basicTypeNdx];
   1212 				const char*		typeName	= glu::getDataTypeName(type);
   1213 				const int		childSize0	= 3;
   1214 				const int		childSize1	= 2;
   1215 				const int		parentSize	= 4;
   1216 				const VarType	childType0	(VarType(type, glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_HIGHP), childSize0);
   1217 				const VarType	childType1	(childType0, childSize1);
   1218 				const VarType	fullType	(childType1, parentSize);
   1219 
   1220 				layoutGroup->addChild(new BlockBasicTypeCase(m_testCtx, typeName, "", fullType, layoutFlags[layoutFlagNdx].flags, 0, LOAD_FULL_MATRIX));
   1221 
   1222 				if (glu::isDataTypeMatrix(type))
   1223 				{
   1224 					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
   1225 					{
   1226 						layoutGroup->addChild(new BlockBasicTypeCase(m_testCtx, (string(matrixFlags[matFlagNdx].name) + "_" + typeName).c_str(), "",
   1227 																	 fullType,
   1228 																	 layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags, 0, LOAD_FULL_MATRIX));
   1229 						layoutGroup->addChild(new BlockBasicTypeCase(m_testCtx, (string(matrixFlags[matFlagNdx].name) + "_" + typeName + "_comp_access").c_str(), "",
   1230 																	 fullType,
   1231 																	 layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags, 0, LOAD_MATRIX_COMPONENTS));
   1232 					}
   1233 				}
   1234 			}
   1235 		}
   1236 	}
   1237 
   1238 	// ssbo.3_level_unsized_array
   1239 	{
   1240 		tcu::TestCaseGroup* nestedArrayGroup = new tcu::TestCaseGroup(m_testCtx, "3_level_unsized_array", "3-level nested array, top-level array unsized");
   1241 		addChild(nestedArrayGroup);
   1242 
   1243 		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
   1244 		{
   1245 			tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
   1246 			nestedArrayGroup->addChild(layoutGroup);
   1247 
   1248 			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
   1249 			{
   1250 				glu::DataType	type		= basicTypes[basicTypeNdx];
   1251 				const char*		typeName	= glu::getDataTypeName(type);
   1252 				const int		childSize0	= 2;
   1253 				const int		childSize1	= 4;
   1254 				const int		parentSize	= 3;
   1255 				const VarType	childType0	(VarType(type, glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_HIGHP), childSize0);
   1256 				const VarType	childType1	(childType0, childSize1);
   1257 
   1258 				layoutGroup->addChild(new BlockBasicUnsizedArrayCase(m_testCtx, typeName, "", childType1, parentSize, layoutFlags[layoutFlagNdx].flags, LOAD_FULL_MATRIX));
   1259 
   1260 				if (glu::isDataTypeMatrix(type))
   1261 				{
   1262 					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
   1263 					{
   1264 						layoutGroup->addChild(new BlockBasicUnsizedArrayCase(m_testCtx, (string(matrixFlags[matFlagNdx].name) + "_" + typeName).c_str(), "",
   1265 																			 childType1, parentSize,
   1266 																			 layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags, LOAD_FULL_MATRIX));
   1267 						layoutGroup->addChild(new BlockBasicUnsizedArrayCase(m_testCtx, (string(matrixFlags[matFlagNdx].name) + "_" + typeName + "_comp_access").c_str(), "",
   1268 																			 childType1, parentSize,
   1269 																			 layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags, LOAD_MATRIX_COMPONENTS));
   1270 					}
   1271 				}
   1272 			}
   1273 		}
   1274 	}
   1275 
   1276 	// ssbo.single_struct
   1277 	{
   1278 		tcu::TestCaseGroup* singleStructGroup = new tcu::TestCaseGroup(m_testCtx, "single_struct", "Single struct in uniform block");
   1279 		addChild(singleStructGroup);
   1280 
   1281 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
   1282 		{
   1283 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
   1284 			singleStructGroup->addChild(modeGroup);
   1285 
   1286 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
   1287 			{
   1288 				for (int isArray = 0; isArray < 2; isArray++)
   1289 				{
   1290 					const deUint32	caseFlags	= layoutFlags[layoutFlagNdx].flags;
   1291 					string			caseName	= layoutFlags[layoutFlagNdx].name;
   1292 
   1293 					if (bufferModes[modeNdx].mode == SSBOLayoutCase::BUFFERMODE_SINGLE && isArray == 0)
   1294 						continue; // Doesn't make sense to add this variant.
   1295 
   1296 					if (isArray)
   1297 						caseName += "_instance_array";
   1298 
   1299 					modeGroup->addChild(new BlockSingleStructCase(m_testCtx, caseName.c_str(),					  "", caseFlags, bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
   1300 					modeGroup->addChild(new BlockSingleStructCase(m_testCtx, (caseName + "_comp_access").c_str(), "", caseFlags, bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
   1301 				}
   1302 			}
   1303 		}
   1304 	}
   1305 
   1306 	// ssbo.single_struct_array
   1307 	{
   1308 		tcu::TestCaseGroup* singleStructArrayGroup = new tcu::TestCaseGroup(m_testCtx, "single_struct_array", "Struct array in one uniform block");
   1309 		addChild(singleStructArrayGroup);
   1310 
   1311 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
   1312 		{
   1313 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
   1314 			singleStructArrayGroup->addChild(modeGroup);
   1315 
   1316 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
   1317 			{
   1318 				for (int isArray = 0; isArray < 2; isArray++)
   1319 				{
   1320 					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
   1321 					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
   1322 
   1323 					if (bufferModes[modeNdx].mode == SSBOLayoutCase::BUFFERMODE_SINGLE && isArray == 0)
   1324 						continue; // Doesn't make sense to add this variant.
   1325 
   1326 					if (isArray)
   1327 						baseName += "_instance_array";
   1328 
   1329 					modeGroup->addChild(new BlockSingleStructArrayCase(m_testCtx, baseName.c_str(),						"", baseFlags, bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
   1330 					modeGroup->addChild(new BlockSingleStructArrayCase(m_testCtx, (baseName + "_comp_access").c_str(),	"", baseFlags, bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
   1331 				}
   1332 			}
   1333 		}
   1334 	}
   1335 
   1336 	// ssbo.single_nested_struct
   1337 	{
   1338 		tcu::TestCaseGroup* singleNestedStructGroup = new tcu::TestCaseGroup(m_testCtx, "single_nested_struct", "Nested struct in one uniform block");
   1339 		addChild(singleNestedStructGroup);
   1340 
   1341 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
   1342 		{
   1343 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
   1344 			singleNestedStructGroup->addChild(modeGroup);
   1345 
   1346 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
   1347 			{
   1348 				for (int isArray = 0; isArray < 2; isArray++)
   1349 				{
   1350 					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
   1351 					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
   1352 
   1353 					if (bufferModes[modeNdx].mode == SSBOLayoutCase::BUFFERMODE_SINGLE && isArray == 0)
   1354 						continue; // Doesn't make sense to add this variant.
   1355 
   1356 					if (isArray)
   1357 						baseName += "_instance_array";
   1358 
   1359 					modeGroup->addChild(new BlockSingleNestedStructCase(m_testCtx, baseName.c_str(),					"", baseFlags, bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
   1360 					modeGroup->addChild(new BlockSingleNestedStructCase(m_testCtx, (baseName + "_comp_access").c_str(),	"", baseFlags, bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
   1361 				}
   1362 			}
   1363 		}
   1364 	}
   1365 
   1366 	// ssbo.single_nested_struct_array
   1367 	{
   1368 		tcu::TestCaseGroup* singleNestedStructArrayGroup = new tcu::TestCaseGroup(m_testCtx, "single_nested_struct_array", "Nested struct array in one uniform block");
   1369 		addChild(singleNestedStructArrayGroup);
   1370 
   1371 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
   1372 		{
   1373 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
   1374 			singleNestedStructArrayGroup->addChild(modeGroup);
   1375 
   1376 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
   1377 			{
   1378 				for (int isArray = 0; isArray < 2; isArray++)
   1379 				{
   1380 					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
   1381 					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
   1382 
   1383 					if (bufferModes[modeNdx].mode == SSBOLayoutCase::BUFFERMODE_SINGLE && isArray == 0)
   1384 						continue; // Doesn't make sense to add this variant.
   1385 
   1386 					if (isArray)
   1387 						baseName += "_instance_array";
   1388 
   1389 					modeGroup->addChild(new BlockSingleNestedStructArrayCase(m_testCtx, baseName.c_str(),					 "", baseFlags, bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
   1390 					modeGroup->addChild(new BlockSingleNestedStructArrayCase(m_testCtx, (baseName + "_comp_access").c_str(), "", baseFlags, bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
   1391 				}
   1392 			}
   1393 		}
   1394 	}
   1395 
   1396 	// ssbo.unsized_struct_array
   1397 	{
   1398 		tcu::TestCaseGroup* singleStructArrayGroup = new tcu::TestCaseGroup(m_testCtx, "unsized_struct_array", "Unsized struct array in one uniform block");
   1399 		addChild(singleStructArrayGroup);
   1400 
   1401 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
   1402 		{
   1403 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
   1404 			singleStructArrayGroup->addChild(modeGroup);
   1405 
   1406 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
   1407 			{
   1408 				for (int isArray = 0; isArray < 2; isArray++)
   1409 				{
   1410 					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
   1411 					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
   1412 
   1413 					if (bufferModes[modeNdx].mode == SSBOLayoutCase::BUFFERMODE_SINGLE && isArray == 0)
   1414 						continue; // Doesn't make sense to add this variant.
   1415 
   1416 					if (isArray)
   1417 						baseName += "_instance_array";
   1418 
   1419 					modeGroup->addChild(new BlockUnsizedStructArrayCase(m_testCtx, baseName.c_str(),					"", baseFlags, bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
   1420 					modeGroup->addChild(new BlockUnsizedStructArrayCase(m_testCtx, (baseName + "_comp_access").c_str(),	"", baseFlags, bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
   1421 				}
   1422 			}
   1423 		}
   1424 	}
   1425 
   1426 	// ssbo.2_level_unsized_struct_array
   1427 	{
   1428 		tcu::TestCaseGroup* structArrayGroup = new tcu::TestCaseGroup(m_testCtx, "2_level_unsized_struct_array", "Unsized 2-level struct array in one uniform block");
   1429 		addChild(structArrayGroup);
   1430 
   1431 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
   1432 		{
   1433 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
   1434 			structArrayGroup->addChild(modeGroup);
   1435 
   1436 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
   1437 			{
   1438 				for (int isArray = 0; isArray < 2; isArray++)
   1439 				{
   1440 					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
   1441 					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
   1442 
   1443 					if (bufferModes[modeNdx].mode == SSBOLayoutCase::BUFFERMODE_SINGLE && isArray == 0)
   1444 						continue; // Doesn't make sense to add this variant.
   1445 
   1446 					if (isArray)
   1447 						baseName += "_instance_array";
   1448 
   1449 					modeGroup->addChild(new Block2LevelUnsizedStructArrayCase(m_testCtx, baseName.c_str(),						"", baseFlags, bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
   1450 					modeGroup->addChild(new Block2LevelUnsizedStructArrayCase(m_testCtx, (baseName + "_comp_access").c_str(),	"", baseFlags, bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
   1451 				}
   1452 			}
   1453 		}
   1454 	}
   1455 
   1456 	// ssbo.unsized_nested_struct_array
   1457 	{
   1458 		tcu::TestCaseGroup* singleNestedStructArrayGroup = new tcu::TestCaseGroup(m_testCtx, "unsized_nested_struct_array", "Unsized, nested struct array in one uniform block");
   1459 		addChild(singleNestedStructArrayGroup);
   1460 
   1461 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
   1462 		{
   1463 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
   1464 			singleNestedStructArrayGroup->addChild(modeGroup);
   1465 
   1466 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
   1467 			{
   1468 				for (int isArray = 0; isArray < 2; isArray++)
   1469 				{
   1470 					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
   1471 					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
   1472 
   1473 					if (bufferModes[modeNdx].mode == SSBOLayoutCase::BUFFERMODE_SINGLE && isArray == 0)
   1474 						continue; // Doesn't make sense to add this variant.
   1475 
   1476 					if (isArray)
   1477 						baseName += "_instance_array";
   1478 
   1479 					modeGroup->addChild(new BlockUnsizedNestedStructArrayCase(m_testCtx, baseName.c_str(),					  "", baseFlags, bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
   1480 					modeGroup->addChild(new BlockUnsizedNestedStructArrayCase(m_testCtx, (baseName + "_comp_access").c_str(), "", baseFlags, bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
   1481 				}
   1482 			}
   1483 		}
   1484 	}
   1485 
   1486 	// ssbo.instance_array_basic_type
   1487 	{
   1488 		tcu::TestCaseGroup* instanceArrayBasicTypeGroup = new tcu::TestCaseGroup(m_testCtx, "instance_array_basic_type", "Single basic variable in instance array");
   1489 		addChild(instanceArrayBasicTypeGroup);
   1490 
   1491 		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
   1492 		{
   1493 			tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
   1494 			instanceArrayBasicTypeGroup->addChild(layoutGroup);
   1495 
   1496 			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
   1497 			{
   1498 				glu::DataType	type			= basicTypes[basicTypeNdx];
   1499 				const char*		typeName		= glu::getDataTypeName(type);
   1500 				const int		numInstances	= 3;
   1501 
   1502 				layoutGroup->addChild(new BlockBasicTypeCase(m_testCtx, typeName, "",
   1503 															 VarType(type, glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_HIGHP),
   1504 															 layoutFlags[layoutFlagNdx].flags, numInstances, LOAD_FULL_MATRIX));
   1505 
   1506 				if (glu::isDataTypeMatrix(type))
   1507 				{
   1508 					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
   1509 					{
   1510 						layoutGroup->addChild(new BlockBasicTypeCase(m_testCtx, (string(matrixFlags[matFlagNdx].name) + "_" + typeName).c_str(), "",
   1511 																	 VarType(type, glu::PRECISION_HIGHP), layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags,
   1512 																	 numInstances, LOAD_FULL_MATRIX));
   1513 						layoutGroup->addChild(new BlockBasicTypeCase(m_testCtx, (string(matrixFlags[matFlagNdx].name) + "_" + typeName + "_comp_access").c_str(), "",
   1514 																	 VarType(type, glu::PRECISION_HIGHP), layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags,
   1515 																	 numInstances, LOAD_MATRIX_COMPONENTS));
   1516 					}
   1517 				}
   1518 			}
   1519 		}
   1520 	}
   1521 
   1522 	// ssbo.multi_basic_types
   1523 	{
   1524 		tcu::TestCaseGroup* multiBasicTypesGroup = new tcu::TestCaseGroup(m_testCtx, "multi_basic_types", "Multiple buffers with basic types");
   1525 		addChild(multiBasicTypesGroup);
   1526 
   1527 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
   1528 		{
   1529 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
   1530 			multiBasicTypesGroup->addChild(modeGroup);
   1531 
   1532 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
   1533 			{
   1534 				for (int isArray = 0; isArray < 2; isArray++)
   1535 				{
   1536 					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
   1537 					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
   1538 
   1539 					if (isArray)
   1540 						baseName += "_instance_array";
   1541 
   1542 					modeGroup->addChild(new BlockMultiBasicTypesCase(m_testCtx, baseName.c_str(),					 "", baseFlags, baseFlags, bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
   1543 					modeGroup->addChild(new BlockMultiBasicTypesCase(m_testCtx, (baseName + "_comp_access").c_str(), "", baseFlags, baseFlags, bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
   1544 				}
   1545 			}
   1546 
   1547 			for (int isArray = 0; isArray < 2; isArray++)
   1548 			{
   1549 				std::string	baseName	= "relaxed_block";
   1550 				deUint32	baseFlags	= LAYOUT_RELAXED;
   1551 
   1552 				if (isArray)
   1553 					baseName += "_instance_array";
   1554 
   1555 				modeGroup->addChild(new BlockMultiBasicTypesCase(m_testCtx, baseName.c_str(),					 "", baseFlags, baseFlags, bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
   1556 				modeGroup->addChild(new BlockMultiBasicTypesCase(m_testCtx, (baseName + "_comp_access").c_str(), "", baseFlags, baseFlags, bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
   1557 			}
   1558 		}
   1559 	}
   1560 
   1561 	// ssbo.multi_nested_struct
   1562 	{
   1563 		tcu::TestCaseGroup* multiNestedStructGroup = new tcu::TestCaseGroup(m_testCtx, "multi_nested_struct", "Multiple buffers with nested structs");
   1564 		addChild(multiNestedStructGroup);
   1565 
   1566 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
   1567 		{
   1568 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
   1569 			multiNestedStructGroup->addChild(modeGroup);
   1570 
   1571 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
   1572 			{
   1573 				for (int isArray = 0; isArray < 2; isArray++)
   1574 				{
   1575 					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
   1576 					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
   1577 
   1578 					if (isArray)
   1579 						baseName += "_instance_array";
   1580 
   1581 					modeGroup->addChild(new BlockMultiNestedStructCase(m_testCtx, baseName.c_str(),						"", baseFlags, baseFlags, bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
   1582 					modeGroup->addChild(new BlockMultiNestedStructCase(m_testCtx, (baseName + "_comp_access").c_str(), "", baseFlags, baseFlags, bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
   1583 				}
   1584 			}
   1585 		}
   1586 	}
   1587 
   1588 	// ssbo.random
   1589 	{
   1590 		const deUint32	allStdLayouts	= FEATURE_STD140_LAYOUT|FEATURE_STD430_LAYOUT;
   1591 		const deUint32	allBasicTypes	= FEATURE_VECTORS|FEATURE_MATRICES;
   1592 		const deUint32	unused			= FEATURE_UNUSED_MEMBERS|FEATURE_UNUSED_VARS;
   1593 		const deUint32	unsized			= FEATURE_UNSIZED_ARRAYS;
   1594 		const deUint32	matFlags		= FEATURE_MATRIX_LAYOUT;
   1595 		const deUint32	allButRelaxed	= ~FEATURE_RELAXED_LAYOUT;
   1596 		const deUint32	allRelaxed		= FEATURE_VECTORS|FEATURE_RELAXED_LAYOUT|FEATURE_INSTANCE_ARRAYS;
   1597 
   1598 		tcu::TestCaseGroup* randomGroup = new tcu::TestCaseGroup(m_testCtx, "random", "Random Uniform Block cases");
   1599 		addChild(randomGroup);
   1600 
   1601 		// Basic types.
   1602 		createRandomCaseGroup(randomGroup, m_testCtx, "scalar_types",		"Scalar types only, per-block buffers",				SSBOLayoutCase::BUFFERMODE_PER_BLOCK,	allStdLayouts|unused,																			25, 0);
   1603 		createRandomCaseGroup(randomGroup, m_testCtx, "vector_types",		"Scalar and vector types only, per-block buffers",	SSBOLayoutCase::BUFFERMODE_PER_BLOCK,	allStdLayouts|unused|FEATURE_VECTORS,															25, 25);
   1604 		createRandomCaseGroup(randomGroup, m_testCtx, "basic_types",		"All basic types, per-block buffers",				SSBOLayoutCase::BUFFERMODE_PER_BLOCK,	allStdLayouts|unused|allBasicTypes|matFlags,													25, 50);
   1605 		createRandomCaseGroup(randomGroup, m_testCtx, "basic_arrays",		"Arrays, per-block buffers",						SSBOLayoutCase::BUFFERMODE_PER_BLOCK,	allStdLayouts|unused|allBasicTypes|matFlags|FEATURE_ARRAYS,									25, 50);
   1606 		createRandomCaseGroup(randomGroup, m_testCtx, "unsized_arrays",		"Unsized arrays, per-block buffers",				SSBOLayoutCase::BUFFERMODE_PER_BLOCK,	allStdLayouts|unused|allBasicTypes|matFlags|unsized|FEATURE_ARRAYS,							25, 50);
   1607 		createRandomCaseGroup(randomGroup, m_testCtx, "arrays_of_arrays",	"Arrays of arrays, per-block buffers",				SSBOLayoutCase::BUFFERMODE_PER_BLOCK,	allStdLayouts|unused|allBasicTypes|matFlags|unsized|FEATURE_ARRAYS|FEATURE_ARRAYS_OF_ARRAYS,	25, 950);
   1608 
   1609 		createRandomCaseGroup(randomGroup, m_testCtx, "basic_instance_arrays",					"Basic instance arrays, per-block buffers",				SSBOLayoutCase::BUFFERMODE_PER_BLOCK,	allStdLayouts|unused|allBasicTypes|matFlags|unsized|FEATURE_INSTANCE_ARRAYS,															25, 75);
   1610 		createRandomCaseGroup(randomGroup, m_testCtx, "nested_structs",							"Nested structs, per-block buffers",					SSBOLayoutCase::BUFFERMODE_PER_BLOCK,	allStdLayouts|unused|allBasicTypes|matFlags|unsized|FEATURE_STRUCTS,																	25, 100);
   1611 		createRandomCaseGroup(randomGroup, m_testCtx, "nested_structs_arrays",					"Nested structs, arrays, per-block buffers",			SSBOLayoutCase::BUFFERMODE_PER_BLOCK,	allStdLayouts|unused|allBasicTypes|matFlags|unsized|FEATURE_STRUCTS|FEATURE_ARRAYS|FEATURE_ARRAYS_OF_ARRAYS,							25, 150);
   1612 		createRandomCaseGroup(randomGroup, m_testCtx, "nested_structs_instance_arrays",			"Nested structs, instance arrays, per-block buffers",	SSBOLayoutCase::BUFFERMODE_PER_BLOCK,	allStdLayouts|unused|allBasicTypes|matFlags|unsized|FEATURE_STRUCTS|FEATURE_INSTANCE_ARRAYS,											25, 125);
   1613 		createRandomCaseGroup(randomGroup, m_testCtx, "nested_structs_arrays_instance_arrays",	"Nested structs, instance arrays, per-block buffers",	SSBOLayoutCase::BUFFERMODE_PER_BLOCK,	allStdLayouts|unused|allBasicTypes|matFlags|unsized|FEATURE_STRUCTS|FEATURE_ARRAYS|FEATURE_ARRAYS_OF_ARRAYS|FEATURE_INSTANCE_ARRAYS,	25, 175);
   1614 		createRandomCaseGroup(randomGroup, m_testCtx, "all_per_block_buffers",	"All random features, per-block buffers",	SSBOLayoutCase::BUFFERMODE_PER_BLOCK,	allButRelaxed,	50, 200);
   1615 		createRandomCaseGroup(randomGroup, m_testCtx, "all_shared_buffer",		"All random features, shared buffer",		SSBOLayoutCase::BUFFERMODE_SINGLE,		allButRelaxed,	50, 250);
   1616 
   1617 		createRandomCaseGroup(randomGroup, m_testCtx, "relaxed",			"VK_KHR_relaxed_block_layout",				SSBOLayoutCase::BUFFERMODE_SINGLE,		allRelaxed, 100, deInt32Hash(313));
   1618 	}
   1619 }
   1620 
   1621 void createUnsizedArrayTests (tcu::TestCaseGroup* testGroup)
   1622 {
   1623 	const UnsizedArrayCaseParams subcases[] =
   1624 	{
   1625 		{ 4, 256, 0, 256,			  "float_no_offset_explicit_size" },
   1626 		{ 4, 256, 0, VK_WHOLE_SIZE,	  "float_no_offset_whole_size" },
   1627 		{ 4, 256, 128, 32,			  "float_offset_explicit_size" },
   1628 		{ 4, 256, 128, VK_WHOLE_SIZE, "float_offset_whole_size" },
   1629 	};
   1630 
   1631 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(subcases); ndx++)
   1632 	{
   1633 		const UnsizedArrayCaseParams& params = subcases[ndx];
   1634 		addFunctionCaseWithPrograms<UnsizedArrayCaseParams>(testGroup, params.name, "", createUnsizedArrayLengthProgs, ssboUnsizedArrayLengthTest, params);
   1635 	}
   1636 }
   1637 
   1638 } // anonymous
   1639 
   1640 tcu::TestCaseGroup* createTests (tcu::TestContext& testCtx)
   1641 {
   1642 	de::MovePtr<tcu::TestCaseGroup> ssboTestGroup (new tcu::TestCaseGroup(testCtx, "ssbo", "Shader Storage Buffer Object Tests"));
   1643 
   1644 	ssboTestGroup->addChild(new SSBOLayoutTests(testCtx));
   1645 	addTestGroup(ssboTestGroup.get(), "unsized_array_length", "SSBO unsized array length tests", createUnsizedArrayTests);
   1646 
   1647 	return ssboTestGroup.release();
   1648 }
   1649 
   1650 } // ssbo
   1651 } // vkt
   1652