• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
34 namespace deqp
35 {
36 
37 using std::string;
38 using std::vector;
39 using deqp::Context;
40 
41 using namespace ub;
42 
43 enum 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 
62 class RandomUniformBlockCase : public UniformBlockCase
63 {
64 public:
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 
70 private:
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 
RandomUniformBlockCase(Context & context,const char * name,const char * description,glu::GLSLVersion glslVersion,BufferMode bufferMode,deUint32 features,deUint32 seed)91 RandomUniformBlockCase::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 
init(void)111 void 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 
generateBlock(de::Random & rnd,deUint32 layoutFlags)129 void 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 
genName(char first,char last,int ndx)171 static 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 
generateUniform(de::Random & rnd,UniformBlock & block)187 void 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 
generateType(de::Random & rnd,int typeDepth,bool arrayOk)204 VarType 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 
295 class BlockBasicTypeCase : public UniformBlockCase
296 {
297 public:
BlockBasicTypeCase(Context & context,const char * name,const char * description,glu::GLSLVersion glslVersion,const VarType & type,deUint32 layoutFlags,int numInstances)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 
createRandomCaseGroup(tcu::TestCaseGroup * parentGroup,Context & context,const char * groupName,const char * description,glu::GLSLVersion glslVersion,UniformBlockCase::BufferMode bufferMode,deUint32 features,int numCases,deUint32 baseSeed)314 static 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 
329 class BlockSingleStructCase : public UniformBlockCase
330 {
331 public:
BlockSingleStructCase(Context & context,const char * name,const char * description,glu::GLSLVersion glslVersion,deUint32 layoutFlags,BufferMode bufferMode,int numInstances)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 
init(void)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 
358 private:
359 	deUint32 m_layoutFlags;
360 	int		 m_numInstances;
361 };
362 
363 class BlockSingleStructArrayCase : public UniformBlockCase
364 {
365 public:
BlockSingleStructArrayCase(Context & context,const char * name,const char * description,glu::GLSLVersion glslVersion,deUint32 layoutFlags,BufferMode bufferMode,int numInstances)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 
init(void)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 
395 private:
396 	deUint32 m_layoutFlags;
397 	int		 m_numInstances;
398 };
399 
400 class BlockSingleNestedStructCase : public UniformBlockCase
401 {
402 public:
BlockSingleNestedStructCase(Context & context,const char * name,const char * description,glu::GLSLVersion glslVersion,deUint32 layoutFlags,BufferMode bufferMode,int numInstances)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 
init(void)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 
437 private:
438 	deUint32 m_layoutFlags;
439 	int		 m_numInstances;
440 };
441 
442 class BlockSingleNestedStructArrayCase : public UniformBlockCase
443 {
444 public:
BlockSingleNestedStructArrayCase(Context & context,const char * name,const char * description,glu::GLSLVersion glslVersion,deUint32 layoutFlags,BufferMode bufferMode,int numInstances)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 
init(void)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 
479 private:
480 	deUint32 m_layoutFlags;
481 	int		 m_numInstances;
482 };
483 
484 class BlockMultiBasicTypesCase : public UniformBlockCase
485 {
486 public:
BlockMultiBasicTypesCase(Context & context,const char * name,const char * description,glu::GLSLVersion glslVersion,deUint32 flagsA,deUint32 flagsB,BufferMode bufferMode,int numInstances)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 
init(void)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 
520 private:
521 	deUint32 m_flagsA;
522 	deUint32 m_flagsB;
523 	int		 m_numInstances;
524 };
525 
526 class BlockMultiNestedStructCase : public UniformBlockCase
527 {
528 public:
BlockMultiNestedStructCase(Context & context,const char * name,const char * description,glu::GLSLVersion glslVersion,deUint32 flagsA,deUint32 flagsB,BufferMode bufferMode,int numInstances)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 
init(void)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 
573 private:
574 	deUint32 m_flagsA;
575 	deUint32 m_flagsB;
576 	int		 m_numInstances;
577 };
578 
579 class UniformBlockPrecisionMatching : public TestCase
580 {
581 public:
UniformBlockPrecisionMatching(Context & context,glu::GLSLVersion glslVersion)582 	UniformBlockPrecisionMatching(Context& context, glu::GLSLVersion glslVersion)
583 		: TestCase(context, "precision_matching", ""), m_glslVersion(glslVersion)
584 	{
585 	}
586 
iterate(void)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 
Link(const std::string & vs,const std::string & fs)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 
678 private:
679 	glu::GLSLVersion m_glslVersion;
680 };
681 
682 class UniformBlockNameMatching : public TestCase
683 {
684 public:
UniformBlockNameMatching(Context & context,glu::GLSLVersion glslVersion)685 	UniformBlockNameMatching(Context& context, glu::GLSLVersion glslVersion)
686 		: TestCase(context, "name_matching", ""), m_glslVersion(glslVersion)
687 	{
688 	}
689 
iterate(void)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 
Test(const std::string & vs,const std::string & fs,glw::GLint expectedLinkStatus)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 
867 private:
868 	glu::GLSLVersion m_glslVersion;
869 };
870 
UniformBlockTests(Context & context,glu::GLSLVersion glslVersion)871 UniformBlockTests::UniformBlockTests(Context& context, glu::GLSLVersion glslVersion)
872 	: TestCaseGroup(context, "uniform_block", "Uniform Block tests"), m_glslVersion(glslVersion)
873 {
874 }
875 
~UniformBlockTests(void)876 UniformBlockTests::~UniformBlockTests(void)
877 {
878 }
879 
init(void)880 void 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