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 
createRandomCaseGroup(tcu::TestCaseGroup * parentGroup,Context & context,const char * groupName,const char * description,UniformBlockCase::BufferMode bufferMode,deUint32 features,int numCases,deUint32 baseSeed)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:
BlockBasicTypeCase(Context & context,const char * name,const char * description,const VarType & type,deUint32 layoutFlags,int numInstances)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 
createBlockBasicTypeCases(tcu::TestCaseGroup * group,Context & context,const char * name,const VarType & type,deUint32 layoutFlags,int numInstances=0)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:
BlockSingleStructCase(Context & context,const char * name,const char * description,deUint32 layoutFlags,BufferMode bufferMode,int numInstances)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 
init(void)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:
BlockSingleStructArrayCase(Context & context,const char * name,const char * description,deUint32 layoutFlags,BufferMode bufferMode,int numInstances)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 
init(void)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:
BlockSingleNestedStructCase(Context & context,const char * name,const char * description,deUint32 layoutFlags,BufferMode bufferMode,int numInstances)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 
init(void)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:
BlockSingleNestedStructArrayCase(Context & context,const char * name,const char * description,deUint32 layoutFlags,BufferMode bufferMode,int numInstances)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 
init(void)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:
BlockMultiBasicTypesCase(Context & context,const char * name,const char * description,deUint32 flagsA,deUint32 flagsB,BufferMode bufferMode,int numInstances)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 
init(void)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:
BlockMultiNestedStructCase(Context & context,const char * name,const char * description,deUint32 flagsA,deUint32 flagsB,BufferMode bufferMode,int numInstances)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 
init(void)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 
UniformBlockTests(Context & context)324 UniformBlockTests::UniformBlockTests (Context& context)
325 	: TestCaseGroup(context, "ubo", "Uniform Block tests")
326 {
327 }
328 
~UniformBlockTests(void)329 UniformBlockTests::~UniformBlockTests (void)
330 {
331 }
332 
init(void)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