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 BlockSingleNestedStructMixedMatrixPackingCase : public UniformBlockCase
193{
194public:
195	BlockSingleNestedStructMixedMatrixPackingCase (Context& context, const char* name, const char* description, deUint32 blockLayoutFlags, deUint32 matrixLayoutFlags, deUint32 matrixArrayLayoutFlags, BufferMode bufferMode, int numInstances)
196			: UniformBlockCase			(context.getTestContext(), context.getRenderContext(), name, description, glu::GLSL_VERSION_300_ES, bufferMode)
197			, m_blockLayoutFlags		(blockLayoutFlags)
198			, m_matrixLayoutFlags		(matrixLayoutFlags)
199			, m_matrixArrayLayoutFlags	(matrixArrayLayoutFlags)
200			, m_numInstances			(numInstances)
201	{
202	}
203
204	void init (void)
205	{
206		StructType& typeS = m_interface.allocStruct("S");
207		typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH));
208		typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM), 4));
209		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH), UNUSED_BOTH);
210
211		StructType& typeT = m_interface.allocStruct("T");
212		typeT.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM));
213		typeT.addMember("b", VarType(&typeS));
214
215		UniformBlock& block = m_interface.allocBlock("Block");
216		block.addUniform(Uniform("s", VarType(&typeS, m_matrixArrayLayoutFlags), 0));
217		block.addUniform(Uniform("v", VarType(glu::TYPE_FLOAT_VEC2, PRECISION_LOW), UNUSED_BOTH));
218		block.addUniform(Uniform("t", VarType(&typeT, m_matrixLayoutFlags), 0));
219		block.addUniform(Uniform("u", VarType(glu::TYPE_UINT, PRECISION_HIGH), 0));
220		block.setFlags(m_blockLayoutFlags);
221
222		if (m_numInstances > 0)
223		{
224			block.setInstanceName("block");
225			block.setArraySize(m_numInstances);
226		}
227	}
228
229private:
230	deUint32	m_blockLayoutFlags;
231	deUint32	m_matrixLayoutFlags;
232	deUint32	m_matrixArrayLayoutFlags;
233	int			m_numInstances;
234};
235
236class BlockSingleNestedStructArrayCase : public UniformBlockCase
237{
238public:
239	BlockSingleNestedStructArrayCase (Context& context, const char* name, const char* description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances)
240		: UniformBlockCase	(context.getTestContext(), context.getRenderContext(), name, description, glu::GLSL_VERSION_300_ES, bufferMode)
241		, m_layoutFlags		(layoutFlags)
242		, m_numInstances	(numInstances)
243	{
244	}
245
246	void init (void)
247	{
248		StructType& typeS = m_interface.allocStruct("S");
249		typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH));
250		typeS.addMember("b", VarType(VarType(glu::TYPE_INT_VEC2, PRECISION_MEDIUM), 4));
251		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH), UNUSED_BOTH);
252
253		StructType& typeT = m_interface.allocStruct("T");
254		typeT.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM));
255		typeT.addMember("b", VarType(VarType(&typeS), 3));
256
257		UniformBlock& block = m_interface.allocBlock("Block");
258		block.addUniform(Uniform("s", VarType(&typeS), 0));
259		block.addUniform(Uniform("v", VarType(glu::TYPE_FLOAT_VEC2, PRECISION_LOW), UNUSED_BOTH));
260		block.addUniform(Uniform("t", VarType(VarType(&typeT), 2), 0));
261		block.addUniform(Uniform("u", VarType(glu::TYPE_UINT, PRECISION_HIGH), 0));
262		block.setFlags(m_layoutFlags);
263
264		if (m_numInstances > 0)
265		{
266			block.setInstanceName("block");
267			block.setArraySize(m_numInstances);
268		}
269	}
270
271private:
272	deUint32	m_layoutFlags;
273	int			m_numInstances;
274};
275
276class BlockMultiBasicTypesCase : public UniformBlockCase
277{
278public:
279	BlockMultiBasicTypesCase (Context& context, const char* name, const char* description, deUint32 flagsA, deUint32 flagsB, BufferMode bufferMode, int numInstances)
280		: UniformBlockCase	(context.getTestContext(), context.getRenderContext(), name, description, glu::GLSL_VERSION_300_ES, bufferMode)
281		, m_flagsA			(flagsA)
282		, m_flagsB			(flagsB)
283		, m_numInstances	(numInstances)
284	{
285	}
286
287	void init (void)
288	{
289		UniformBlock& blockA = m_interface.allocBlock("BlockA");
290		blockA.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT, PRECISION_HIGH)));
291		blockA.addUniform(Uniform("b", VarType(glu::TYPE_UINT_VEC3, PRECISION_LOW), UNUSED_BOTH));
292		blockA.addUniform(Uniform("c", VarType(glu::TYPE_FLOAT_MAT2, PRECISION_MEDIUM)));
293		blockA.setInstanceName("blockA");
294		blockA.setFlags(m_flagsA);
295
296		UniformBlock& blockB = m_interface.allocBlock("BlockB");
297		blockB.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM)));
298		blockB.addUniform(Uniform("b", VarType(glu::TYPE_INT_VEC2, PRECISION_LOW)));
299		blockB.addUniform(Uniform("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH), UNUSED_BOTH));
300		blockB.addUniform(Uniform("d", VarType(glu::TYPE_BOOL, 0)));
301		blockB.setInstanceName("blockB");
302		blockB.setFlags(m_flagsB);
303
304		if (m_numInstances > 0)
305		{
306			blockA.setArraySize(m_numInstances);
307			blockB.setArraySize(m_numInstances);
308		}
309	}
310
311private:
312	deUint32	m_flagsA;
313	deUint32	m_flagsB;
314	int			m_numInstances;
315};
316
317class BlockMultiNestedStructCase : public UniformBlockCase
318{
319public:
320	BlockMultiNestedStructCase (Context& context, const char* name, const char* description, deUint32 flagsA, deUint32 flagsB, BufferMode bufferMode, int numInstances)
321		: UniformBlockCase	(context.getTestContext(), context.getRenderContext(), name, description, glu::GLSL_VERSION_300_ES, bufferMode)
322		, m_flagsA			(flagsA)
323		, m_flagsB			(flagsB)
324		, m_numInstances	(numInstances)
325	{
326	}
327
328	void init (void)
329	{
330		StructType& typeS = m_interface.allocStruct("S");
331		typeS.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_LOW));
332		typeS.addMember("b", VarType(VarType(glu::TYPE_INT_VEC2, PRECISION_MEDIUM), 4));
333		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH));
334
335		StructType& typeT = m_interface.allocStruct("T");
336		typeT.addMember("a", VarType(glu::TYPE_UINT, PRECISION_MEDIUM), UNUSED_BOTH);
337		typeT.addMember("b", VarType(&typeS));
338		typeT.addMember("c", VarType(glu::TYPE_BOOL_VEC4, 0));
339
340		UniformBlock& blockA = m_interface.allocBlock("BlockA");
341		blockA.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT, PRECISION_HIGH)));
342		blockA.addUniform(Uniform("b", VarType(&typeS)));
343		blockA.addUniform(Uniform("c", VarType(glu::TYPE_UINT_VEC3, PRECISION_LOW), UNUSED_BOTH));
344		blockA.setInstanceName("blockA");
345		blockA.setFlags(m_flagsA);
346
347		UniformBlock& blockB = m_interface.allocBlock("BlockB");
348		blockB.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT_MAT2, PRECISION_MEDIUM)));
349		blockB.addUniform(Uniform("b", VarType(&typeT)));
350		blockB.addUniform(Uniform("c", VarType(glu::TYPE_BOOL_VEC4, 0), UNUSED_BOTH));
351		blockB.addUniform(Uniform("d", VarType(glu::TYPE_BOOL, 0)));
352		blockB.setInstanceName("blockB");
353		blockB.setFlags(m_flagsB);
354
355		if (m_numInstances > 0)
356		{
357			blockA.setArraySize(m_numInstances);
358			blockB.setArraySize(m_numInstances);
359		}
360	}
361
362private:
363	deUint32	m_flagsA;
364	deUint32	m_flagsB;
365	int			m_numInstances;
366};
367
368UniformBlockTests::UniformBlockTests (Context& context)
369	: TestCaseGroup(context, "ubo", "Uniform Block tests")
370{
371}
372
373UniformBlockTests::~UniformBlockTests (void)
374{
375}
376
377void UniformBlockTests::init (void)
378{
379	static const glu::DataType basicTypes[] =
380	{
381		glu::TYPE_FLOAT,
382		glu::TYPE_FLOAT_VEC2,
383		glu::TYPE_FLOAT_VEC3,
384		glu::TYPE_FLOAT_VEC4,
385		glu::TYPE_INT,
386		glu::TYPE_INT_VEC2,
387		glu::TYPE_INT_VEC3,
388		glu::TYPE_INT_VEC4,
389		glu::TYPE_UINT,
390		glu::TYPE_UINT_VEC2,
391		glu::TYPE_UINT_VEC3,
392		glu::TYPE_UINT_VEC4,
393		glu::TYPE_BOOL,
394		glu::TYPE_BOOL_VEC2,
395		glu::TYPE_BOOL_VEC3,
396		glu::TYPE_BOOL_VEC4,
397		glu::TYPE_FLOAT_MAT2,
398		glu::TYPE_FLOAT_MAT3,
399		glu::TYPE_FLOAT_MAT4,
400		glu::TYPE_FLOAT_MAT2X3,
401		glu::TYPE_FLOAT_MAT2X4,
402		glu::TYPE_FLOAT_MAT3X2,
403		glu::TYPE_FLOAT_MAT3X4,
404		glu::TYPE_FLOAT_MAT4X2,
405		glu::TYPE_FLOAT_MAT4X3
406	};
407
408	static const struct
409	{
410		const char*		name;
411		deUint32		flags;
412	} precisionFlags[] =
413	{
414		{ "lowp",		PRECISION_LOW		},
415		{ "mediump",	PRECISION_MEDIUM	},
416		{ "highp",		PRECISION_HIGH		}
417	};
418
419	static const struct
420	{
421		const char*		name;
422		deUint32		flags;
423	} layoutFlags[] =
424	{
425		{ "shared",		LAYOUT_SHARED	},
426		{ "packed",		LAYOUT_PACKED	},
427		{ "std140",		LAYOUT_STD140	}
428	};
429
430	static const struct
431	{
432		const char*		name;
433		deUint32		flags;
434	} matrixFlags[] =
435	{
436		{ "row_major",		LAYOUT_ROW_MAJOR	},
437		{ "column_major",	LAYOUT_COLUMN_MAJOR }
438	};
439
440	static const struct
441	{
442		const char*							name;
443		UniformBlockCase::BufferMode		mode;
444	} bufferModes[] =
445	{
446		{ "per_block_buffer",	UniformBlockCase::BUFFERMODE_PER_BLOCK },
447		{ "single_buffer",		UniformBlockCase::BUFFERMODE_SINGLE	}
448	};
449
450	// ubo.single_basic_type
451	{
452		tcu::TestCaseGroup* singleBasicTypeGroup = new tcu::TestCaseGroup(m_testCtx, "single_basic_type", "Single basic variable in single buffer");
453		addChild(singleBasicTypeGroup);
454
455		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
456		{
457			tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
458			singleBasicTypeGroup->addChild(layoutGroup);
459
460			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
461			{
462				glu::DataType	type		= basicTypes[basicTypeNdx];
463				const char*		typeName	= glu::getDataTypeName(type);
464
465				if (glu::isDataTypeBoolOrBVec(type))
466					createBlockBasicTypeCases(layoutGroup, m_context, typeName, VarType(type, 0), layoutFlags[layoutFlagNdx].flags);
467				else
468				{
469					for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisionFlags); precNdx++)
470						createBlockBasicTypeCases(layoutGroup, m_context, (string(precisionFlags[precNdx].name) + "_" + typeName).c_str(),
471												  VarType(type, precisionFlags[precNdx].flags), layoutFlags[layoutFlagNdx].flags);
472				}
473
474				if (glu::isDataTypeMatrix(type))
475				{
476					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
477					{
478						for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisionFlags); precNdx++)
479							createBlockBasicTypeCases(layoutGroup, m_context, (string(matrixFlags[matFlagNdx].name) + "_" + precisionFlags[precNdx].name + "_" + typeName).c_str(),
480													  VarType(type, precisionFlags[precNdx].flags), layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags);
481					}
482				}
483			}
484		}
485	}
486
487	// ubo.single_basic_array
488	{
489		tcu::TestCaseGroup* singleBasicArrayGroup = new tcu::TestCaseGroup(m_testCtx, "single_basic_array", "Single basic array variable in single buffer");
490		addChild(singleBasicArrayGroup);
491
492		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
493		{
494			tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
495			singleBasicArrayGroup->addChild(layoutGroup);
496
497			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
498			{
499				glu::DataType	type		= basicTypes[basicTypeNdx];
500				const char*		typeName	= glu::getDataTypeName(type);
501				const int		arraySize	= 3;
502
503				createBlockBasicTypeCases(layoutGroup, m_context, typeName,
504										  VarType(VarType(type, glu::isDataTypeBoolOrBVec(type) ? 0 : PRECISION_HIGH), arraySize),
505										  layoutFlags[layoutFlagNdx].flags);
506
507				if (glu::isDataTypeMatrix(type))
508				{
509					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
510						createBlockBasicTypeCases(layoutGroup, m_context, (string(matrixFlags[matFlagNdx].name) + "_" + typeName).c_str(),
511												  VarType(VarType(type, PRECISION_HIGH), arraySize),
512												  layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags);
513				}
514			}
515		}
516	}
517
518	// ubo.single_struct
519	{
520		tcu::TestCaseGroup* singleStructGroup = new tcu::TestCaseGroup(m_testCtx, "single_struct", "Single struct in uniform block");
521		addChild(singleStructGroup);
522
523		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
524		{
525			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
526			singleStructGroup->addChild(modeGroup);
527
528			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
529			{
530				for (int isArray = 0; isArray < 2; isArray++)
531				{
532					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
533					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
534
535					if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
536						continue; // Doesn't make sense to add this variant.
537
538					if (isArray)
539						baseName += "_instance_array";
540
541					modeGroup->addChild(new BlockSingleStructCase(m_context, (baseName + "_vertex").c_str(),	"", baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0));
542					modeGroup->addChild(new BlockSingleStructCase(m_context, (baseName + "_fragment").c_str(),	"", baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0));
543
544					if (!(baseFlags & LAYOUT_PACKED))
545						modeGroup->addChild(new BlockSingleStructCase(m_context, (baseName + "_both").c_str(),		"", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0));
546				}
547			}
548		}
549	}
550
551	// ubo.single_struct_array
552	{
553		tcu::TestCaseGroup* singleStructArrayGroup = new tcu::TestCaseGroup(m_testCtx, "single_struct_array", "Struct array in one uniform block");
554		addChild(singleStructArrayGroup);
555
556		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
557		{
558			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
559			singleStructArrayGroup->addChild(modeGroup);
560
561			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
562			{
563				for (int isArray = 0; isArray < 2; isArray++)
564				{
565					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
566					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
567
568					if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
569						continue; // Doesn't make sense to add this variant.
570
571					if (isArray)
572						baseName += "_instance_array";
573
574					modeGroup->addChild(new BlockSingleStructArrayCase(m_context, (baseName + "_vertex").c_str(),	"", baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0));
575					modeGroup->addChild(new BlockSingleStructArrayCase(m_context, (baseName + "_fragment").c_str(),	"", baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0));
576
577					if (!(baseFlags & LAYOUT_PACKED))
578						modeGroup->addChild(new BlockSingleStructArrayCase(m_context, (baseName + "_both").c_str(),		"", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0));
579				}
580			}
581		}
582	}
583
584	// ubo.single_nested_struct
585	{
586		tcu::TestCaseGroup* singleNestedStructGroup = new tcu::TestCaseGroup(m_testCtx, "single_nested_struct", "Nested struct in one uniform block");
587		addChild(singleNestedStructGroup);
588
589		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
590		{
591			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
592			singleNestedStructGroup->addChild(modeGroup);
593
594			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
595			{
596				for (int isArray = 0; isArray < 2; isArray++)
597				{
598					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
599					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
600
601					if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
602						continue; // Doesn't make sense to add this variant.
603
604					if (isArray)
605						baseName += "_instance_array";
606
607					modeGroup->addChild(new BlockSingleNestedStructCase(m_context, (baseName + "_vertex").c_str(),		"", baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0));
608					modeGroup->addChild(new BlockSingleNestedStructCase(m_context, (baseName + "_fragment").c_str(),	"", baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0));
609
610					if (!(baseFlags & LAYOUT_PACKED))
611						modeGroup->addChild(new BlockSingleNestedStructCase(m_context, (baseName + "_both").c_str(),		"", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0));
612				}
613			}
614		}
615	}
616
617	// ubo.single_nested_struct_mixed_matrix_packing
618	{
619		tcu::TestCaseGroup* singleNestedStructMixedMatrixPackingGroup = new tcu::TestCaseGroup(m_testCtx, "single_nested_struct_mixed_matrix_packing", "Nested struct in one uniform block with a mixed matrix packing");
620		addChild(singleNestedStructMixedMatrixPackingGroup);
621
622		for (const auto& bufferMode : bufferModes)
623		{
624			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferMode.name, "");
625			singleNestedStructMixedMatrixPackingGroup->addChild(modeGroup);
626
627			for (const auto& layoutFlag : layoutFlags)
628			for (const auto& blockMatrixFlag : matrixFlags)
629			for (const auto& singleMatrixFlag : matrixFlags)
630			for (const auto& arrayMatrixFlag : matrixFlags)
631			for (int isArray = 0; isArray < 2; isArray++)
632			{
633				std::string	baseName	= layoutFlag.name;
634				deUint32	baseFlags	= layoutFlag.flags;
635				deUint32	blockFlags	= baseFlags | blockMatrixFlag.flags;
636
637				baseName += std::string("_block_") + blockMatrixFlag.name;
638				baseName += std::string("_matrix_") + singleMatrixFlag.name;
639				baseName += std::string("_matrixarray_") + arrayMatrixFlag.name;
640
641				if (bufferMode.mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
642					continue; // Doesn't make sense to add this variant.
643
644				if (isArray)
645					baseName += "_instance_array";
646
647				modeGroup->addChild(new BlockSingleNestedStructMixedMatrixPackingCase(m_context, (baseName + "_vertex").c_str(), "", blockFlags | DECLARE_VERTEX, singleMatrixFlag.flags, arrayMatrixFlag.flags, bufferMode.mode, isArray ? 3 : 0));
648				modeGroup->addChild(new BlockSingleNestedStructMixedMatrixPackingCase(m_context, (baseName + "_fragment").c_str(), "", blockFlags | DECLARE_FRAGMENT, singleMatrixFlag.flags, arrayMatrixFlag.flags, bufferMode.mode, isArray ? 3 : 0));
649
650				if (!(baseFlags & LAYOUT_PACKED))
651					modeGroup->addChild(new BlockSingleNestedStructMixedMatrixPackingCase(m_context, (baseName + "_both").c_str(), "", blockFlags | DECLARE_VERTEX | DECLARE_FRAGMENT, singleMatrixFlag.flags, arrayMatrixFlag.flags, bufferMode.mode, isArray ? 3 : 0));
652			}
653		}
654	}
655
656	// ubo.single_nested_struct_array
657	{
658		tcu::TestCaseGroup* singleNestedStructArrayGroup = new tcu::TestCaseGroup(m_testCtx, "single_nested_struct_array", "Nested struct array in one uniform block");
659		addChild(singleNestedStructArrayGroup);
660
661		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
662		{
663			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
664			singleNestedStructArrayGroup->addChild(modeGroup);
665
666			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
667			{
668				for (int isArray = 0; isArray < 2; isArray++)
669				{
670					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
671					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
672
673					if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
674						continue; // Doesn't make sense to add this variant.
675
676					if (isArray)
677						baseName += "_instance_array";
678
679					modeGroup->addChild(new BlockSingleNestedStructArrayCase(m_context, (baseName + "_vertex").c_str(),		"", baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0));
680					modeGroup->addChild(new BlockSingleNestedStructArrayCase(m_context, (baseName + "_fragment").c_str(),	"", baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0));
681
682					if (!(baseFlags & LAYOUT_PACKED))
683						modeGroup->addChild(new BlockSingleNestedStructArrayCase(m_context, (baseName + "_both").c_str(),		"", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0));
684				}
685			}
686		}
687	}
688
689	// ubo.instance_array_basic_type
690	{
691		tcu::TestCaseGroup* instanceArrayBasicTypeGroup = new tcu::TestCaseGroup(m_testCtx, "instance_array_basic_type", "Single basic variable in instance array");
692		addChild(instanceArrayBasicTypeGroup);
693
694		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
695		{
696			tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
697			instanceArrayBasicTypeGroup->addChild(layoutGroup);
698
699			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
700			{
701				glu::DataType	type			= basicTypes[basicTypeNdx];
702				const char*		typeName		= glu::getDataTypeName(type);
703				const int		numInstances	= 3;
704
705				createBlockBasicTypeCases(layoutGroup, m_context, typeName,
706										  VarType(type, glu::isDataTypeBoolOrBVec(type) ? 0 : PRECISION_HIGH),
707										  layoutFlags[layoutFlagNdx].flags, numInstances);
708
709				if (glu::isDataTypeMatrix(type))
710				{
711					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
712						createBlockBasicTypeCases(layoutGroup, m_context, (string(matrixFlags[matFlagNdx].name) + "_" + typeName).c_str(),
713												  VarType(type, PRECISION_HIGH), layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags,
714												  numInstances);
715				}
716			}
717		}
718	}
719
720	// ubo.multi_basic_types
721	{
722		tcu::TestCaseGroup* multiBasicTypesGroup = new tcu::TestCaseGroup(m_testCtx, "multi_basic_types", "Multiple buffers with basic types");
723		addChild(multiBasicTypesGroup);
724
725		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
726		{
727			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
728			multiBasicTypesGroup->addChild(modeGroup);
729
730			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
731			{
732				for (int isArray = 0; isArray < 2; isArray++)
733				{
734					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
735					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
736
737					if (isArray)
738						baseName += "_instance_array";
739
740					modeGroup->addChild(new BlockMultiBasicTypesCase(m_context, (baseName + "_vertex").c_str(),		"", baseFlags|DECLARE_VERTEX,					baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0));
741					modeGroup->addChild(new BlockMultiBasicTypesCase(m_context, (baseName + "_fragment").c_str(),	"", baseFlags|DECLARE_FRAGMENT,					baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0));
742
743					if (!(baseFlags & LAYOUT_PACKED))
744						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));
745
746					modeGroup->addChild(new BlockMultiBasicTypesCase(m_context, (baseName + "_mixed").c_str(),		"", baseFlags|DECLARE_VERTEX,					baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0));
747				}
748			}
749		}
750	}
751
752	// ubo.multi_nested_struct
753	{
754		tcu::TestCaseGroup* multiNestedStructGroup = new tcu::TestCaseGroup(m_testCtx, "multi_nested_struct", "Multiple buffers with nested structs");
755		addChild(multiNestedStructGroup);
756
757		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
758		{
759			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
760			multiNestedStructGroup->addChild(modeGroup);
761
762			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
763			{
764				for (int isArray = 0; isArray < 2; isArray++)
765				{
766					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
767					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
768
769					if (isArray)
770						baseName += "_instance_array";
771
772					modeGroup->addChild(new BlockMultiNestedStructCase(m_context, (baseName + "_vertex").c_str(),	"", baseFlags|DECLARE_VERTEX,					baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0));
773					modeGroup->addChild(new BlockMultiNestedStructCase(m_context, (baseName + "_fragment").c_str(),	"", baseFlags|DECLARE_FRAGMENT,					baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0));
774
775					if (!(baseFlags & LAYOUT_PACKED))
776						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));
777
778					modeGroup->addChild(new BlockMultiNestedStructCase(m_context, (baseName + "_mixed").c_str(),	"", baseFlags|DECLARE_VERTEX,					baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0));
779				}
780			}
781		}
782	}
783
784	// ubo.random
785	{
786		const deUint32	allShaders		= FEATURE_VERTEX_BLOCKS|FEATURE_FRAGMENT_BLOCKS|FEATURE_SHARED_BLOCKS;
787		const deUint32	allLayouts		= FEATURE_PACKED_LAYOUT|FEATURE_SHARED_LAYOUT|FEATURE_STD140_LAYOUT;
788		const deUint32	allBasicTypes	= FEATURE_VECTORS|FEATURE_MATRICES;
789		const deUint32	unused			= FEATURE_UNUSED_MEMBERS|FEATURE_UNUSED_UNIFORMS;
790		const deUint32	matFlags		= FEATURE_MATRIX_LAYOUT;
791		const deUint32	allFeatures		= ~FEATURE_ARRAYS_OF_ARRAYS;
792
793		tcu::TestCaseGroup* randomGroup = new tcu::TestCaseGroup(m_testCtx, "random", "Random Uniform Block cases");
794		addChild(randomGroup);
795
796		// Basic types.
797		createRandomCaseGroup(randomGroup, m_context, "scalar_types",	"Scalar types only, per-block buffers",				UniformBlockCase::BUFFERMODE_PER_BLOCK,	allShaders|allLayouts|unused,										25, 0);
798		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);
799		createRandomCaseGroup(randomGroup, m_context, "basic_types",	"All basic types, per-block buffers",				UniformBlockCase::BUFFERMODE_PER_BLOCK, allShaders|allLayouts|unused|allBasicTypes|matFlags,				25, 50);
800		createRandomCaseGroup(randomGroup, m_context, "basic_arrays",	"Arrays, per-block buffers",						UniformBlockCase::BUFFERMODE_PER_BLOCK,	allShaders|allLayouts|unused|allBasicTypes|matFlags|FEATURE_ARRAYS,	25, 50);
801
802		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);
803		createRandomCaseGroup(randomGroup, m_context, "nested_structs",							"Nested structs, per-block buffers",					UniformBlockCase::BUFFERMODE_PER_BLOCK,	allShaders|allLayouts|unused|allBasicTypes|matFlags|FEATURE_STRUCTS,										25, 100);
804		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);
805		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);
806		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);
807
808		createRandomCaseGroup(randomGroup, m_context, "all_per_block_buffers",	"All random features, per-block buffers",	UniformBlockCase::BUFFERMODE_PER_BLOCK,	allFeatures,	50, 200);
809		createRandomCaseGroup(randomGroup, m_context, "all_shared_buffer",		"All random features, shared buffer",		UniformBlockCase::BUFFERMODE_SINGLE,	allFeatures,	50, 250);
810	}
811}
812
813} // Functional
814} // gles3
815} // deqp
816