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