• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2015 The Khronos Group Inc.
6  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
7  * Copyright (c) 2016 The Android Open Source Project
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*!
22  * \file
23  * \brief Uniform block tests.
24  *//*--------------------------------------------------------------------*/
25 
26 #include "vktUniformBlockTests.hpp"
27 
28 #include "vktUniformBlockCase.hpp"
29 #include "vktRandomUniformBlockCase.hpp"
30 
31 #include "tcuCommandLine.hpp"
32 #include "deStringUtil.hpp"
33 
34 namespace vkt
35 {
36 namespace ubo
37 {
38 
39 namespace
40 {
41 
42 class BlockBasicTypeCase : public UniformBlockCase
43 {
44 public:
BlockBasicTypeCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const VarType & type,deUint32 layoutFlags,int numInstances,MatrixLoadFlags matrixLoadFlag)45 	BlockBasicTypeCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const VarType& type, deUint32 layoutFlags, int numInstances, MatrixLoadFlags matrixLoadFlag)
46 		: UniformBlockCase(testCtx, name, description, BUFFERMODE_PER_BLOCK, matrixLoadFlag)
47 	{
48 		UniformBlock& block = m_interface.allocBlock("Block");
49 		block.addUniform(Uniform("var", type, 0));
50 		block.setFlags(layoutFlags);
51 
52 		if (numInstances > 0)
53 		{
54 			block.setArraySize(numInstances);
55 			block.setInstanceName("block");
56 		}
57 
58 		init();
59 	}
60 };
61 
createBlockBasicTypeCases(tcu::TestCaseGroup * group,tcu::TestContext & testCtx,const std::string & name,const VarType & type,deUint32 layoutFlags,int numInstances=0)62 static void createBlockBasicTypeCases (tcu::TestCaseGroup* group, tcu::TestContext& testCtx, const std::string& name, const VarType& type, deUint32 layoutFlags, int numInstances = 0)
63 {
64 	group->addChild(new BlockBasicTypeCase(testCtx, name + "_vertex",			"", type, layoutFlags|DECLARE_VERTEX,						numInstances, LOAD_FULL_MATRIX));
65 	group->addChild(new BlockBasicTypeCase(testCtx, name + "_fragment",			"", type, layoutFlags|DECLARE_FRAGMENT,						numInstances, LOAD_FULL_MATRIX));
66 	group->addChild(new BlockBasicTypeCase(testCtx, name + "_both",				"",	type, layoutFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,		numInstances, LOAD_FULL_MATRIX));
67 	group->addChild(new BlockBasicTypeCase(testCtx, name + "_vertex_comp_access",		"", type, layoutFlags|DECLARE_VERTEX,				numInstances, LOAD_MATRIX_COMPONENTS));
68 	group->addChild(new BlockBasicTypeCase(testCtx, name + "_fragment_comp_access",	"", type, layoutFlags|DECLARE_FRAGMENT,					numInstances, LOAD_MATRIX_COMPONENTS));
69 	group->addChild(new BlockBasicTypeCase(testCtx, name + "_both_comp_access",		"",	type, layoutFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	numInstances, LOAD_MATRIX_COMPONENTS));
70 }
71 
72 class BlockSingleStructCase : public UniformBlockCase
73 {
74 public:
BlockSingleStructCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,deUint32 layoutFlags,BufferMode bufferMode,int numInstances,MatrixLoadFlags matrixLoadFlag)75 	BlockSingleStructCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag)
76 		: UniformBlockCase	(testCtx, name, description, bufferMode, matrixLoadFlag)
77 	{
78 		StructType& typeS = m_interface.allocStruct("S");
79 		typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH), UNUSED_BOTH); // First member is unused.
80 		typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM), 4));
81 		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH));
82 
83 		UniformBlock& block = m_interface.allocBlock("Block");
84 		block.addUniform(Uniform("s", VarType(&typeS), 0));
85 		block.setFlags(layoutFlags);
86 
87 		if (numInstances > 0)
88 		{
89 			block.setInstanceName("block");
90 			block.setArraySize(numInstances);
91 		}
92 
93 		init();
94 	}
95 };
96 
97 class BlockSingleStructArrayCase : public UniformBlockCase
98 {
99 public:
BlockSingleStructArrayCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,deUint32 layoutFlags,BufferMode bufferMode,int numInstances,MatrixLoadFlags matrixLoadFlag)100 	BlockSingleStructArrayCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag)
101 		: UniformBlockCase	(testCtx, name, description, bufferMode, matrixLoadFlag)
102 	{
103 		StructType& typeS = m_interface.allocStruct("S");
104 		typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH), UNUSED_BOTH);
105 		typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM), 4));
106 		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH));
107 
108 		UniformBlock& block = m_interface.allocBlock("Block");
109 		block.addUniform(Uniform("u", VarType(glu::TYPE_UINT, PRECISION_LOW)));
110 		block.addUniform(Uniform("s", VarType(VarType(&typeS), 3)));
111 		block.addUniform(Uniform("v", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_MEDIUM)));
112 		block.setFlags(layoutFlags);
113 
114 		if (numInstances > 0)
115 		{
116 			block.setInstanceName("block");
117 			block.setArraySize(numInstances);
118 		}
119 
120 		init();
121 	}
122 };
123 
124 class BlockSingleNestedStructCase : public UniformBlockCase
125 {
126 public:
BlockSingleNestedStructCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,deUint32 layoutFlags,BufferMode bufferMode,int numInstances,MatrixLoadFlags matrixLoadFlag)127 	BlockSingleNestedStructCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag)
128 		: UniformBlockCase	(testCtx, name, description, bufferMode, matrixLoadFlag)
129 	{
130 		StructType& typeS = m_interface.allocStruct("S");
131 		typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH));
132 		typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM), 4));
133 		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH), UNUSED_BOTH);
134 
135 		StructType& typeT = m_interface.allocStruct("T");
136 		typeT.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM));
137 		typeT.addMember("b", VarType(&typeS));
138 
139 		UniformBlock& block = m_interface.allocBlock("Block");
140 		block.addUniform(Uniform("s", VarType(&typeS), 0));
141 		block.addUniform(Uniform("v", VarType(glu::TYPE_FLOAT_VEC2, PRECISION_LOW), UNUSED_BOTH));
142 		block.addUniform(Uniform("t", VarType(&typeT), 0));
143 		block.addUniform(Uniform("u", VarType(glu::TYPE_UINT, PRECISION_HIGH), 0));
144 		block.setFlags(layoutFlags);
145 
146 		if (numInstances > 0)
147 		{
148 			block.setInstanceName("block");
149 			block.setArraySize(numInstances);
150 		}
151 
152 		init();
153 	}
154 };
155 
156 class BlockSingleNestedStructArrayCase : public UniformBlockCase
157 {
158 public:
BlockSingleNestedStructArrayCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,deUint32 layoutFlags,BufferMode bufferMode,int numInstances,MatrixLoadFlags matrixLoadFlag)159 	BlockSingleNestedStructArrayCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag)
160 		: UniformBlockCase	(testCtx, name, description, bufferMode, matrixLoadFlag)
161 	{
162 		StructType& typeS = m_interface.allocStruct("S");
163 		typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH));
164 		typeS.addMember("b", VarType(VarType(glu::TYPE_INT_VEC2, PRECISION_MEDIUM), 4));
165 		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH), UNUSED_BOTH);
166 
167 		StructType& typeT = m_interface.allocStruct("T");
168 		typeT.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM));
169 		typeT.addMember("b", VarType(VarType(&typeS), 3));
170 
171 		UniformBlock& block = m_interface.allocBlock("Block");
172 		block.addUniform(Uniform("s", VarType(&typeS), 0));
173 		block.addUniform(Uniform("v", VarType(glu::TYPE_FLOAT_VEC2, PRECISION_LOW), UNUSED_BOTH));
174 		block.addUniform(Uniform("t", VarType(VarType(&typeT), 2), 0));
175 		block.addUniform(Uniform("u", VarType(glu::TYPE_UINT, PRECISION_HIGH), 0));
176 		block.setFlags(layoutFlags);
177 
178 		if (numInstances > 0)
179 		{
180 			block.setInstanceName("block");
181 			block.setArraySize(numInstances);
182 		}
183 
184 		init();
185 	}
186 };
187 
188 class BlockMultiBasicTypesCase : public UniformBlockCase
189 {
190 public:
BlockMultiBasicTypesCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,deUint32 flagsA,deUint32 flagsB,BufferMode bufferMode,int numInstances,MatrixLoadFlags matrixLoadFlag)191 	BlockMultiBasicTypesCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, deUint32 flagsA, deUint32 flagsB, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag)
192 		: UniformBlockCase	(testCtx, name, description, bufferMode, matrixLoadFlag)
193 	{
194 		UniformBlock& blockA = m_interface.allocBlock("BlockA");
195 		blockA.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT, PRECISION_HIGH)));
196 		blockA.addUniform(Uniform("b", VarType(glu::TYPE_UINT_VEC3, PRECISION_LOW), UNUSED_BOTH));
197 		blockA.addUniform(Uniform("c", VarType(glu::TYPE_FLOAT_MAT2, PRECISION_MEDIUM)));
198 		blockA.setInstanceName("blockA");
199 		blockA.setFlags(flagsA);
200 
201 		UniformBlock& blockB = m_interface.allocBlock("BlockB");
202 		blockB.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM)));
203 		blockB.addUniform(Uniform("b", VarType(glu::TYPE_INT_VEC2, PRECISION_LOW)));
204 		blockB.addUniform(Uniform("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH), UNUSED_BOTH));
205 		blockB.addUniform(Uniform("d", VarType(glu::TYPE_BOOL, 0)));
206 		blockB.setInstanceName("blockB");
207 		blockB.setFlags(flagsB);
208 
209 		if (numInstances > 0)
210 		{
211 			blockA.setArraySize(numInstances);
212 			blockB.setArraySize(numInstances);
213 		}
214 
215 		init();
216 	}
217 };
218 
219 class BlockMultiNestedStructCase : public UniformBlockCase
220 {
221 public:
BlockMultiNestedStructCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,deUint32 flagsA,deUint32 flagsB,BufferMode bufferMode,int numInstances,MatrixLoadFlags matrixLoadFlag)222 	BlockMultiNestedStructCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, deUint32 flagsA, deUint32 flagsB, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag)
223 		: UniformBlockCase	(testCtx, name, description, bufferMode, matrixLoadFlag)
224 	{
225 		StructType& typeS = m_interface.allocStruct("S");
226 		typeS.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_LOW));
227 		typeS.addMember("b", VarType(VarType(glu::TYPE_INT_VEC2, PRECISION_MEDIUM), 4));
228 		typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH));
229 
230 		StructType& typeT = m_interface.allocStruct("T");
231 		typeT.addMember("a", VarType(glu::TYPE_UINT, PRECISION_MEDIUM), UNUSED_BOTH);
232 		typeT.addMember("b", VarType(&typeS));
233 		typeT.addMember("c", VarType(glu::TYPE_BOOL_VEC4, 0));
234 
235 		UniformBlock& blockA = m_interface.allocBlock("BlockA");
236 		blockA.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT, PRECISION_HIGH)));
237 		blockA.addUniform(Uniform("b", VarType(&typeS)));
238 		blockA.addUniform(Uniform("c", VarType(glu::TYPE_UINT_VEC3, PRECISION_LOW), UNUSED_BOTH));
239 		blockA.setInstanceName("blockA");
240 		blockA.setFlags(flagsA);
241 
242 		UniformBlock& blockB = m_interface.allocBlock("BlockB");
243 		blockB.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT_MAT2, PRECISION_MEDIUM)));
244 		blockB.addUniform(Uniform("b", VarType(&typeT)));
245 		blockB.addUniform(Uniform("c", VarType(glu::TYPE_BOOL_VEC4, 0), UNUSED_BOTH));
246 		blockB.addUniform(Uniform("d", VarType(glu::TYPE_BOOL, 0)));
247 		blockB.setInstanceName("blockB");
248 		blockB.setFlags(flagsB);
249 
250 		if (numInstances > 0)
251 		{
252 			blockA.setArraySize(numInstances);
253 			blockB.setArraySize(numInstances);
254 		}
255 
256 		init();
257 	}
258 };
259 
260 class Block2LevelStructArrayCase : public UniformBlockCase
261 {
262 public:
Block2LevelStructArrayCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,deUint32 layoutFlags,BufferMode bufferMode,int numInstances,MatrixLoadFlags matrixLoadFlag)263 	Block2LevelStructArrayCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag)
264 		: UniformBlockCase	(testCtx, name, description, bufferMode, matrixLoadFlag)
265 		, m_layoutFlags		(layoutFlags)
266 		, m_numInstances	(numInstances)
267 	{
268 		StructType& typeS = m_interface.allocStruct("S");
269 		typeS.addMember("a", VarType(glu::TYPE_UINT_VEC3, PRECISION_HIGH), UNUSED_BOTH);
270 		typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT2, PRECISION_MEDIUM), 4));
271 		typeS.addMember("c", VarType(glu::TYPE_UINT, PRECISION_LOW));
272 
273 		UniformBlock& block = m_interface.allocBlock("Block");
274 		block.addUniform(Uniform("u", VarType(glu::TYPE_INT, PRECISION_MEDIUM)));
275 		block.addUniform(Uniform("s", VarType(VarType(VarType(&typeS), 3), 2)));
276 		block.addUniform(Uniform("v", VarType(glu::TYPE_FLOAT_VEC2, PRECISION_MEDIUM)));
277 		block.setFlags(m_layoutFlags);
278 
279 		if (m_numInstances > 0)
280 		{
281 			block.setInstanceName("block");
282 			block.setArraySize(m_numInstances);
283 		}
284 
285 		init();
286 	}
287 
288 private:
289 	deUint32	m_layoutFlags;
290 	int			m_numInstances;
291 };
292 
293 class LinkByBindingCase : public UniformBlockCase
294 {
295 public:
LinkByBindingCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,BufferMode bufferMode,int numInstances)296 	LinkByBindingCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, BufferMode bufferMode, int numInstances)
297 		: UniformBlockCase	(testCtx, name, description, bufferMode, LOAD_FULL_MATRIX)
298 	{
299 		UniformBlock& blockA = m_interface.allocBlock("TestBlock");
300 		blockA.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT, PRECISION_HIGH)));
301 		blockA.addUniform(Uniform("b", VarType(glu::TYPE_UINT_VEC3, PRECISION_LOW), UNUSED_BOTH));
302 		blockA.addUniform(Uniform("c", VarType(glu::TYPE_FLOAT_MAT2, PRECISION_MEDIUM)));
303 		blockA.setFlags(LAYOUT_STD140|DECLARE_VERTEX);
304 
305 		UniformBlock& blockB = m_interface.allocBlock("TestBlock");
306 		blockB.addUniform(Uniform("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM)));
307 		blockB.addUniform(Uniform("b", VarType(glu::TYPE_INT_VEC2, PRECISION_LOW)));
308 		blockB.addUniform(Uniform("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH), UNUSED_BOTH));
309 		blockB.addUniform(Uniform("d", VarType(glu::TYPE_BOOL, 0)));
310 		blockB.setFlags(LAYOUT_STD140|DECLARE_FRAGMENT);
311 
312 		if (numInstances > 0)
313 		{
314 			blockA.setInstanceName("testBlock");
315 			blockA.setArraySize(numInstances);
316 			blockB.setInstanceName("testBlock");
317 			blockB.setArraySize(numInstances);
318 		}
319 
320 		init();
321 	}
322 };
323 
createRandomCaseGroup(tcu::TestCaseGroup * parentGroup,tcu::TestContext & testCtx,const char * groupName,const char * description,UniformBlockCase::BufferMode bufferMode,deUint32 features,int numCases,deUint32 baseSeed)324 void createRandomCaseGroup (tcu::TestCaseGroup* parentGroup, tcu::TestContext& testCtx, const char* groupName, const char* description, UniformBlockCase::BufferMode bufferMode, deUint32 features, int numCases, deUint32 baseSeed)
325 {
326 	tcu::TestCaseGroup* group = new tcu::TestCaseGroup(testCtx, groupName, description);
327 	parentGroup->addChild(group);
328 
329 	baseSeed += (deUint32)testCtx.getCommandLine().getBaseSeed();
330 
331 	for (int ndx = 0; ndx < numCases; ndx++)
332 		group->addChild(new RandomUniformBlockCase(testCtx, de::toString(ndx), "", bufferMode, features, (deUint32)ndx + baseSeed));
333 }
334 
335 // UniformBlockTests
336 
337 class UniformBlockTests : public tcu::TestCaseGroup
338 {
339 public:
340 							UniformBlockTests		(tcu::TestContext& testCtx);
341 							~UniformBlockTests		(void);
342 
343 	void					init					(void);
344 
345 private:
346 							UniformBlockTests		(const UniformBlockTests& other);
347 	UniformBlockTests&		operator=				(const UniformBlockTests& other);
348 };
349 
UniformBlockTests(tcu::TestContext & testCtx)350 UniformBlockTests::UniformBlockTests (tcu::TestContext& testCtx)
351 	: TestCaseGroup(testCtx, "ubo", "Uniform Block tests")
352 {
353 }
354 
~UniformBlockTests(void)355 UniformBlockTests::~UniformBlockTests (void)
356 {
357 }
358 
init(void)359 void UniformBlockTests::init (void)
360 {
361 	static const glu::DataType basicTypes[] =
362 	{
363 		glu::TYPE_FLOAT,
364 		glu::TYPE_FLOAT_VEC2,
365 		glu::TYPE_FLOAT_VEC3,
366 		glu::TYPE_FLOAT_VEC4,
367 		glu::TYPE_INT,
368 		glu::TYPE_INT_VEC2,
369 		glu::TYPE_INT_VEC3,
370 		glu::TYPE_INT_VEC4,
371 		glu::TYPE_UINT,
372 		glu::TYPE_UINT_VEC2,
373 		glu::TYPE_UINT_VEC3,
374 		glu::TYPE_UINT_VEC4,
375 		glu::TYPE_BOOL,
376 		glu::TYPE_BOOL_VEC2,
377 		glu::TYPE_BOOL_VEC3,
378 		glu::TYPE_BOOL_VEC4,
379 		glu::TYPE_FLOAT_MAT2,
380 		glu::TYPE_FLOAT_MAT3,
381 		glu::TYPE_FLOAT_MAT4,
382 		glu::TYPE_FLOAT_MAT2X3,
383 		glu::TYPE_FLOAT_MAT2X4,
384 		glu::TYPE_FLOAT_MAT3X2,
385 		glu::TYPE_FLOAT_MAT3X4,
386 		glu::TYPE_FLOAT_MAT4X2,
387 		glu::TYPE_FLOAT_MAT4X3
388 	};
389 
390 	static const struct
391 	{
392 		const std::string	name;
393 		deUint32			flags;
394 	} precisionFlags[] =
395 	{
396 		// TODO remove PRECISION_LOW because both PRECISION_LOW and PRECISION_MEDIUM means relaxed precision?
397 		{ "lowp",		PRECISION_LOW		},
398 		{ "mediump",	PRECISION_MEDIUM	},
399 		{ "highp",		PRECISION_HIGH		}
400 	};
401 
402 	static const struct
403 	{
404 		const char*			name;
405 		deUint32			flags;
406 	} layoutFlags[] =
407 	{
408 		{ "std140",		LAYOUT_STD140	}
409 	};
410 
411 	static const struct
412 	{
413 		const std::string	name;
414 		deUint32			flags;
415 	} matrixFlags[] =
416 	{
417 		{ "row_major",		LAYOUT_ROW_MAJOR	},
418 		{ "column_major",	LAYOUT_COLUMN_MAJOR }
419 	};
420 
421 	static const struct
422 	{
423 		const char*							name;
424 		UniformBlockCase::BufferMode		mode;
425 	} bufferModes[] =
426 	{
427 		{ "per_block_buffer",	UniformBlockCase::BUFFERMODE_PER_BLOCK },
428 		{ "single_buffer",		UniformBlockCase::BUFFERMODE_SINGLE	}
429 	};
430 
431 	// ubo.2_level_array
432 	{
433 		tcu::TestCaseGroup* nestedArrayGroup = new tcu::TestCaseGroup(m_testCtx, "2_level_array", "2-level basic array variable in single buffer");
434 		addChild(nestedArrayGroup);
435 
436 		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
437 		{
438 			tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
439 			nestedArrayGroup->addChild(layoutGroup);
440 
441 			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
442 			{
443 				const glu::DataType	type		= basicTypes[basicTypeNdx];
444 				const char*			typeName	= glu::getDataTypeName(type);
445 				const int			childSize	= 4;
446 				const int			parentSize	= 3;
447 				const VarType		childType	(VarType(type, glu::isDataTypeBoolOrBVec(type) ? 0 : PRECISION_HIGH), childSize);
448 				const VarType		parentType	(childType, parentSize);
449 
450 				createBlockBasicTypeCases(layoutGroup, m_testCtx, typeName, parentType, layoutFlags[layoutFlagNdx].flags);
451 
452 				if (glu::isDataTypeMatrix(type))
453 				{
454 					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
455 						createBlockBasicTypeCases(layoutGroup, m_testCtx, (std::string(matrixFlags[matFlagNdx].name) + "_" + typeName),
456 												  parentType, layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags);
457 				}
458 			}
459 		}
460 	}
461 
462 	// ubo.3_level_array
463 	{
464 		tcu::TestCaseGroup* nestedArrayGroup = new tcu::TestCaseGroup(m_testCtx, "3_level_array", "3-level basic array variable in single buffer");
465 		addChild(nestedArrayGroup);
466 
467 		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
468 		{
469 			tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
470 			nestedArrayGroup->addChild(layoutGroup);
471 
472 			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
473 			{
474 				const glu::DataType	type		= basicTypes[basicTypeNdx];
475 				const char*			typeName	= glu::getDataTypeName(type);
476 				const int			childSize0	= 2;
477 				const int			childSize1	= 4;
478 				const int			parentSize	= 3;
479 				const VarType		childType0	(VarType(type, glu::isDataTypeBoolOrBVec(type) ? 0 : PRECISION_HIGH), childSize0);
480 				const VarType		childType1	(childType0, childSize1);
481 				const VarType		parentType	(childType1, parentSize);
482 
483 				createBlockBasicTypeCases(layoutGroup, m_testCtx, typeName, parentType, layoutFlags[layoutFlagNdx].flags);
484 
485 				if (glu::isDataTypeMatrix(type))
486 				{
487 					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
488 						createBlockBasicTypeCases(layoutGroup, m_testCtx, (std::string(matrixFlags[matFlagNdx].name) + "_" + typeName),
489 												  parentType, layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags);
490 				}
491 			}
492 		}
493 	}
494 
495 	// ubo.2_level_struct_array
496 	{
497 		tcu::TestCaseGroup* structArrayArrayGroup = new tcu::TestCaseGroup(m_testCtx, "2_level_struct_array", "Struct array in one uniform block");
498 		addChild(structArrayArrayGroup);
499 
500 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
501 		{
502 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
503 			structArrayArrayGroup->addChild(modeGroup);
504 
505 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
506 			{
507 				for (int isArray = 0; isArray < 2; isArray++)
508 				{
509 					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
510 					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
511 
512 					if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
513 						continue; // Doesn't make sense to add this variant.
514 
515 					if (isArray)
516 						baseName += "_instance_array";
517 
518 					modeGroup->addChild(new Block2LevelStructArrayCase(m_testCtx, (baseName + "_vertex"),				"", baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
519 					modeGroup->addChild(new Block2LevelStructArrayCase(m_testCtx, (baseName + "_fragment"),				"", baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
520 					modeGroup->addChild(new Block2LevelStructArrayCase(m_testCtx, (baseName + "_both"),					"", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
521 					modeGroup->addChild(new Block2LevelStructArrayCase(m_testCtx, (baseName + "_vertex_comp_access"),	"", baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
522 					modeGroup->addChild(new Block2LevelStructArrayCase(m_testCtx, (baseName + "_fragment_comp_access"),	"", baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
523 					modeGroup->addChild(new Block2LevelStructArrayCase(m_testCtx, (baseName + "_both_comp_access"),		"", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
524 				}
525 			}
526 		}
527 	}
528 
529 	// ubo.single_basic_type
530 	{
531 		tcu::TestCaseGroup* singleBasicTypeGroup = new tcu::TestCaseGroup(m_testCtx, "single_basic_type", "Single basic variable in single buffer");
532 		addChild(singleBasicTypeGroup);
533 
534 		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
535 		{
536 			tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
537 			singleBasicTypeGroup->addChild(layoutGroup);
538 
539 			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
540 			{
541 				glu::DataType	type		= basicTypes[basicTypeNdx];
542 				const char*		typeName	= glu::getDataTypeName(type);
543 
544 				if (glu::isDataTypeBoolOrBVec(type))
545 					createBlockBasicTypeCases(layoutGroup, m_testCtx, typeName, VarType(type, 0), layoutFlags[layoutFlagNdx].flags);
546 				else
547 				{
548 					for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisionFlags); precNdx++)
549 						createBlockBasicTypeCases(layoutGroup, m_testCtx, precisionFlags[precNdx].name + "_" + typeName,
550 												  VarType(type, precisionFlags[precNdx].flags), layoutFlags[layoutFlagNdx].flags);
551 				}
552 
553 				if (glu::isDataTypeMatrix(type))
554 				{
555 					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
556 					{
557 						for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisionFlags); precNdx++)
558 							createBlockBasicTypeCases(layoutGroup, m_testCtx, matrixFlags[matFlagNdx].name + "_" + precisionFlags[precNdx].name + "_" + typeName,
559 													  VarType(type, precisionFlags[precNdx].flags), layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags);
560 					}
561 				}
562 			}
563 		}
564 	}
565 
566 	// ubo.single_basic_array
567 	{
568 		tcu::TestCaseGroup* singleBasicArrayGroup = new tcu::TestCaseGroup(m_testCtx, "single_basic_array", "Single basic array variable in single buffer");
569 		addChild(singleBasicArrayGroup);
570 
571 		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
572 		{
573 			tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
574 			singleBasicArrayGroup->addChild(layoutGroup);
575 
576 			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
577 			{
578 				glu::DataType	type		= basicTypes[basicTypeNdx];
579 				const char*		typeName	= glu::getDataTypeName(type);
580 				const int		arraySize	= 3;
581 
582 				createBlockBasicTypeCases(layoutGroup, m_testCtx, typeName,
583 										  VarType(VarType(type, glu::isDataTypeBoolOrBVec(type) ? 0 : PRECISION_HIGH), arraySize),
584 										  layoutFlags[layoutFlagNdx].flags);
585 
586 				if (glu::isDataTypeMatrix(type))
587 				{
588 					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
589 						createBlockBasicTypeCases(layoutGroup, m_testCtx, matrixFlags[matFlagNdx].name + "_" + typeName,
590 												  VarType(VarType(type, PRECISION_HIGH), arraySize),
591 												  layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags);
592 				}
593 			}
594 		}
595 	}
596 
597 	// ubo.single_struct
598 	{
599 		tcu::TestCaseGroup* singleStructGroup = new tcu::TestCaseGroup(m_testCtx, "single_struct", "Single struct in uniform block");
600 		addChild(singleStructGroup);
601 
602 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
603 		{
604 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
605 			singleStructGroup->addChild(modeGroup);
606 
607 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
608 			{
609 				for (int isArray = 0; isArray < 2; isArray++)
610 				{
611 					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
612 					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
613 
614 					if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
615 						continue; // Doesn't make sense to add this variant.
616 
617 					if (isArray)
618 						baseName += "_instance_array";
619 
620 					modeGroup->addChild(new BlockSingleStructCase(m_testCtx, baseName + "_vertex",				 "", baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
621 					modeGroup->addChild(new BlockSingleStructCase(m_testCtx, baseName + "_fragment",			 "", baseFlags|DECLARE_FRAGMENT,				bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
622 					modeGroup->addChild(new BlockSingleStructCase(m_testCtx, baseName + "_both",				 "", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
623 					modeGroup->addChild(new BlockSingleStructCase(m_testCtx, baseName + "_vertex_comp_access",	 "", baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
624 					modeGroup->addChild(new BlockSingleStructCase(m_testCtx, baseName + "_fragment_comp_access", "", baseFlags|DECLARE_FRAGMENT,				bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
625 					modeGroup->addChild(new BlockSingleStructCase(m_testCtx, baseName + "_both_comp_access",	 "", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
626 				}
627 			}
628 		}
629 	}
630 
631 	// ubo.single_struct_array
632 	{
633 		tcu::TestCaseGroup* singleStructArrayGroup = new tcu::TestCaseGroup(m_testCtx, "single_struct_array", "Struct array in one uniform block");
634 		addChild(singleStructArrayGroup);
635 
636 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
637 		{
638 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
639 			singleStructArrayGroup->addChild(modeGroup);
640 
641 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
642 			{
643 				for (int isArray = 0; isArray < 2; isArray++)
644 				{
645 					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
646 					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
647 
648 					if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
649 						continue; // Doesn't make sense to add this variant.
650 
651 					if (isArray)
652 						baseName += "_instance_array";
653 
654 					modeGroup->addChild(new BlockSingleStructArrayCase(m_testCtx, baseName + "_vertex",				  "", baseFlags|DECLARE_VERTEX,						bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
655 					modeGroup->addChild(new BlockSingleStructArrayCase(m_testCtx, baseName + "_fragment",			  "", baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
656 					modeGroup->addChild(new BlockSingleStructArrayCase(m_testCtx, baseName + "_both",				  "",	baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
657 					modeGroup->addChild(new BlockSingleStructArrayCase(m_testCtx, baseName + "_vertex_comp_access",	  "", baseFlags|DECLARE_VERTEX,						bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
658 					modeGroup->addChild(new BlockSingleStructArrayCase(m_testCtx, baseName + "_fragment_comp_access", "", baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
659 					modeGroup->addChild(new BlockSingleStructArrayCase(m_testCtx, baseName + "_both_comp_access",	  "",	baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
660 				}
661 			}
662 		}
663 	}
664 
665 	// ubo.single_nested_struct
666 	{
667 		tcu::TestCaseGroup* singleNestedStructGroup = new tcu::TestCaseGroup(m_testCtx, "single_nested_struct", "Nested struct in one uniform block");
668 		addChild(singleNestedStructGroup);
669 
670 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
671 		{
672 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
673 			singleNestedStructGroup->addChild(modeGroup);
674 
675 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
676 			{
677 				for (int isArray = 0; isArray < 2; isArray++)
678 				{
679 					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
680 					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
681 
682 					if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
683 						continue; // Doesn't make sense to add this variant.
684 
685 					if (isArray)
686 						baseName += "_instance_array";
687 
688 					modeGroup->addChild(new BlockSingleNestedStructCase(m_testCtx, baseName + "_vertex",				"", baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
689 					modeGroup->addChild(new BlockSingleNestedStructCase(m_testCtx, baseName + "_fragment",				"", baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
690 					modeGroup->addChild(new BlockSingleNestedStructCase(m_testCtx, baseName + "_both",					"", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
691 					modeGroup->addChild(new BlockSingleNestedStructCase(m_testCtx, baseName + "_vertex_comp_access",	"", baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
692 					modeGroup->addChild(new BlockSingleNestedStructCase(m_testCtx, baseName + "_fragment_comp_access",	"", baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
693 					modeGroup->addChild(new BlockSingleNestedStructCase(m_testCtx, baseName + "_both_comp_access",		"", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
694 				}
695 			}
696 		}
697 	}
698 
699 	// ubo.single_nested_struct_array
700 	{
701 		tcu::TestCaseGroup* singleNestedStructArrayGroup = new tcu::TestCaseGroup(m_testCtx, "single_nested_struct_array", "Nested struct array in one uniform block");
702 		addChild(singleNestedStructArrayGroup);
703 
704 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
705 		{
706 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
707 			singleNestedStructArrayGroup->addChild(modeGroup);
708 
709 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
710 			{
711 				for (int isArray = 0; isArray < 2; isArray++)
712 				{
713 					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
714 					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
715 
716 					if (bufferModes[modeNdx].mode == UniformBlockCase::BUFFERMODE_SINGLE && isArray == 0)
717 						continue; // Doesn't make sense to add this variant.
718 
719 					if (isArray)
720 						baseName += "_instance_array";
721 
722 					modeGroup->addChild(new BlockSingleNestedStructArrayCase(m_testCtx, baseName + "_vertex",				"", baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
723 					modeGroup->addChild(new BlockSingleNestedStructArrayCase(m_testCtx, baseName + "_fragment",				"", baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
724 					modeGroup->addChild(new BlockSingleNestedStructArrayCase(m_testCtx, baseName + "_both",					"",	baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
725 					modeGroup->addChild(new BlockSingleNestedStructArrayCase(m_testCtx, baseName + "_vertex_comp_access",	"", baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
726 					modeGroup->addChild(new BlockSingleNestedStructArrayCase(m_testCtx, baseName + "_fragment_comp_access",	"", baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
727 					modeGroup->addChild(new BlockSingleNestedStructArrayCase(m_testCtx, baseName + "_both_comp_access",		"",	baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
728 				}
729 			}
730 		}
731 	}
732 
733 	// ubo.instance_array_basic_type
734 	{
735 		tcu::TestCaseGroup* instanceArrayBasicTypeGroup = new tcu::TestCaseGroup(m_testCtx, "instance_array_basic_type", "Single basic variable in instance array");
736 		addChild(instanceArrayBasicTypeGroup);
737 
738 		for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
739 		{
740 			tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
741 			instanceArrayBasicTypeGroup->addChild(layoutGroup);
742 
743 			for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
744 			{
745 				glu::DataType	type			= basicTypes[basicTypeNdx];
746 				const char*		typeName		= glu::getDataTypeName(type);
747 				const int		numInstances	= 3;
748 
749 				createBlockBasicTypeCases(layoutGroup, m_testCtx, typeName,
750 										  VarType(type, glu::isDataTypeBoolOrBVec(type) ? 0 : PRECISION_HIGH),
751 										  layoutFlags[layoutFlagNdx].flags, numInstances);
752 
753 				if (glu::isDataTypeMatrix(type))
754 				{
755 					for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
756 						createBlockBasicTypeCases(layoutGroup, m_testCtx, matrixFlags[matFlagNdx].name + "_" + typeName,
757 												  VarType(type, PRECISION_HIGH), layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags,
758 												  numInstances);
759 				}
760 			}
761 		}
762 	}
763 
764 	// ubo.multi_basic_types
765 	{
766 		tcu::TestCaseGroup* multiBasicTypesGroup = new tcu::TestCaseGroup(m_testCtx, "multi_basic_types", "Multiple buffers with basic types");
767 		addChild(multiBasicTypesGroup);
768 
769 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
770 		{
771 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
772 			multiBasicTypesGroup->addChild(modeGroup);
773 
774 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
775 			{
776 				for (int isArray = 0; isArray < 2; isArray++)
777 				{
778 					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
779 					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
780 
781 					if (isArray)
782 						baseName += "_instance_array";
783 
784 					modeGroup->addChild(new BlockMultiBasicTypesCase(m_testCtx, baseName + "_vertex",				"", baseFlags|DECLARE_VERTEX,					baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
785 					modeGroup->addChild(new BlockMultiBasicTypesCase(m_testCtx, baseName + "_fragment",				"", baseFlags|DECLARE_FRAGMENT,					baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
786 					modeGroup->addChild(new BlockMultiBasicTypesCase(m_testCtx, baseName + "_both",					"", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
787 					modeGroup->addChild(new BlockMultiBasicTypesCase(m_testCtx, baseName + "_mixed",				"", baseFlags|DECLARE_VERTEX,					baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
788 					modeGroup->addChild(new BlockMultiBasicTypesCase(m_testCtx, baseName + "_vertex_comp_access",	"", baseFlags|DECLARE_VERTEX,					baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
789 					modeGroup->addChild(new BlockMultiBasicTypesCase(m_testCtx, baseName + "_fragment_comp_access",	"", baseFlags|DECLARE_FRAGMENT,					baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
790 					modeGroup->addChild(new BlockMultiBasicTypesCase(m_testCtx, baseName + "_both_comp_access",		"", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
791 					modeGroup->addChild(new BlockMultiBasicTypesCase(m_testCtx, baseName + "_mixed_comp_access",	"", baseFlags|DECLARE_VERTEX,					baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
792 				}
793 			}
794 		}
795 	}
796 
797 	// ubo.multi_nested_struct
798 	{
799 		tcu::TestCaseGroup* multiNestedStructGroup = new tcu::TestCaseGroup(m_testCtx, "multi_nested_struct", "Multiple buffers with nested structs");
800 		addChild(multiNestedStructGroup);
801 
802 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
803 		{
804 			tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
805 			multiNestedStructGroup->addChild(modeGroup);
806 
807 			for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
808 			{
809 				for (int isArray = 0; isArray < 2; isArray++)
810 				{
811 					std::string	baseName	= layoutFlags[layoutFlagNdx].name;
812 					deUint32	baseFlags	= layoutFlags[layoutFlagNdx].flags;
813 
814 					if (isArray)
815 						baseName += "_instance_array";
816 
817 					modeGroup->addChild(new BlockMultiNestedStructCase(m_testCtx, baseName + "_vertex",				  "", baseFlags|DECLARE_VERTEX,						baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
818 					modeGroup->addChild(new BlockMultiNestedStructCase(m_testCtx, baseName + "_fragment",			  "", baseFlags|DECLARE_FRAGMENT,					baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
819 					modeGroup->addChild(new BlockMultiNestedStructCase(m_testCtx, baseName + "_both",				  "", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
820 					modeGroup->addChild(new BlockMultiNestedStructCase(m_testCtx, baseName + "_mixed",				  "", baseFlags|DECLARE_VERTEX,						baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_FULL_MATRIX));
821 					modeGroup->addChild(new BlockMultiNestedStructCase(m_testCtx, baseName + "_vertex_comp_access",	  "", baseFlags|DECLARE_VERTEX,						baseFlags|DECLARE_VERTEX,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
822 					modeGroup->addChild(new BlockMultiNestedStructCase(m_testCtx, baseName + "_fragment_comp_access", "", baseFlags|DECLARE_FRAGMENT,					baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
823 					modeGroup->addChild(new BlockMultiNestedStructCase(m_testCtx, baseName + "_both_comp_access",	  "", baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	baseFlags|DECLARE_VERTEX|DECLARE_FRAGMENT,	bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
824 					modeGroup->addChild(new BlockMultiNestedStructCase(m_testCtx, baseName + "_mixed_comp_access",	  "", baseFlags|DECLARE_VERTEX,						baseFlags|DECLARE_FRAGMENT,					bufferModes[modeNdx].mode, isArray ? 3 : 0, LOAD_MATRIX_COMPONENTS));
825 				}
826 			}
827 		}
828 	}
829 
830 	// .link_by_binding
831 	{
832 		tcu::TestCaseGroup* linkByBindingGroup = new tcu::TestCaseGroup(m_testCtx, "link_by_binding", "Blocks with same name but different binding");
833 		addChild(linkByBindingGroup);
834 
835 		linkByBindingGroup->addChild(new LinkByBindingCase(m_testCtx, "single_buf_single_instance",		"", UniformBlockCase::BUFFERMODE_SINGLE, 0));
836 		linkByBindingGroup->addChild(new LinkByBindingCase(m_testCtx, "single_buf_instance_array",		"", UniformBlockCase::BUFFERMODE_SINGLE, 2));
837 		linkByBindingGroup->addChild(new LinkByBindingCase(m_testCtx, "per_block_buf_single_instance",	"", UniformBlockCase::BUFFERMODE_PER_BLOCK, 0));
838 		linkByBindingGroup->addChild(new LinkByBindingCase(m_testCtx, "per_block_buf_instance_array",	"", UniformBlockCase::BUFFERMODE_PER_BLOCK, 2));
839 	}
840 
841 	// ubo.random
842 	{
843 		const deUint32	allShaders		= FEATURE_VERTEX_BLOCKS|FEATURE_FRAGMENT_BLOCKS|FEATURE_SHARED_BLOCKS;
844 		const deUint32	allLayouts		= FEATURE_STD140_LAYOUT;
845 		const deUint32	allBasicTypes	= FEATURE_VECTORS|FEATURE_MATRICES;
846 		const deUint32	unused			= FEATURE_UNUSED_MEMBERS|FEATURE_UNUSED_UNIFORMS;
847 		const deUint32	matFlags		= FEATURE_MATRIX_LAYOUT;
848 		const deUint32	allFeatures		= ~FEATURE_OUT_OF_ORDER_OFFSETS;  // OOO offsets handled in a dedicated case group
849 
850 		tcu::TestCaseGroup* randomGroup = new tcu::TestCaseGroup(m_testCtx, "random", "Random Uniform Block cases");
851 		addChild(randomGroup);
852 
853 		// Basic types.
854 		createRandomCaseGroup(randomGroup, m_testCtx, "scalar_types",	"Scalar types only, per-block buffers",				UniformBlockCase::BUFFERMODE_PER_BLOCK,	allShaders|allLayouts|unused,										25, 0);
855 		createRandomCaseGroup(randomGroup, m_testCtx, "vector_types",	"Scalar and vector types only, per-block buffers",	UniformBlockCase::BUFFERMODE_PER_BLOCK,	allShaders|allLayouts|unused|FEATURE_VECTORS,						25, 25);
856 		createRandomCaseGroup(randomGroup, m_testCtx, "basic_types",	"All basic types, per-block buffers",				UniformBlockCase::BUFFERMODE_PER_BLOCK, allShaders|allLayouts|unused|allBasicTypes|matFlags,				25, 50);
857 		createRandomCaseGroup(randomGroup, m_testCtx, "basic_arrays",	"Arrays, per-block buffers",						UniformBlockCase::BUFFERMODE_PER_BLOCK,	allShaders|allLayouts|unused|allBasicTypes|matFlags|FEATURE_ARRAYS,	25, 50);
858 
859 		createRandomCaseGroup(randomGroup, m_testCtx, "basic_instance_arrays",					"Basic instance arrays, per-block buffers",				UniformBlockCase::BUFFERMODE_PER_BLOCK,	allShaders|allLayouts|unused|allBasicTypes|matFlags|FEATURE_INSTANCE_ARRAYS,								25, 75);
860 		createRandomCaseGroup(randomGroup, m_testCtx, "nested_structs",							"Nested structs, per-block buffers",					UniformBlockCase::BUFFERMODE_PER_BLOCK,	allShaders|allLayouts|unused|allBasicTypes|matFlags|FEATURE_STRUCTS,										25, 100);
861 		createRandomCaseGroup(randomGroup, m_testCtx, "nested_structs_arrays",					"Nested structs, arrays, per-block buffers",			UniformBlockCase::BUFFERMODE_PER_BLOCK,	allShaders|allLayouts|unused|allBasicTypes|matFlags|FEATURE_STRUCTS|FEATURE_ARRAYS,							25, 150);
862 		createRandomCaseGroup(randomGroup, m_testCtx, "nested_structs_instance_arrays",			"Nested structs, instance arrays, per-block buffers",	UniformBlockCase::BUFFERMODE_PER_BLOCK,	allShaders|allLayouts|unused|allBasicTypes|matFlags|FEATURE_STRUCTS|FEATURE_INSTANCE_ARRAYS,				25, 125);
863 		createRandomCaseGroup(randomGroup, m_testCtx, "nested_structs_arrays_instance_arrays",	"Nested structs, instance arrays, per-block buffers",	UniformBlockCase::BUFFERMODE_PER_BLOCK,	allShaders|allLayouts|unused|allBasicTypes|matFlags|FEATURE_STRUCTS|FEATURE_ARRAYS|FEATURE_INSTANCE_ARRAYS,	25, 175);
864 
865 		createRandomCaseGroup(randomGroup, m_testCtx, "all_per_block_buffers",	"All random features, per-block buffers",	UniformBlockCase::BUFFERMODE_PER_BLOCK,	allFeatures,	50, 200);
866 		createRandomCaseGroup(randomGroup, m_testCtx, "all_shared_buffer",		"All random features, shared buffer",		UniformBlockCase::BUFFERMODE_SINGLE,	allFeatures,	50, 250);
867 
868 		createRandomCaseGroup(randomGroup, m_testCtx, "all_out_of_order_offsets",	"All random features, out of order member offsets",		UniformBlockCase::BUFFERMODE_PER_BLOCK,	allFeatures | FEATURE_OUT_OF_ORDER_OFFSETS,	50, 300);
869 	}
870 }
871 
872 } // anonymous
873 
createTests(tcu::TestContext & testCtx)874 tcu::TestCaseGroup*	createTests	(tcu::TestContext& testCtx)
875 {
876 	return new UniformBlockTests(testCtx);
877 }
878 
879 } // ubo
880 } // vkt
881