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