1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 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 SSBO layout tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es31fSSBOLayoutTests.hpp"
25#include "es31fSSBOLayoutCase.hpp"
26#include "tcuCommandLine.hpp"
27#include "deRandom.hpp"
28#include "deStringUtil.hpp"
29#include "deString.h"
30
31using std::string;
32using std::vector;
33
34namespace deqp
35{
36namespace gles31
37{
38namespace Functional
39{
40
41using namespace bb;
42using glu::VarType;
43using glu::StructType;
44
45namespace
46{
47
48enum FeatureBits
49{
50	FEATURE_VECTORS				= (1<<0),
51	FEATURE_MATRICES			= (1<<1),
52	FEATURE_ARRAYS				= (1<<2),
53	FEATURE_STRUCTS				= (1<<3),
54	FEATURE_NESTED_STRUCTS		= (1<<4),
55	FEATURE_INSTANCE_ARRAYS		= (1<<5),
56	FEATURE_UNUSED_VARS			= (1<<6),
57	FEATURE_UNUSED_MEMBERS		= (1<<7),
58	FEATURE_PACKED_LAYOUT		= (1<<8),
59	FEATURE_SHARED_LAYOUT		= (1<<9),
60	FEATURE_STD140_LAYOUT		= (1<<10),
61	FEATURE_STD430_LAYOUT		= (1<<11),
62	FEATURE_MATRIX_LAYOUT		= (1<<12),	//!< Matrix layout flags.
63	FEATURE_UNSIZED_ARRAYS		= (1<<13),
64	FEATURE_ARRAYS_OF_ARRAYS	= (1<<14)
65};
66
67class RandomSSBOLayoutCase : public SSBOLayoutCase
68{
69public:
70
71							RandomSSBOLayoutCase		(Context& context, const char* name, const char* description, BufferMode bufferMode, deUint32 features, deUint32 seed);
72
73	void					init						(void);
74
75private:
76	void					generateBlock				(de::Random& rnd, deUint32 layoutFlags);
77	void					generateBufferVar			(de::Random& rnd, BufferBlock& block, bool isLastMember);
78	glu::VarType			generateType				(de::Random& rnd, int typeDepth, bool arrayOk, bool unusedArrayOk);
79
80	deUint32				m_features;
81	int						m_maxBlocks;
82	int						m_maxInstances;
83	int						m_maxArrayLength;
84	int						m_maxStructDepth;
85	int						m_maxBlockMembers;
86	int						m_maxStructMembers;
87	deUint32				m_seed;
88
89	int						m_blockNdx;
90	int						m_bufferVarNdx;
91	int						m_structNdx;
92};
93
94RandomSSBOLayoutCase::RandomSSBOLayoutCase (Context& context, const char* name, const char* description, BufferMode bufferMode, deUint32 features, deUint32 seed)
95	: SSBOLayoutCase		(context.getTestContext(), context.getRenderContext(), name, description, glu::GLSL_VERSION_310_ES, bufferMode)
96	, m_features			(features)
97	, m_maxBlocks			(4)
98	, m_maxInstances		((features & FEATURE_INSTANCE_ARRAYS)	? 3 : 0)
99	, m_maxArrayLength		((features & FEATURE_ARRAYS)			? 8 : 0)
100	, m_maxStructDepth		((features & FEATURE_STRUCTS)			? 2 : 0)
101	, m_maxBlockMembers		(5)
102	, m_maxStructMembers	(4)
103	, m_seed				(seed)
104	, m_blockNdx			(1)
105	, m_bufferVarNdx		(1)
106	, m_structNdx			(1)
107{
108}
109
110void RandomSSBOLayoutCase::init (void)
111{
112	de::Random rnd(m_seed);
113
114	const int numBlocks = rnd.getInt(1, m_maxBlocks);
115
116	for (int ndx = 0; ndx < numBlocks; ndx++)
117		generateBlock(rnd, 0);
118}
119
120void RandomSSBOLayoutCase::generateBlock (de::Random& rnd, deUint32 layoutFlags)
121{
122	DE_ASSERT(m_blockNdx <= 'z' - 'a');
123
124	const float		instanceArrayWeight	= 0.3f;
125	BufferBlock&	block				= m_interface.allocBlock((string("Block") + (char)('A' + m_blockNdx)).c_str());
126	int				numInstances		= (m_maxInstances > 0 && rnd.getFloat() < instanceArrayWeight) ? rnd.getInt(0, m_maxInstances) : 0;
127	int				numVars				= rnd.getInt(1, m_maxBlockMembers);
128
129	if (numInstances > 0)
130		block.setArraySize(numInstances);
131
132	if (numInstances > 0 || rnd.getBool())
133		block.setInstanceName((string("block") + (char)('A' + m_blockNdx)).c_str());
134
135	// Layout flag candidates.
136	vector<deUint32> layoutFlagCandidates;
137	layoutFlagCandidates.push_back(0);
138	if (m_features & FEATURE_PACKED_LAYOUT)
139		layoutFlagCandidates.push_back(LAYOUT_PACKED);
140	if ((m_features & FEATURE_SHARED_LAYOUT))
141		layoutFlagCandidates.push_back(LAYOUT_SHARED);
142	if (m_features & FEATURE_STD140_LAYOUT)
143		layoutFlagCandidates.push_back(LAYOUT_STD140);
144
145	layoutFlags |= rnd.choose<deUint32>(layoutFlagCandidates.begin(), layoutFlagCandidates.end());
146
147	if (m_features & FEATURE_MATRIX_LAYOUT)
148	{
149		static const deUint32 matrixCandidates[] = { 0, LAYOUT_ROW_MAJOR, LAYOUT_COLUMN_MAJOR };
150		layoutFlags |= rnd.choose<deUint32>(&matrixCandidates[0], &matrixCandidates[DE_LENGTH_OF_ARRAY(matrixCandidates)]);
151	}
152
153	block.setFlags(layoutFlags);
154
155	for (int ndx = 0; ndx < numVars; ndx++)
156		generateBufferVar(rnd, block, (ndx+1 == numVars));
157
158	if (numVars > 0)
159	{
160		const BufferVar&	lastVar			= *(block.end()-1);
161		const glu::VarType&	lastType		= lastVar.getType();
162		const bool			isUnsizedArr	= lastType.isArrayType() && (lastType.getArraySize() == glu::VarType::UNSIZED_ARRAY);
163
164		if (isUnsizedArr)
165		{
166			for (int instanceNdx = 0; instanceNdx < (numInstances ? numInstances : 1); instanceNdx++)
167			{
168				const int arrSize = rnd.getInt(0, m_maxArrayLength);
169				block.setLastUnsizedArraySize(instanceNdx, arrSize);
170			}
171		}
172	}
173
174	m_blockNdx += 1;
175}
176
177static std::string genName (char first, char last, int ndx)
178{
179	std::string	str			= "";
180	int			alphabetLen	= last - first + 1;
181
182	while (ndx > alphabetLen)
183	{
184		str.insert(str.begin(), (char)(first + ((ndx-1)%alphabetLen)));
185		ndx = ((ndx-1) / alphabetLen);
186	}
187
188	str.insert(str.begin(), (char)(first + (ndx%(alphabetLen+1)) - 1));
189
190	return str;
191}
192
193void RandomSSBOLayoutCase::generateBufferVar (de::Random& rnd, BufferBlock& block, bool isLastMember)
194{
195	const float			readWeight			= 0.7f;
196	const float			writeWeight			= 0.7f;
197	const float			accessWeight		= 0.85f;
198	const bool			unusedOk			= (m_features & FEATURE_UNUSED_VARS) != 0;
199	const std::string	name				= genName('a', 'z', m_bufferVarNdx);
200	const glu::VarType	type				= generateType(rnd, 0, true, isLastMember && (m_features & FEATURE_UNSIZED_ARRAYS));
201	const bool			access				= !unusedOk || (rnd.getFloat() < accessWeight);
202	const bool			read				= access ? (rnd.getFloat() < readWeight) : false;
203	const bool			write				= access ? (!read || (rnd.getFloat() < writeWeight)) : false;
204	const deUint32		flags				= (read ? ACCESS_READ : 0) | (write ? ACCESS_WRITE : 0);
205
206	block.addMember(BufferVar(name.c_str(), type, flags));
207
208	m_bufferVarNdx += 1;
209}
210
211glu::VarType RandomSSBOLayoutCase::generateType (de::Random& rnd, int typeDepth, bool arrayOk, bool unsizedArrayOk)
212{
213	const float structWeight		= 0.1f;
214	const float arrayWeight			= 0.1f;
215	const float	unsizedArrayWeight	= 0.8f;
216
217	DE_ASSERT(arrayOk || !unsizedArrayOk);
218
219	if (unsizedArrayOk && (rnd.getFloat() < unsizedArrayWeight))
220	{
221		const bool			childArrayOk	= (m_features & FEATURE_ARRAYS_OF_ARRAYS) != 0;
222		const glu::VarType	elementType		= generateType(rnd, typeDepth, childArrayOk, false);
223		return glu::VarType(elementType, glu::VarType::UNSIZED_ARRAY);
224	}
225	else if (typeDepth < m_maxStructDepth && rnd.getFloat() < structWeight)
226	{
227		// \todo [2013-10-14 pyry] Implement unused flags for members!
228//		bool					unusedOk			= (m_features & FEATURE_UNUSED_MEMBERS) != 0;
229		vector<glu::VarType>	memberTypes;
230		int						numMembers = rnd.getInt(1, m_maxStructMembers);
231
232		// Generate members first so nested struct declarations are in correct order.
233		for (int ndx = 0; ndx < numMembers; ndx++)
234			memberTypes.push_back(generateType(rnd, typeDepth+1, true, false));
235
236		glu::StructType& structType = m_interface.allocStruct((string("s") + genName('A', 'Z', m_structNdx)).c_str());
237		m_structNdx += 1;
238
239		DE_ASSERT(numMembers <= 'Z' - 'A');
240		for (int ndx = 0; ndx < numMembers; ndx++)
241		{
242			structType.addMember((string("m") + (char)('A' + ndx)).c_str(), memberTypes[ndx]);
243		}
244
245		return glu::VarType(&structType);
246	}
247	else if (m_maxArrayLength > 0 && arrayOk && rnd.getFloat() < arrayWeight)
248	{
249		const int			arrayLength		= rnd.getInt(1, m_maxArrayLength);
250		const bool			childArrayOk	= (m_features & FEATURE_ARRAYS_OF_ARRAYS) != 0;
251		const glu::VarType	elementType		= generateType(rnd, typeDepth, childArrayOk, false);
252
253		return glu::VarType(elementType, arrayLength);
254	}
255	else
256	{
257		vector<glu::DataType> typeCandidates;
258
259		typeCandidates.push_back(glu::TYPE_FLOAT);
260		typeCandidates.push_back(glu::TYPE_INT);
261		typeCandidates.push_back(glu::TYPE_UINT);
262		typeCandidates.push_back(glu::TYPE_BOOL);
263
264		if (m_features & FEATURE_VECTORS)
265		{
266			typeCandidates.push_back(glu::TYPE_FLOAT_VEC2);
267			typeCandidates.push_back(glu::TYPE_FLOAT_VEC3);
268			typeCandidates.push_back(glu::TYPE_FLOAT_VEC4);
269			typeCandidates.push_back(glu::TYPE_INT_VEC2);
270			typeCandidates.push_back(glu::TYPE_INT_VEC3);
271			typeCandidates.push_back(glu::TYPE_INT_VEC4);
272			typeCandidates.push_back(glu::TYPE_UINT_VEC2);
273			typeCandidates.push_back(glu::TYPE_UINT_VEC3);
274			typeCandidates.push_back(glu::TYPE_UINT_VEC4);
275			typeCandidates.push_back(glu::TYPE_BOOL_VEC2);
276			typeCandidates.push_back(glu::TYPE_BOOL_VEC3);
277			typeCandidates.push_back(glu::TYPE_BOOL_VEC4);
278		}
279
280		if (m_features & FEATURE_MATRICES)
281		{
282			typeCandidates.push_back(glu::TYPE_FLOAT_MAT2);
283			typeCandidates.push_back(glu::TYPE_FLOAT_MAT2X3);
284			typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X2);
285			typeCandidates.push_back(glu::TYPE_FLOAT_MAT3);
286			typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X4);
287			typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X2);
288			typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X3);
289			typeCandidates.push_back(glu::TYPE_FLOAT_MAT4);
290		}
291
292		glu::DataType	type		= rnd.choose<glu::DataType>(typeCandidates.begin(), typeCandidates.end());
293		glu::Precision	precision;
294
295		if (!glu::isDataTypeBoolOrBVec(type))
296		{
297			// Precision.
298			static const glu::Precision precisionCandidates[] = { glu::PRECISION_LOWP, glu::PRECISION_MEDIUMP, glu::PRECISION_HIGHP };
299			precision = rnd.choose<glu::Precision>(&precisionCandidates[0], &precisionCandidates[DE_LENGTH_OF_ARRAY(precisionCandidates)]);
300		}
301		else
302			precision = glu::PRECISION_LAST;
303
304		return glu::VarType(type, precision);
305	}
306}
307
308class BlockBasicTypeCase : public SSBOLayoutCase
309{
310public:
311	BlockBasicTypeCase (Context& context, const char* name, const char* description, const VarType& type, deUint32 layoutFlags, int numInstances)
312		: SSBOLayoutCase(context.getTestContext(), context.getRenderContext(), name, description, glu::GLSL_VERSION_310_ES, BUFFERMODE_PER_BLOCK)
313	{
314		BufferBlock& block = m_interface.allocBlock("Block");
315		block.addMember(BufferVar("var", type, ACCESS_READ|ACCESS_WRITE));
316		block.setFlags(layoutFlags);
317
318		if (numInstances > 0)
319		{
320			block.setArraySize(numInstances);
321			block.setInstanceName("block");
322		}
323	}
324};
325
326class BlockBasicUnsizedArrayCase : public SSBOLayoutCase
327{
328public:
329	BlockBasicUnsizedArrayCase (Context& context, const char* name, const char* description, const VarType& elementType, int arraySize, deUint32 layoutFlags)
330		: SSBOLayoutCase(context.getTestContext(), context.getRenderContext(), name, description, glu::GLSL_VERSION_310_ES, BUFFERMODE_PER_BLOCK)
331	{
332		BufferBlock& block = m_interface.allocBlock("Block");
333		block.addMember(BufferVar("var", VarType(elementType, VarType::UNSIZED_ARRAY), ACCESS_READ|ACCESS_WRITE));
334		block.setFlags(layoutFlags);
335
336		block.setLastUnsizedArraySize(0, arraySize);
337	}
338};
339
340static void createRandomCaseGroup (tcu::TestCaseGroup* parentGroup, Context& context, const char* groupName, const char* description, SSBOLayoutCase::BufferMode bufferMode, deUint32 features, int numCases, deUint32 baseSeed)
341{
342	tcu::TestCaseGroup* group = new tcu::TestCaseGroup(context.getTestContext(), groupName, description);
343	parentGroup->addChild(group);
344
345	baseSeed += (deUint32)context.getTestContext().getCommandLine().getBaseSeed();
346
347	for (int ndx = 0; ndx < numCases; ndx++)
348		group->addChild(new RandomSSBOLayoutCase(context, de::toString(ndx).c_str(), "", bufferMode, features, (deUint32)ndx+baseSeed));
349}
350
351class BlockSingleStructCase : public SSBOLayoutCase
352{
353public:
354	BlockSingleStructCase (Context& context, const char* name, const char* description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances)
355		: SSBOLayoutCase	(context.getTestContext(), context.getRenderContext(), name, description, glu::GLSL_VERSION_310_ES, bufferMode)
356		, m_layoutFlags		(layoutFlags)
357		, m_numInstances	(numInstances)
358	{
359	}
360
361	void init (void)
362	{
363		StructType& typeS = m_interface.allocStruct("S");
364		typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, glu::PRECISION_HIGHP)); // \todo [pyry] First member is unused.
365		typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, glu::PRECISION_MEDIUMP), 4));
366		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP));
367
368		BufferBlock& block = m_interface.allocBlock("Block");
369		block.addMember(BufferVar("s", VarType(&typeS), ACCESS_READ|ACCESS_WRITE));
370		block.setFlags(m_layoutFlags);
371
372		if (m_numInstances > 0)
373		{
374			block.setInstanceName("block");
375			block.setArraySize(m_numInstances);
376		}
377	}
378
379private:
380	deUint32	m_layoutFlags;
381	int			m_numInstances;
382};
383
384class BlockSingleStructArrayCase : public SSBOLayoutCase
385{
386public:
387	BlockSingleStructArrayCase (Context& context, const char* name, const char* description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances)
388		: SSBOLayoutCase	(context.getTestContext(), context.getRenderContext(), name, description, glu::GLSL_VERSION_310_ES, bufferMode)
389		, m_layoutFlags		(layoutFlags)
390		, m_numInstances	(numInstances)
391	{
392	}
393
394	void init (void)
395	{
396		StructType& typeS = m_interface.allocStruct("S");
397		typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, glu::PRECISION_HIGHP)); // \todo [pyry] UNUSED
398		typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, glu::PRECISION_MEDIUMP), 4));
399		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP));
400
401		BufferBlock& block = m_interface.allocBlock("Block");
402		block.addMember(BufferVar("u", VarType(glu::TYPE_UINT, glu::PRECISION_LOWP), 0 /* no access */));
403		block.addMember(BufferVar("s", VarType(VarType(&typeS), 3), ACCESS_READ|ACCESS_WRITE));
404		block.addMember(BufferVar("v", VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_MEDIUMP), ACCESS_WRITE));
405		block.setFlags(m_layoutFlags);
406
407		if (m_numInstances > 0)
408		{
409			block.setInstanceName("block");
410			block.setArraySize(m_numInstances);
411		}
412	}
413
414private:
415	deUint32	m_layoutFlags;
416	int			m_numInstances;
417};
418
419class BlockSingleNestedStructCase : public SSBOLayoutCase
420{
421public:
422	BlockSingleNestedStructCase (Context& context, const char* name, const char* description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances)
423		: SSBOLayoutCase	(context.getTestContext(), context.getRenderContext(), name, description, glu::GLSL_VERSION_310_ES, bufferMode)
424		, m_layoutFlags		(layoutFlags)
425		, m_numInstances	(numInstances)
426	{
427	}
428
429	void init (void)
430	{
431		StructType& typeS = m_interface.allocStruct("S");
432		typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, glu::PRECISION_HIGHP));
433		typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, glu::PRECISION_MEDIUMP), 4));
434		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)); // \todo [pyry] UNUSED
435
436		StructType& typeT = m_interface.allocStruct("T");
437		typeT.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, glu::PRECISION_MEDIUMP));
438		typeT.addMember("b", VarType(&typeS));
439
440		BufferBlock& block = m_interface.allocBlock("Block");
441		block.addMember(BufferVar("s", VarType(&typeS), ACCESS_READ));
442		block.addMember(BufferVar("v", VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_LOWP), 0 /* no access */));
443		block.addMember(BufferVar("t", VarType(&typeT), ACCESS_READ|ACCESS_WRITE));
444		block.addMember(BufferVar("u", VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP), ACCESS_WRITE));
445		block.setFlags(m_layoutFlags);
446
447		if (m_numInstances > 0)
448		{
449			block.setInstanceName("block");
450			block.setArraySize(m_numInstances);
451		}
452	}
453
454private:
455	deUint32	m_layoutFlags;
456	int			m_numInstances;
457};
458
459class BlockSingleNestedStructArrayCase : public SSBOLayoutCase
460{
461public:
462	BlockSingleNestedStructArrayCase (Context& context, const char* name, const char* description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances)
463		: SSBOLayoutCase	(context.getTestContext(), context.getRenderContext(), name, description, glu::GLSL_VERSION_310_ES, bufferMode)
464		, m_layoutFlags		(layoutFlags)
465		, m_numInstances	(numInstances)
466	{
467	}
468
469	void init (void)
470	{
471		StructType& typeS = m_interface.allocStruct("S");
472		typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, glu::PRECISION_HIGHP));
473		typeS.addMember("b", VarType(VarType(glu::TYPE_INT_VEC2, glu::PRECISION_MEDIUMP), 4));
474		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)); // \todo [pyry] UNUSED
475
476		StructType& typeT = m_interface.allocStruct("T");
477		typeT.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, glu::PRECISION_MEDIUMP));
478		typeT.addMember("b", VarType(VarType(&typeS), 3));
479
480		BufferBlock& block = m_interface.allocBlock("Block");
481		block.addMember(BufferVar("s", VarType(&typeS), ACCESS_WRITE));
482		block.addMember(BufferVar("v", VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_LOWP), 0 /* no access */));
483		block.addMember(BufferVar("t", VarType(VarType(&typeT), 2), ACCESS_READ));
484		block.addMember(BufferVar("u", VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP), ACCESS_READ|ACCESS_WRITE));
485		block.setFlags(m_layoutFlags);
486
487		if (m_numInstances > 0)
488		{
489			block.setInstanceName("block");
490			block.setArraySize(m_numInstances);
491		}
492	}
493
494private:
495	deUint32	m_layoutFlags;
496	int			m_numInstances;
497};
498
499class BlockUnsizedStructArrayCase : public SSBOLayoutCase
500{
501public:
502	BlockUnsizedStructArrayCase (Context& context, const char* name, const char* description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances)
503		: SSBOLayoutCase	(context.getTestContext(), context.getRenderContext(), name, description, glu::GLSL_VERSION_310_ES, bufferMode)
504		, m_layoutFlags		(layoutFlags)
505		, m_numInstances	(numInstances)
506	{
507	}
508
509	void init (void)
510	{
511		StructType& typeS = m_interface.allocStruct("S");
512		typeS.addMember("a", VarType(glu::TYPE_UINT_VEC2, glu::PRECISION_HIGHP)); // \todo [pyry] UNUSED
513		typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT2X4, glu::PRECISION_MEDIUMP), 4));
514		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC3, glu::PRECISION_HIGHP));
515
516		BufferBlock& block = m_interface.allocBlock("Block");
517		block.addMember(BufferVar("u", VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_LOWP), 0 /* no access */));
518		block.addMember(BufferVar("v", VarType(glu::TYPE_UINT, glu::PRECISION_MEDIUMP), ACCESS_WRITE));
519		block.addMember(BufferVar("s", VarType(VarType(&typeS), VarType::UNSIZED_ARRAY), ACCESS_READ|ACCESS_WRITE));
520		block.setFlags(m_layoutFlags);
521
522		if (m_numInstances > 0)
523		{
524			block.setInstanceName("block");
525			block.setArraySize(m_numInstances);
526		}
527
528		{
529			de::Random rnd(246);
530			for (int ndx = 0; ndx < (m_numInstances ? m_numInstances : 1); ndx++)
531			{
532				const int lastArrayLen = rnd.getInt(1, 5);
533				block.setLastUnsizedArraySize(ndx, lastArrayLen);
534			}
535		}
536	}
537
538private:
539	deUint32	m_layoutFlags;
540	int			m_numInstances;
541};
542
543class Block2LevelUnsizedStructArrayCase : public SSBOLayoutCase
544{
545public:
546	Block2LevelUnsizedStructArrayCase (Context& context, const char* name, const char* description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances)
547		: SSBOLayoutCase	(context.getTestContext(), context.getRenderContext(), name, description, glu::GLSL_VERSION_310_ES, bufferMode)
548		, m_layoutFlags		(layoutFlags)
549		, m_numInstances	(numInstances)
550	{
551	}
552
553	void init (void)
554	{
555		StructType& typeS = m_interface.allocStruct("S");
556		typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, glu::PRECISION_HIGHP));
557		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP));
558
559		BufferBlock& block = m_interface.allocBlock("Block");
560		block.addMember(BufferVar("u", VarType(glu::TYPE_UINT, glu::PRECISION_LOWP), 0 /* no access */));
561		block.addMember(BufferVar("v", VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_MEDIUMP), ACCESS_WRITE));
562		block.addMember(BufferVar("s", VarType(VarType(VarType(&typeS), 2), VarType::UNSIZED_ARRAY), ACCESS_READ|ACCESS_WRITE));
563		block.setFlags(m_layoutFlags);
564
565		if (m_numInstances > 0)
566		{
567			block.setInstanceName("block");
568			block.setArraySize(m_numInstances);
569		}
570
571		{
572			de::Random rnd(2344);
573			for (int ndx = 0; ndx < (m_numInstances ? m_numInstances : 1); ndx++)
574			{
575				const int lastArrayLen = rnd.getInt(1, 5);
576				block.setLastUnsizedArraySize(ndx, lastArrayLen);
577			}
578		}
579	}
580
581private:
582	deUint32	m_layoutFlags;
583	int			m_numInstances;
584};
585
586class BlockUnsizedNestedStructArrayCase : public SSBOLayoutCase
587{
588public:
589	BlockUnsizedNestedStructArrayCase (Context& context, const char* name, const char* description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances)
590		: SSBOLayoutCase	(context.getTestContext(), context.getRenderContext(), name, description, glu::GLSL_VERSION_310_ES, bufferMode)
591		, m_layoutFlags		(layoutFlags)
592		, m_numInstances	(numInstances)
593	{
594	}
595
596	void init (void)
597	{
598		StructType& typeS = m_interface.allocStruct("S");
599		typeS.addMember("a", VarType(glu::TYPE_UINT_VEC3, glu::PRECISION_HIGHP));
600		typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_MEDIUMP), 4));
601		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)); // \todo [pyry] UNUSED
602
603		StructType& typeT = m_interface.allocStruct("T");
604		typeT.addMember("a", VarType(glu::TYPE_FLOAT_MAT4X3, glu::PRECISION_MEDIUMP));
605		typeT.addMember("b", VarType(VarType(&typeS), 3));
606		typeT.addMember("c", VarType(glu::TYPE_INT, glu::PRECISION_HIGHP));
607
608		BufferBlock& block = m_interface.allocBlock("Block");
609		block.addMember(BufferVar("s", VarType(&typeS), ACCESS_WRITE));
610		block.addMember(BufferVar("v", VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_LOWP), 0 /* no access */));
611		block.addMember(BufferVar("u", VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP), ACCESS_READ|ACCESS_WRITE));
612		block.addMember(BufferVar("t", VarType(VarType(&typeT), VarType::UNSIZED_ARRAY), ACCESS_READ));
613		block.setFlags(m_layoutFlags);
614
615		if (m_numInstances > 0)
616		{
617			block.setInstanceName("block");
618			block.setArraySize(m_numInstances);
619		}
620
621		{
622			de::Random rnd(7921);
623			for (int ndx = 0; ndx < (m_numInstances ? m_numInstances : 1); ndx++)
624			{
625				const int lastArrayLen = rnd.getInt(1, 5);
626				block.setLastUnsizedArraySize(ndx, lastArrayLen);
627			}
628		}
629	}
630
631private:
632	deUint32	m_layoutFlags;
633	int			m_numInstances;
634};
635
636class BlockMultiBasicTypesCase : public SSBOLayoutCase
637{
638public:
639	BlockMultiBasicTypesCase (Context& context, const char* name, const char* description, deUint32 flagsA, deUint32 flagsB, BufferMode bufferMode, int numInstances)
640		: SSBOLayoutCase	(context.getTestContext(), context.getRenderContext(), name, description, glu::GLSL_VERSION_310_ES, bufferMode)
641		, m_flagsA			(flagsA)
642		, m_flagsB			(flagsB)
643		, m_numInstances	(numInstances)
644	{
645	}
646
647	void init (void)
648	{
649		BufferBlock& blockA = m_interface.allocBlock("BlockA");
650		blockA.addMember(BufferVar("a", VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP), ACCESS_READ|ACCESS_WRITE));
651		blockA.addMember(BufferVar("b", VarType(glu::TYPE_UINT_VEC3, glu::PRECISION_LOWP), 0 /* no access */));
652		blockA.addMember(BufferVar("c", VarType(glu::TYPE_FLOAT_MAT2, glu::PRECISION_MEDIUMP), ACCESS_READ));
653		blockA.setInstanceName("blockA");
654		blockA.setFlags(m_flagsA);
655
656		BufferBlock& blockB = m_interface.allocBlock("BlockB");
657		blockB.addMember(BufferVar("a", VarType(glu::TYPE_FLOAT_MAT3, glu::PRECISION_MEDIUMP), ACCESS_WRITE));
658		blockB.addMember(BufferVar("b", VarType(glu::TYPE_INT_VEC2, glu::PRECISION_LOWP), ACCESS_READ));
659		blockB.addMember(BufferVar("c", VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP), 0 /* no access */));
660		blockB.addMember(BufferVar("d", VarType(glu::TYPE_BOOL, glu::PRECISION_LAST), ACCESS_READ|ACCESS_WRITE));
661		blockB.setInstanceName("blockB");
662		blockB.setFlags(m_flagsB);
663
664		if (m_numInstances > 0)
665		{
666			blockA.setArraySize(m_numInstances);
667			blockB.setArraySize(m_numInstances);
668		}
669	}
670
671private:
672	deUint32	m_flagsA;
673	deUint32	m_flagsB;
674	int			m_numInstances;
675};
676
677class BlockMultiNestedStructCase : public SSBOLayoutCase
678{
679public:
680	BlockMultiNestedStructCase (Context& context, const char* name, const char* description, deUint32 flagsA, deUint32 flagsB, BufferMode bufferMode, int numInstances)
681		: SSBOLayoutCase	(context.getTestContext(), context.getRenderContext(), name, description, glu::GLSL_VERSION_310_ES, bufferMode)
682		, m_flagsA			(flagsA)
683		, m_flagsB			(flagsB)
684		, m_numInstances	(numInstances)
685	{
686	}
687
688	void init (void)
689	{
690		StructType& typeS = m_interface.allocStruct("S");
691		typeS.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, glu::PRECISION_LOWP));
692		typeS.addMember("b", VarType(VarType(glu::TYPE_INT_VEC2, glu::PRECISION_MEDIUMP), 4));
693		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP));
694
695		StructType& typeT = m_interface.allocStruct("T");
696		typeT.addMember("a", VarType(glu::TYPE_UINT, glu::PRECISION_MEDIUMP)); // \todo [pyry] UNUSED
697		typeT.addMember("b", VarType(&typeS));
698		typeT.addMember("c", VarType(glu::TYPE_BOOL_VEC4, glu::PRECISION_LAST));
699
700		BufferBlock& blockA = m_interface.allocBlock("BlockA");
701		blockA.addMember(BufferVar("a", VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP), ACCESS_READ|ACCESS_WRITE));
702		blockA.addMember(BufferVar("b", VarType(&typeS), ACCESS_WRITE));
703		blockA.addMember(BufferVar("c", VarType(glu::TYPE_UINT_VEC3, glu::PRECISION_LOWP), 0 /* no access */));
704		blockA.setInstanceName("blockA");
705		blockA.setFlags(m_flagsA);
706
707		BufferBlock& blockB = m_interface.allocBlock("BlockB");
708		blockB.addMember(BufferVar("a", VarType(glu::TYPE_FLOAT_MAT2, glu::PRECISION_MEDIUMP), ACCESS_WRITE));
709		blockB.addMember(BufferVar("b", VarType(&typeT), ACCESS_READ|ACCESS_WRITE));
710		blockB.addMember(BufferVar("c", VarType(glu::TYPE_BOOL_VEC4, glu::PRECISION_LAST), 0 /* no access */));
711		blockB.addMember(BufferVar("d", VarType(glu::TYPE_BOOL, glu::PRECISION_LAST), ACCESS_READ|ACCESS_WRITE));
712		blockB.setInstanceName("blockB");
713		blockB.setFlags(m_flagsB);
714
715		if (m_numInstances > 0)
716		{
717			blockA.setArraySize(m_numInstances);
718			blockB.setArraySize(m_numInstances);
719		}
720	}
721
722private:
723	deUint32	m_flagsA;
724	deUint32	m_flagsB;
725	int			m_numInstances;
726};
727
728} // anonymous
729
730SSBOLayoutTests::SSBOLayoutTests (Context& context)
731	: TestCaseGroup(context, "layout", "SSBO Layout Tests")
732{
733}
734
735SSBOLayoutTests::~SSBOLayoutTests (void)
736{
737}
738
739void SSBOLayoutTests::init (void)
740{
741	static const glu::DataType basicTypes[] =
742	{
743		glu::TYPE_FLOAT,
744		glu::TYPE_FLOAT_VEC2,
745		glu::TYPE_FLOAT_VEC3,
746		glu::TYPE_FLOAT_VEC4,
747		glu::TYPE_INT,
748		glu::TYPE_INT_VEC2,
749		glu::TYPE_INT_VEC3,
750		glu::TYPE_INT_VEC4,
751		glu::TYPE_UINT,
752		glu::TYPE_UINT_VEC2,
753		glu::TYPE_UINT_VEC3,
754		glu::TYPE_UINT_VEC4,
755		glu::TYPE_BOOL,
756		glu::TYPE_BOOL_VEC2,
757		glu::TYPE_BOOL_VEC3,
758		glu::TYPE_BOOL_VEC4,
759		glu::TYPE_FLOAT_MAT2,
760		glu::TYPE_FLOAT_MAT3,
761		glu::TYPE_FLOAT_MAT4,
762		glu::TYPE_FLOAT_MAT2X3,
763		glu::TYPE_FLOAT_MAT2X4,
764		glu::TYPE_FLOAT_MAT3X2,
765		glu::TYPE_FLOAT_MAT3X4,
766		glu::TYPE_FLOAT_MAT4X2,
767		glu::TYPE_FLOAT_MAT4X3
768	};
769
770	static const struct
771	{
772		const char*		name;
773		deUint32		flags;
774	} layoutFlags[] =
775	{
776		{ "shared",		LAYOUT_SHARED	},
777		{ "packed",		LAYOUT_PACKED	},
778		{ "std140",		LAYOUT_STD140	},
779		{ "std430",		LAYOUT_STD430	}
780	};
781
782	static const struct
783	{
784		const char*		name;
785		deUint32		flags;
786	} matrixFlags[] =
787	{
788		{ "row_major",		LAYOUT_ROW_MAJOR	},
789		{ "column_major",	LAYOUT_COLUMN_MAJOR }
790	};
791
792	static const struct
793	{
794		const char*							name;
795		SSBOLayoutCase::BufferMode		mode;
796	} bufferModes[] =
797	{
798		{ "per_block_buffer",	SSBOLayoutCase::BUFFERMODE_PER_BLOCK },
799		{ "single_buffer",		SSBOLayoutCase::BUFFERMODE_SINGLE	}
800	};
801
802	// ubo.single_basic_type
803	{
804		tcu::TestCaseGroup* singleBasicTypeGroup = new tcu::TestCaseGroup(m_testCtx, "single_basic_type", "Single basic variable in single buffer");
805		addChild(singleBasicTypeGroup);
806
807		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
808		{
809			tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
810			singleBasicTypeGroup->addChild(layoutGroup);
811
812			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
813			{
814				glu::DataType	type		= basicTypes[basicTypeNdx];
815				const char*		typeName	= glu::getDataTypeName(type);
816
817				if (glu::isDataTypeBoolOrBVec(type))
818					layoutGroup->addChild(new BlockBasicTypeCase(m_context, typeName, "", VarType(type, glu::PRECISION_LAST), layoutFlags[layoutFlagNdx].flags, 0));
819				else
820				{
821					for (int precNdx = 0; precNdx < glu::PRECISION_LAST; precNdx++)
822					{
823						const glu::Precision	precision	= glu::Precision(precNdx);
824						const string			caseName	= string(glu::getPrecisionName(precision)) + "_" + typeName;
825
826						layoutGroup->addChild(new BlockBasicTypeCase(m_context, caseName.c_str(), "", VarType(type, precision), layoutFlags[layoutFlagNdx].flags, 0));
827					}
828				}
829
830				if (glu::isDataTypeMatrix(type))
831				{
832					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
833					{
834						for (int precNdx = 0; precNdx < glu::PRECISION_LAST; precNdx++)
835						{
836							const glu::Precision	precision	= glu::Precision(precNdx);
837							const string			caseName	= string(matrixFlags[matFlagNdx].name) + "_" + string(glu::getPrecisionName(precision)) + "_" + typeName;
838
839							layoutGroup->addChild(new BlockBasicTypeCase(m_context, caseName.c_str(), "", glu::VarType(type, precision), layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags, 0));
840						}
841					}
842				}
843			}
844		}
845	}
846
847	// ubo.single_basic_array
848	{
849		tcu::TestCaseGroup* singleBasicArrayGroup = new tcu::TestCaseGroup(m_testCtx, "single_basic_array", "Single basic array variable in single buffer");
850		addChild(singleBasicArrayGroup);
851
852		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
853		{
854			tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
855			singleBasicArrayGroup->addChild(layoutGroup);
856
857			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
858			{
859				glu::DataType	type		= basicTypes[basicTypeNdx];
860				const char*		typeName	= glu::getDataTypeName(type);
861				const int		arraySize	= 3;
862
863				layoutGroup->addChild(new BlockBasicTypeCase(m_context, typeName, "",
864															 VarType(VarType(type, glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_HIGHP), arraySize),
865															 layoutFlags[layoutFlagNdx].flags, 0));
866
867				if (glu::isDataTypeMatrix(type))
868				{
869					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
870						layoutGroup->addChild(new BlockBasicTypeCase(m_context, (string(matrixFlags[matFlagNdx].name) + "_" + typeName).c_str(), "",
871																	 VarType(VarType(type, glu::PRECISION_HIGHP), arraySize),
872																	 layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags, 0));
873				}
874			}
875		}
876	}
877
878	// ubo.basic_unsized_array
879	{
880		tcu::TestCaseGroup* basicUnsizedArray = new tcu::TestCaseGroup(m_testCtx, "basic_unsized_array", "Basic unsized array tests");
881		addChild(basicUnsizedArray);
882
883		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
884		{
885			tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
886			basicUnsizedArray->addChild(layoutGroup);
887
888			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
889			{
890				glu::DataType	type		= basicTypes[basicTypeNdx];
891				const char*		typeName	= glu::getDataTypeName(type);
892				const int		arraySize	= 19;
893
894				layoutGroup->addChild(new BlockBasicUnsizedArrayCase(m_context, typeName, "",
895																	 VarType(type, glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_HIGHP),
896																	 arraySize, layoutFlags[layoutFlagNdx].flags));
897
898				if (glu::isDataTypeMatrix(type))
899				{
900					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
901						layoutGroup->addChild(new BlockBasicUnsizedArrayCase(m_context, (string(matrixFlags[matFlagNdx].name) + "_" + typeName).c_str(), "",
902																			 VarType(type, glu::PRECISION_HIGHP), arraySize,
903																			 layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags));
904				}
905			}
906		}
907	}
908
909	// ubo.2_level_array
910	{
911		tcu::TestCaseGroup* nestedArrayGroup = new tcu::TestCaseGroup(m_testCtx, "2_level_array", "2-level nested array");
912		addChild(nestedArrayGroup);
913
914		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
915		{
916			tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
917			nestedArrayGroup->addChild(layoutGroup);
918
919			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
920			{
921				glu::DataType	type		= basicTypes[basicTypeNdx];
922				const char*		typeName	= glu::getDataTypeName(type);
923				const int		childSize	= 3;
924				const int		parentSize	= 4;
925				const VarType	childType	(VarType(type, glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_HIGHP), childSize);
926				const VarType	fullType	(childType, parentSize);
927
928				layoutGroup->addChild(new BlockBasicTypeCase(m_context, typeName, "", fullType, layoutFlags[layoutFlagNdx].flags, 0));
929
930				if (glu::isDataTypeMatrix(type))
931				{
932					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
933						layoutGroup->addChild(new BlockBasicTypeCase(m_context, (string(matrixFlags[matFlagNdx].name) + "_" + typeName).c_str(), "",
934																	 fullType,
935																	 layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags, 0));
936				}
937			}
938		}
939	}
940
941	// ubo.3_level_array
942	{
943		tcu::TestCaseGroup* nestedArrayGroup = new tcu::TestCaseGroup(m_testCtx, "3_level_array", "3-level nested array");
944		addChild(nestedArrayGroup);
945
946		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
947		{
948			tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
949			nestedArrayGroup->addChild(layoutGroup);
950
951			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
952			{
953				glu::DataType	type		= basicTypes[basicTypeNdx];
954				const char*		typeName	= glu::getDataTypeName(type);
955				const int		childSize0	= 3;
956				const int		childSize1	= 2;
957				const int		parentSize	= 4;
958				const VarType	childType0	(VarType(type, glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_HIGHP), childSize0);
959				const VarType	childType1	(childType0, childSize1);
960				const VarType	fullType	(childType1, parentSize);
961
962				layoutGroup->addChild(new BlockBasicTypeCase(m_context, typeName, "", fullType, layoutFlags[layoutFlagNdx].flags, 0));
963
964				if (glu::isDataTypeMatrix(type))
965				{
966					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
967						layoutGroup->addChild(new BlockBasicTypeCase(m_context, (string(matrixFlags[matFlagNdx].name) + "_" + typeName).c_str(), "",
968																	 fullType,
969																	 layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags, 0));
970				}
971			}
972		}
973	}
974
975	// ubo.3_level_unsized_array
976	{
977		tcu::TestCaseGroup* nestedArrayGroup = new tcu::TestCaseGroup(m_testCtx, "3_level_unsized_array", "3-level nested array, top-level array unsized");
978		addChild(nestedArrayGroup);
979
980		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
981		{
982			tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
983			nestedArrayGroup->addChild(layoutGroup);
984
985			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
986			{
987				glu::DataType	type		= basicTypes[basicTypeNdx];
988				const char*		typeName	= glu::getDataTypeName(type);
989				const int		childSize0	= 2;
990				const int		childSize1	= 4;
991				const int		parentSize	= 3;
992				const VarType	childType0	(VarType(type, glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_HIGHP), childSize0);
993				const VarType	childType1	(childType0, childSize1);
994
995				layoutGroup->addChild(new BlockBasicUnsizedArrayCase(m_context, typeName, "", childType1, parentSize, layoutFlags[layoutFlagNdx].flags));
996
997				if (glu::isDataTypeMatrix(type))
998				{
999					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
1000						layoutGroup->addChild(new BlockBasicUnsizedArrayCase(m_context, (string(matrixFlags[matFlagNdx].name) + "_" + typeName).c_str(), "",
1001																			 childType1, parentSize,
1002																			 layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags));
1003				}
1004			}
1005		}
1006	}
1007
1008	// ubo.single_struct
1009	{
1010		tcu::TestCaseGroup* singleStructGroup = new tcu::TestCaseGroup(m_testCtx, "single_struct", "Single struct in uniform block");
1011		addChild(singleStructGroup);
1012
1013		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1014		{
1015			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
1016			singleStructGroup->addChild(modeGroup);
1017
1018			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1019			{
1020				for (int isArray = 0; isArray < 2; isArray++)
1021				{
1022					const deUint32	caseFlags	= layoutFlags[layoutFlagNdx].flags;
1023					string			caseName	= layoutFlags[layoutFlagNdx].name;
1024
1025					if (bufferModes[modeNdx].mode == SSBOLayoutCase::BUFFERMODE_SINGLE && isArray == 0)
1026						continue; // Doesn't make sense to add this variant.
1027
1028					if (isArray)
1029						caseName += "_instance_array";
1030
1031					modeGroup->addChild(new BlockSingleStructCase(m_context, caseName.c_str(), "", caseFlags, bufferModes[modeNdx].mode, isArray ? 3 : 0));
1032				}
1033			}
1034		}
1035	}
1036
1037	// ubo.single_struct_array
1038	{
1039		tcu::TestCaseGroup* singleStructArrayGroup = new tcu::TestCaseGroup(m_testCtx, "single_struct_array", "Struct array in one uniform block");
1040		addChild(singleStructArrayGroup);
1041
1042		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1043		{
1044			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
1045			singleStructArrayGroup->addChild(modeGroup);
1046
1047			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1048			{
1049				for (int isArray = 0; isArray < 2; isArray++)
1050				{
1051					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
1052					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
1053
1054					if (bufferModes[modeNdx].mode == SSBOLayoutCase::BUFFERMODE_SINGLE && isArray == 0)
1055						continue; // Doesn't make sense to add this variant.
1056
1057					if (isArray)
1058						baseName += "_instance_array";
1059
1060					modeGroup->addChild(new BlockSingleStructArrayCase(m_context, baseName.c_str(),	"", baseFlags, bufferModes[modeNdx].mode, isArray ? 3 : 0));
1061				}
1062			}
1063		}
1064	}
1065
1066	// ubo.single_nested_struct
1067	{
1068		tcu::TestCaseGroup* singleNestedStructGroup = new tcu::TestCaseGroup(m_testCtx, "single_nested_struct", "Nested struct in one uniform block");
1069		addChild(singleNestedStructGroup);
1070
1071		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1072		{
1073			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
1074			singleNestedStructGroup->addChild(modeGroup);
1075
1076			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1077			{
1078				for (int isArray = 0; isArray < 2; isArray++)
1079				{
1080					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
1081					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
1082
1083					if (bufferModes[modeNdx].mode == SSBOLayoutCase::BUFFERMODE_SINGLE && isArray == 0)
1084						continue; // Doesn't make sense to add this variant.
1085
1086					if (isArray)
1087						baseName += "_instance_array";
1088
1089					modeGroup->addChild(new BlockSingleNestedStructCase(m_context, baseName.c_str(), "", baseFlags, bufferModes[modeNdx].mode, isArray ? 3 : 0));
1090				}
1091			}
1092		}
1093	}
1094
1095	// ubo.single_nested_struct_array
1096	{
1097		tcu::TestCaseGroup* singleNestedStructArrayGroup = new tcu::TestCaseGroup(m_testCtx, "single_nested_struct_array", "Nested struct array in one uniform block");
1098		addChild(singleNestedStructArrayGroup);
1099
1100		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1101		{
1102			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
1103			singleNestedStructArrayGroup->addChild(modeGroup);
1104
1105			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1106			{
1107				for (int isArray = 0; isArray < 2; isArray++)
1108				{
1109					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
1110					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
1111
1112					if (bufferModes[modeNdx].mode == SSBOLayoutCase::BUFFERMODE_SINGLE && isArray == 0)
1113						continue; // Doesn't make sense to add this variant.
1114
1115					if (isArray)
1116						baseName += "_instance_array";
1117
1118					modeGroup->addChild(new BlockSingleNestedStructArrayCase(m_context, baseName.c_str(), "", baseFlags, bufferModes[modeNdx].mode, isArray ? 3 : 0));
1119				}
1120			}
1121		}
1122	}
1123
1124	// ubo.unsized_struct_array
1125	{
1126		tcu::TestCaseGroup* singleStructArrayGroup = new tcu::TestCaseGroup(m_testCtx, "unsized_struct_array", "Unsized struct array in one uniform block");
1127		addChild(singleStructArrayGroup);
1128
1129		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1130		{
1131			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
1132			singleStructArrayGroup->addChild(modeGroup);
1133
1134			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1135			{
1136				for (int isArray = 0; isArray < 2; isArray++)
1137				{
1138					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
1139					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
1140
1141					if (bufferModes[modeNdx].mode == SSBOLayoutCase::BUFFERMODE_SINGLE && isArray == 0)
1142						continue; // Doesn't make sense to add this variant.
1143
1144					if (isArray)
1145						baseName += "_instance_array";
1146
1147					modeGroup->addChild(new BlockUnsizedStructArrayCase(m_context, baseName.c_str(),	"", baseFlags, bufferModes[modeNdx].mode, isArray ? 3 : 0));
1148				}
1149			}
1150		}
1151	}
1152
1153	// ubo.2_level_unsized_struct_array
1154	{
1155		tcu::TestCaseGroup* structArrayGroup = new tcu::TestCaseGroup(m_testCtx, "2_level_unsized_struct_array", "Unsized 2-level struct array in one uniform block");
1156		addChild(structArrayGroup);
1157
1158		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1159		{
1160			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
1161			structArrayGroup->addChild(modeGroup);
1162
1163			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1164			{
1165				for (int isArray = 0; isArray < 2; isArray++)
1166				{
1167					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
1168					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
1169
1170					if (bufferModes[modeNdx].mode == SSBOLayoutCase::BUFFERMODE_SINGLE && isArray == 0)
1171						continue; // Doesn't make sense to add this variant.
1172
1173					if (isArray)
1174						baseName += "_instance_array";
1175
1176					modeGroup->addChild(new Block2LevelUnsizedStructArrayCase(m_context, baseName.c_str(),	"", baseFlags, bufferModes[modeNdx].mode, isArray ? 3 : 0));
1177				}
1178			}
1179		}
1180	}
1181
1182	// ubo.unsized_nested_struct_array
1183	{
1184		tcu::TestCaseGroup* singleNestedStructArrayGroup = new tcu::TestCaseGroup(m_testCtx, "unsized_nested_struct_array", "Unsized, nested struct array in one uniform block");
1185		addChild(singleNestedStructArrayGroup);
1186
1187		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1188		{
1189			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
1190			singleNestedStructArrayGroup->addChild(modeGroup);
1191
1192			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1193			{
1194				for (int isArray = 0; isArray < 2; isArray++)
1195				{
1196					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
1197					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
1198
1199					if (bufferModes[modeNdx].mode == SSBOLayoutCase::BUFFERMODE_SINGLE && isArray == 0)
1200						continue; // Doesn't make sense to add this variant.
1201
1202					if (isArray)
1203						baseName += "_instance_array";
1204
1205					modeGroup->addChild(new BlockUnsizedNestedStructArrayCase(m_context, baseName.c_str(), "", baseFlags, bufferModes[modeNdx].mode, isArray ? 3 : 0));
1206				}
1207			}
1208		}
1209	}
1210
1211	// ubo.instance_array_basic_type
1212	{
1213		tcu::TestCaseGroup* instanceArrayBasicTypeGroup = new tcu::TestCaseGroup(m_testCtx, "instance_array_basic_type", "Single basic variable in instance array");
1214		addChild(instanceArrayBasicTypeGroup);
1215
1216		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1217		{
1218			tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
1219			instanceArrayBasicTypeGroup->addChild(layoutGroup);
1220
1221			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
1222			{
1223				glu::DataType	type			= basicTypes[basicTypeNdx];
1224				const char*		typeName		= glu::getDataTypeName(type);
1225				const int		numInstances	= 3;
1226
1227				layoutGroup->addChild(new BlockBasicTypeCase(m_context, typeName, "",
1228															 VarType(type, glu::isDataTypeBoolOrBVec(type) ? glu::PRECISION_LAST : glu::PRECISION_HIGHP),
1229															 layoutFlags[layoutFlagNdx].flags, numInstances));
1230
1231				if (glu::isDataTypeMatrix(type))
1232				{
1233					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
1234						layoutGroup->addChild(new BlockBasicTypeCase(m_context, (string(matrixFlags[matFlagNdx].name) + "_" + typeName).c_str(), "",
1235																	 VarType(type, glu::PRECISION_HIGHP), layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags,
1236																	 numInstances));
1237				}
1238			}
1239		}
1240	}
1241
1242	// ubo.multi_basic_types
1243	{
1244		tcu::TestCaseGroup* multiBasicTypesGroup = new tcu::TestCaseGroup(m_testCtx, "multi_basic_types", "Multiple buffers with basic types");
1245		addChild(multiBasicTypesGroup);
1246
1247		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1248		{
1249			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
1250			multiBasicTypesGroup->addChild(modeGroup);
1251
1252			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1253			{
1254				for (int isArray = 0; isArray < 2; isArray++)
1255				{
1256					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
1257					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
1258
1259					if (isArray)
1260						baseName += "_instance_array";
1261
1262					modeGroup->addChild(new BlockMultiBasicTypesCase(m_context, baseName.c_str(), "", baseFlags, baseFlags, bufferModes[modeNdx].mode, isArray ? 3 : 0));
1263				}
1264			}
1265		}
1266	}
1267
1268	// ubo.multi_nested_struct
1269	{
1270		tcu::TestCaseGroup* multiNestedStructGroup = new tcu::TestCaseGroup(m_testCtx, "multi_nested_struct", "Multiple buffers with nested structs");
1271		addChild(multiNestedStructGroup);
1272
1273		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1274		{
1275			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
1276			multiNestedStructGroup->addChild(modeGroup);
1277
1278			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1279			{
1280				for (int isArray = 0; isArray < 2; isArray++)
1281				{
1282					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
1283					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
1284
1285					if (isArray)
1286						baseName += "_instance_array";
1287
1288					modeGroup->addChild(new BlockMultiNestedStructCase(m_context, baseName.c_str(), "", baseFlags, baseFlags, bufferModes[modeNdx].mode, isArray ? 3 : 0));
1289				}
1290			}
1291		}
1292	}
1293
1294	// ubo.random
1295	{
1296		const deUint32	allLayouts		= FEATURE_PACKED_LAYOUT|FEATURE_SHARED_LAYOUT|FEATURE_STD140_LAYOUT;
1297		const deUint32	allBasicTypes	= FEATURE_VECTORS|FEATURE_MATRICES;
1298		const deUint32	unused			= FEATURE_UNUSED_MEMBERS|FEATURE_UNUSED_VARS;
1299		const deUint32	unsized			= FEATURE_UNSIZED_ARRAYS;
1300		const deUint32	matFlags		= FEATURE_MATRIX_LAYOUT;
1301
1302		tcu::TestCaseGroup* randomGroup = new tcu::TestCaseGroup(m_testCtx, "random", "Random Uniform Block cases");
1303		addChild(randomGroup);
1304
1305		// Basic types.
1306		createRandomCaseGroup(randomGroup, m_context, "scalar_types",		"Scalar types only, per-block buffers",				SSBOLayoutCase::BUFFERMODE_PER_BLOCK,	allLayouts|unused,																			25, 0);
1307		createRandomCaseGroup(randomGroup, m_context, "vector_types",		"Scalar and vector types only, per-block buffers",	SSBOLayoutCase::BUFFERMODE_PER_BLOCK,	allLayouts|unused|FEATURE_VECTORS,															25, 25);
1308		createRandomCaseGroup(randomGroup, m_context, "basic_types",		"All basic types, per-block buffers",				SSBOLayoutCase::BUFFERMODE_PER_BLOCK,	allLayouts|unused|allBasicTypes|matFlags,													25, 50);
1309		createRandomCaseGroup(randomGroup, m_context, "basic_arrays",		"Arrays, per-block buffers",						SSBOLayoutCase::BUFFERMODE_PER_BLOCK,	allLayouts|unused|allBasicTypes|matFlags|FEATURE_ARRAYS,									25, 50);
1310		createRandomCaseGroup(randomGroup, m_context, "unsized_arrays",		"Unsized arrays, per-block buffers",				SSBOLayoutCase::BUFFERMODE_PER_BLOCK,	allLayouts|unused|allBasicTypes|matFlags|unsized|FEATURE_ARRAYS,							25, 50);
1311		createRandomCaseGroup(randomGroup, m_context, "arrays_of_arrays",	"Arrays of arrays, per-block buffers",				SSBOLayoutCase::BUFFERMODE_PER_BLOCK,	allLayouts|unused|allBasicTypes|matFlags|unsized|FEATURE_ARRAYS|FEATURE_ARRAYS_OF_ARRAYS,	25, 950);
1312
1313		createRandomCaseGroup(randomGroup, m_context, "basic_instance_arrays",					"Basic instance arrays, per-block buffers",				SSBOLayoutCase::BUFFERMODE_PER_BLOCK,	allLayouts|unused|allBasicTypes|matFlags|unsized|FEATURE_INSTANCE_ARRAYS,															25, 75);
1314		createRandomCaseGroup(randomGroup, m_context, "nested_structs",							"Nested structs, per-block buffers",					SSBOLayoutCase::BUFFERMODE_PER_BLOCK,	allLayouts|unused|allBasicTypes|matFlags|unsized|FEATURE_STRUCTS,																	25, 100);
1315		createRandomCaseGroup(randomGroup, m_context, "nested_structs_arrays",					"Nested structs, arrays, per-block buffers",			SSBOLayoutCase::BUFFERMODE_PER_BLOCK,	allLayouts|unused|allBasicTypes|matFlags|unsized|FEATURE_STRUCTS|FEATURE_ARRAYS|FEATURE_ARRAYS_OF_ARRAYS,							25, 150);
1316		createRandomCaseGroup(randomGroup, m_context, "nested_structs_instance_arrays",			"Nested structs, instance arrays, per-block buffers",	SSBOLayoutCase::BUFFERMODE_PER_BLOCK,	allLayouts|unused|allBasicTypes|matFlags|unsized|FEATURE_STRUCTS|FEATURE_INSTANCE_ARRAYS,											25, 125);
1317		createRandomCaseGroup(randomGroup, m_context, "nested_structs_arrays_instance_arrays",	"Nested structs, instance arrays, per-block buffers",	SSBOLayoutCase::BUFFERMODE_PER_BLOCK,	allLayouts|unused|allBasicTypes|matFlags|unsized|FEATURE_STRUCTS|FEATURE_ARRAYS|FEATURE_ARRAYS_OF_ARRAYS|FEATURE_INSTANCE_ARRAYS,	25, 175);
1318
1319		createRandomCaseGroup(randomGroup, m_context, "all_per_block_buffers",	"All random features, per-block buffers",	SSBOLayoutCase::BUFFERMODE_PER_BLOCK,	~0u,	50, 200);
1320		createRandomCaseGroup(randomGroup, m_context, "all_shared_buffer",		"All random features, shared buffer",		SSBOLayoutCase::BUFFERMODE_SINGLE,		~0u,	50, 250);
1321	}
1322}
1323
1324} // Functional
1325} // gles31
1326} // deqp
1327