Home | History | Annotate | Download | only in functional
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL ES 3.0 Module
      3  * -------------------------------------------------
      4  *
      5  * Copyright 2014 The Android Open Source Project
      6  *
      7  * Licensed under the Apache License, Version 2.0 (the "License");
      8  * you may not use this file except in compliance with the License.
      9  * You may obtain a copy of the License at
     10  *
     11  *      http://www.apache.org/licenses/LICENSE-2.0
     12  *
     13  * Unless required by applicable law or agreed to in writing, software
     14  * distributed under the License is distributed on an "AS IS" BASIS,
     15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16  * See the License for the specific language governing permissions and
     17  * limitations under the License.
     18  *
     19  *//*!
     20  * \file
     21  * \brief Uniform block tests.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "es3fUniformBlockTests.hpp"
     25 #include "glsUniformBlockCase.hpp"
     26 #include "glsRandomUniformBlockCase.hpp"
     27 #include "tcuCommandLine.hpp"
     28 #include "deRandom.hpp"
     29 #include "deStringUtil.hpp"
     30 
     31 using std::string;
     32 using std::vector;
     33 
     34 namespace deqp
     35 {
     36 namespace gles3
     37 {
     38 namespace Functional
     39 {
     40 
     41 using gls::UniformBlockCase;
     42 using gls::RandomUniformBlockCase;
     43 using namespace gls::ub;
     44 
     45 static void createRandomCaseGroup (tcu::TestCaseGroup* parentGroup, Context& context, const char* groupName, const char* description, UniformBlockCase::BufferMode bufferMode, deUint32 features, int numCases, deUint32 baseSeed)
     46 {
     47 	tcu::TestCaseGroup* group = new tcu::TestCaseGroup(context.getTestContext(), groupName, description);
     48 	parentGroup->addChild(group);
     49 
     50 	baseSeed += (deUint32)context.getTestContext().getCommandLine().getBaseSeed();
     51 
     52 	for (int ndx = 0; ndx < numCases; ndx++)
     53 		group->addChild(new RandomUniformBlockCase(context.getTestContext(), context.getRenderContext(), glu::GLSL_VERSION_300_ES,
     54 												   de::toString(ndx).c_str(), "", bufferMode, features, (deUint32)ndx+baseSeed));
     55 }
     56 
     57 class BlockBasicTypeCase : public UniformBlockCase
     58 {
     59 public:
     60 	BlockBasicTypeCase (Context& context, const char* name, const char* description, const VarType& type, deUint32 layoutFlags, int numInstances)
     61 		: UniformBlockCase(context.getTestContext(), context.getRenderContext(), name, description, glu::GLSL_VERSION_300_ES, BUFFERMODE_PER_BLOCK)
     62 	{
     63 		UniformBlock& block = m_interface.allocBlock("Block");
     64 		block.addUniform(Uniform("var", type, 0));
     65 		block.setFlags(layoutFlags);
     66 
     67 		if (numInstances > 0)
     68 		{
     69 			block.setArraySize(numInstances);
     70 			block.setInstanceName("block");
     71 		}
     72 	}
     73 };
     74 
     75 static void createBlockBasicTypeCases (tcu::TestCaseGroup* group, Context& context, const char* name, const VarType& type, deUint32 layoutFlags, int numInstances = 0)
     76 {
     77 	group->addChild(new BlockBasicTypeCase(context, (string(name) + "_vertex").c_str(),		"", type, layoutFlags|DECLARE_VERTEX,					numInstances));
     78 	group->addChild(new BlockBasicTypeCase(context, (string(name) + "_fragment").c_str(),	"", type, layoutFlags|DECLARE_FRAGMENT,					numInstances));
     79 
     80 	if (!(layoutFlags & LAYOUT_PACKED))
     81 		group->addChild(new BlockBasicTypeCase(context, (string(name) + "_both").c_str(),		"", type, layoutFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	numInstances));
     82 }
     83 
     84 class BlockSingleStructCase : public UniformBlockCase
     85 {
     86 public:
     87 	BlockSingleStructCase (Context& context, const char* name, const char* description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances)
     88 		: UniformBlockCase	(context.getTestContext(), context.getRenderContext(), name, description, glu::GLSL_VERSION_300_ES, bufferMode)
     89 		, m_layoutFlags		(layoutFlags)
     90 		, m_numInstances	(numInstances)
     91 	{
     92 	}
     93 
     94 	void init (void)
     95 	{
     96 		StructType& typeS = m_interface.allocStruct("S");
     97 		typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH), UNUSED_BOTH); // First member is unused.
     98 		typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM), 4));
     99 		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH));
    100 
    101 		UniformBlock& block = m_interface.allocBlock("Block");
    102 		block.addUniform(Uniform("s", VarType(&typeS), 0));
    103 		block.setFlags(m_layoutFlags);
    104 
    105 		if (m_numInstances > 0)
    106 		{
    107 			block.setInstanceName("block");
    108 			block.setArraySize(m_numInstances);
    109 		}
    110 	}
    111 
    112 private:
    113 	deUint32	m_layoutFlags;
    114 	int			m_numInstances;
    115 };
    116 
    117 class BlockSingleStructArrayCase : public UniformBlockCase
    118 {
    119 public:
    120 	BlockSingleStructArrayCase (Context& context, const char* name, const char* description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances)
    121 		: UniformBlockCase	(context.getTestContext(), context.getRenderContext(), name, description, glu::GLSL_VERSION_300_ES, bufferMode)
    122 		, m_layoutFlags		(layoutFlags)
    123 		, m_numInstances	(numInstances)
    124 	{
    125 	}
    126 
    127 	void init (void)
    128 	{
    129 		StructType& typeS = m_interface.allocStruct("S");
    130 		typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH), UNUSED_BOTH);
    131 		typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM), 4));
    132 		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH));
    133 
    134 		UniformBlock& block = m_interface.allocBlock("Block");
    135 		block.addUniform(Uniform("u", VarType(glu::TYPE_UINT, PRECISION_LOW)));
    136 		block.addUniform(Uniform("s", VarType(VarType(&typeS), 3)));
    137 		block.addUniform(Uniform("v", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_MEDIUM)));
    138 		block.setFlags(m_layoutFlags);
    139 
    140 		if (m_numInstances > 0)
    141 		{
    142 			block.setInstanceName("block");
    143 			block.setArraySize(m_numInstances);
    144 		}
    145 	}
    146 
    147 private:
    148 	deUint32	m_layoutFlags;
    149 	int			m_numInstances;
    150 };
    151 
    152 class BlockSingleNestedStructCase : public UniformBlockCase
    153 {
    154 public:
    155 	BlockSingleNestedStructCase (Context& context, const char* name, const char* description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances)
    156 		: UniformBlockCase	(context.getTestContext(), context.getRenderContext(), name, description, glu::GLSL_VERSION_300_ES, bufferMode)
    157 		, m_layoutFlags		(layoutFlags)
    158 		, m_numInstances	(numInstances)
    159 	{
    160 	}
    161 
    162 	void init (void)
    163 	{
    164 		StructType& typeS = m_interface.allocStruct("S");
    165 		typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH));
    166 		typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM), 4));
    167 		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH), UNUSED_BOTH);
    168 
    169 		StructType& typeT = m_interface.allocStruct("T");
    170 		typeT.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM));
    171 		typeT.addMember("b", VarType(&typeS));
    172 
    173 		UniformBlock& block = m_interface.allocBlock("Block");
    174 		block.addUniform(Uniform("s", VarType(&typeS), 0));
    175 		block.addUniform(Uniform("v", VarType(glu::TYPE_FLOAT_VEC2, PRECISION_LOW), UNUSED_BOTH));
    176 		block.addUniform(Uniform("t", VarType(&typeT), 0));
    177 		block.addUniform(Uniform("u", VarType(glu::TYPE_UINT, PRECISION_HIGH), 0));
    178 		block.setFlags(m_layoutFlags);
    179 
    180 		if (m_numInstances > 0)
    181 		{
    182 			block.setInstanceName("block");
    183 			block.setArraySize(m_numInstances);
    184 		}
    185 	}
    186 
    187 private:
    188 	deUint32	m_layoutFlags;
    189 	int			m_numInstances;
    190 };
    191 
    192 class BlockSingleNestedStructArrayCase : public UniformBlockCase
    193 {
    194 public:
    195 	BlockSingleNestedStructArrayCase (Context& context, const char* name, const char* description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances)
    196 		: UniformBlockCase	(context.getTestContext(), context.getRenderContext(), name, description, glu::GLSL_VERSION_300_ES, bufferMode)
    197 		, m_layoutFlags		(layoutFlags)
    198 		, m_numInstances	(numInstances)
    199 	{
    200 	}
    201 
    202 	void init (void)
    203 	{
    204 		StructType& typeS = m_interface.allocStruct("S");
    205 		typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH));
    206 		typeS.addMember("b", VarType(VarType(glu::TYPE_INT_VEC2, PRECISION_MEDIUM), 4));
    207 		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH), UNUSED_BOTH);
    208 
    209 		StructType& typeT = m_interface.allocStruct("T");
    210 		typeT.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM));
    211 		typeT.addMember("b", VarType(VarType(&typeS), 3));
    212 
    213 		UniformBlock& block = m_interface.allocBlock("Block");
    214 		block.addUniform(Uniform("s", VarType(&typeS), 0));
    215 		block.addUniform(Uniform("v", VarType(glu::TYPE_FLOAT_VEC2, PRECISION_LOW), UNUSED_BOTH));
    216 		block.addUniform(Uniform("t", VarType(VarType(&typeT), 2), 0));
    217 		block.addUniform(Uniform("u", VarType(glu::TYPE_UINT, PRECISION_HIGH), 0));
    218 		block.setFlags(m_layoutFlags);
    219 
    220 		if (m_numInstances > 0)
    221 		{
    222 			block.setInstanceName("block");
    223 			block.setArraySize(m_numInstances);
    224 		}
    225 	}
    226 
    227 private:
    228 	deUint32	m_layoutFlags;
    229 	int			m_numInstances;
    230 };
    231 
    232 class BlockMultiBasicTypesCase : public UniformBlockCase
    233 {
    234 public:
    235 	BlockMultiBasicTypesCase (Context& context, const char* name, const char* description, deUint32 flagsA, deUint32 flagsB, BufferMode bufferMode, int numInstances)
    236 		: UniformBlockCase	(context.getTestContext(), context.getRenderContext(), name, description, glu::GLSL_VERSION_300_ES, bufferMode)
    237 		, m_flagsA			(flagsA)
    238 		, m_flagsB			(flagsB)
    239 		, m_numInstances	(numInstances)
    240 	{
    241 	}
    242 
    243 	void init (void)
    244 	{
    245 		UniformBlock& blockA = m_interface.allocBlock("BlockA");
    246 		blockA.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT, PRECISION_HIGH)));
    247 		blockA.addUniform(Uniform("b", VarType(glu::TYPE_UINT_VEC3, PRECISION_LOW), UNUSED_BOTH));
    248 		blockA.addUniform(Uniform("c", VarType(glu::TYPE_FLOAT_MAT2, PRECISION_MEDIUM)));
    249 		blockA.setInstanceName("blockA");
    250 		blockA.setFlags(m_flagsA);
    251 
    252 		UniformBlock& blockB = m_interface.allocBlock("BlockB");
    253 		blockB.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM)));
    254 		blockB.addUniform(Uniform("b", VarType(glu::TYPE_INT_VEC2, PRECISION_LOW)));
    255 		blockB.addUniform(Uniform("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH), UNUSED_BOTH));
    256 		blockB.addUniform(Uniform("d", VarType(glu::TYPE_BOOL, 0)));
    257 		blockB.setInstanceName("blockB");
    258 		blockB.setFlags(m_flagsB);
    259 
    260 		if (m_numInstances > 0)
    261 		{
    262 			blockA.setArraySize(m_numInstances);
    263 			blockB.setArraySize(m_numInstances);
    264 		}
    265 	}
    266 
    267 private:
    268 	deUint32	m_flagsA;
    269 	deUint32	m_flagsB;
    270 	int			m_numInstances;
    271 };
    272 
    273 class BlockMultiNestedStructCase : public UniformBlockCase
    274 {
    275 public:
    276 	BlockMultiNestedStructCase (Context& context, const char* name, const char* description, deUint32 flagsA, deUint32 flagsB, BufferMode bufferMode, int numInstances)
    277 		: UniformBlockCase	(context.getTestContext(), context.getRenderContext(), name, description, glu::GLSL_VERSION_300_ES, bufferMode)
    278 		, m_flagsA			(flagsA)
    279 		, m_flagsB			(flagsB)
    280 		, m_numInstances	(numInstances)
    281 	{
    282 	}
    283 
    284 	void init (void)
    285 	{
    286 		StructType& typeS = m_interface.allocStruct("S");
    287 		typeS.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_LOW));
    288 		typeS.addMember("b", VarType(VarType(glu::TYPE_INT_VEC2, PRECISION_MEDIUM), 4));
    289 		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH));
    290 
    291 		StructType& typeT = m_interface.allocStruct("T");
    292 		typeT.addMember("a", VarType(glu::TYPE_UINT, PRECISION_MEDIUM), UNUSED_BOTH);
    293 		typeT.addMember("b", VarType(&typeS));
    294 		typeT.addMember("c", VarType(glu::TYPE_BOOL_VEC4, 0));
    295 
    296 		UniformBlock& blockA = m_interface.allocBlock("BlockA");
    297 		blockA.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT, PRECISION_HIGH)));
    298 		blockA.addUniform(Uniform("b", VarType(&typeS)));
    299 		blockA.addUniform(Uniform("c", VarType(glu::TYPE_UINT_VEC3, PRECISION_LOW), UNUSED_BOTH));
    300 		blockA.setInstanceName("blockA");
    301 		blockA.setFlags(m_flagsA);
    302 
    303 		UniformBlock& blockB = m_interface.allocBlock("BlockB");
    304 		blockB.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT_MAT2, PRECISION_MEDIUM)));
    305 		blockB.addUniform(Uniform("b", VarType(&typeT)));
    306 		blockB.addUniform(Uniform("c", VarType(glu::TYPE_BOOL_VEC4, 0), UNUSED_BOTH));
    307 		blockB.addUniform(Uniform("d", VarType(glu::TYPE_BOOL, 0)));
    308 		blockB.setInstanceName("blockB");
    309 		blockB.setFlags(m_flagsB);
    310 
    311 		if (m_numInstances > 0)
    312 		{
    313 			blockA.setArraySize(m_numInstances);
    314 			blockB.setArraySize(m_numInstances);
    315 		}
    316 	}
    317 
    318 private:
    319 	deUint32	m_flagsA;
    320 	deUint32	m_flagsB;
    321 	int			m_numInstances;
    322 };
    323 
    324 UniformBlockTests::UniformBlockTests (Context& context)
    325 	: TestCaseGroup(context, "ubo", "Uniform Block tests")
    326 {
    327 }
    328 
    329 UniformBlockTests::~UniformBlockTests (void)
    330 {
    331 }
    332 
    333 void UniformBlockTests::init (void)
    334 {
    335 	static const glu::DataType basicTypes[] =
    336 	{
    337 		glu::TYPE_FLOAT,
    338 		glu::TYPE_FLOAT_VEC2,
    339 		glu::TYPE_FLOAT_VEC3,
    340 		glu::TYPE_FLOAT_VEC4,
    341 		glu::TYPE_INT,
    342 		glu::TYPE_INT_VEC2,
    343 		glu::TYPE_INT_VEC3,
    344 		glu::TYPE_INT_VEC4,
    345 		glu::TYPE_UINT,
    346 		glu::TYPE_UINT_VEC2,
    347 		glu::TYPE_UINT_VEC3,
    348 		glu::TYPE_UINT_VEC4,
    349 		glu::TYPE_BOOL,
    350 		glu::TYPE_BOOL_VEC2,
    351 		glu::TYPE_BOOL_VEC3,
    352 		glu::TYPE_BOOL_VEC4,
    353 		glu::TYPE_FLOAT_MAT2,
    354 		glu::TYPE_FLOAT_MAT3,
    355 		glu::TYPE_FLOAT_MAT4,
    356 		glu::TYPE_FLOAT_MAT2X3,
    357 		glu::TYPE_FLOAT_MAT2X4,
    358 		glu::TYPE_FLOAT_MAT3X2,
    359 		glu::TYPE_FLOAT_MAT3X4,
    360 		glu::TYPE_FLOAT_MAT4X2,
    361 		glu::TYPE_FLOAT_MAT4X3
    362 	};
    363 
    364 	static const struct
    365 	{
    366 		const char*		name;
    367 		deUint32		flags;
    368 	} precisionFlags[] =
    369 	{
    370 		{ "lowp",		PRECISION_LOW		},
    371 		{ "mediump",	PRECISION_MEDIUM	},
    372 		{ "highp",		PRECISION_HIGH		}
    373 	};
    374 
    375 	static const struct
    376 	{
    377 		const char*		name;
    378 		deUint32		flags;
    379 	} layoutFlags[] =
    380 	{
    381 		{ "shared",		LAYOUT_SHARED	},
    382 		{ "packed",		LAYOUT_PACKED	},
    383 		{ "std140",		LAYOUT_STD140	}
    384 	};
    385 
    386 	static const struct
    387 	{
    388 		const char*		name;
    389 		deUint32		flags;
    390 	} matrixFlags[] =
    391 	{
    392 		{ "row_major",		LAYOUT_ROW_MAJOR	},
    393 		{ "column_major",	LAYOUT_COLUMN_MAJOR }
    394 	};
    395 
    396 	static const struct
    397 	{
    398 		const char*							name;
    399 		UniformBlockCase::BufferMode		mode;
    400 	} bufferModes[] =
    401 	{
    402 		{ "per_block_buffer",	UniformBlockCase::BUFFERMODE_PER_BLOCK },
    403 		{ "single_buffer",		UniformBlockCase::BUFFERMODE_SINGLE	}
    404 	};
    405 
    406 	// ubo.single_basic_type
    407 	{
    408 		tcu::TestCaseGroup* singleBasicTypeGroup = new tcu::TestCaseGroup(m_testCtx, "single_basic_type", "Single basic variable in single buffer");
    409 		addChild(singleBasicTypeGroup);
    410 
    411 		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
    412 		{
    413 			tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
    414 			singleBasicTypeGroup->addChild(layoutGroup);
    415 
    416 			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
    417 			{
    418 				glu::DataType	type		= basicTypes[basicTypeNdx];
    419 				const char*		typeName	= glu::getDataTypeName(type);
    420 
    421 				if (glu::isDataTypeBoolOrBVec(type))
    422 					createBlockBasicTypeCases(layoutGroup, m_context, typeName, VarType(type, 0), layoutFlags[layoutFlagNdx].flags);
    423 				else
    424 				{
    425 					for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisionFlags); precNdx++)
    426 						createBlockBasicTypeCases(layoutGroup, m_context, (string(precisionFlags[precNdx].name) + "_" + typeName).c_str(),
    427 												  VarType(type, precisionFlags[precNdx].flags), layoutFlags[layoutFlagNdx].flags);
    428 				}
    429 
    430 				if (glu::isDataTypeMatrix(type))
    431 				{
    432 					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
    433 					{
    434 						for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisionFlags); precNdx++)
    435 							createBlockBasicTypeCases(layoutGroup, m_context, (string(matrixFlags[matFlagNdx].name) + "_" + precisionFlags[precNdx].name + "_" + typeName).c_str(),
    436 													  VarType(type, precisionFlags[precNdx].flags), layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags);
    437 					}
    438 				}
    439 			}
    440 		}
    441 	}
    442 
    443 	// ubo.single_basic_array
    444 	{
    445 		tcu::TestCaseGroup* singleBasicArrayGroup = new tcu::TestCaseGroup(m_testCtx, "single_basic_array", "Single basic array variable in single buffer");
    446 		addChild(singleBasicArrayGroup);
    447 
    448 		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
    449 		{
    450 			tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
    451 			singleBasicArrayGroup->addChild(layoutGroup);
    452 
    453 			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
    454 			{
    455 				glu::DataType	type		= basicTypes[basicTypeNdx];
    456 				const char*		typeName	= glu::getDataTypeName(type);
    457 				const int		arraySize	= 3;
    458 
    459 				createBlockBasicTypeCases(layoutGroup, m_context, typeName,
    460 										  VarType(VarType(type, glu::isDataTypeBoolOrBVec(type) ? 0 : PRECISION_HIGH), arraySize),
    461 										  layoutFlags[layoutFlagNdx].flags);
    462 
    463 				if (glu::isDataTypeMatrix(type))
    464 				{
    465 					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
    466 						createBlockBasicTypeCases(layoutGroup, m_context, (string(matrixFlags[matFlagNdx].name) + "_" + typeName).c_str(),
    467 												  VarType(VarType(type, PRECISION_HIGH), arraySize),
    468 												  layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags);
    469 				}
    470 			}
    471 		}
    472 	}
    473 
    474 	// ubo.single_struct
    475 	{
    476 		tcu::TestCaseGroup* singleStructGroup = new tcu::TestCaseGroup(m_testCtx, "single_struct", "Single struct in uniform block");
    477 		addChild(singleStructGroup);
    478 
    479 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
    480 		{
    481 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
    482 			singleStructGroup->addChild(modeGroup);
    483 
    484 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
    485 			{
    486 				for (int isArray = 0; isArray < 2; isArray++)
    487 				{
    488 					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
    489 					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
    490 
    491 					if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
    492 						continue; // Doesn't make sense to add this variant.
    493 
    494 					if (isArray)
    495 						baseName += "_instance_array";
    496 
    497 					modeGroup->addChild(new BlockSingleStructCase(m_context, (baseName + "_vertex").c_str(),	"", baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0));
    498 					modeGroup->addChild(new BlockSingleStructCase(m_context, (baseName + "_fragment").c_str(),	"", baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0));
    499 
    500 					if (!(baseFlags & LAYOUT_PACKED))
    501 						modeGroup->addChild(new BlockSingleStructCase(m_context, (baseName + "_both").c_str(),		"", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0));
    502 				}
    503 			}
    504 		}
    505 	}
    506 
    507 	// ubo.single_struct_array
    508 	{
    509 		tcu::TestCaseGroup* singleStructArrayGroup = new tcu::TestCaseGroup(m_testCtx, "single_struct_array", "Struct array in one uniform block");
    510 		addChild(singleStructArrayGroup);
    511 
    512 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
    513 		{
    514 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
    515 			singleStructArrayGroup->addChild(modeGroup);
    516 
    517 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
    518 			{
    519 				for (int isArray = 0; isArray < 2; isArray++)
    520 				{
    521 					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
    522 					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
    523 
    524 					if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
    525 						continue; // Doesn't make sense to add this variant.
    526 
    527 					if (isArray)
    528 						baseName += "_instance_array";
    529 
    530 					modeGroup->addChild(new BlockSingleStructArrayCase(m_context, (baseName + "_vertex").c_str(),	"", baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0));
    531 					modeGroup->addChild(new BlockSingleStructArrayCase(m_context, (baseName + "_fragment").c_str(),	"", baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0));
    532 
    533 					if (!(baseFlags & LAYOUT_PACKED))
    534 						modeGroup->addChild(new BlockSingleStructArrayCase(m_context, (baseName + "_both").c_str(),		"", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0));
    535 				}
    536 			}
    537 		}
    538 	}
    539 
    540 	// ubo.single_nested_struct
    541 	{
    542 		tcu::TestCaseGroup* singleNestedStructGroup = new tcu::TestCaseGroup(m_testCtx, "single_nested_struct", "Nested struct in one uniform block");
    543 		addChild(singleNestedStructGroup);
    544 
    545 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
    546 		{
    547 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
    548 			singleNestedStructGroup->addChild(modeGroup);
    549 
    550 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
    551 			{
    552 				for (int isArray = 0; isArray < 2; isArray++)
    553 				{
    554 					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
    555 					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
    556 
    557 					if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
    558 						continue; // Doesn't make sense to add this variant.
    559 
    560 					if (isArray)
    561 						baseName += "_instance_array";
    562 
    563 					modeGroup->addChild(new BlockSingleNestedStructCase(m_context, (baseName + "_vertex").c_str(),		"", baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0));
    564 					modeGroup->addChild(new BlockSingleNestedStructCase(m_context, (baseName + "_fragment").c_str(),	"", baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0));
    565 
    566 					if (!(baseFlags & LAYOUT_PACKED))
    567 						modeGroup->addChild(new BlockSingleNestedStructCase(m_context, (baseName + "_both").c_str(),		"", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0));
    568 				}
    569 			}
    570 		}
    571 	}
    572 
    573 	// ubo.single_nested_struct_array
    574 	{
    575 		tcu::TestCaseGroup* singleNestedStructArrayGroup = new tcu::TestCaseGroup(m_testCtx, "single_nested_struct_array", "Nested struct array in one uniform block");
    576 		addChild(singleNestedStructArrayGroup);
    577 
    578 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
    579 		{
    580 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
    581 			singleNestedStructArrayGroup->addChild(modeGroup);
    582 
    583 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
    584 			{
    585 				for (int isArray = 0; isArray < 2; isArray++)
    586 				{
    587 					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
    588 					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
    589 
    590 					if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
    591 						continue; // Doesn't make sense to add this variant.
    592 
    593 					if (isArray)
    594 						baseName += "_instance_array";
    595 
    596 					modeGroup->addChild(new BlockSingleNestedStructArrayCase(m_context, (baseName + "_vertex").c_str(),		"", baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0));
    597 					modeGroup->addChild(new BlockSingleNestedStructArrayCase(m_context, (baseName + "_fragment").c_str(),	"", baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0));
    598 
    599 					if (!(baseFlags & LAYOUT_PACKED))
    600 						modeGroup->addChild(new BlockSingleNestedStructArrayCase(m_context, (baseName + "_both").c_str(),		"", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0));
    601 				}
    602 			}
    603 		}
    604 	}
    605 
    606 	// ubo.instance_array_basic_type
    607 	{
    608 		tcu::TestCaseGroup* instanceArrayBasicTypeGroup = new tcu::TestCaseGroup(m_testCtx, "instance_array_basic_type", "Single basic variable in instance array");
    609 		addChild(instanceArrayBasicTypeGroup);
    610 
    611 		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
    612 		{
    613 			tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
    614 			instanceArrayBasicTypeGroup->addChild(layoutGroup);
    615 
    616 			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
    617 			{
    618 				glu::DataType	type			= basicTypes[basicTypeNdx];
    619 				const char*		typeName		= glu::getDataTypeName(type);
    620 				const int		numInstances	= 3;
    621 
    622 				createBlockBasicTypeCases(layoutGroup, m_context, typeName,
    623 										  VarType(type, glu::isDataTypeBoolOrBVec(type) ? 0 : PRECISION_HIGH),
    624 										  layoutFlags[layoutFlagNdx].flags, numInstances);
    625 
    626 				if (glu::isDataTypeMatrix(type))
    627 				{
    628 					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
    629 						createBlockBasicTypeCases(layoutGroup, m_context, (string(matrixFlags[matFlagNdx].name) + "_" + typeName).c_str(),
    630 												  VarType(type, PRECISION_HIGH), layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags,
    631 												  numInstances);
    632 				}
    633 			}
    634 		}
    635 	}
    636 
    637 	// ubo.multi_basic_types
    638 	{
    639 		tcu::TestCaseGroup* multiBasicTypesGroup = new tcu::TestCaseGroup(m_testCtx, "multi_basic_types", "Multiple buffers with basic types");
    640 		addChild(multiBasicTypesGroup);
    641 
    642 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
    643 		{
    644 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
    645 			multiBasicTypesGroup->addChild(modeGroup);
    646 
    647 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
    648 			{
    649 				for (int isArray = 0; isArray < 2; isArray++)
    650 				{
    651 					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
    652 					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
    653 
    654 					if (isArray)
    655 						baseName += "_instance_array";
    656 
    657 					modeGroup->addChild(new BlockMultiBasicTypesCase(m_context, (baseName + "_vertex").c_str(),		"", baseFlags|DECLARE_VERTEX,					baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0));
    658 					modeGroup->addChild(new BlockMultiBasicTypesCase(m_context, (baseName + "_fragment").c_str(),	"", baseFlags|DECLARE_FRAGMENT,					baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0));
    659 
    660 					if (!(baseFlags & LAYOUT_PACKED))
    661 						modeGroup->addChild(new BlockMultiBasicTypesCase(m_context, (baseName + "_both").c_str(),		"", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0));
    662 
    663 					modeGroup->addChild(new BlockMultiBasicTypesCase(m_context, (baseName + "_mixed").c_str(),		"", baseFlags|DECLARE_VERTEX,					baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0));
    664 				}
    665 			}
    666 		}
    667 	}
    668 
    669 	// ubo.multi_nested_struct
    670 	{
    671 		tcu::TestCaseGroup* multiNestedStructGroup = new tcu::TestCaseGroup(m_testCtx, "multi_nested_struct", "Multiple buffers with nested structs");
    672 		addChild(multiNestedStructGroup);
    673 
    674 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
    675 		{
    676 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
    677 			multiNestedStructGroup->addChild(modeGroup);
    678 
    679 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
    680 			{
    681 				for (int isArray = 0; isArray < 2; isArray++)
    682 				{
    683 					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
    684 					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
    685 
    686 					if (isArray)
    687 						baseName += "_instance_array";
    688 
    689 					modeGroup->addChild(new BlockMultiNestedStructCase(m_context, (baseName + "_vertex").c_str(),	"", baseFlags|DECLARE_VERTEX,					baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0));
    690 					modeGroup->addChild(new BlockMultiNestedStructCase(m_context, (baseName + "_fragment").c_str(),	"", baseFlags|DECLARE_FRAGMENT,					baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0));
    691 
    692 					if (!(baseFlags & LAYOUT_PACKED))
    693 						modeGroup->addChild(new BlockMultiNestedStructCase(m_context, (baseName + "_both").c_str(),		"", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0));
    694 
    695 					modeGroup->addChild(new BlockMultiNestedStructCase(m_context, (baseName + "_mixed").c_str(),	"", baseFlags|DECLARE_VERTEX,					baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0));
    696 				}
    697 			}
    698 		}
    699 	}
    700 
    701 	// ubo.random
    702 	{
    703 		const deUint32	allShaders		= FEATURE_VERTEX_BLOCKS|FEATURE_FRAGMENT_BLOCKS|FEATURE_SHARED_BLOCKS;
    704 		const deUint32	allLayouts		= FEATURE_PACKED_LAYOUT|FEATURE_SHARED_LAYOUT|FEATURE_STD140_LAYOUT;
    705 		const deUint32	allBasicTypes	= FEATURE_VECTORS|FEATURE_MATRICES;
    706 		const deUint32	unused			= FEATURE_UNUSED_MEMBERS|FEATURE_UNUSED_UNIFORMS;
    707 		const deUint32	matFlags		= FEATURE_MATRIX_LAYOUT;
    708 		const deUint32	allFeatures		= ~FEATURE_ARRAYS_OF_ARRAYS;
    709 
    710 		tcu::TestCaseGroup* randomGroup = new tcu::TestCaseGroup(m_testCtx, "random", "Random Uniform Block cases");
    711 		addChild(randomGroup);
    712 
    713 		// Basic types.
    714 		createRandomCaseGroup(randomGroup, m_context, "scalar_types",	"Scalar types only, per-block buffers",				UniformBlockCase::BUFFERMODE_PER_BLOCK,	allShaders|allLayouts|unused,										25, 0);
    715 		createRandomCaseGroup(randomGroup, m_context, "vector_types",	"Scalar and vector types only, per-block buffers",	UniformBlockCase::BUFFERMODE_PER_BLOCK,	allShaders|allLayouts|unused|FEATURE_VECTORS,						25, 25);
    716 		createRandomCaseGroup(randomGroup, m_context, "basic_types",	"All basic types, per-block buffers",				UniformBlockCase::BUFFERMODE_PER_BLOCK, allShaders|allLayouts|unused|allBasicTypes|matFlags,				25, 50);
    717 		createRandomCaseGroup(randomGroup, m_context, "basic_arrays",	"Arrays, per-block buffers",						UniformBlockCase::BUFFERMODE_PER_BLOCK,	allShaders|allLayouts|unused|allBasicTypes|matFlags|FEATURE_ARRAYS,	25, 50);
    718 
    719 		createRandomCaseGroup(randomGroup, m_context, "basic_instance_arrays",					"Basic instance arrays, per-block buffers",				UniformBlockCase::BUFFERMODE_PER_BLOCK,	allShaders|allLayouts|unused|allBasicTypes|matFlags|FEATURE_INSTANCE_ARRAYS,								25, 75);
    720 		createRandomCaseGroup(randomGroup, m_context, "nested_structs",							"Nested structs, per-block buffers",					UniformBlockCase::BUFFERMODE_PER_BLOCK,	allShaders|allLayouts|unused|allBasicTypes|matFlags|FEATURE_STRUCTS,										25, 100);
    721 		createRandomCaseGroup(randomGroup, m_context, "nested_structs_arrays",					"Nested structs, arrays, per-block buffers",			UniformBlockCase::BUFFERMODE_PER_BLOCK,	allShaders|allLayouts|unused|allBasicTypes|matFlags|FEATURE_STRUCTS|FEATURE_ARRAYS,							25, 150);
    722 		createRandomCaseGroup(randomGroup, m_context, "nested_structs_instance_arrays",			"Nested structs, instance arrays, per-block buffers",	UniformBlockCase::BUFFERMODE_PER_BLOCK,	allShaders|allLayouts|unused|allBasicTypes|matFlags|FEATURE_STRUCTS|FEATURE_INSTANCE_ARRAYS,				25, 125);
    723 		createRandomCaseGroup(randomGroup, m_context, "nested_structs_arrays_instance_arrays",	"Nested structs, instance arrays, per-block buffers",	UniformBlockCase::BUFFERMODE_PER_BLOCK,	allShaders|allLayouts|unused|allBasicTypes|matFlags|FEATURE_STRUCTS|FEATURE_ARRAYS|FEATURE_INSTANCE_ARRAYS,	25, 175);
    724 
    725 		createRandomCaseGroup(randomGroup, m_context, "all_per_block_buffers",	"All random features, per-block buffers",	UniformBlockCase::BUFFERMODE_PER_BLOCK,	allFeatures,	50, 200);
    726 		createRandomCaseGroup(randomGroup, m_context, "all_shared_buffer",		"All random features, shared buffer",		UniformBlockCase::BUFFERMODE_SINGLE,	allFeatures,	50, 250);
    727 	}
    728 }
    729 
    730 } // Functional
    731 } // gles3
    732 } // deqp
    733