Home | History | Annotate | Download | only in common
      1 /*-------------------------------------------------------------------------
      2  * OpenGL Conformance Test Suite
      3  * -----------------------------
      4  *
      5  * Copyright (c) 2016 Google Inc.
      6  * Copyright (c) 2016 The Khronos Group Inc.
      7  *
      8  * Licensed under the Apache License, Version 2.0 (the "License");
      9  * you may not use this file except in compliance with the License.
     10  * You may obtain a copy of the License at
     11  *
     12  *      http://www.apache.org/licenses/LICENSE-2.0
     13  *
     14  * Unless required by applicable law or agreed to in writing, software
     15  * distributed under the License is distributed on an "AS IS" BASIS,
     16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     17  * See the License for the specific language governing permissions and
     18  * limitations under the License.
     19  *
     20  */ /*!
     21  * \file
     22  * \brief Uniform block tests.
     23  */ /*-------------------------------------------------------------------*/
     24 
     25 #include "glcUniformBlockTests.hpp"
     26 #include "deRandom.hpp"
     27 #include "deStringUtil.hpp"
     28 #include "glcUniformBlockCase.hpp"
     29 #include "glwEnums.hpp"
     30 #include "glwFunctions.hpp"
     31 #include "tcuCommandLine.hpp"
     32 #include "tcuTestLog.hpp"
     33 
     34 namespace deqp
     35 {
     36 
     37 using std::string;
     38 using std::vector;
     39 using deqp::Context;
     40 
     41 using namespace ub;
     42 
     43 enum FeatureBits
     44 {
     45 	FEATURE_VECTORS			= (1 << 0),
     46 	FEATURE_MATRICES		= (1 << 1),
     47 	FEATURE_ARRAYS			= (1 << 2),
     48 	FEATURE_STRUCTS			= (1 << 3),
     49 	FEATURE_NESTED_STRUCTS  = (1 << 4),
     50 	FEATURE_INSTANCE_ARRAYS = (1 << 5),
     51 	FEATURE_VERTEX_BLOCKS   = (1 << 6),
     52 	FEATURE_FRAGMENT_BLOCKS = (1 << 7),
     53 	FEATURE_SHARED_BLOCKS   = (1 << 8),
     54 	FEATURE_UNUSED_UNIFORMS = (1 << 9),
     55 	FEATURE_UNUSED_MEMBERS  = (1 << 10),
     56 	FEATURE_PACKED_LAYOUT   = (1 << 11),
     57 	FEATURE_SHARED_LAYOUT   = (1 << 12),
     58 	FEATURE_STD140_LAYOUT   = (1 << 13),
     59 	FEATURE_MATRIX_LAYOUT   = (1 << 14) //!< Matrix layout flags.
     60 };
     61 
     62 class RandomUniformBlockCase : public UniformBlockCase
     63 {
     64 public:
     65 	RandomUniformBlockCase(Context& context, const char* name, const char* description, glu::GLSLVersion glslVersion,
     66 						   BufferMode bufferMode, deUint32 features, deUint32 seed);
     67 
     68 	void init(void);
     69 
     70 private:
     71 	void generateBlock(de::Random& rnd, deUint32 layoutFlags);
     72 	void generateUniform(de::Random& rnd, UniformBlock& block);
     73 	VarType generateType(de::Random& rnd, int typeDepth, bool arrayOk);
     74 
     75 	deUint32 m_features;
     76 	int		 m_maxVertexBlocks;
     77 	int		 m_maxFragmentBlocks;
     78 	int		 m_maxSharedBlocks;
     79 	int		 m_maxInstances;
     80 	int		 m_maxArrayLength;
     81 	int		 m_maxStructDepth;
     82 	int		 m_maxBlockMembers;
     83 	int		 m_maxStructMembers;
     84 	deUint32 m_seed;
     85 
     86 	int m_blockNdx;
     87 	int m_uniformNdx;
     88 	int m_structNdx;
     89 };
     90 
     91 RandomUniformBlockCase::RandomUniformBlockCase(Context& context, const char* name, const char* description,
     92 											   glu::GLSLVersion glslVersion, BufferMode bufferMode, deUint32 features,
     93 											   deUint32 seed)
     94 	: UniformBlockCase(context, name, description, glslVersion, bufferMode)
     95 	, m_features(features)
     96 	, m_maxVertexBlocks((features & FEATURE_VERTEX_BLOCKS) ? 4 : 0)
     97 	, m_maxFragmentBlocks((features & FEATURE_FRAGMENT_BLOCKS) ? 4 : 0)
     98 	, m_maxSharedBlocks((features & FEATURE_SHARED_BLOCKS) ? 4 : 0)
     99 	, m_maxInstances((features & FEATURE_INSTANCE_ARRAYS) ? 3 : 0)
    100 	, m_maxArrayLength((features & FEATURE_ARRAYS) ? 8 : 0)
    101 	, m_maxStructDepth((features & FEATURE_STRUCTS) ? 2 : 0)
    102 	, m_maxBlockMembers(5)
    103 	, m_maxStructMembers(4)
    104 	, m_seed(seed)
    105 	, m_blockNdx(1)
    106 	, m_uniformNdx(1)
    107 	, m_structNdx(1)
    108 {
    109 }
    110 
    111 void RandomUniformBlockCase::init(void)
    112 {
    113 	de::Random rnd(m_seed);
    114 
    115 	int numShared	 = m_maxSharedBlocks > 0 ? rnd.getInt(1, m_maxSharedBlocks) : 0;
    116 	int numVtxBlocks  = m_maxVertexBlocks - numShared > 0 ? rnd.getInt(1, m_maxVertexBlocks - numShared) : 0;
    117 	int numFragBlocks = m_maxFragmentBlocks - numShared > 0 ? rnd.getInt(1, m_maxFragmentBlocks - numShared) : 0;
    118 
    119 	for (int ndx = 0; ndx < numShared; ndx++)
    120 		generateBlock(rnd, DECLARE_VERTEX | DECLARE_FRAGMENT);
    121 
    122 	for (int ndx = 0; ndx < numVtxBlocks; ndx++)
    123 		generateBlock(rnd, DECLARE_VERTEX);
    124 
    125 	for (int ndx = 0; ndx < numFragBlocks; ndx++)
    126 		generateBlock(rnd, DECLARE_FRAGMENT);
    127 }
    128 
    129 void RandomUniformBlockCase::generateBlock(de::Random& rnd, deUint32 layoutFlags)
    130 {
    131 	DE_ASSERT(m_blockNdx <= 'z' - 'a');
    132 
    133 	const float   instanceArrayWeight = 0.3f;
    134 	UniformBlock& block				  = m_interface.allocBlock((string("Block") + (char)('A' + m_blockNdx)).c_str());
    135 	int numInstances = (m_maxInstances > 0 && rnd.getFloat() < instanceArrayWeight) ? rnd.getInt(0, m_maxInstances) : 0;
    136 	int numUniforms  = rnd.getInt(1, m_maxBlockMembers);
    137 
    138 	if (numInstances > 0)
    139 		block.setArraySize(numInstances);
    140 
    141 	if (numInstances > 0 || rnd.getBool())
    142 		block.setInstanceName((string("block") + (char)('A' + m_blockNdx)).c_str());
    143 
    144 	// Layout flag candidates.
    145 	vector<deUint32> layoutFlagCandidates;
    146 	layoutFlagCandidates.push_back(0);
    147 	if (m_features & FEATURE_PACKED_LAYOUT)
    148 		layoutFlagCandidates.push_back(LAYOUT_SHARED);
    149 	if ((m_features & FEATURE_SHARED_LAYOUT) && ((layoutFlags & DECLARE_BOTH) != DECLARE_BOTH))
    150 		layoutFlagCandidates.push_back(LAYOUT_PACKED); // \note packed layout can only be used in a single shader stage.
    151 	if (m_features & FEATURE_STD140_LAYOUT)
    152 		layoutFlagCandidates.push_back(LAYOUT_STD140);
    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 |=
    160 			rnd.choose<deUint32>(&matrixCandidates[0], &matrixCandidates[DE_LENGTH_OF_ARRAY(matrixCandidates)]);
    161 	}
    162 
    163 	block.setFlags(layoutFlags);
    164 
    165 	for (int ndx = 0; ndx < numUniforms; ndx++)
    166 		generateUniform(rnd, block);
    167 
    168 	m_blockNdx += 1;
    169 }
    170 
    171 static std::string genName(char first, char last, int ndx)
    172 {
    173 	std::string str			= "";
    174 	int			alphabetLen = last - first + 1;
    175 
    176 	while (ndx > alphabetLen)
    177 	{
    178 		str.insert(str.begin(), (char)(first + ((ndx - 1) % alphabetLen)));
    179 		ndx = ((ndx - 1) / alphabetLen);
    180 	}
    181 
    182 	str.insert(str.begin(), (char)(first + (ndx % (alphabetLen + 1)) - 1));
    183 
    184 	return str;
    185 }
    186 
    187 void RandomUniformBlockCase::generateUniform(de::Random& rnd, UniformBlock& block)
    188 {
    189 	const float unusedVtxWeight  = 0.15f;
    190 	const float unusedFragWeight = 0.15f;
    191 	bool		unusedOk		 = (m_features & FEATURE_UNUSED_UNIFORMS) != 0;
    192 	deUint32	flags			 = 0;
    193 	std::string name			 = genName('a', 'z', m_uniformNdx);
    194 	VarType		type			 = generateType(rnd, 0, true);
    195 
    196 	flags |= (unusedOk && rnd.getFloat() < unusedVtxWeight) ? UNUSED_VERTEX : 0;
    197 	flags |= (unusedOk && rnd.getFloat() < unusedFragWeight) ? UNUSED_FRAGMENT : 0;
    198 
    199 	block.addUniform(Uniform(name.c_str(), type, flags));
    200 
    201 	m_uniformNdx += 1;
    202 }
    203 
    204 VarType RandomUniformBlockCase::generateType(de::Random& rnd, int typeDepth, bool arrayOk)
    205 {
    206 	const float structWeight = 0.1f;
    207 	const float arrayWeight  = 0.1f;
    208 
    209 	if (typeDepth < m_maxStructDepth && rnd.getFloat() < structWeight)
    210 	{
    211 		const float		unusedVtxWeight  = 0.15f;
    212 		const float		unusedFragWeight = 0.15f;
    213 		bool			unusedOk		 = (m_features & FEATURE_UNUSED_MEMBERS) != 0;
    214 		vector<VarType> memberTypes;
    215 		int				numMembers = rnd.getInt(1, m_maxStructMembers);
    216 
    217 		// Generate members first so nested struct declarations are in correct order.
    218 		for (int ndx = 0; ndx < numMembers; ndx++)
    219 			memberTypes.push_back(generateType(rnd, typeDepth + 1, true));
    220 
    221 		StructType& structType = m_interface.allocStruct((string("s") + genName('A', 'Z', m_structNdx)).c_str());
    222 		m_structNdx += 1;
    223 
    224 		DE_ASSERT(numMembers <= 'Z' - 'A');
    225 		for (int ndx = 0; ndx < numMembers; ndx++)
    226 		{
    227 			deUint32 flags = 0;
    228 
    229 			flags |= (unusedOk && rnd.getFloat() < unusedVtxWeight) ? UNUSED_VERTEX : 0;
    230 			flags |= (unusedOk && rnd.getFloat() < unusedFragWeight) ? UNUSED_FRAGMENT : 0;
    231 
    232 			structType.addMember((string("m") + (char)('A' + ndx)).c_str(), memberTypes[ndx], flags);
    233 		}
    234 
    235 		return VarType(&structType);
    236 	}
    237 	else if (m_maxArrayLength > 0 && arrayOk && rnd.getFloat() < arrayWeight)
    238 	{
    239 		int		arrayLength = rnd.getInt(1, m_maxArrayLength);
    240 		VarType elementType = generateType(rnd, typeDepth, false /* nested arrays are not allowed */);
    241 		return VarType(elementType, arrayLength);
    242 	}
    243 	else
    244 	{
    245 		vector<glu::DataType> typeCandidates;
    246 
    247 		typeCandidates.push_back(glu::TYPE_FLOAT);
    248 		typeCandidates.push_back(glu::TYPE_INT);
    249 		typeCandidates.push_back(glu::TYPE_UINT);
    250 		typeCandidates.push_back(glu::TYPE_BOOL);
    251 
    252 		if (m_features & FEATURE_VECTORS)
    253 		{
    254 			typeCandidates.push_back(glu::TYPE_FLOAT_VEC2);
    255 			typeCandidates.push_back(glu::TYPE_FLOAT_VEC3);
    256 			typeCandidates.push_back(glu::TYPE_FLOAT_VEC4);
    257 			typeCandidates.push_back(glu::TYPE_INT_VEC2);
    258 			typeCandidates.push_back(glu::TYPE_INT_VEC3);
    259 			typeCandidates.push_back(glu::TYPE_INT_VEC4);
    260 			typeCandidates.push_back(glu::TYPE_UINT_VEC2);
    261 			typeCandidates.push_back(glu::TYPE_UINT_VEC3);
    262 			typeCandidates.push_back(glu::TYPE_UINT_VEC4);
    263 			typeCandidates.push_back(glu::TYPE_BOOL_VEC2);
    264 			typeCandidates.push_back(glu::TYPE_BOOL_VEC3);
    265 			typeCandidates.push_back(glu::TYPE_BOOL_VEC4);
    266 		}
    267 
    268 		if (m_features & FEATURE_MATRICES)
    269 		{
    270 			typeCandidates.push_back(glu::TYPE_FLOAT_MAT2);
    271 			typeCandidates.push_back(glu::TYPE_FLOAT_MAT2X3);
    272 			typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X2);
    273 			typeCandidates.push_back(glu::TYPE_FLOAT_MAT3);
    274 			typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X4);
    275 			typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X2);
    276 			typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X3);
    277 			typeCandidates.push_back(glu::TYPE_FLOAT_MAT4);
    278 		}
    279 
    280 		glu::DataType type  = rnd.choose<glu::DataType>(typeCandidates.begin(), typeCandidates.end());
    281 		deUint32	  flags = 0;
    282 
    283 		if (!glu::isDataTypeBoolOrBVec(type))
    284 		{
    285 			// Precision.
    286 			static const deUint32 precisionCandidates[] = { PRECISION_LOW, PRECISION_MEDIUM, PRECISION_HIGH };
    287 			flags |= rnd.choose<deUint32>(&precisionCandidates[0],
    288 										  &precisionCandidates[DE_LENGTH_OF_ARRAY(precisionCandidates)]);
    289 		}
    290 
    291 		return VarType(type, flags);
    292 	}
    293 }
    294 
    295 class BlockBasicTypeCase : public UniformBlockCase
    296 {
    297 public:
    298 	BlockBasicTypeCase(Context& context, const char* name, const char* description, glu::GLSLVersion glslVersion,
    299 					   const VarType& type, deUint32 layoutFlags, int numInstances)
    300 		: UniformBlockCase(context, name, description, glslVersion, BUFFERMODE_PER_BLOCK)
    301 	{
    302 		UniformBlock& block = m_interface.allocBlock("Block");
    303 		block.addUniform(Uniform("var", type, 0));
    304 		block.setFlags(layoutFlags);
    305 
    306 		if (numInstances > 0)
    307 		{
    308 			block.setArraySize(numInstances);
    309 			block.setInstanceName("block");
    310 		}
    311 	}
    312 };
    313 
    314 static void createRandomCaseGroup(tcu::TestCaseGroup* parentGroup, Context& context, const char* groupName,
    315 								  const char* description, glu::GLSLVersion glslVersion,
    316 								  UniformBlockCase::BufferMode bufferMode, deUint32 features, int numCases,
    317 								  deUint32 baseSeed)
    318 {
    319 	tcu::TestCaseGroup* group = new tcu::TestCaseGroup(context.getTestContext(), groupName, description);
    320 	parentGroup->addChild(group);
    321 
    322 	baseSeed += (deUint32)context.getTestContext().getCommandLine().getBaseSeed();
    323 
    324 	for (int ndx = 0; ndx < numCases; ndx++)
    325 		group->addChild(new RandomUniformBlockCase(context, de::toString(ndx).c_str(), "", glslVersion, bufferMode,
    326 												   features, (deUint32)deInt32Hash(ndx + baseSeed)));
    327 }
    328 
    329 class BlockSingleStructCase : public UniformBlockCase
    330 {
    331 public:
    332 	BlockSingleStructCase(Context& context, const char* name, const char* description, glu::GLSLVersion glslVersion,
    333 						  deUint32 layoutFlags, BufferMode bufferMode, int numInstances)
    334 		: UniformBlockCase(context, name, description, glslVersion, bufferMode)
    335 		, m_layoutFlags(layoutFlags)
    336 		, m_numInstances(numInstances)
    337 	{
    338 	}
    339 
    340 	void init(void)
    341 	{
    342 		StructType& typeS = m_interface.allocStruct("S");
    343 		typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH), UNUSED_BOTH); // First member is unused.
    344 		typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM), 4));
    345 		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH));
    346 
    347 		UniformBlock& block = m_interface.allocBlock("Block");
    348 		block.addUniform(Uniform("s", VarType(&typeS), 0));
    349 		block.setFlags(m_layoutFlags);
    350 
    351 		if (m_numInstances > 0)
    352 		{
    353 			block.setInstanceName("block");
    354 			block.setArraySize(m_numInstances);
    355 		}
    356 	}
    357 
    358 private:
    359 	deUint32 m_layoutFlags;
    360 	int		 m_numInstances;
    361 };
    362 
    363 class BlockSingleStructArrayCase : public UniformBlockCase
    364 {
    365 public:
    366 	BlockSingleStructArrayCase(Context& context, const char* name, const char* description,
    367 							   glu::GLSLVersion glslVersion, deUint32 layoutFlags, BufferMode bufferMode,
    368 							   int numInstances)
    369 		: UniformBlockCase(context, name, description, glslVersion, bufferMode)
    370 		, m_layoutFlags(layoutFlags)
    371 		, m_numInstances(numInstances)
    372 	{
    373 	}
    374 
    375 	void init(void)
    376 	{
    377 		StructType& typeS = m_interface.allocStruct("S");
    378 		typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH), UNUSED_BOTH);
    379 		typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM), 4));
    380 		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH));
    381 
    382 		UniformBlock& block = m_interface.allocBlock("Block");
    383 		block.addUniform(Uniform("u", VarType(glu::TYPE_UINT, PRECISION_LOW)));
    384 		block.addUniform(Uniform("s", VarType(VarType(&typeS), 3)));
    385 		block.addUniform(Uniform("v", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_MEDIUM)));
    386 		block.setFlags(m_layoutFlags);
    387 
    388 		if (m_numInstances > 0)
    389 		{
    390 			block.setInstanceName("block");
    391 			block.setArraySize(m_numInstances);
    392 		}
    393 	}
    394 
    395 private:
    396 	deUint32 m_layoutFlags;
    397 	int		 m_numInstances;
    398 };
    399 
    400 class BlockSingleNestedStructCase : public UniformBlockCase
    401 {
    402 public:
    403 	BlockSingleNestedStructCase(Context& context, const char* name, const char* description,
    404 								glu::GLSLVersion glslVersion, deUint32 layoutFlags, BufferMode bufferMode,
    405 								int numInstances)
    406 		: UniformBlockCase(context, name, description, glslVersion, bufferMode)
    407 		, m_layoutFlags(layoutFlags)
    408 		, m_numInstances(numInstances)
    409 	{
    410 	}
    411 
    412 	void init(void)
    413 	{
    414 		StructType& typeS = m_interface.allocStruct("S");
    415 		typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH));
    416 		typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM), 4));
    417 		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH), UNUSED_BOTH);
    418 
    419 		StructType& typeT = m_interface.allocStruct("T");
    420 		typeT.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM));
    421 		typeT.addMember("b", VarType(&typeS));
    422 
    423 		UniformBlock& block = m_interface.allocBlock("Block");
    424 		block.addUniform(Uniform("s", VarType(&typeS), 0));
    425 		block.addUniform(Uniform("v", VarType(glu::TYPE_FLOAT_VEC2, PRECISION_LOW), UNUSED_BOTH));
    426 		block.addUniform(Uniform("t", VarType(&typeT), 0));
    427 		block.addUniform(Uniform("u", VarType(glu::TYPE_UINT, PRECISION_HIGH), 0));
    428 		block.setFlags(m_layoutFlags);
    429 
    430 		if (m_numInstances > 0)
    431 		{
    432 			block.setInstanceName("block");
    433 			block.setArraySize(m_numInstances);
    434 		}
    435 	}
    436 
    437 private:
    438 	deUint32 m_layoutFlags;
    439 	int		 m_numInstances;
    440 };
    441 
    442 class BlockSingleNestedStructArrayCase : public UniformBlockCase
    443 {
    444 public:
    445 	BlockSingleNestedStructArrayCase(Context& context, const char* name, const char* description,
    446 									 glu::GLSLVersion glslVersion, deUint32 layoutFlags, BufferMode bufferMode,
    447 									 int numInstances)
    448 		: UniformBlockCase(context, name, description, glslVersion, bufferMode)
    449 		, m_layoutFlags(layoutFlags)
    450 		, m_numInstances(numInstances)
    451 	{
    452 	}
    453 
    454 	void init(void)
    455 	{
    456 		StructType& typeS = m_interface.allocStruct("S");
    457 		typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH));
    458 		typeS.addMember("b", VarType(VarType(glu::TYPE_INT_VEC2, PRECISION_MEDIUM), 4));
    459 		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH), UNUSED_BOTH);
    460 
    461 		StructType& typeT = m_interface.allocStruct("T");
    462 		typeT.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM));
    463 		typeT.addMember("b", VarType(VarType(&typeS), 3));
    464 
    465 		UniformBlock& block = m_interface.allocBlock("Block");
    466 		block.addUniform(Uniform("s", VarType(&typeS), 0));
    467 		block.addUniform(Uniform("v", VarType(glu::TYPE_FLOAT_VEC2, PRECISION_LOW), UNUSED_BOTH));
    468 		block.addUniform(Uniform("t", VarType(VarType(&typeT), 2), 0));
    469 		block.addUniform(Uniform("u", VarType(glu::TYPE_UINT, PRECISION_HIGH), 0));
    470 		block.setFlags(m_layoutFlags);
    471 
    472 		if (m_numInstances > 0)
    473 		{
    474 			block.setInstanceName("block");
    475 			block.setArraySize(m_numInstances);
    476 		}
    477 	}
    478 
    479 private:
    480 	deUint32 m_layoutFlags;
    481 	int		 m_numInstances;
    482 };
    483 
    484 class BlockMultiBasicTypesCase : public UniformBlockCase
    485 {
    486 public:
    487 	BlockMultiBasicTypesCase(Context& context, const char* name, const char* description, glu::GLSLVersion glslVersion,
    488 							 deUint32 flagsA, deUint32 flagsB, BufferMode bufferMode, int numInstances)
    489 		: UniformBlockCase(context, name, description, glslVersion, bufferMode)
    490 		, m_flagsA(flagsA)
    491 		, m_flagsB(flagsB)
    492 		, m_numInstances(numInstances)
    493 	{
    494 	}
    495 
    496 	void init(void)
    497 	{
    498 		UniformBlock& blockA = m_interface.allocBlock("BlockA");
    499 		blockA.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT, PRECISION_HIGH)));
    500 		blockA.addUniform(Uniform("b", VarType(glu::TYPE_UINT_VEC3, PRECISION_LOW), UNUSED_BOTH));
    501 		blockA.addUniform(Uniform("c", VarType(glu::TYPE_FLOAT_MAT2, PRECISION_MEDIUM)));
    502 		blockA.setInstanceName("blockA");
    503 		blockA.setFlags(m_flagsA);
    504 
    505 		UniformBlock& blockB = m_interface.allocBlock("BlockB");
    506 		blockB.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM)));
    507 		blockB.addUniform(Uniform("b", VarType(glu::TYPE_INT_VEC2, PRECISION_LOW)));
    508 		blockB.addUniform(Uniform("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH), UNUSED_BOTH));
    509 		blockB.addUniform(Uniform("d", VarType(glu::TYPE_BOOL, 0)));
    510 		blockB.setInstanceName("blockB");
    511 		blockB.setFlags(m_flagsB);
    512 
    513 		if (m_numInstances > 0)
    514 		{
    515 			blockA.setArraySize(m_numInstances);
    516 			blockB.setArraySize(m_numInstances);
    517 		}
    518 	}
    519 
    520 private:
    521 	deUint32 m_flagsA;
    522 	deUint32 m_flagsB;
    523 	int		 m_numInstances;
    524 };
    525 
    526 class BlockMultiNestedStructCase : public UniformBlockCase
    527 {
    528 public:
    529 	BlockMultiNestedStructCase(Context& context, const char* name, const char* description,
    530 							   glu::GLSLVersion glslVersion, deUint32 flagsA, deUint32 flagsB, BufferMode bufferMode,
    531 							   int numInstances)
    532 		: UniformBlockCase(context, name, description, glslVersion, bufferMode)
    533 		, m_flagsA(flagsA)
    534 		, m_flagsB(flagsB)
    535 		, m_numInstances(numInstances)
    536 	{
    537 	}
    538 
    539 	void init(void)
    540 	{
    541 		StructType& typeS = m_interface.allocStruct("S");
    542 		typeS.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_LOW));
    543 		typeS.addMember("b", VarType(VarType(glu::TYPE_INT_VEC2, PRECISION_MEDIUM), 4));
    544 		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH));
    545 
    546 		StructType& typeT = m_interface.allocStruct("T");
    547 		typeT.addMember("a", VarType(glu::TYPE_UINT, PRECISION_MEDIUM), UNUSED_BOTH);
    548 		typeT.addMember("b", VarType(&typeS));
    549 		typeT.addMember("c", VarType(glu::TYPE_BOOL_VEC4, 0));
    550 
    551 		UniformBlock& blockA = m_interface.allocBlock("BlockA");
    552 		blockA.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT, PRECISION_HIGH)));
    553 		blockA.addUniform(Uniform("b", VarType(&typeS)));
    554 		blockA.addUniform(Uniform("c", VarType(glu::TYPE_UINT_VEC3, PRECISION_LOW), UNUSED_BOTH));
    555 		blockA.setInstanceName("blockA");
    556 		blockA.setFlags(m_flagsA);
    557 
    558 		UniformBlock& blockB = m_interface.allocBlock("BlockB");
    559 		blockB.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT_MAT2, PRECISION_MEDIUM)));
    560 		blockB.addUniform(Uniform("b", VarType(&typeT)));
    561 		blockB.addUniform(Uniform("c", VarType(glu::TYPE_BOOL_VEC4, 0), UNUSED_BOTH));
    562 		blockB.addUniform(Uniform("d", VarType(glu::TYPE_BOOL, 0)));
    563 		blockB.setInstanceName("blockB");
    564 		blockB.setFlags(m_flagsB);
    565 
    566 		if (m_numInstances > 0)
    567 		{
    568 			blockA.setArraySize(m_numInstances);
    569 			blockB.setArraySize(m_numInstances);
    570 		}
    571 	}
    572 
    573 private:
    574 	deUint32 m_flagsA;
    575 	deUint32 m_flagsB;
    576 	int		 m_numInstances;
    577 };
    578 
    579 class UniformBlockPrecisionMatching : public TestCase
    580 {
    581 public:
    582 	UniformBlockPrecisionMatching(Context& context, glu::GLSLVersion glslVersion)
    583 		: TestCase(context, "precision_matching", ""), m_glslVersion(glslVersion)
    584 	{
    585 	}
    586 
    587 	IterateResult iterate(void)
    588 	{
    589 		std::string vs1("layout (std140) uniform Data { lowp float x; } myData;\n"
    590 						"void main() {\n"
    591 						"  gl_Position = vec4(myData.x, 0.0, 0.0, 1.0);\n"
    592 						"}");
    593 		std::string fs1("precision highp float;\n"
    594 						"out vec4 color;\n"
    595 						"layout (std140) uniform Data { float x; } myData;\n"
    596 						"void main() {\n"
    597 						"  color = vec4(myData.x);\n"
    598 						"}");
    599 
    600 		std::string vs2("layout (std140) uniform Data { highp int x; mediump int y; } myData;\n"
    601 						"void main() {\n"
    602 						"  gl_Position = vec4(float(myData.x), 0.0, 0.0, 1.0);\n"
    603 						"}");
    604 		std::string fs2("precision highp float;\n"
    605 						"out vec4 color;\n"
    606 						"layout (std140) uniform Data { mediump int x; highp int y; } myData;\n"
    607 						"void main() {\n"
    608 						"  color = vec4(float(myData.y));\n"
    609 						"}");
    610 
    611 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    612 		if (!Link(vs1, fs1) || !Link(vs2, fs2))
    613 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
    614 		return STOP;
    615 	}
    616 
    617 	bool Link(const std::string& vs, const std::string& fs)
    618 	{
    619 		const glw::Functions& gl	  = m_context.getRenderContext().getFunctions();
    620 		const glw::GLuint	 p		  = gl.createProgram();
    621 		const std::string	 version = glu::getGLSLVersionDeclaration(m_glslVersion);
    622 
    623 		static const struct
    624 		{
    625 			const char*		   name;
    626 			const std::string& body;
    627 			glw::GLenum		   type;
    628 		} shaderDefinition[] = { { "VS", vs, GL_VERTEX_SHADER }, { "FS", fs, GL_FRAGMENT_SHADER } };
    629 
    630 		for (unsigned int index = 0; index < 2; ++index)
    631 		{
    632 			std::string shaderSource	= version + "\n" + shaderDefinition[index].body;
    633 			const char* shaderSourcePtr = shaderSource.c_str();
    634 
    635 			glw::GLuint sh = gl.createShader(shaderDefinition[index].type);
    636 			gl.attachShader(p, sh);
    637 			gl.deleteShader(sh);
    638 			gl.shaderSource(sh, 1, &shaderSourcePtr, NULL);
    639 			gl.compileShader(sh);
    640 
    641 			glw::GLint status;
    642 			gl.getShaderiv(sh, GL_COMPILE_STATUS, &status);
    643 			if (status == GL_FALSE)
    644 			{
    645 				glw::GLint length;
    646 				gl.getShaderiv(sh, GL_INFO_LOG_LENGTH, &length);
    647 				if (length > 0)
    648 				{
    649 					std::vector<glw::GLchar> log(length);
    650 					gl.getShaderInfoLog(sh, length, NULL, &log[0]);
    651 					m_context.getTestContext().getLog() << tcu::TestLog::Message << shaderDefinition[index].name
    652 														<< " compilation should succed. Info Log:\n"
    653 														<< &log[0] << tcu::TestLog::EndMessage;
    654 				}
    655 				gl.deleteProgram(p);
    656 				return false;
    657 			}
    658 		}
    659 
    660 		gl.linkProgram(p);
    661 
    662 		bool	   result = true;
    663 		glw::GLint status;
    664 		gl.getProgramiv(p, GL_LINK_STATUS, &status);
    665 		if (status == GL_FALSE)
    666 		{
    667 			glw::GLchar log[1024];
    668 			gl.getProgramInfoLog(p, sizeof(log), NULL, log);
    669 			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Link operation should succed. Info Log:\n"
    670 												<< log << tcu::TestLog::EndMessage;
    671 			result = false;
    672 		}
    673 
    674 		gl.deleteProgram(p);
    675 		return result;
    676 	}
    677 
    678 private:
    679 	glu::GLSLVersion m_glslVersion;
    680 };
    681 
    682 UniformBlockTests::UniformBlockTests(Context& context, glu::GLSLVersion glslVersion)
    683 	: TestCaseGroup(context, "uniform_block", "Uniform Block tests"), m_glslVersion(glslVersion)
    684 {
    685 }
    686 
    687 UniformBlockTests::~UniformBlockTests(void)
    688 {
    689 }
    690 
    691 void UniformBlockTests::init(void)
    692 {
    693 	static const glu::DataType basicTypes[] = { glu::TYPE_FLOAT,		glu::TYPE_FLOAT_VEC2,   glu::TYPE_FLOAT_VEC3,
    694 												glu::TYPE_FLOAT_VEC4,   glu::TYPE_INT,			glu::TYPE_INT_VEC2,
    695 												glu::TYPE_INT_VEC3,		glu::TYPE_INT_VEC4,		glu::TYPE_UINT,
    696 												glu::TYPE_UINT_VEC2,	glu::TYPE_UINT_VEC3,	glu::TYPE_UINT_VEC4,
    697 												glu::TYPE_BOOL,			glu::TYPE_BOOL_VEC2,	glu::TYPE_BOOL_VEC3,
    698 												glu::TYPE_BOOL_VEC4,	glu::TYPE_FLOAT_MAT2,   glu::TYPE_FLOAT_MAT3,
    699 												glu::TYPE_FLOAT_MAT4,   glu::TYPE_FLOAT_MAT2X3, glu::TYPE_FLOAT_MAT2X4,
    700 												glu::TYPE_FLOAT_MAT3X2, glu::TYPE_FLOAT_MAT3X4, glu::TYPE_FLOAT_MAT4X2,
    701 												glu::TYPE_FLOAT_MAT4X3 };
    702 
    703 	static const struct
    704 	{
    705 		const char* name;
    706 		deUint32	flags;
    707 	} precisionFlags[] = { { "lowp", PRECISION_LOW }, { "mediump", PRECISION_MEDIUM }, { "highp", PRECISION_HIGH } };
    708 
    709 	static const struct
    710 	{
    711 		const char* name;
    712 		deUint32	flags;
    713 	} layoutFlags[] = { { "shared", LAYOUT_SHARED }, { "packed", LAYOUT_PACKED }, { "std140", LAYOUT_STD140 } };
    714 
    715 	static const struct
    716 	{
    717 		const char* name;
    718 		deUint32	flags;
    719 	} matrixFlags[] = { { "row_major", LAYOUT_ROW_MAJOR }, { "column_major", LAYOUT_COLUMN_MAJOR } };
    720 
    721 	static const struct
    722 	{
    723 		const char*					 name;
    724 		UniformBlockCase::BufferMode mode;
    725 	} bufferModes[] = { { "per_block_buffer", UniformBlockCase::BUFFERMODE_PER_BLOCK },
    726 						{ "single_buffer", UniformBlockCase::BUFFERMODE_SINGLE } };
    727 
    728 	// ubo.single_basic_type
    729 	{
    730 		tcu::TestCaseGroup* singleBasicTypeGroup =
    731 			new tcu::TestCaseGroup(m_testCtx, "single_basic_type", "Single basic variable in single buffer");
    732 		addChild(singleBasicTypeGroup);
    733 
    734 		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
    735 		{
    736 			tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
    737 			singleBasicTypeGroup->addChild(layoutGroup);
    738 
    739 			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
    740 			{
    741 				glu::DataType type		= basicTypes[basicTypeNdx];
    742 				const char*   typeName  = glu::getDataTypeName(type);
    743 				deUint32	  baseFlags = layoutFlags[layoutFlagNdx].flags;
    744 				deUint32	  flags		= baseFlags | ((baseFlags & LAYOUT_PACKED) ?
    745 												  (basicTypeNdx % 2 == 0 ? DECLARE_VERTEX : DECLARE_FRAGMENT) :
    746 												  DECLARE_BOTH);
    747 
    748 				if (glu::isDataTypeBoolOrBVec(type))
    749 					layoutGroup->addChild(new BlockBasicTypeCase(m_context, typeName, "", m_glslVersion,
    750 																 VarType(type, 0), flags, 0 /* no instance array */));
    751 				else
    752 				{
    753 					for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisionFlags); precNdx++)
    754 						layoutGroup->addChild(new BlockBasicTypeCase(
    755 							m_context, (string(precisionFlags[precNdx].name) + "_" + typeName).c_str(), "",
    756 							m_glslVersion, VarType(type, precisionFlags[precNdx].flags), flags,
    757 							0 /* no instance array */));
    758 				}
    759 
    760 				if (glu::isDataTypeMatrix(type))
    761 				{
    762 					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
    763 					{
    764 						for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisionFlags); precNdx++)
    765 							layoutGroup->addChild(new BlockBasicTypeCase(
    766 								m_context,
    767 								(string(matrixFlags[matFlagNdx].name) + "_" + precisionFlags[precNdx].name + "_" +
    768 								 typeName)
    769 									.c_str(),
    770 								"", m_glslVersion, VarType(type, precisionFlags[precNdx].flags),
    771 								flags | matrixFlags[matFlagNdx].flags, 0 /* no instance array */));
    772 					}
    773 				}
    774 			}
    775 		}
    776 	}
    777 
    778 	// ubo.single_basic_array
    779 	{
    780 		tcu::TestCaseGroup* singleBasicArrayGroup =
    781 			new tcu::TestCaseGroup(m_testCtx, "single_basic_array", "Single basic array variable in single buffer");
    782 		addChild(singleBasicArrayGroup);
    783 
    784 		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
    785 		{
    786 			tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
    787 			singleBasicArrayGroup->addChild(layoutGroup);
    788 
    789 			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
    790 			{
    791 				glu::DataType type		= basicTypes[basicTypeNdx];
    792 				const char*   typeName  = glu::getDataTypeName(type);
    793 				const int	 arraySize = 3;
    794 				deUint32	  baseFlags = layoutFlags[layoutFlagNdx].flags;
    795 				deUint32	  flags		= baseFlags | ((baseFlags & LAYOUT_PACKED) ?
    796 												  (basicTypeNdx % 2 == 0 ? DECLARE_VERTEX : DECLARE_FRAGMENT) :
    797 												  DECLARE_BOTH);
    798 
    799 				layoutGroup->addChild(new BlockBasicTypeCase(
    800 					m_context, typeName, "", m_glslVersion,
    801 					VarType(VarType(type, glu::isDataTypeBoolOrBVec(type) ? 0 : PRECISION_HIGH), arraySize), flags,
    802 					0 /* no instance array */));
    803 
    804 				if (glu::isDataTypeMatrix(type))
    805 				{
    806 					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
    807 						layoutGroup->addChild(new BlockBasicTypeCase(
    808 							m_context, (string(matrixFlags[matFlagNdx].name) + "_" + typeName).c_str(), "",
    809 							m_glslVersion, VarType(VarType(type, PRECISION_HIGH), arraySize),
    810 							flags | matrixFlags[matFlagNdx].flags, 0 /* no instance array */));
    811 				}
    812 			}
    813 		}
    814 	}
    815 
    816 	// ubo.single_struct
    817 	{
    818 		tcu::TestCaseGroup* singleStructGroup =
    819 			new tcu::TestCaseGroup(m_testCtx, "single_struct", "Single struct in uniform block");
    820 		addChild(singleStructGroup);
    821 
    822 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
    823 		{
    824 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
    825 			{
    826 				for (int isArray = 0; isArray < 2; isArray++)
    827 				{
    828 					std::string name = std::string(bufferModes[modeNdx].name) + "_" + layoutFlags[layoutFlagNdx].name;
    829 					deUint32	baseFlags = layoutFlags[layoutFlagNdx].flags;
    830 					deUint32	flags	 = baseFlags | ((baseFlags & LAYOUT_PACKED) ? DECLARE_VERTEX : DECLARE_BOTH);
    831 
    832 					if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
    833 						continue; // Doesn't make sense to add this variant.
    834 
    835 					if (isArray)
    836 						name += "_instance_array";
    837 
    838 					singleStructGroup->addChild(new BlockSingleStructCase(
    839 						m_context, name.c_str(), "", m_glslVersion, flags, bufferModes[modeNdx].mode, isArray ? 3 : 0));
    840 				}
    841 			}
    842 		}
    843 	}
    844 
    845 	// ubo.single_struct_array
    846 	{
    847 		tcu::TestCaseGroup* singleStructArrayGroup =
    848 			new tcu::TestCaseGroup(m_testCtx, "single_struct_array", "Struct array in one uniform block");
    849 		addChild(singleStructArrayGroup);
    850 
    851 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
    852 		{
    853 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
    854 			{
    855 				for (int isArray = 0; isArray < 2; isArray++)
    856 				{
    857 					std::string name = std::string(bufferModes[modeNdx].name) + "_" + layoutFlags[layoutFlagNdx].name;
    858 					deUint32	baseFlags = layoutFlags[layoutFlagNdx].flags;
    859 					deUint32	flags	 = baseFlags | ((baseFlags & LAYOUT_PACKED) ? DECLARE_FRAGMENT : DECLARE_BOTH);
    860 
    861 					if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
    862 						continue; // Doesn't make sense to add this variant.
    863 
    864 					if (isArray)
    865 						name += "_instance_array";
    866 
    867 					singleStructArrayGroup->addChild(new BlockSingleStructArrayCase(
    868 						m_context, name.c_str(), "", m_glslVersion, flags, bufferModes[modeNdx].mode, isArray ? 3 : 0));
    869 				}
    870 			}
    871 		}
    872 	}
    873 
    874 	// ubo.single_nested_struct
    875 	{
    876 		tcu::TestCaseGroup* singleNestedStructGroup =
    877 			new tcu::TestCaseGroup(m_testCtx, "single_nested_struct", "Nested struct in one uniform block");
    878 		addChild(singleNestedStructGroup);
    879 
    880 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
    881 		{
    882 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
    883 			{
    884 				for (int isArray = 0; isArray < 2; isArray++)
    885 				{
    886 					std::string name = std::string(bufferModes[modeNdx].name) + "_" + layoutFlags[layoutFlagNdx].name;
    887 					deUint32	baseFlags = layoutFlags[layoutFlagNdx].flags;
    888 					deUint32	flags	 = baseFlags | ((baseFlags & LAYOUT_PACKED) ? DECLARE_VERTEX : DECLARE_BOTH);
    889 
    890 					if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
    891 						continue; // Doesn't make sense to add this variant.
    892 
    893 					if (isArray)
    894 						name += "_instance_array";
    895 
    896 					singleNestedStructGroup->addChild(new BlockSingleNestedStructCase(
    897 						m_context, name.c_str(), "", m_glslVersion, flags, bufferModes[modeNdx].mode, isArray ? 3 : 0));
    898 				}
    899 			}
    900 		}
    901 	}
    902 
    903 	// ubo.single_nested_struct_array
    904 	{
    905 		tcu::TestCaseGroup* singleNestedStructArrayGroup =
    906 			new tcu::TestCaseGroup(m_testCtx, "single_nested_struct_array", "Nested struct array in one uniform block");
    907 		addChild(singleNestedStructArrayGroup);
    908 
    909 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
    910 		{
    911 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
    912 			{
    913 				for (int isArray = 0; isArray < 2; isArray++)
    914 				{
    915 					std::string name = std::string(bufferModes[modeNdx].name) + "_" + layoutFlags[layoutFlagNdx].name;
    916 					deUint32	baseFlags = layoutFlags[layoutFlagNdx].flags;
    917 					deUint32	flags	 = baseFlags | ((baseFlags & LAYOUT_PACKED) ? DECLARE_FRAGMENT : DECLARE_BOTH);
    918 
    919 					if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
    920 						continue; // Doesn't make sense to add this variant.
    921 
    922 					if (isArray)
    923 						name += "_instance_array";
    924 
    925 					singleNestedStructArrayGroup->addChild(new BlockSingleNestedStructArrayCase(
    926 						m_context, name.c_str(), "", m_glslVersion, flags, bufferModes[modeNdx].mode, isArray ? 3 : 0));
    927 				}
    928 			}
    929 		}
    930 	}
    931 
    932 	// ubo.instance_array_basic_type
    933 	{
    934 		tcu::TestCaseGroup* instanceArrayBasicTypeGroup =
    935 			new tcu::TestCaseGroup(m_testCtx, "instance_array_basic_type", "Single basic variable in instance array");
    936 		addChild(instanceArrayBasicTypeGroup);
    937 
    938 		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
    939 		{
    940 			tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
    941 			instanceArrayBasicTypeGroup->addChild(layoutGroup);
    942 
    943 			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
    944 			{
    945 				glu::DataType type		   = basicTypes[basicTypeNdx];
    946 				const char*   typeName	 = glu::getDataTypeName(type);
    947 				const int	 numInstances = 3;
    948 				deUint32	  baseFlags	= layoutFlags[layoutFlagNdx].flags;
    949 				deUint32	  flags		   = baseFlags | ((baseFlags & LAYOUT_PACKED) ?
    950 												  (basicTypeNdx % 2 == 0 ? DECLARE_VERTEX : DECLARE_FRAGMENT) :
    951 												  DECLARE_BOTH);
    952 
    953 				layoutGroup->addChild(new BlockBasicTypeCase(
    954 					m_context, typeName, "", m_glslVersion,
    955 					VarType(type, glu::isDataTypeBoolOrBVec(type) ? 0 : PRECISION_HIGH), flags, numInstances));
    956 
    957 				if (glu::isDataTypeMatrix(type))
    958 				{
    959 					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
    960 						layoutGroup->addChild(new BlockBasicTypeCase(
    961 							m_context, (string(matrixFlags[matFlagNdx].name) + "_" + typeName).c_str(), "",
    962 							m_glslVersion, VarType(type, PRECISION_HIGH), flags | matrixFlags[matFlagNdx].flags,
    963 							numInstances));
    964 				}
    965 			}
    966 		}
    967 	}
    968 
    969 	// ubo.multi_basic_types
    970 	{
    971 		tcu::TestCaseGroup* multiBasicTypesGroup =
    972 			new tcu::TestCaseGroup(m_testCtx, "multi_basic_types", "Multiple buffers with basic types");
    973 		addChild(multiBasicTypesGroup);
    974 
    975 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
    976 		{
    977 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
    978 			multiBasicTypesGroup->addChild(modeGroup);
    979 
    980 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
    981 			{
    982 				for (int isArray = 0; isArray < 2; isArray++)
    983 				{
    984 					std::string baseName  = layoutFlags[layoutFlagNdx].name;
    985 					deUint32	baseFlags = layoutFlags[layoutFlagNdx].flags;
    986 
    987 					if (isArray)
    988 						baseName += "_instance_array";
    989 
    990 					modeGroup->addChild(new BlockMultiBasicTypesCase(
    991 						m_context, (baseName + "_mixed").c_str(), "", m_glslVersion, baseFlags | DECLARE_VERTEX,
    992 						baseFlags | DECLARE_FRAGMENT, bufferModes[modeNdx].mode, isArray ? 3 : 0));
    993 
    994 					if (!(baseFlags & LAYOUT_PACKED))
    995 						modeGroup->addChild(new BlockMultiBasicTypesCase(
    996 							m_context, (baseName + "_both").c_str(), "", m_glslVersion,
    997 							baseFlags | DECLARE_VERTEX | DECLARE_FRAGMENT,
    998 							baseFlags | DECLARE_VERTEX | DECLARE_FRAGMENT, bufferModes[modeNdx].mode, isArray ? 3 : 0));
    999 				}
   1000 			}
   1001 		}
   1002 	}
   1003 
   1004 	// ubo.multi_nested_struct
   1005 	{
   1006 		tcu::TestCaseGroup* multiNestedStructGroup =
   1007 			new tcu::TestCaseGroup(m_testCtx, "multi_nested_struct", "Multiple buffers with nested structs");
   1008 		addChild(multiNestedStructGroup);
   1009 
   1010 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
   1011 		{
   1012 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
   1013 			multiNestedStructGroup->addChild(modeGroup);
   1014 
   1015 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
   1016 			{
   1017 				for (int isArray = 0; isArray < 2; isArray++)
   1018 				{
   1019 					std::string baseName  = layoutFlags[layoutFlagNdx].name;
   1020 					deUint32	baseFlags = layoutFlags[layoutFlagNdx].flags;
   1021 
   1022 					if (isArray)
   1023 						baseName += "_instance_array";
   1024 
   1025 					modeGroup->addChild(new BlockMultiNestedStructCase(
   1026 						m_context, (baseName + "_mixed").c_str(), "", m_glslVersion, baseFlags | DECLARE_VERTEX,
   1027 						baseFlags | DECLARE_FRAGMENT, bufferModes[modeNdx].mode, isArray ? 3 : 0));
   1028 
   1029 					if (!(baseFlags & LAYOUT_PACKED))
   1030 						modeGroup->addChild(new BlockMultiNestedStructCase(
   1031 							m_context, (baseName + "_both").c_str(), "", m_glslVersion,
   1032 							baseFlags | DECLARE_VERTEX | DECLARE_FRAGMENT,
   1033 							baseFlags | DECLARE_VERTEX | DECLARE_FRAGMENT, bufferModes[modeNdx].mode, isArray ? 3 : 0));
   1034 				}
   1035 			}
   1036 		}
   1037 	}
   1038 
   1039 	// ubo.random
   1040 	{
   1041 		const deUint32 allShaders	= FEATURE_VERTEX_BLOCKS | FEATURE_FRAGMENT_BLOCKS | FEATURE_SHARED_BLOCKS;
   1042 		const deUint32 allLayouts	= FEATURE_PACKED_LAYOUT | FEATURE_SHARED_LAYOUT | FEATURE_STD140_LAYOUT;
   1043 		const deUint32 allBasicTypes = FEATURE_VECTORS | FEATURE_MATRICES;
   1044 		const deUint32 unused		 = FEATURE_UNUSED_MEMBERS | FEATURE_UNUSED_UNIFORMS;
   1045 		const deUint32 matFlags		 = FEATURE_MATRIX_LAYOUT;
   1046 
   1047 		tcu::TestCaseGroup* randomGroup = new tcu::TestCaseGroup(m_testCtx, "random", "Random Uniform Block cases");
   1048 		addChild(randomGroup);
   1049 
   1050 		// Basic types.
   1051 		createRandomCaseGroup(randomGroup, m_context, "scalar_types", "Scalar types only, per-block buffers",
   1052 							  m_glslVersion, UniformBlockCase::BUFFERMODE_PER_BLOCK, allShaders | allLayouts | unused,
   1053 							  10, 0);
   1054 		createRandomCaseGroup(randomGroup, m_context, "vector_types", "Scalar and vector types only, per-block buffers",
   1055 							  m_glslVersion, UniformBlockCase::BUFFERMODE_PER_BLOCK,
   1056 							  allShaders | allLayouts | unused | FEATURE_VECTORS, 10, 25);
   1057 		createRandomCaseGroup(randomGroup, m_context, "basic_types", "All basic types, per-block buffers",
   1058 							  m_glslVersion, UniformBlockCase::BUFFERMODE_PER_BLOCK,
   1059 							  allShaders | allLayouts | unused | allBasicTypes | matFlags, 10, 50);
   1060 		createRandomCaseGroup(randomGroup, m_context, "basic_arrays", "Arrays, per-block buffers", m_glslVersion,
   1061 							  UniformBlockCase::BUFFERMODE_PER_BLOCK,
   1062 							  allShaders | allLayouts | unused | allBasicTypes | matFlags | FEATURE_ARRAYS, 10, 50);
   1063 
   1064 		createRandomCaseGroup(
   1065 			randomGroup, m_context, "basic_instance_arrays", "Basic instance arrays, per-block buffers", m_glslVersion,
   1066 			UniformBlockCase::BUFFERMODE_PER_BLOCK,
   1067 			allShaders | allLayouts | unused | allBasicTypes | matFlags | FEATURE_INSTANCE_ARRAYS, 10, 75);
   1068 		createRandomCaseGroup(randomGroup, m_context, "nested_structs", "Nested structs, per-block buffers",
   1069 							  m_glslVersion, UniformBlockCase::BUFFERMODE_PER_BLOCK,
   1070 							  allShaders | allLayouts | unused | allBasicTypes | matFlags | FEATURE_STRUCTS, 10, 100);
   1071 		createRandomCaseGroup(
   1072 			randomGroup, m_context, "nested_structs_arrays", "Nested structs, arrays, per-block buffers", m_glslVersion,
   1073 			UniformBlockCase::BUFFERMODE_PER_BLOCK,
   1074 			allShaders | allLayouts | unused | allBasicTypes | matFlags | FEATURE_STRUCTS | FEATURE_ARRAYS, 10, 150);
   1075 		createRandomCaseGroup(
   1076 			randomGroup, m_context, "nested_structs_instance_arrays",
   1077 			"Nested structs, instance arrays, per-block buffers", m_glslVersion, UniformBlockCase::BUFFERMODE_PER_BLOCK,
   1078 			allShaders | allLayouts | unused | allBasicTypes | matFlags | FEATURE_STRUCTS | FEATURE_INSTANCE_ARRAYS, 10,
   1079 			125);
   1080 		createRandomCaseGroup(randomGroup, m_context, "nested_structs_arrays_instance_arrays",
   1081 							  "Nested structs, instance arrays, per-block buffers", m_glslVersion,
   1082 							  UniformBlockCase::BUFFERMODE_PER_BLOCK,
   1083 							  allShaders | allLayouts | unused | allBasicTypes | matFlags | FEATURE_STRUCTS |
   1084 								  FEATURE_ARRAYS | FEATURE_INSTANCE_ARRAYS,
   1085 							  10, 175);
   1086 
   1087 		createRandomCaseGroup(randomGroup, m_context, "all_per_block_buffers", "All random features, per-block buffers",
   1088 							  m_glslVersion, UniformBlockCase::BUFFERMODE_PER_BLOCK, ~0u, 20, 200);
   1089 		createRandomCaseGroup(randomGroup, m_context, "all_shared_buffer", "All random features, shared buffer",
   1090 							  m_glslVersion, UniformBlockCase::BUFFERMODE_SINGLE, ~0u, 20, 250);
   1091 	}
   1092 
   1093 	// ubo.common
   1094 	if (glu::isGLSLVersionSupported(m_context.getRenderContext().getType(), glu::GLSL_VERSION_300_ES))
   1095 	{
   1096 		tcu::TestCaseGroup* commonGroup = new tcu::TestCaseGroup(m_testCtx, "common", "Common Uniform Block cases");
   1097 		addChild(commonGroup);
   1098 		commonGroup->addChild(new UniformBlockPrecisionMatching(m_context, m_glslVersion));
   1099 	}
   1100 }
   1101 
   1102 } // deqp
   1103