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  * Copyright (c) 2018 The Khronos Group Inc.
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  *//*!
23  * \file
24  * \brief Vulkan Transform Feedback Fuzz Layout Tests
25  *//*--------------------------------------------------------------------*/
26 
27 #include "vktTransformFeedbackFuzzLayoutCase.hpp"
28 #include "vktTransformFeedbackRandomLayoutCase.hpp"
29 
30 #include "tcuCommandLine.hpp"
31 #include "deStringUtil.hpp"
32 
33 namespace vkt
34 {
35 namespace TransformFeedback
36 {
37 
38 namespace
39 {
40 
41 class BlockBasicTypeCase : public InterfaceBlockCase
42 {
43 public:
BlockBasicTypeCase(tcu::TestContext & testCtx,const std::string & name,const VarType & type,uint32_t layoutFlags,int numInstances,MatrixLoadFlags matrixLoadFlag,TestStageFlags testStageFlags)44     BlockBasicTypeCase(tcu::TestContext &testCtx, const std::string &name, const VarType &type, uint32_t layoutFlags,
45                        int numInstances, MatrixLoadFlags matrixLoadFlag, TestStageFlags testStageFlags)
46         : InterfaceBlockCase(testCtx, name, matrixLoadFlag, testStageFlags)
47     {
48         InterfaceBlock &block = m_interface.allocBlock("Block");
49         block.addInterfaceMember(InterfaceBlockMember("var", type, 0));
50 
51         VarType tempType = type;
52         while (tempType.isArrayType())
53         {
54             tempType = tempType.getElementType();
55         }
56 
57         block.setFlags(layoutFlags);
58 
59         if (numInstances > 0)
60         {
61             block.setArraySize(numInstances);
62             block.setInstanceName("block");
63         }
64     }
65 };
66 
createBlockBasicTypeCases(tcu::TestCaseGroup & group,tcu::TestContext & testCtx,const std::string & name,const VarType & type,uint32_t layoutFlags,int numInstances=0)67 void createBlockBasicTypeCases(tcu::TestCaseGroup &group, tcu::TestContext &testCtx, const std::string &name,
68                                const VarType &type, uint32_t layoutFlags, int numInstances = 0)
69 {
70     de::MovePtr<tcu::TestCaseGroup> typeGroup(new tcu::TestCaseGroup(group.getTestContext(), name.c_str()));
71 
72     typeGroup->addChild(new BlockBasicTypeCase(testCtx, "vertex", type, layoutFlags, numInstances, LOAD_FULL_MATRIX,
73                                                TEST_STAGE_VERTEX));
74     typeGroup->addChild(new BlockBasicTypeCase(testCtx, "geometry", type, layoutFlags, numInstances, LOAD_FULL_MATRIX,
75                                                TEST_STAGE_GEOMETRY));
76 
77     group.addChild(typeGroup.release());
78 }
79 
80 class BlockSingleStructCase : public InterfaceBlockCase
81 {
82 public:
BlockSingleStructCase(tcu::TestContext & testCtx,const std::string & name,uint32_t layoutFlags,int numInstances,MatrixLoadFlags matrixLoadFlag,TestStageFlags testStageFlags)83     BlockSingleStructCase(tcu::TestContext &testCtx, const std::string &name, uint32_t layoutFlags, int numInstances,
84                           MatrixLoadFlags matrixLoadFlag, TestStageFlags testStageFlags)
85         : InterfaceBlockCase(testCtx, name, matrixLoadFlag, testStageFlags)
86     {
87         StructType &typeS = m_interface.allocStruct("S");
88         typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH), FIELD_UNASSIGNED); // First member is unused.
89         typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_VEC3, PRECISION_HIGH), 2));
90         typeS.addMember("c", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM));
91 
92         InterfaceBlock &block = m_interface.allocBlock("Block");
93         block.addInterfaceMember(InterfaceBlockMember("s", VarType(&typeS), 0));
94         block.setFlags(layoutFlags);
95 
96         if (numInstances > 0)
97         {
98             block.setInstanceName("block");
99             block.setArraySize(numInstances);
100         }
101     }
102 };
103 
104 class BlockSingleStructArrayCase : public InterfaceBlockCase
105 {
106 public:
BlockSingleStructArrayCase(tcu::TestContext & testCtx,const std::string & name,uint32_t layoutFlags,int numInstances,MatrixLoadFlags matrixLoadFlag,TestStageFlags testStageFlags)107     BlockSingleStructArrayCase(tcu::TestContext &testCtx, const std::string &name, uint32_t layoutFlags,
108                                int numInstances, MatrixLoadFlags matrixLoadFlag, TestStageFlags testStageFlags)
109         : InterfaceBlockCase(testCtx, name, matrixLoadFlag, testStageFlags)
110     {
111         StructType &typeS = m_interface.allocStruct("S");
112         typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH), FIELD_UNASSIGNED);
113         typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT2, PRECISION_MEDIUM), 2));
114         typeS.addMember("c", VarType(glu::TYPE_FLOAT, PRECISION_HIGH));
115 
116         InterfaceBlock &block = m_interface.allocBlock("Block");
117         block.addInterfaceMember(InterfaceBlockMember("u", VarType(glu::TYPE_UINT, PRECISION_LOW)));
118         block.addInterfaceMember(InterfaceBlockMember("s", VarType(VarType(&typeS), 2)));
119         block.addInterfaceMember(InterfaceBlockMember("v", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_MEDIUM)));
120         block.setFlags(layoutFlags);
121 
122         if (numInstances > 0)
123         {
124             block.setInstanceName("block");
125             block.setArraySize(numInstances);
126         }
127     }
128 };
129 
130 class BlockSingleNestedStructCase : public InterfaceBlockCase
131 {
132 public:
BlockSingleNestedStructCase(tcu::TestContext & testCtx,const std::string & name,uint32_t layoutFlags,int numInstances,MatrixLoadFlags matrixLoadFlag,TestStageFlags testStageFlags)133     BlockSingleNestedStructCase(tcu::TestContext &testCtx, const std::string &name, uint32_t layoutFlags,
134                                 int numInstances, MatrixLoadFlags matrixLoadFlag, TestStageFlags testStageFlags)
135         : InterfaceBlockCase(testCtx, name, matrixLoadFlag, testStageFlags)
136     {
137         StructType &typeS = m_interface.allocStruct("S");
138         typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, PRECISION_HIGH));
139         typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT2, PRECISION_MEDIUM), 2));
140         typeS.addMember("c", VarType(glu::TYPE_FLOAT, PRECISION_HIGH), FIELD_UNASSIGNED);
141 
142         StructType &typeT = m_interface.allocStruct("T");
143         typeT.addMember("a", VarType(glu::TYPE_FLOAT_VEC3, PRECISION_MEDIUM));
144         typeT.addMember("b", VarType(&typeS));
145 
146         InterfaceBlock &block = m_interface.allocBlock("Block");
147         block.addInterfaceMember(InterfaceBlockMember("s", VarType(&typeS), 0));
148         block.addInterfaceMember(InterfaceBlockMember("v", VarType(glu::TYPE_UINT, PRECISION_LOW), FIELD_UNASSIGNED));
149         block.addInterfaceMember(InterfaceBlockMember("t", VarType(&typeT), 0));
150         block.addInterfaceMember(InterfaceBlockMember("u", VarType(glu::TYPE_FLOAT_VEC2, PRECISION_HIGH), 0));
151         block.setFlags(layoutFlags);
152 
153         if (numInstances > 0)
154         {
155             block.setInstanceName("block");
156             block.setArraySize(numInstances);
157         }
158     }
159 };
160 
161 class BlockSingleNestedStructArrayCase : public InterfaceBlockCase
162 {
163 public:
BlockSingleNestedStructArrayCase(tcu::TestContext & testCtx,const std::string & name,uint32_t layoutFlags,int numInstances,MatrixLoadFlags matrixLoadFlag,TestStageFlags testStageFlags)164     BlockSingleNestedStructArrayCase(tcu::TestContext &testCtx, const std::string &name, uint32_t layoutFlags,
165                                      int numInstances, MatrixLoadFlags matrixLoadFlag, TestStageFlags testStageFlags)
166         : InterfaceBlockCase(testCtx, name, matrixLoadFlag, testStageFlags)
167     {
168         StructType &typeS = m_interface.allocStruct("S");
169         typeS.addMember("a", VarType(VarType(glu::TYPE_FLOAT, PRECISION_HIGH), 2));
170 
171         StructType &typeT = m_interface.allocStruct("T");
172         typeT.addMember("a", VarType(glu::TYPE_FLOAT_MAT2, PRECISION_MEDIUM));
173         typeT.addMember("b", VarType(VarType(&typeS), 2));
174 
175         InterfaceBlock &block = m_interface.allocBlock("Block");
176         block.addInterfaceMember(InterfaceBlockMember("s", VarType(&typeS), 0));
177         block.addInterfaceMember(
178             InterfaceBlockMember("v", VarType(glu::TYPE_FLOAT_VEC2, PRECISION_LOW), FIELD_UNASSIGNED));
179         block.addInterfaceMember(InterfaceBlockMember("t", VarType(VarType(&typeT), 2), 0));
180         block.addInterfaceMember(InterfaceBlockMember("u", VarType(glu::TYPE_UINT, PRECISION_HIGH), 0));
181         block.setFlags(layoutFlags);
182 
183         if (numInstances > 0)
184         {
185             block.setInstanceName("block");
186             block.setArraySize(numInstances);
187         }
188     }
189 };
190 
191 class BlockMultiBasicTypesCase : public InterfaceBlockCase
192 {
193 public:
BlockMultiBasicTypesCase(tcu::TestContext & testCtx,const std::string & name,uint32_t flagsA,uint32_t flagsB,int numInstances,MatrixLoadFlags matrixLoadFlag,TestStageFlags testStageFlags)194     BlockMultiBasicTypesCase(tcu::TestContext &testCtx, const std::string &name, uint32_t flagsA, uint32_t flagsB,
195                              int numInstances, MatrixLoadFlags matrixLoadFlag, TestStageFlags testStageFlags)
196         : InterfaceBlockCase(testCtx, name, matrixLoadFlag, testStageFlags)
197     {
198         InterfaceBlock &blockA = m_interface.allocBlock("BlockA");
199         blockA.addInterfaceMember(InterfaceBlockMember("a", VarType(glu::TYPE_FLOAT, PRECISION_HIGH)));
200         blockA.addInterfaceMember(
201             InterfaceBlockMember("b", VarType(glu::TYPE_UINT_VEC3, PRECISION_LOW), FIELD_UNASSIGNED));
202         blockA.addInterfaceMember(InterfaceBlockMember("c", VarType(glu::TYPE_FLOAT_MAT2, PRECISION_MEDIUM)));
203         blockA.setInstanceName("blockA");
204         blockA.setFlags(flagsA);
205 
206         InterfaceBlock &blockB = m_interface.allocBlock("BlockB");
207         blockB.addInterfaceMember(InterfaceBlockMember("a", VarType(glu::TYPE_FLOAT_MAT3, PRECISION_MEDIUM)));
208         blockB.addInterfaceMember(InterfaceBlockMember("b", VarType(glu::TYPE_INT_VEC2, PRECISION_LOW)));
209         blockB.addInterfaceMember(
210             InterfaceBlockMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH), FIELD_UNASSIGNED));
211         blockB.addInterfaceMember(InterfaceBlockMember("d", VarType(glu::TYPE_INT, 0)));
212         blockB.setInstanceName("blockB");
213         blockB.setFlags(flagsB);
214 
215         if (numInstances > 0)
216         {
217             blockA.setArraySize(numInstances);
218             blockB.setArraySize(numInstances);
219         }
220     }
221 };
222 
223 class BlockMultiNestedStructCase : public InterfaceBlockCase
224 {
225 public:
BlockMultiNestedStructCase(tcu::TestContext & testCtx,const std::string & name,uint32_t flagsA,uint32_t flagsB,int numInstances,MatrixLoadFlags matrixLoadFlag,TestStageFlags testStageFlags)226     BlockMultiNestedStructCase(tcu::TestContext &testCtx, const std::string &name, uint32_t flagsA, uint32_t flagsB,
227                                int numInstances, MatrixLoadFlags matrixLoadFlag, TestStageFlags testStageFlags)
228         : InterfaceBlockCase(testCtx, name, matrixLoadFlag, testStageFlags)
229     {
230         StructType &typeS = m_interface.allocStruct("S");
231         typeS.addMember("a", VarType(glu::TYPE_FLOAT_MAT2, PRECISION_LOW));
232         typeS.addMember("b", VarType(VarType(glu::TYPE_INT_VEC2, PRECISION_MEDIUM), 2));
233 
234         StructType &typeT = m_interface.allocStruct("T");
235         typeT.addMember("a", VarType(glu::TYPE_UINT, PRECISION_MEDIUM), FIELD_UNASSIGNED);
236         typeT.addMember("b", VarType(&typeS));
237         typeT.addMember("c", VarType(glu::TYPE_UINT_VEC3, 0));
238 
239         InterfaceBlock &blockA = m_interface.allocBlock("BlockA");
240         blockA.addInterfaceMember(InterfaceBlockMember("a", VarType(glu::TYPE_FLOAT, PRECISION_HIGH)));
241         blockA.addInterfaceMember(InterfaceBlockMember("b", VarType(&typeS)));
242         blockA.addInterfaceMember(InterfaceBlockMember("c", VarType(glu::TYPE_UINT, PRECISION_LOW), FIELD_UNASSIGNED));
243         blockA.setInstanceName("blockA");
244         blockA.setFlags(flagsA);
245 
246         InterfaceBlock &blockB = m_interface.allocBlock("BlockB");
247         blockB.addInterfaceMember(InterfaceBlockMember("a", VarType(glu::TYPE_FLOAT_MAT2, PRECISION_MEDIUM)));
248         blockB.addInterfaceMember(InterfaceBlockMember("b", VarType(&typeT)));
249         blockB.addInterfaceMember(InterfaceBlockMember("c", VarType(glu::TYPE_INT, 0)));
250         blockB.setInstanceName("blockB");
251         blockB.setFlags(flagsB);
252 
253         if (numInstances > 0)
254         {
255             blockA.setArraySize(numInstances);
256             blockB.setArraySize(numInstances);
257         }
258     }
259 };
260 
261 class BlockVariousBuffersCase : public InterfaceBlockCase
262 {
263 public:
BlockVariousBuffersCase(tcu::TestContext & testCtx,const std::string & name,uint32_t flags,uint32_t xfbBufferA,uint32_t xfbBufferB,uint32_t xfbBufferC,int numInstances,MatrixLoadFlags matrixLoadFlag,TestStageFlags testStageFlags)264     BlockVariousBuffersCase(tcu::TestContext &testCtx, const std::string &name, uint32_t flags, uint32_t xfbBufferA,
265                             uint32_t xfbBufferB, uint32_t xfbBufferC, int numInstances, MatrixLoadFlags matrixLoadFlag,
266                             TestStageFlags testStageFlags)
267         : InterfaceBlockCase(testCtx, name, matrixLoadFlag, testStageFlags)
268     {
269         StructType &typeS = m_interface.allocStruct("S");
270         typeS.addMember("a", VarType(VarType(glu::TYPE_FLOAT, PRECISION_LOW), 3));
271         typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_VEC2, PRECISION_MEDIUM), 2));
272         typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, PRECISION_HIGH));
273 
274         StructType &typeT = m_interface.allocStruct("T");
275         typeT.addMember("a", VarType(glu::TYPE_UINT, PRECISION_MEDIUM), FIELD_UNASSIGNED);
276         typeT.addMember("b", VarType(glu::TYPE_INT_VEC3, 0));
277 
278         InterfaceBlock &blockA = m_interface.allocBlock("BlockA");
279         blockA.addInterfaceMember(InterfaceBlockMember("a", VarType(glu::TYPE_INT, PRECISION_HIGH)));
280         blockA.addInterfaceMember(InterfaceBlockMember("b", VarType(&typeS)));
281         blockA.addInterfaceMember(
282             InterfaceBlockMember("c", VarType(glu::TYPE_UINT_VEC3, PRECISION_LOW), FIELD_UNASSIGNED));
283         blockA.setInstanceName("blockA");
284         blockA.setFlags(flags);
285         blockA.setXfbBuffer(xfbBufferA);
286 
287         InterfaceBlock &blockB = m_interface.allocBlock("BlockB");
288         blockB.addInterfaceMember(InterfaceBlockMember("a", VarType(glu::TYPE_FLOAT_MAT2, PRECISION_MEDIUM)));
289         blockB.addInterfaceMember(InterfaceBlockMember("b", VarType(&typeT)));
290         blockB.addInterfaceMember(InterfaceBlockMember("c", VarType(glu::TYPE_INT_VEC4, 0), FIELD_UNASSIGNED));
291         blockB.addInterfaceMember(InterfaceBlockMember("d", VarType(glu::TYPE_INT, 0)));
292         blockB.setInstanceName("blockB");
293         blockB.setFlags(flags);
294         blockB.setXfbBuffer(xfbBufferB);
295 
296         InterfaceBlock &blockC = m_interface.allocBlock("BlockC");
297         blockC.addInterfaceMember(InterfaceBlockMember("a", VarType(glu::TYPE_UINT, PRECISION_HIGH)));
298         blockC.addInterfaceMember(InterfaceBlockMember("b", VarType(glu::TYPE_FLOAT_MAT2, PRECISION_HIGH)));
299         blockC.setInstanceName("blockC");
300         blockC.setFlags(flags);
301         blockC.setXfbBuffer(xfbBufferC);
302 
303         if (numInstances > 0)
304         {
305             blockA.setArraySize(numInstances);
306             blockB.setArraySize(numInstances);
307         }
308     }
309 };
310 
311 class Block2LevelStructArrayCase : public InterfaceBlockCase
312 {
313 public:
Block2LevelStructArrayCase(tcu::TestContext & testCtx,const std::string & name,uint32_t flags,int numInstances,MatrixLoadFlags matrixLoadFlag,TestStageFlags testStageFlags)314     Block2LevelStructArrayCase(tcu::TestContext &testCtx, const std::string &name, uint32_t flags, int numInstances,
315                                MatrixLoadFlags matrixLoadFlag, TestStageFlags testStageFlags)
316         : InterfaceBlockCase(testCtx, name, matrixLoadFlag, testStageFlags)
317     {
318         StructType &typeS = m_interface.allocStruct("S");
319         typeS.addMember("a", VarType(glu::TYPE_UINT_VEC3, PRECISION_HIGH), FIELD_UNASSIGNED);
320         typeS.addMember("b", VarType(glu::TYPE_FLOAT_MAT2, PRECISION_MEDIUM));
321 
322         InterfaceBlock &block = m_interface.allocBlock("Block");
323         block.addInterfaceMember(InterfaceBlockMember("u", VarType(glu::TYPE_INT, PRECISION_MEDIUM)));
324         block.addInterfaceMember(InterfaceBlockMember("s", VarType(VarType(VarType(&typeS), 2), 2)));
325         block.addInterfaceMember(InterfaceBlockMember("v", VarType(glu::TYPE_FLOAT_VEC2, PRECISION_MEDIUM)));
326         block.setFlags(flags);
327 
328         if (numInstances > 0)
329         {
330             block.setInstanceName("block");
331             block.setArraySize(numInstances);
332         }
333     }
334 };
335 
createRandomCaseGroup(tcu::TestCaseGroup * parentGroup,tcu::TestContext & testCtx,const char * groupName,uint32_t numCases,TestStageFlags testStageFlags,uint32_t features)336 void createRandomCaseGroup(tcu::TestCaseGroup *parentGroup, tcu::TestContext &testCtx, const char *groupName,
337                            uint32_t numCases, TestStageFlags testStageFlags, uint32_t features)
338 {
339     const uint32_t baseSeed   = deStringHash(groupName) + static_cast<uint32_t>(testCtx.getCommandLine().getBaseSeed());
340     tcu::TestCaseGroup *group = new tcu::TestCaseGroup(testCtx, groupName);
341 
342     parentGroup->addChild(group);
343 
344     for (uint32_t ndx = 0; ndx < numCases; ndx++)
345         group->addChild(
346             new RandomInterfaceBlockCase(testCtx, de::toString(ndx), testStageFlags, features, ndx + baseSeed));
347 }
348 
349 // InterfaceBlockTests
350 
351 class InterfaceBlockTests : public tcu::TestCaseGroup
352 {
353 public:
354     InterfaceBlockTests(tcu::TestContext &testCtx);
355     ~InterfaceBlockTests(void);
356 
357     void init(void);
358 
359 private:
360     InterfaceBlockTests(const InterfaceBlockTests &other);
361     InterfaceBlockTests &operator=(const InterfaceBlockTests &other);
362 };
363 
InterfaceBlockTests(tcu::TestContext & testCtx)364 InterfaceBlockTests::InterfaceBlockTests(tcu::TestContext &testCtx) : TestCaseGroup(testCtx, "fuzz")
365 {
366 }
367 
~InterfaceBlockTests(void)368 InterfaceBlockTests::~InterfaceBlockTests(void)
369 {
370 }
371 
init(void)372 void InterfaceBlockTests::init(void)
373 {
374     static const glu::DataType basicTypes[] = {
375         glu::TYPE_FLOAT,         glu::TYPE_FLOAT_VEC2,   glu::TYPE_FLOAT_VEC3,    glu::TYPE_FLOAT_VEC4,
376         glu::TYPE_INT,           glu::TYPE_INT_VEC2,     glu::TYPE_INT_VEC3,      glu::TYPE_INT_VEC4,
377         glu::TYPE_UINT,          glu::TYPE_UINT_VEC2,    glu::TYPE_UINT_VEC3,     glu::TYPE_UINT_VEC4,
378         glu::TYPE_FLOAT_MAT2,    glu::TYPE_FLOAT_MAT3,   glu::TYPE_FLOAT_MAT4,    glu::TYPE_FLOAT_MAT2X3,
379         glu::TYPE_FLOAT_MAT2X4,  glu::TYPE_FLOAT_MAT3X2, glu::TYPE_FLOAT_MAT3X4,  glu::TYPE_FLOAT_MAT4X2,
380         glu::TYPE_FLOAT_MAT4X3,  glu::TYPE_DOUBLE,       glu::TYPE_DOUBLE_VEC2,   glu::TYPE_DOUBLE_VEC3,
381         glu::TYPE_DOUBLE_VEC4,   glu::TYPE_DOUBLE_MAT2,  glu::TYPE_DOUBLE_MAT2X3, glu::TYPE_DOUBLE_MAT2X4,
382         glu::TYPE_DOUBLE_MAT3X2, glu::TYPE_DOUBLE_MAT3,  glu::TYPE_DOUBLE_MAT3X4, glu::TYPE_DOUBLE_MAT4X2,
383         glu::TYPE_DOUBLE_MAT4X3, glu::TYPE_DOUBLE_MAT4,
384     };
385 
386     static const struct
387     {
388         const std::string name;
389         uint32_t flags;
390     } precisionFlags[] = {
391         // TODO remove PRECISION_LOW because both PRECISION_LOW and PRECISION_MEDIUM means relaxed precision?
392         {"lowp", PRECISION_LOW},
393         {"mediump", PRECISION_MEDIUM},
394         {"highp", PRECISION_HIGH}};
395     const uint32_t defaultFlags = LAYOUT_XFBBUFFER | LAYOUT_XFBOFFSET;
396 
397     // .2_level_array
398     {
399         // 2-level basic array variable in single buffer
400         tcu::TestCaseGroup *nestedArrayGroup = new tcu::TestCaseGroup(m_testCtx, "2_level_array");
401         addChild(nestedArrayGroup);
402 
403         for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
404         {
405             const glu::DataType type   = basicTypes[basicTypeNdx];
406             const char *const typeName = glu::getDataTypeName(type);
407             const int childSize        = 2;
408             const int parentSize       = 2;
409             const VarType childType(VarType(type, !dataTypeSupportsPrecisionModifier(type) ? 0 : PRECISION_HIGH),
410                                     childSize);
411             const VarType parentType(childType, parentSize);
412 
413             createBlockBasicTypeCases(*nestedArrayGroup, m_testCtx, typeName, parentType, defaultFlags);
414         }
415     }
416 
417     // .3_level_array
418     {
419         // 3-level basic array variable in single buffer
420         tcu::TestCaseGroup *nestedArrayGroup = new tcu::TestCaseGroup(m_testCtx, "3_level_array");
421         addChild(nestedArrayGroup);
422 
423         for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
424         {
425             const glu::DataType type   = basicTypes[basicTypeNdx];
426             const char *const typeName = glu::getDataTypeName(type);
427             const int childSize0       = 2;
428             const int childSize1       = 2;
429             const int parentSize       = 2;
430             const VarType childType0(VarType(type, !dataTypeSupportsPrecisionModifier(type) ? 0 : PRECISION_HIGH),
431                                      childSize0);
432             const VarType childType1(childType0, childSize1);
433             const VarType parentType(childType1, parentSize);
434 
435             createBlockBasicTypeCases(*nestedArrayGroup, m_testCtx, typeName, parentType, defaultFlags);
436         }
437     }
438 
439     // .2_level_struct_array
440     {
441         tcu::TestCaseGroup *structArrayArrayGroup = new tcu::TestCaseGroup(m_testCtx, "2_level_struct_array");
442         addChild(structArrayArrayGroup);
443 
444         for (int isArray = 0; isArray < 2; isArray++)
445         {
446             const std::string baseName = isArray ? "instance_array" : "std";
447             const int numInstances     = isArray ? 2 : 0;
448 
449             structArrayArrayGroup->addChild(new Block2LevelStructArrayCase(
450                 m_testCtx, (baseName + "_vertex"), defaultFlags, numInstances, LOAD_FULL_MATRIX, TEST_STAGE_VERTEX));
451             structArrayArrayGroup->addChild(new Block2LevelStructArrayCase(m_testCtx, (baseName + "_geometry"),
452                                                                            defaultFlags, numInstances, LOAD_FULL_MATRIX,
453                                                                            TEST_STAGE_GEOMETRY));
454         }
455     }
456 
457     // .single_basic_type
458     {
459         tcu::TestCaseGroup *singleBasicTypeGroup = new tcu::TestCaseGroup(m_testCtx, "single_basic_type");
460         addChild(singleBasicTypeGroup);
461 
462         for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
463         {
464             glu::DataType type         = basicTypes[basicTypeNdx];
465             const char *const typeName = glu::getDataTypeName(type);
466 
467             if (!dataTypeSupportsPrecisionModifier(type))
468                 createBlockBasicTypeCases(*singleBasicTypeGroup, m_testCtx, typeName, VarType(type, 0), defaultFlags);
469         }
470 
471         for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisionFlags); precNdx++)
472         {
473             de::MovePtr<tcu::TestCaseGroup> precGroup(
474                 new tcu::TestCaseGroup(m_testCtx, precisionFlags[precNdx].name.c_str()));
475 
476             for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
477             {
478                 glu::DataType type         = basicTypes[basicTypeNdx];
479                 const char *const typeName = glu::getDataTypeName(type);
480 
481                 if (dataTypeSupportsPrecisionModifier(type))
482                     createBlockBasicTypeCases(*precGroup, m_testCtx, typeName,
483                                               VarType(type, precisionFlags[precNdx].flags), defaultFlags);
484             }
485             singleBasicTypeGroup->addChild(precGroup.release());
486         }
487     }
488 
489     // .single_basic_array
490     {
491         tcu::TestCaseGroup *singleBasicArrayGroup = new tcu::TestCaseGroup(m_testCtx, "single_basic_array");
492         addChild(singleBasicArrayGroup);
493 
494         for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
495         {
496             glu::DataType type         = basicTypes[basicTypeNdx];
497             const char *const typeName = glu::getDataTypeName(type);
498             const int arraySize        = 3;
499 
500             createBlockBasicTypeCases(
501                 *singleBasicArrayGroup, m_testCtx, typeName,
502                 VarType(VarType(type, !dataTypeSupportsPrecisionModifier(type) ? 0 : PRECISION_HIGH), arraySize),
503                 defaultFlags);
504         }
505     }
506 
507     // .single_struct
508     {
509         tcu::TestCaseGroup *singleStructGroup = new tcu::TestCaseGroup(m_testCtx, "single_struct");
510         addChild(singleStructGroup);
511 
512         for (int isArray = 0; isArray < 2; isArray++)
513         {
514             const std::string baseName = isArray ? "instance_array" : "std";
515             const int numInstances     = isArray ? 3 : 0;
516 
517             singleStructGroup->addChild(new BlockSingleStructCase(m_testCtx, baseName + "_vertex", defaultFlags,
518                                                                   numInstances, LOAD_FULL_MATRIX, TEST_STAGE_VERTEX));
519             singleStructGroup->addChild(new BlockSingleStructCase(m_testCtx, baseName + "_geometry", defaultFlags,
520                                                                   numInstances, LOAD_FULL_MATRIX, TEST_STAGE_GEOMETRY));
521         }
522     }
523 
524     // .single_struct_array
525     {
526         tcu::TestCaseGroup *singleStructArrayGroup = new tcu::TestCaseGroup(m_testCtx, "single_struct_array");
527         addChild(singleStructArrayGroup);
528 
529         for (int isArray = 0; isArray < 2; isArray++)
530         {
531             const std::string baseName = isArray ? "instance_array" : "std";
532             const int numInstances     = isArray ? 2 : 0;
533 
534             singleStructArrayGroup->addChild(new BlockSingleStructArrayCase(
535                 m_testCtx, baseName + "_vertex", defaultFlags, numInstances, LOAD_FULL_MATRIX, TEST_STAGE_VERTEX));
536             singleStructArrayGroup->addChild(new BlockSingleStructArrayCase(
537                 m_testCtx, baseName + "_geometry", defaultFlags, numInstances, LOAD_FULL_MATRIX, TEST_STAGE_GEOMETRY));
538         }
539     }
540 
541     // .single_nested_struct
542     {
543         tcu::TestCaseGroup *singleNestedStructGroup = new tcu::TestCaseGroup(m_testCtx, "single_nested_struct");
544         addChild(singleNestedStructGroup);
545 
546         for (int isArray = 0; isArray < 2; isArray++)
547         {
548             const std::string baseName = isArray ? "instance_array" : "std";
549             const int numInstances     = isArray ? 2 : 0;
550 
551             singleNestedStructGroup->addChild(new BlockSingleNestedStructCase(
552                 m_testCtx, baseName + "_vertex", defaultFlags, numInstances, LOAD_FULL_MATRIX, TEST_STAGE_VERTEX));
553             singleNestedStructGroup->addChild(new BlockSingleNestedStructCase(
554                 m_testCtx, baseName + "_geometry", defaultFlags, numInstances, LOAD_FULL_MATRIX, TEST_STAGE_GEOMETRY));
555         }
556     }
557 
558     // .single_nested_struct_array
559     {
560         tcu::TestCaseGroup *singleNestedStructArrayGroup =
561             new tcu::TestCaseGroup(m_testCtx, "single_nested_struct_array");
562         addChild(singleNestedStructArrayGroup);
563 
564         for (int isArray = 0; isArray < 2; isArray++)
565         {
566             const std::string baseName = isArray ? "instance_array" : "std";
567             const int numInstances     = isArray ? 2 : 0;
568 
569             singleNestedStructArrayGroup->addChild(new BlockSingleNestedStructArrayCase(
570                 m_testCtx, baseName + "_vertex", defaultFlags, numInstances, LOAD_FULL_MATRIX, TEST_STAGE_VERTEX));
571             singleNestedStructArrayGroup->addChild(new BlockSingleNestedStructArrayCase(
572                 m_testCtx, baseName + "_geometry", defaultFlags, numInstances, LOAD_FULL_MATRIX, TEST_STAGE_GEOMETRY));
573         }
574     }
575 
576     // .instance_array_basic_type
577     {
578         tcu::TestCaseGroup *instanceArrayBasicTypeGroup =
579             new tcu::TestCaseGroup(m_testCtx, "instance_array_basic_type");
580         addChild(instanceArrayBasicTypeGroup);
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             const int numInstances     = 3;
587 
588             createBlockBasicTypeCases(*instanceArrayBasicTypeGroup, m_testCtx, typeName,
589                                       VarType(type, !dataTypeSupportsPrecisionModifier(type) ? 0 : PRECISION_HIGH),
590                                       defaultFlags, numInstances);
591         }
592     }
593 
594     // .multi_basic_types
595     {
596         tcu::TestCaseGroup *multiBasicTypesGroup = new tcu::TestCaseGroup(m_testCtx, "multi_basic_types");
597         addChild(multiBasicTypesGroup);
598 
599         for (int isArray = 0; isArray < 2; isArray++)
600         {
601             const std::string baseName = isArray ? "instance_array" : "std";
602             const int numInstances     = isArray ? 2 : 0;
603 
604             multiBasicTypesGroup->addChild(new BlockMultiBasicTypesCase(m_testCtx, baseName + "_vertex", defaultFlags,
605                                                                         defaultFlags, numInstances, LOAD_FULL_MATRIX,
606                                                                         TEST_STAGE_VERTEX));
607             multiBasicTypesGroup->addChild(new BlockMultiBasicTypesCase(m_testCtx, baseName + "_geometry", defaultFlags,
608                                                                         defaultFlags, numInstances, LOAD_FULL_MATRIX,
609                                                                         TEST_STAGE_GEOMETRY));
610         }
611     }
612 
613     // .multi_nested_struct
614     {
615         tcu::TestCaseGroup *multiNestedStructGroup = new tcu::TestCaseGroup(m_testCtx, "multi_nested_struct");
616         addChild(multiNestedStructGroup);
617 
618         for (int isArray = 0; isArray < 2; isArray++)
619         {
620             const std::string baseName = isArray ? "instance_array" : "std";
621             const int numInstances     = isArray ? 2 : 0;
622 
623             multiNestedStructGroup->addChild(new BlockMultiNestedStructCase(m_testCtx, baseName + "_vertex",
624                                                                             defaultFlags, defaultFlags, numInstances,
625                                                                             LOAD_FULL_MATRIX, TEST_STAGE_VERTEX));
626             multiNestedStructGroup->addChild(new BlockMultiNestedStructCase(m_testCtx, baseName + "_geometry",
627                                                                             defaultFlags, defaultFlags, numInstances,
628                                                                             LOAD_FULL_MATRIX, TEST_STAGE_GEOMETRY));
629         }
630     }
631 
632     // .various_buffers
633     {
634         static const struct
635         {
636             const std::string name;
637             uint32_t bufferA;
638             uint32_t bufferB;
639             uint32_t bufferC;
640         } xfbBufferNumbers[] = {
641             {"000", 0, 0, 0},
642             {"010", 0, 1, 0},
643             {"100", 1, 0, 0},
644             {"110", 1, 1, 0},
645         };
646 
647         tcu::TestCaseGroup *multiNestedStructGroup = new tcu::TestCaseGroup(m_testCtx, "various_buffers");
648         addChild(multiNestedStructGroup);
649 
650         for (int xfbBufferNdx = 0; xfbBufferNdx < DE_LENGTH_OF_ARRAY(xfbBufferNumbers); xfbBufferNdx++)
651         {
652             const uint32_t bufferA = xfbBufferNumbers[xfbBufferNdx].bufferA;
653             const uint32_t bufferB = xfbBufferNumbers[xfbBufferNdx].bufferB;
654             const uint32_t bufferC = xfbBufferNumbers[xfbBufferNdx].bufferC;
655 
656             for (int isArray = 0; isArray < 2; isArray++)
657             {
658                 std::string baseName   = "buffers" + xfbBufferNumbers[xfbBufferNdx].name;
659                 const int numInstances = isArray ? 2 : 0;
660 
661                 if (isArray)
662                     baseName += "_instance_array";
663 
664                 multiNestedStructGroup->addChild(
665                     new BlockVariousBuffersCase(m_testCtx, baseName + "_vertex", defaultFlags, bufferA, bufferB,
666                                                 bufferC, numInstances, LOAD_FULL_MATRIX, TEST_STAGE_VERTEX));
667                 multiNestedStructGroup->addChild(
668                     new BlockVariousBuffersCase(m_testCtx, baseName + "_geometry", defaultFlags, bufferA, bufferB,
669                                                 bufferC, numInstances, LOAD_FULL_MATRIX, TEST_STAGE_GEOMETRY));
670             }
671         }
672     }
673 
674     // .random
675     {
676         static const struct
677         {
678             std::string name;
679             TestStageFlags testStageFlags;
680         } stages[] = {
681             {"vertex", TEST_STAGE_VERTEX},
682             {"geometry", TEST_STAGE_GEOMETRY},
683         };
684 
685         for (size_t stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(stages); ++stageNdx)
686         {
687             const std::string groupName  = "random_" + stages[stageNdx].name;
688             const TestStageFlags stage   = stages[stageNdx].testStageFlags;
689             const uint32_t allBasicTypes = FEATURE_VECTORS | FEATURE_MATRICES | FEATURE_DOUBLES;
690             const uint32_t unused        = FEATURE_UNASSIGNED_FIELDS | FEATURE_UNASSIGNED_BLOCK_MEMBERS;
691             const uint32_t disabled =
692                 FEATURE_INSTANCE_ARRAYS | FEATURE_MISSING_BLOCK_MEMBERS |
693                 FEATURE_OUT_OF_ORDER_OFFSETS; // OOO & missing offsets handled in a dedicated case group
694             const uint32_t allFeatures = ~disabled;
695             const uint32_t numCases    = 50;
696 
697             tcu::TestCaseGroup *group = new tcu::TestCaseGroup(m_testCtx, groupName.c_str());
698             addChild(group);
699 
700             // Scalar types only, per-block buffers
701             createRandomCaseGroup(group, m_testCtx, "scalar_types", numCases, stage, unused);
702             // Scalar and vector types only, per-block buffers
703             createRandomCaseGroup(group, m_testCtx, "vector_types", numCases, stage, unused | FEATURE_VECTORS);
704             // All basic types, per-block buffers
705             createRandomCaseGroup(group, m_testCtx, "basic_types", numCases, stage, unused | allBasicTypes);
706             // Arrays, per-block buffers
707             createRandomCaseGroup(group, m_testCtx, "basic_arrays", numCases, stage,
708                                   unused | allBasicTypes | FEATURE_ARRAYS);
709 
710             // Basic instance arrays, per-block buffers
711             createRandomCaseGroup(group, m_testCtx, "basic_instance_arrays", numCases, stage,
712                                   unused | allBasicTypes | FEATURE_INSTANCE_ARRAYS);
713             // Nested structs, per-block buffers
714             createRandomCaseGroup(group, m_testCtx, "nested_structs", numCases, stage,
715                                   unused | allBasicTypes | FEATURE_STRUCTS);
716             // Nested structs, arrays, per-block buffers
717             createRandomCaseGroup(group, m_testCtx, "nested_structs_arrays", numCases, stage,
718                                   unused | allBasicTypes | FEATURE_STRUCTS | FEATURE_ARRAYS);
719             // Nested structs, instance arrays, per-block buffers
720             createRandomCaseGroup(group, m_testCtx, "nested_structs_instance_arrays", numCases, stage,
721                                   unused | allBasicTypes | FEATURE_STRUCTS | FEATURE_INSTANCE_ARRAYS);
722             // Nested structs, instance arrays, per-block buffers
723             createRandomCaseGroup(group, m_testCtx, "nested_structs_arrays_instance_arrays", numCases, stage,
724                                   unused | allBasicTypes | FEATURE_STRUCTS | FEATURE_ARRAYS | FEATURE_INSTANCE_ARRAYS);
725 
726             // All random features, shared buffer
727             createRandomCaseGroup(group, m_testCtx, "all_instance_array", numCases * 2, stage,
728                                   allFeatures | FEATURE_INSTANCE_ARRAYS);
729             // All random features, out of order member offsets
730             createRandomCaseGroup(group, m_testCtx, "all_unordered_and_instance_array", numCases * 2, stage,
731                                   allFeatures | FEATURE_OUT_OF_ORDER_OFFSETS | FEATURE_INSTANCE_ARRAYS);
732             // All random features, missing interface members
733             createRandomCaseGroup(group, m_testCtx, "all_missing", numCases * 2, stage,
734                                   allFeatures | FEATURE_MISSING_BLOCK_MEMBERS);
735             // All random features, unordered and missing members
736             createRandomCaseGroup(group, m_testCtx, "all_unordered_and_missing", numCases * 2, stage,
737                                   allFeatures | FEATURE_OUT_OF_ORDER_OFFSETS | FEATURE_MISSING_BLOCK_MEMBERS);
738         }
739     }
740 }
741 
742 } // namespace
743 
createTransformFeedbackFuzzLayoutTests(tcu::TestContext & testCtx)744 tcu::TestCaseGroup *createTransformFeedbackFuzzLayoutTests(tcu::TestContext &testCtx)
745 {
746     return new InterfaceBlockTests(testCtx);
747 }
748 
749 } // namespace TransformFeedback
750 } // namespace vkt
751