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
31using std::string;
32using std::vector;
33
34namespace deqp
35{
36namespace gles3
37{
38namespace Functional
39{
40
41using gls::UniformBlockCase;
42using gls::RandomUniformBlockCase;
43using namespace gls::ub;
44
45static 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
57class BlockBasicTypeCase : public UniformBlockCase
58{
59public:
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
75static 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
84class BlockSingleStructCase : public UniformBlockCase
85{
86public:
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
112private:
113	deUint32	m_layoutFlags;
114	int			m_numInstances;
115};
116
117class BlockSingleStructArrayCase : public UniformBlockCase
118{
119public:
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
147private:
148	deUint32	m_layoutFlags;
149	int			m_numInstances;
150};
151
152class BlockSingleNestedStructCase : public UniformBlockCase
153{
154public:
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
187private:
188	deUint32	m_layoutFlags;
189	int			m_numInstances;
190};
191
192class BlockSingleNestedStructArrayCase : public UniformBlockCase
193{
194public:
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
227private:
228	deUint32	m_layoutFlags;
229	int			m_numInstances;
230};
231
232class BlockMultiBasicTypesCase : public UniformBlockCase
233{
234public:
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
267private:
268	deUint32	m_flagsA;
269	deUint32	m_flagsB;
270	int			m_numInstances;
271};
272
273class BlockMultiNestedStructCase : public UniformBlockCase
274{
275public:
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
318private:
319	deUint32	m_flagsA;
320	deUint32	m_flagsB;
321	int			m_numInstances;
322};
323
324UniformBlockTests::UniformBlockTests (Context& context)
325	: TestCaseGroup(context, "ubo", "Uniform Block tests")
326{
327}
328
329UniformBlockTests::~UniformBlockTests (void)
330{
331}
332
333void 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