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