Home | History | Annotate | Download | only in ubo
      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 Uniform block tests.
     24  *//*--------------------------------------------------------------------*/
     25 
     26 #include "vktUniformBlockTests.hpp"
     27 
     28 #include "vktUniformBlockCase.hpp"
     29 #include "vktRandomUniformBlockCase.hpp"
     30 
     31 #include "tcuCommandLine.hpp"
     32 #include "deStringUtil.hpp"
     33 
     34 namespace vkt
     35 {
     36 namespace ubo
     37 {
     38 
     39 namespace
     40 {
     41 
     42 class BlockBasicTypeCase : public UniformBlockCase
     43 {
     44 public:
     45 	BlockBasicTypeCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const VarType& type, deUint32 layoutFlags, int numInstances, MatrixLoadFlags matrixLoadFlag)
     46 		: UniformBlockCase(testCtx, name, description, BUFFERMODE_PER_BLOCK, matrixLoadFlag)
     47 	{
     48 		VarType tempType = type;
     49 		while (tempType.isArrayType())
     50 		{
     51 			tempType = tempType.getElementType();
     52 		}
     53 		if (getDataTypeScalarType(tempType.getBasicType()) == glu::TYPE_UINT16 ||
     54 			getDataTypeScalarType(tempType.getBasicType()) == glu::TYPE_INT16 ||
     55 			getDataTypeScalarType(tempType.getBasicType()) == glu::TYPE_FLOAT16)
     56 		{
     57 			layoutFlags |= LAYOUT_16BIT_STORAGE;
     58 		}
     59 		if (getDataTypeScalarType(tempType.getBasicType()) == glu::TYPE_UINT8 ||
     60 			getDataTypeScalarType(tempType.getBasicType()) == glu::TYPE_INT8)
     61 		{
     62 			layoutFlags |= LAYOUT_8BIT_STORAGE;
     63 		}
     64 
     65 		UniformBlock& block = m_interface.allocBlock("Block");
     66 		// For scalar layout tests with non-scalar types, add a scalar padding variable
     67 		// before "var", to make var only be scalar aligned.
     68 		if ((layoutFlags & LAYOUT_SCALAR) && !isDataTypeScalar(type.getBasicType())) {
     69 			block.addUniform(Uniform("padding", VarType(getDataTypeScalarType(tempType.getBasicType()), 0), 0));
     70 		}
     71 		block.addUniform(Uniform("var", type, 0));
     72 
     73 		block.setFlags(layoutFlags);
     74 
     75 		if (numInstances > 0)
     76 		{
     77 			block.setArraySize(numInstances);
     78 			block.setInstanceName("block");
     79 		}
     80 
     81 		init();
     82 	}
     83 };
     84 
     85 void createBlockBasicTypeCases (tcu::TestCaseGroup& group, tcu::TestContext& testCtx, const std::string& name, const VarType& type, deUint32 layoutFlags, int numInstances = 0)
     86 {
     87 	de::MovePtr<tcu::TestCaseGroup>	typeGroup(new tcu::TestCaseGroup(group.getTestContext(), name.c_str(), ""));
     88 
     89 	typeGroup->addChild(new BlockBasicTypeCase(testCtx, "vertex",				"", type, layoutFlags|DECLARE_VERTEX,					numInstances, LOAD_FULL_MATRIX));
     90 	typeGroup->addChild(new BlockBasicTypeCase(testCtx, "fragment",				"", type, layoutFlags|DECLARE_FRAGMENT,					numInstances, LOAD_FULL_MATRIX));
     91 	typeGroup->addChild(new BlockBasicTypeCase(testCtx, "both",					"",	type, layoutFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	numInstances, LOAD_FULL_MATRIX));
     92 	typeGroup->addChild(new BlockBasicTypeCase(testCtx, "vertex_comp_access",	"", type, layoutFlags|DECLARE_VERTEX,					numInstances, LOAD_MATRIX_COMPONENTS));
     93 	typeGroup->addChild(new BlockBasicTypeCase(testCtx, "fragment_comp_access",	"", type, layoutFlags|DECLARE_FRAGMENT,					numInstances, LOAD_MATRIX_COMPONENTS));
     94 	typeGroup->addChild(new BlockBasicTypeCase(testCtx, "both_comp_access",		"",	type, layoutFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	numInstances, LOAD_MATRIX_COMPONENTS));
     95 
     96 	group.addChild(typeGroup.release());
     97 }
     98 
     99 class BlockSingleStructCase : public UniformBlockCase
    100 {
    101 public:
    102 	BlockSingleStructCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag)
    103 		: UniformBlockCase	(testCtx, name, description, bufferMode, matrixLoadFlag)
    104 	{
    105 		StructType& typeS = m_interface.allocStruct("S");
    106 		typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH), UNUSED_BOTH); // First member is unused.
    107 		typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM), 4));
    108 		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH));
    109 
    110 		UniformBlock& block = m_interface.allocBlock("Block");
    111 		block.addUniform(Uniform("s", VarType(&typeS), 0));
    112 		block.setFlags(layoutFlags);
    113 
    114 		if (numInstances > 0)
    115 		{
    116 			block.setInstanceName("block");
    117 			block.setArraySize(numInstances);
    118 		}
    119 
    120 		init();
    121 	}
    122 };
    123 
    124 class BlockSingleStructArrayCase : public UniformBlockCase
    125 {
    126 public:
    127 	BlockSingleStructArrayCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag)
    128 		: UniformBlockCase	(testCtx, name, description, bufferMode, matrixLoadFlag)
    129 	{
    130 		StructType& typeS = m_interface.allocStruct("S");
    131 		typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH), UNUSED_BOTH);
    132 		typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM), 4));
    133 		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH));
    134 
    135 		UniformBlock& block = m_interface.allocBlock("Block");
    136 		block.addUniform(Uniform("u", VarType(glu::TYPE_UINT, PRECISION_LOW)));
    137 		block.addUniform(Uniform("s", VarType(VarType(&typeS), 3)));
    138 		block.addUniform(Uniform("v", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_MEDIUM)));
    139 		block.setFlags(layoutFlags);
    140 
    141 		if (numInstances > 0)
    142 		{
    143 			block.setInstanceName("block");
    144 			block.setArraySize(numInstances);
    145 		}
    146 
    147 		init();
    148 	}
    149 };
    150 
    151 class BlockSingleNestedStructCase : public UniformBlockCase
    152 {
    153 public:
    154 	BlockSingleNestedStructCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag)
    155 		: UniformBlockCase	(testCtx, name, description, bufferMode, matrixLoadFlag)
    156 	{
    157 		StructType& typeS = m_interface.allocStruct("S");
    158 		typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH));
    159 		typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM), 4));
    160 		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH), UNUSED_BOTH);
    161 
    162 		StructType& typeT = m_interface.allocStruct("T");
    163 		typeT.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM));
    164 		typeT.addMember("b", VarType(&typeS));
    165 
    166 		UniformBlock& block = m_interface.allocBlock("Block");
    167 		block.addUniform(Uniform("s", VarType(&typeS), 0));
    168 		block.addUniform(Uniform("v", VarType(glu::TYPE_FLOAT_VEC2, PRECISION_LOW), UNUSED_BOTH));
    169 		block.addUniform(Uniform("t", VarType(&typeT), 0));
    170 		block.addUniform(Uniform("u", VarType(glu::TYPE_UINT, PRECISION_HIGH), 0));
    171 		block.setFlags(layoutFlags);
    172 
    173 		if (numInstances > 0)
    174 		{
    175 			block.setInstanceName("block");
    176 			block.setArraySize(numInstances);
    177 		}
    178 
    179 		init();
    180 	}
    181 };
    182 
    183 class BlockSingleNestedStructArrayCase : public UniformBlockCase
    184 {
    185 public:
    186 	BlockSingleNestedStructArrayCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag)
    187 		: UniformBlockCase	(testCtx, name, description, bufferMode, matrixLoadFlag)
    188 	{
    189 		StructType& typeS = m_interface.allocStruct("S");
    190 		typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH));
    191 		typeS.addMember("b", VarType(VarType(glu::TYPE_INT_VEC2, PRECISION_MEDIUM), 4));
    192 		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH), UNUSED_BOTH);
    193 
    194 		StructType& typeT = m_interface.allocStruct("T");
    195 		typeT.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM));
    196 		typeT.addMember("b", VarType(VarType(&typeS), 3));
    197 
    198 		UniformBlock& block = m_interface.allocBlock("Block");
    199 		block.addUniform(Uniform("s", VarType(&typeS), 0));
    200 		block.addUniform(Uniform("v", VarType(glu::TYPE_FLOAT_VEC2, PRECISION_LOW), UNUSED_BOTH));
    201 		block.addUniform(Uniform("t", VarType(VarType(&typeT), 2), 0));
    202 		block.addUniform(Uniform("u", VarType(glu::TYPE_UINT, PRECISION_HIGH), 0));
    203 		block.setFlags(layoutFlags);
    204 
    205 		if (numInstances > 0)
    206 		{
    207 			block.setInstanceName("block");
    208 			block.setArraySize(numInstances);
    209 		}
    210 
    211 		init();
    212 	}
    213 };
    214 
    215 class BlockMultiBasicTypesCase : public UniformBlockCase
    216 {
    217 public:
    218 	BlockMultiBasicTypesCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, deUint32 flagsA, deUint32 flagsB, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag)
    219 		: UniformBlockCase	(testCtx, name, description, bufferMode, matrixLoadFlag)
    220 	{
    221 		UniformBlock& blockA = m_interface.allocBlock("BlockA");
    222 		blockA.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT, PRECISION_HIGH)));
    223 		blockA.addUniform(Uniform("b", VarType(glu::TYPE_UINT_VEC3, PRECISION_LOW), UNUSED_BOTH));
    224 		blockA.addUniform(Uniform("c", VarType(glu::TYPE_FLOAT_MAT2, PRECISION_MEDIUM)));
    225 		blockA.setInstanceName("blockA");
    226 		blockA.setFlags(flagsA);
    227 
    228 		UniformBlock& blockB = m_interface.allocBlock("BlockB");
    229 		blockB.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM)));
    230 		blockB.addUniform(Uniform("b", VarType(glu::TYPE_INT_VEC2, PRECISION_LOW)));
    231 		blockB.addUniform(Uniform("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH), UNUSED_BOTH));
    232 		blockB.addUniform(Uniform("d", VarType(glu::TYPE_BOOL, 0)));
    233 		blockB.setInstanceName("blockB");
    234 		blockB.setFlags(flagsB);
    235 
    236 		if (numInstances > 0)
    237 		{
    238 			blockA.setArraySize(numInstances);
    239 			blockB.setArraySize(numInstances);
    240 		}
    241 
    242 		init();
    243 	}
    244 };
    245 
    246 class BlockMultiNestedStructCase : public UniformBlockCase
    247 {
    248 public:
    249 	BlockMultiNestedStructCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, deUint32 flagsA, deUint32 flagsB, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag)
    250 		: UniformBlockCase	(testCtx, name, description, bufferMode, matrixLoadFlag)
    251 	{
    252 		StructType& typeS = m_interface.allocStruct("S");
    253 		typeS.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_LOW));
    254 		typeS.addMember("b", VarType(VarType(glu::TYPE_INT_VEC2, PRECISION_MEDIUM), 4));
    255 		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH));
    256 
    257 		StructType& typeT = m_interface.allocStruct("T");
    258 		typeT.addMember("a", VarType(glu::TYPE_UINT, PRECISION_MEDIUM), UNUSED_BOTH);
    259 		typeT.addMember("b", VarType(&typeS));
    260 		typeT.addMember("c", VarType(glu::TYPE_BOOL_VEC4, 0));
    261 
    262 		UniformBlock& blockA = m_interface.allocBlock("BlockA");
    263 		blockA.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT, PRECISION_HIGH)));
    264 		blockA.addUniform(Uniform("b", VarType(&typeS)));
    265 		blockA.addUniform(Uniform("c", VarType(glu::TYPE_UINT_VEC3, PRECISION_LOW), UNUSED_BOTH));
    266 		blockA.setInstanceName("blockA");
    267 		blockA.setFlags(flagsA);
    268 
    269 		UniformBlock& blockB = m_interface.allocBlock("BlockB");
    270 		blockB.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT_MAT2, PRECISION_MEDIUM)));
    271 		blockB.addUniform(Uniform("b", VarType(&typeT)));
    272 		blockB.addUniform(Uniform("c", VarType(glu::TYPE_BOOL_VEC4, 0), UNUSED_BOTH));
    273 		blockB.addUniform(Uniform("d", VarType(glu::TYPE_BOOL, 0)));
    274 		blockB.setInstanceName("blockB");
    275 		blockB.setFlags(flagsB);
    276 
    277 		if (numInstances > 0)
    278 		{
    279 			blockA.setArraySize(numInstances);
    280 			blockB.setArraySize(numInstances);
    281 		}
    282 
    283 		init();
    284 	}
    285 };
    286 
    287 class Block2LevelStructArrayCase : public UniformBlockCase
    288 {
    289 public:
    290 	Block2LevelStructArrayCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag)
    291 		: UniformBlockCase	(testCtx, name, description, bufferMode, matrixLoadFlag)
    292 		, m_layoutFlags		(layoutFlags)
    293 		, m_numInstances	(numInstances)
    294 	{
    295 		StructType& typeS = m_interface.allocStruct("S");
    296 		typeS.addMember("a", VarType(glu::TYPE_UINT_VEC3, PRECISION_HIGH), UNUSED_BOTH);
    297 		typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT2, PRECISION_MEDIUM), 4));
    298 		typeS.addMember("c", VarType(glu::TYPE_UINT, PRECISION_LOW));
    299 
    300 		UniformBlock& block = m_interface.allocBlock("Block");
    301 		block.addUniform(Uniform("u", VarType(glu::TYPE_INT, PRECISION_MEDIUM)));
    302 		block.addUniform(Uniform("s", VarType(VarType(VarType(&typeS), 3), 2)));
    303 		block.addUniform(Uniform("v", VarType(glu::TYPE_FLOAT_VEC2, PRECISION_MEDIUM)));
    304 		block.setFlags(m_layoutFlags);
    305 
    306 		if (m_numInstances > 0)
    307 		{
    308 			block.setInstanceName("block");
    309 			block.setArraySize(m_numInstances);
    310 		}
    311 
    312 		init();
    313 	}
    314 
    315 private:
    316 	deUint32	m_layoutFlags;
    317 	int			m_numInstances;
    318 };
    319 
    320 class LinkByBindingCase : public UniformBlockCase
    321 {
    322 public:
    323 	LinkByBindingCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, BufferMode bufferMode, int numInstances)
    324 		: UniformBlockCase	(testCtx, name, description, bufferMode, LOAD_FULL_MATRIX)
    325 	{
    326 		UniformBlock& blockA = m_interface.allocBlock("TestBlock");
    327 		blockA.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT, PRECISION_HIGH)));
    328 		blockA.addUniform(Uniform("b", VarType(glu::TYPE_UINT_VEC3, PRECISION_LOW), UNUSED_BOTH));
    329 		blockA.addUniform(Uniform("c", VarType(glu::TYPE_FLOAT_MAT2, PRECISION_MEDIUM)));
    330 		blockA.setFlags(LAYOUT_STD140|DECLARE_VERTEX);
    331 
    332 		UniformBlock& blockB = m_interface.allocBlock("TestBlock");
    333 		blockB.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM)));
    334 		blockB.addUniform(Uniform("b", VarType(glu::TYPE_INT_VEC2, PRECISION_LOW)));
    335 		blockB.addUniform(Uniform("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH), UNUSED_BOTH));
    336 		blockB.addUniform(Uniform("d", VarType(glu::TYPE_BOOL, 0)));
    337 		blockB.setFlags(LAYOUT_STD140|DECLARE_FRAGMENT);
    338 
    339 		if (numInstances > 0)
    340 		{
    341 			blockA.setInstanceName("testBlock");
    342 			blockA.setArraySize(numInstances);
    343 			blockB.setInstanceName("testBlock");
    344 			blockB.setArraySize(numInstances);
    345 		}
    346 
    347 		init();
    348 	}
    349 };
    350 
    351 void createRandomCaseGroup (tcu::TestCaseGroup* parentGroup, tcu::TestContext& testCtx, const char* groupName, const char* description, UniformBlockCase::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 RandomUniformBlockCase(testCtx, de::toString(ndx), "", bufferMode, features, (deUint32)ndx + baseSeed));
    360 }
    361 
    362 // UniformBlockTests
    363 
    364 class UniformBlockTests : public tcu::TestCaseGroup
    365 {
    366 public:
    367 							UniformBlockTests		(tcu::TestContext& testCtx);
    368 							~UniformBlockTests		(void);
    369 
    370 	void					init					(void);
    371 
    372 private:
    373 							UniformBlockTests		(const UniformBlockTests& other);
    374 	UniformBlockTests&		operator=				(const UniformBlockTests& other);
    375 };
    376 
    377 UniformBlockTests::UniformBlockTests (tcu::TestContext& testCtx)
    378 	: TestCaseGroup(testCtx, "ubo", "Uniform Block tests")
    379 {
    380 }
    381 
    382 UniformBlockTests::~UniformBlockTests (void)
    383 {
    384 }
    385 
    386 void UniformBlockTests::init (void)
    387 {
    388 	static const glu::DataType basicTypes[] =
    389 	{
    390 		glu::TYPE_FLOAT,
    391 		glu::TYPE_FLOAT_VEC2,
    392 		glu::TYPE_FLOAT_VEC3,
    393 		glu::TYPE_FLOAT_VEC4,
    394 		glu::TYPE_INT,
    395 		glu::TYPE_INT_VEC2,
    396 		glu::TYPE_INT_VEC3,
    397 		glu::TYPE_INT_VEC4,
    398 		glu::TYPE_UINT,
    399 		glu::TYPE_UINT_VEC2,
    400 		glu::TYPE_UINT_VEC3,
    401 		glu::TYPE_UINT_VEC4,
    402 		glu::TYPE_BOOL,
    403 		glu::TYPE_BOOL_VEC2,
    404 		glu::TYPE_BOOL_VEC3,
    405 		glu::TYPE_BOOL_VEC4,
    406 		glu::TYPE_FLOAT_MAT2,
    407 		glu::TYPE_FLOAT_MAT3,
    408 		glu::TYPE_FLOAT_MAT4,
    409 		glu::TYPE_FLOAT_MAT2X3,
    410 		glu::TYPE_FLOAT_MAT2X4,
    411 		glu::TYPE_FLOAT_MAT3X2,
    412 		glu::TYPE_FLOAT_MAT3X4,
    413 		glu::TYPE_FLOAT_MAT4X2,
    414 		glu::TYPE_FLOAT_MAT4X3,
    415 		glu::TYPE_UINT8,
    416 		glu::TYPE_UINT8_VEC2,
    417 		glu::TYPE_UINT8_VEC3,
    418 		glu::TYPE_UINT8_VEC4,
    419 		glu::TYPE_INT8,
    420 		glu::TYPE_INT8_VEC2,
    421 		glu::TYPE_INT8_VEC3,
    422 		glu::TYPE_INT8_VEC4,
    423 		glu::TYPE_UINT16,
    424 		glu::TYPE_UINT16_VEC2,
    425 		glu::TYPE_UINT16_VEC3,
    426 		glu::TYPE_UINT16_VEC4,
    427 		glu::TYPE_INT16,
    428 		glu::TYPE_INT16_VEC2,
    429 		glu::TYPE_INT16_VEC3,
    430 		glu::TYPE_INT16_VEC4,
    431 		glu::TYPE_FLOAT16,
    432 		glu::TYPE_FLOAT16_VEC2,
    433 		glu::TYPE_FLOAT16_VEC3,
    434 		glu::TYPE_FLOAT16_VEC4,
    435 	};
    436 
    437 	static const struct
    438 	{
    439 		const std::string	name;
    440 		deUint32			flags;
    441 	} precisionFlags[] =
    442 	{
    443 		// TODO remove PRECISION_LOW because both PRECISION_LOW and PRECISION_MEDIUM means relaxed precision?
    444 		{ "lowp",		PRECISION_LOW		},
    445 		{ "mediump",	PRECISION_MEDIUM	},
    446 		{ "highp",		PRECISION_HIGH		}
    447 	};
    448 
    449 	static const struct
    450 	{
    451 		const char*			name;
    452 		deUint32			flags;
    453 	} layoutFlags[] =
    454 	{
    455 		{ "std140",		LAYOUT_STD140	},
    456 		{ "std430",		LAYOUT_STD430	},
    457 		{ "scalar",		LAYOUT_SCALAR	}
    458 	};
    459 
    460 	static const struct
    461 	{
    462 		const std::string	name;
    463 		deUint32			flags;
    464 	} matrixFlags[] =
    465 	{
    466 		{ "row_major",		LAYOUT_ROW_MAJOR	},
    467 		{ "column_major",	LAYOUT_COLUMN_MAJOR }
    468 	};
    469 
    470 	static const struct
    471 	{
    472 		const char*							name;
    473 		UniformBlockCase::BufferMode		mode;
    474 	} bufferModes[] =
    475 	{
    476 		{ "per_block_buffer",	UniformBlockCase::BUFFERMODE_PER_BLOCK },
    477 		{ "single_buffer",		UniformBlockCase::BUFFERMODE_SINGLE	}
    478 	};
    479 
    480 	// ubo.2_level_array
    481 	{
    482 		tcu::TestCaseGroup* nestedArrayGroup = new tcu::TestCaseGroup(m_testCtx, "2_level_array", "2-level basic array variable in single buffer");
    483 		addChild(nestedArrayGroup);
    484 
    485 		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
    486 		{
    487 			de::MovePtr<tcu::TestCaseGroup> layoutGroup(new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, ""));
    488 
    489 			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
    490 			{
    491 				const glu::DataType	type		= basicTypes[basicTypeNdx];
    492 				const char* const	typeName	= glu::getDataTypeName(type);
    493 				const int			childSize	= 4;
    494 				const int			parentSize	= 3;
    495 				const VarType		childType	(VarType(type, !dataTypeSupportsPrecisionModifier(type) ? 0 : PRECISION_HIGH), childSize);
    496 				const VarType		parentType	(childType, parentSize);
    497 
    498 				createBlockBasicTypeCases(*layoutGroup, m_testCtx, typeName, parentType, layoutFlags[layoutFlagNdx].flags);
    499 
    500 				if (glu::isDataTypeMatrix(type))
    501 				{
    502 					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
    503 						createBlockBasicTypeCases(*layoutGroup, m_testCtx, (std::string(matrixFlags[matFlagNdx].name) + "_" + typeName),
    504 												  parentType, layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags);
    505 				}
    506 			}
    507 			nestedArrayGroup->addChild(layoutGroup.release());
    508 		}
    509 	}
    510 
    511 	// ubo.3_level_array
    512 	{
    513 		tcu::TestCaseGroup* nestedArrayGroup = new tcu::TestCaseGroup(m_testCtx, "3_level_array", "3-level basic array variable in single buffer");
    514 		addChild(nestedArrayGroup);
    515 
    516 		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
    517 		{
    518 			de::MovePtr<tcu::TestCaseGroup> layoutGroup(new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, ""));
    519 
    520 			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
    521 			{
    522 				const glu::DataType	type		= basicTypes[basicTypeNdx];
    523 				const char* const	typeName	= glu::getDataTypeName(type);
    524 				const int			childSize0	= 2;
    525 				const int			childSize1	= 4;
    526 				const int			parentSize	= 3;
    527 				const VarType		childType0	(VarType(type, !dataTypeSupportsPrecisionModifier(type) ? 0 : PRECISION_HIGH), childSize0);
    528 				const VarType		childType1	(childType0, childSize1);
    529 				const VarType		parentType	(childType1, parentSize);
    530 
    531 				createBlockBasicTypeCases(*layoutGroup, m_testCtx, typeName, parentType, layoutFlags[layoutFlagNdx].flags);
    532 
    533 				if (glu::isDataTypeMatrix(type))
    534 				{
    535 					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
    536 						createBlockBasicTypeCases(*layoutGroup, m_testCtx, (std::string(matrixFlags[matFlagNdx].name) + "_" + typeName),
    537 												  parentType, layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags);
    538 				}
    539 			}
    540 			nestedArrayGroup->addChild(layoutGroup.release());
    541 		}
    542 	}
    543 
    544 	// ubo.2_level_struct_array
    545 	{
    546 		tcu::TestCaseGroup* structArrayArrayGroup = new tcu::TestCaseGroup(m_testCtx, "2_level_struct_array", "Struct array in one uniform block");
    547 		addChild(structArrayArrayGroup);
    548 
    549 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
    550 		{
    551 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
    552 			structArrayArrayGroup->addChild(modeGroup);
    553 
    554 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
    555 			{
    556 				for (int isArray = 0; isArray < 2; isArray++)
    557 				{
    558 					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
    559 					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
    560 
    561 					if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
    562 						continue; // Doesn't make sense to add this variant.
    563 
    564 					if (isArray)
    565 						baseName += "_instance_array";
    566 
    567 					modeGroup->addChild(new Block2LevelStructArrayCase(m_testCtx, (baseName + "_vertex"),				"", baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
    568 					modeGroup->addChild(new Block2LevelStructArrayCase(m_testCtx, (baseName + "_fragment"),				"", baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
    569 					modeGroup->addChild(new Block2LevelStructArrayCase(m_testCtx, (baseName + "_both"),					"", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
    570 					modeGroup->addChild(new Block2LevelStructArrayCase(m_testCtx, (baseName + "_vertex_comp_access"),	"", baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
    571 					modeGroup->addChild(new Block2LevelStructArrayCase(m_testCtx, (baseName + "_fragment_comp_access"),	"", baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
    572 					modeGroup->addChild(new Block2LevelStructArrayCase(m_testCtx, (baseName + "_both_comp_access"),		"", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
    573 				}
    574 			}
    575 		}
    576 	}
    577 
    578 	// ubo.single_basic_type
    579 	{
    580 		tcu::TestCaseGroup* singleBasicTypeGroup = new tcu::TestCaseGroup(m_testCtx, "single_basic_type", "Single basic variable in single buffer");
    581 		addChild(singleBasicTypeGroup);
    582 
    583 		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
    584 		{
    585 			de::MovePtr<tcu::TestCaseGroup> layoutGroup(new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, ""));
    586 
    587 			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
    588 			{
    589 				glu::DataType		type = basicTypes[basicTypeNdx];
    590 				const char* const	typeName = glu::getDataTypeName(type);
    591 
    592 				if (!dataTypeSupportsPrecisionModifier(type))
    593 					createBlockBasicTypeCases(*layoutGroup, m_testCtx, typeName, VarType(type, 0), layoutFlags[layoutFlagNdx].flags);
    594 			}
    595 
    596 			for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisionFlags); precNdx++)
    597 			{
    598 				de::MovePtr<tcu::TestCaseGroup>	precGroup(new tcu::TestCaseGroup(m_testCtx, precisionFlags[precNdx].name.c_str(), ""));
    599 
    600 				for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
    601 				{
    602 					glu::DataType		type		= basicTypes[basicTypeNdx];
    603 					const char* const	typeName	= glu::getDataTypeName(type);
    604 
    605 					if (dataTypeSupportsPrecisionModifier(type))
    606 						createBlockBasicTypeCases(*precGroup, m_testCtx, typeName,
    607 												  VarType(type, precisionFlags[precNdx].flags), layoutFlags[layoutFlagNdx].flags);
    608 
    609 					if (glu::isDataTypeMatrix(type))
    610 					{
    611 						for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
    612 						{
    613 							createBlockBasicTypeCases(*precGroup, m_testCtx, matrixFlags[matFlagNdx].name + "_" + typeName,
    614 													  VarType(type, precisionFlags[precNdx].flags), layoutFlags[layoutFlagNdx].flags | matrixFlags[matFlagNdx].flags);
    615 
    616 						}
    617 					}
    618 				}
    619 				layoutGroup->addChild(precGroup.release());
    620 			}
    621 			singleBasicTypeGroup->addChild(layoutGroup.release());
    622 		}
    623 	}
    624 
    625 	// ubo.single_basic_array
    626 	{
    627 		tcu::TestCaseGroup* singleBasicArrayGroup = new tcu::TestCaseGroup(m_testCtx, "single_basic_array", "Single basic array variable in single buffer");
    628 		addChild(singleBasicArrayGroup);
    629 
    630 		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
    631 		{
    632 			de::MovePtr<tcu::TestCaseGroup> layoutGroup(new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, ""));
    633 
    634 			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
    635 			{
    636 				glu::DataType		type		= basicTypes[basicTypeNdx];
    637 				const char* const	typeName	= glu::getDataTypeName(type);
    638 				const int			arraySize	= 3;
    639 
    640 				createBlockBasicTypeCases(*layoutGroup, m_testCtx, typeName,
    641 										  VarType(VarType(type, !dataTypeSupportsPrecisionModifier(type) ? 0 : PRECISION_HIGH), arraySize),
    642 										  layoutFlags[layoutFlagNdx].flags);
    643 
    644 				if (glu::isDataTypeMatrix(type))
    645 				{
    646 					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
    647 						createBlockBasicTypeCases(*layoutGroup, m_testCtx, matrixFlags[matFlagNdx].name + "_" + typeName,
    648 												  VarType(VarType(type, PRECISION_HIGH), arraySize),
    649 												  layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags);
    650 				}
    651 			}
    652 			singleBasicArrayGroup->addChild(layoutGroup.release());
    653 		}
    654 	}
    655 
    656 	// ubo.single_struct
    657 	{
    658 		tcu::TestCaseGroup* singleStructGroup = new tcu::TestCaseGroup(m_testCtx, "single_struct", "Single struct in uniform block");
    659 		addChild(singleStructGroup);
    660 
    661 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
    662 		{
    663 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
    664 			singleStructGroup->addChild(modeGroup);
    665 
    666 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
    667 			{
    668 				for (int isArray = 0; isArray < 2; isArray++)
    669 				{
    670 					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
    671 					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
    672 
    673 					if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
    674 						continue; // Doesn't make sense to add this variant.
    675 
    676 					if (isArray)
    677 						baseName += "_instance_array";
    678 
    679 					modeGroup->addChild(new BlockSingleStructCase(m_testCtx, baseName + "_vertex",				 "", baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
    680 					modeGroup->addChild(new BlockSingleStructCase(m_testCtx, baseName + "_fragment",			 "", baseFlags|DECLARE_FRAGMENT,				bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
    681 					modeGroup->addChild(new BlockSingleStructCase(m_testCtx, baseName + "_both",				 "", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
    682 					modeGroup->addChild(new BlockSingleStructCase(m_testCtx, baseName + "_vertex_comp_access",	 "", baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
    683 					modeGroup->addChild(new BlockSingleStructCase(m_testCtx, baseName + "_fragment_comp_access", "", baseFlags|DECLARE_FRAGMENT,				bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
    684 					modeGroup->addChild(new BlockSingleStructCase(m_testCtx, baseName + "_both_comp_access",	 "", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
    685 				}
    686 			}
    687 		}
    688 	}
    689 
    690 	// ubo.single_struct_array
    691 	{
    692 		tcu::TestCaseGroup* singleStructArrayGroup = new tcu::TestCaseGroup(m_testCtx, "single_struct_array", "Struct array in one uniform block");
    693 		addChild(singleStructArrayGroup);
    694 
    695 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
    696 		{
    697 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
    698 			singleStructArrayGroup->addChild(modeGroup);
    699 
    700 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
    701 			{
    702 				for (int isArray = 0; isArray < 2; isArray++)
    703 				{
    704 					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
    705 					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
    706 
    707 					if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
    708 						continue; // Doesn't make sense to add this variant.
    709 
    710 					if (isArray)
    711 						baseName += "_instance_array";
    712 
    713 					modeGroup->addChild(new BlockSingleStructArrayCase(m_testCtx, baseName + "_vertex",				  "", baseFlags|DECLARE_VERTEX,						bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
    714 					modeGroup->addChild(new BlockSingleStructArrayCase(m_testCtx, baseName + "_fragment",			  "", baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
    715 					modeGroup->addChild(new BlockSingleStructArrayCase(m_testCtx, baseName + "_both",				  "",	baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
    716 					modeGroup->addChild(new BlockSingleStructArrayCase(m_testCtx, baseName + "_vertex_comp_access",	  "", baseFlags|DECLARE_VERTEX,						bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
    717 					modeGroup->addChild(new BlockSingleStructArrayCase(m_testCtx, baseName + "_fragment_comp_access", "", baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
    718 					modeGroup->addChild(new BlockSingleStructArrayCase(m_testCtx, baseName + "_both_comp_access",	  "",	baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
    719 				}
    720 			}
    721 		}
    722 	}
    723 
    724 	// ubo.single_nested_struct
    725 	{
    726 		tcu::TestCaseGroup* singleNestedStructGroup = new tcu::TestCaseGroup(m_testCtx, "single_nested_struct", "Nested struct in one uniform block");
    727 		addChild(singleNestedStructGroup);
    728 
    729 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
    730 		{
    731 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
    732 			singleNestedStructGroup->addChild(modeGroup);
    733 
    734 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
    735 			{
    736 				for (int isArray = 0; isArray < 2; isArray++)
    737 				{
    738 					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
    739 					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
    740 
    741 					if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
    742 						continue; // Doesn't make sense to add this variant.
    743 
    744 					if (isArray)
    745 						baseName += "_instance_array";
    746 
    747 					modeGroup->addChild(new BlockSingleNestedStructCase(m_testCtx, baseName + "_vertex",				"", baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
    748 					modeGroup->addChild(new BlockSingleNestedStructCase(m_testCtx, baseName + "_fragment",				"", baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
    749 					modeGroup->addChild(new BlockSingleNestedStructCase(m_testCtx, baseName + "_both",					"", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
    750 					modeGroup->addChild(new BlockSingleNestedStructCase(m_testCtx, baseName + "_vertex_comp_access",	"", baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
    751 					modeGroup->addChild(new BlockSingleNestedStructCase(m_testCtx, baseName + "_fragment_comp_access",	"", baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
    752 					modeGroup->addChild(new BlockSingleNestedStructCase(m_testCtx, baseName + "_both_comp_access",		"", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
    753 				}
    754 			}
    755 		}
    756 	}
    757 
    758 	// ubo.single_nested_struct_array
    759 	{
    760 		tcu::TestCaseGroup* singleNestedStructArrayGroup = new tcu::TestCaseGroup(m_testCtx, "single_nested_struct_array", "Nested struct array in one uniform block");
    761 		addChild(singleNestedStructArrayGroup);
    762 
    763 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
    764 		{
    765 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
    766 			singleNestedStructArrayGroup->addChild(modeGroup);
    767 
    768 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
    769 			{
    770 				for (int isArray = 0; isArray < 2; isArray++)
    771 				{
    772 					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
    773 					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
    774 
    775 					if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
    776 						continue; // Doesn't make sense to add this variant.
    777 
    778 					if (isArray)
    779 						baseName += "_instance_array";
    780 
    781 					modeGroup->addChild(new BlockSingleNestedStructArrayCase(m_testCtx, baseName + "_vertex",				"", baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
    782 					modeGroup->addChild(new BlockSingleNestedStructArrayCase(m_testCtx, baseName + "_fragment",				"", baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
    783 					modeGroup->addChild(new BlockSingleNestedStructArrayCase(m_testCtx, baseName + "_both",					"",	baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
    784 					modeGroup->addChild(new BlockSingleNestedStructArrayCase(m_testCtx, baseName + "_vertex_comp_access",	"", baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
    785 					modeGroup->addChild(new BlockSingleNestedStructArrayCase(m_testCtx, baseName + "_fragment_comp_access",	"", baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
    786 					modeGroup->addChild(new BlockSingleNestedStructArrayCase(m_testCtx, baseName + "_both_comp_access",		"",	baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
    787 				}
    788 			}
    789 		}
    790 	}
    791 
    792 	// ubo.instance_array_basic_type
    793 	{
    794 		tcu::TestCaseGroup* instanceArrayBasicTypeGroup = new tcu::TestCaseGroup(m_testCtx, "instance_array_basic_type", "Single basic variable in instance array");
    795 		addChild(instanceArrayBasicTypeGroup);
    796 
    797 		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
    798 		{
    799 			de::MovePtr<tcu::TestCaseGroup> layoutGroup(new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, ""));
    800 
    801 			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
    802 			{
    803 				glu::DataType		type			= basicTypes[basicTypeNdx];
    804 				const char* const	typeName		= glu::getDataTypeName(type);
    805 				const int			numInstances	= 3;
    806 
    807 				createBlockBasicTypeCases(*layoutGroup, m_testCtx, typeName,
    808 										  VarType(type, !dataTypeSupportsPrecisionModifier(type) ? 0 : PRECISION_HIGH),
    809 										  layoutFlags[layoutFlagNdx].flags, numInstances);
    810 
    811 				if (glu::isDataTypeMatrix(type))
    812 				{
    813 					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
    814 						createBlockBasicTypeCases(*layoutGroup, m_testCtx, matrixFlags[matFlagNdx].name + "_" + typeName,
    815 												  VarType(type, PRECISION_HIGH), layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags,
    816 												  numInstances);
    817 				}
    818 			}
    819 			instanceArrayBasicTypeGroup->addChild(layoutGroup.release());
    820 		}
    821 	}
    822 
    823 	// ubo.multi_basic_types
    824 	{
    825 		tcu::TestCaseGroup* multiBasicTypesGroup = new tcu::TestCaseGroup(m_testCtx, "multi_basic_types", "Multiple buffers with basic types");
    826 		addChild(multiBasicTypesGroup);
    827 
    828 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
    829 		{
    830 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
    831 			multiBasicTypesGroup->addChild(modeGroup);
    832 
    833 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
    834 			{
    835 				for (int isArray = 0; isArray < 2; isArray++)
    836 				{
    837 					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
    838 					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
    839 
    840 					if (isArray)
    841 						baseName += "_instance_array";
    842 
    843 					modeGroup->addChild(new BlockMultiBasicTypesCase(m_testCtx, baseName + "_vertex",				"", baseFlags|DECLARE_VERTEX,					baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
    844 					modeGroup->addChild(new BlockMultiBasicTypesCase(m_testCtx, baseName + "_fragment",				"", baseFlags|DECLARE_FRAGMENT,					baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
    845 					modeGroup->addChild(new BlockMultiBasicTypesCase(m_testCtx, baseName + "_both",					"", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
    846 					modeGroup->addChild(new BlockMultiBasicTypesCase(m_testCtx, baseName + "_mixed",				"", baseFlags|DECLARE_VERTEX,					baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
    847 					modeGroup->addChild(new BlockMultiBasicTypesCase(m_testCtx, baseName + "_vertex_comp_access",	"", baseFlags|DECLARE_VERTEX,					baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
    848 					modeGroup->addChild(new BlockMultiBasicTypesCase(m_testCtx, baseName + "_fragment_comp_access",	"", baseFlags|DECLARE_FRAGMENT,					baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
    849 					modeGroup->addChild(new BlockMultiBasicTypesCase(m_testCtx, baseName + "_both_comp_access",		"", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
    850 					modeGroup->addChild(new BlockMultiBasicTypesCase(m_testCtx, baseName + "_mixed_comp_access",	"", baseFlags|DECLARE_VERTEX,					baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
    851 				}
    852 			}
    853 		}
    854 	}
    855 
    856 	// ubo.multi_nested_struct
    857 	{
    858 		tcu::TestCaseGroup* multiNestedStructGroup = new tcu::TestCaseGroup(m_testCtx, "multi_nested_struct", "Multiple buffers with nested structs");
    859 		addChild(multiNestedStructGroup);
    860 
    861 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
    862 		{
    863 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
    864 			multiNestedStructGroup->addChild(modeGroup);
    865 
    866 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
    867 			{
    868 				for (int isArray = 0; isArray < 2; isArray++)
    869 				{
    870 					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
    871 					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
    872 
    873 					if (isArray)
    874 						baseName += "_instance_array";
    875 
    876 					modeGroup->addChild(new BlockMultiNestedStructCase(m_testCtx, baseName + "_vertex",				  "", baseFlags|DECLARE_VERTEX,						baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
    877 					modeGroup->addChild(new BlockMultiNestedStructCase(m_testCtx, baseName + "_fragment",			  "", baseFlags|DECLARE_FRAGMENT,					baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
    878 					modeGroup->addChild(new BlockMultiNestedStructCase(m_testCtx, baseName + "_both",				  "", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
    879 					modeGroup->addChild(new BlockMultiNestedStructCase(m_testCtx, baseName + "_mixed",				  "", baseFlags|DECLARE_VERTEX,						baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
    880 					modeGroup->addChild(new BlockMultiNestedStructCase(m_testCtx, baseName + "_vertex_comp_access",	  "", baseFlags|DECLARE_VERTEX,						baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
    881 					modeGroup->addChild(new BlockMultiNestedStructCase(m_testCtx, baseName + "_fragment_comp_access", "", baseFlags|DECLARE_FRAGMENT,					baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
    882 					modeGroup->addChild(new BlockMultiNestedStructCase(m_testCtx, baseName + "_both_comp_access",	  "", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
    883 					modeGroup->addChild(new BlockMultiNestedStructCase(m_testCtx, baseName + "_mixed_comp_access",	  "", baseFlags|DECLARE_VERTEX,						baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
    884 				}
    885 			}
    886 		}
    887 	}
    888 
    889 	// .link_by_binding
    890 	{
    891 		tcu::TestCaseGroup* linkByBindingGroup = new tcu::TestCaseGroup(m_testCtx, "link_by_binding", "Blocks with same name but different binding");
    892 		addChild(linkByBindingGroup);
    893 
    894 		linkByBindingGroup->addChild(new LinkByBindingCase(m_testCtx, "single_buf_single_instance",		"", UniformBlockCase::BUFFERMODE_SINGLE, 0));
    895 		linkByBindingGroup->addChild(new LinkByBindingCase(m_testCtx, "single_buf_instance_array",		"", UniformBlockCase::BUFFERMODE_SINGLE, 2));
    896 		linkByBindingGroup->addChild(new LinkByBindingCase(m_testCtx, "per_block_buf_single_instance",	"", UniformBlockCase::BUFFERMODE_PER_BLOCK, 0));
    897 		linkByBindingGroup->addChild(new LinkByBindingCase(m_testCtx, "per_block_buf_instance_array",	"", UniformBlockCase::BUFFERMODE_PER_BLOCK, 2));
    898 	}
    899 
    900 	// ubo.random
    901 	{
    902 		const deUint32	allShaders		= FEATURE_VERTEX_BLOCKS|FEATURE_FRAGMENT_BLOCKS|FEATURE_SHARED_BLOCKS;
    903 		const deUint32	allLayouts		= FEATURE_STD140_LAYOUT;
    904 		const deUint32	allBasicTypes	= FEATURE_VECTORS|FEATURE_MATRICES;
    905 		const deUint32	unused			= FEATURE_UNUSED_MEMBERS|FEATURE_UNUSED_UNIFORMS;
    906 		const deUint32	matFlags		= FEATURE_MATRIX_LAYOUT;
    907 		const deUint32	allFeatures		= ~FEATURE_OUT_OF_ORDER_OFFSETS & ~FEATURE_16BIT_STORAGE & ~FEATURE_8BIT_STORAGE
    908 										  & ~FEATURE_STD430_LAYOUT & ~FEATURE_SCALAR_LAYOUT;  // OOO offsets handled in a dedicated case group
    909 		const deUint32	allScalar		= ~allLayouts & ~FEATURE_16BIT_STORAGE & ~FEATURE_8BIT_STORAGE;
    910 
    911 		tcu::TestCaseGroup* randomGroup = new tcu::TestCaseGroup(m_testCtx, "random", "Random Uniform Block cases");
    912 		addChild(randomGroup);
    913 
    914 		for (int i = 0; i < 3; ++i)
    915 		{
    916 
    917 			tcu::TestCaseGroup* group = randomGroup;
    918 			if (i == 1)
    919 			{
    920 				group = new tcu::TestCaseGroup(m_testCtx, "16bit", "16bit storage");
    921 				randomGroup->addChild(group);
    922 			}
    923 			if (i == 2)
    924 			{
    925 				group = new tcu::TestCaseGroup(m_testCtx, "8bit", "8bit storage");
    926 				randomGroup->addChild(group);
    927 			}
    928 			const deUint32 use16BitStorage = i == 1 ? FEATURE_16BIT_STORAGE : 0;
    929 			const deUint32 use8BitStorage = i == 2 ? FEATURE_8BIT_STORAGE : 0;
    930 
    931 			// Basic types.
    932 			createRandomCaseGroup(group, m_testCtx, "scalar_types",	"Scalar types only, per-block buffers",				UniformBlockCase::BUFFERMODE_PER_BLOCK,	use8BitStorage|use16BitStorage|allShaders|allLayouts|unused,										25, 0);
    933 			createRandomCaseGroup(group, m_testCtx, "vector_types",	"Scalar and vector types only, per-block buffers",	UniformBlockCase::BUFFERMODE_PER_BLOCK,	use8BitStorage|use16BitStorage|allShaders|allLayouts|unused|FEATURE_VECTORS,						25, 25);
    934 			createRandomCaseGroup(group, m_testCtx, "basic_types",	"All basic types, per-block buffers",				UniformBlockCase::BUFFERMODE_PER_BLOCK, use8BitStorage|use16BitStorage|allShaders|allLayouts|unused|allBasicTypes|matFlags,				25, 50);
    935 			createRandomCaseGroup(group, m_testCtx, "basic_arrays",	"Arrays, per-block buffers",						UniformBlockCase::BUFFERMODE_PER_BLOCK,	use8BitStorage|use16BitStorage|allShaders|allLayouts|unused|allBasicTypes|matFlags|FEATURE_ARRAYS,	25, 50);
    936 
    937 			createRandomCaseGroup(group, m_testCtx, "basic_instance_arrays",					"Basic instance arrays, per-block buffers",				UniformBlockCase::BUFFERMODE_PER_BLOCK,	use8BitStorage|use16BitStorage|allShaders|allLayouts|unused|allBasicTypes|matFlags|FEATURE_INSTANCE_ARRAYS,								25, 75);
    938 			createRandomCaseGroup(group, m_testCtx, "nested_structs",							"Nested structs, per-block buffers",					UniformBlockCase::BUFFERMODE_PER_BLOCK,	use8BitStorage|use16BitStorage|allShaders|allLayouts|unused|allBasicTypes|matFlags|FEATURE_STRUCTS,										25, 100);
    939 			createRandomCaseGroup(group, m_testCtx, "nested_structs_arrays",					"Nested structs, arrays, per-block buffers",			UniformBlockCase::BUFFERMODE_PER_BLOCK,	use8BitStorage|use16BitStorage|allShaders|allLayouts|unused|allBasicTypes|matFlags|FEATURE_STRUCTS|FEATURE_ARRAYS,							25, 150);
    940 			createRandomCaseGroup(group, m_testCtx, "nested_structs_instance_arrays",			"Nested structs, instance arrays, per-block buffers",	UniformBlockCase::BUFFERMODE_PER_BLOCK,	use8BitStorage|use16BitStorage|allShaders|allLayouts|unused|allBasicTypes|matFlags|FEATURE_STRUCTS|FEATURE_INSTANCE_ARRAYS,				25, 125);
    941 			createRandomCaseGroup(group, m_testCtx, "nested_structs_arrays_instance_arrays",	"Nested structs, instance arrays, per-block buffers",	UniformBlockCase::BUFFERMODE_PER_BLOCK,	use8BitStorage|use16BitStorage|allShaders|allLayouts|unused|allBasicTypes|matFlags|FEATURE_STRUCTS|FEATURE_ARRAYS|FEATURE_INSTANCE_ARRAYS,	25, 175);
    942 
    943 			createRandomCaseGroup(group, m_testCtx, "all_per_block_buffers",	"All random features, per-block buffers",	UniformBlockCase::BUFFERMODE_PER_BLOCK,	use8BitStorage|use16BitStorage|allFeatures,	50, 200);
    944 			createRandomCaseGroup(group, m_testCtx, "all_shared_buffer",		"All random features, shared buffer",		UniformBlockCase::BUFFERMODE_SINGLE,	use8BitStorage|use16BitStorage|allFeatures,	50, 250);
    945 
    946 			createRandomCaseGroup(group, m_testCtx, "all_out_of_order_offsets",	"All random features, out of order member offsets",		UniformBlockCase::BUFFERMODE_PER_BLOCK,	use8BitStorage|use16BitStorage|allFeatures | FEATURE_OUT_OF_ORDER_OFFSETS,	50, 300);
    947 			createRandomCaseGroup(group, m_testCtx, "scalar",					"VK_EXT_scalar_block_layout",				UniformBlockCase::BUFFERMODE_SINGLE,	use8BitStorage|use16BitStorage|allScalar, 100, deInt32Hash(313));
    948 		}
    949 	}
    950 }
    951 
    952 } // anonymous
    953 
    954 tcu::TestCaseGroup*	createTests	(tcu::TestContext& testCtx)
    955 {
    956 	return new UniformBlockTests(testCtx);
    957 }
    958 
    959 } // ubo
    960 } // vkt
    961