xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/ssbo/vktSSBOLayoutTests.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 SSBO layout tests.
24  *//*--------------------------------------------------------------------*/
25 
26 #include "vktSSBOLayoutTests.hpp"
27 #include "vktSSBOLayoutCase.hpp"
28 #include "vktSSBOCornerCase.hpp"
29 
30 #include "deUniquePtr.hpp"
31 #include "tcuCommandLine.hpp"
32 #include "tcuTestLog.hpp"
33 #include "deRandom.hpp"
34 #include "deStringUtil.hpp"
35 #include "deString.h"
36 #include "vktTestCaseUtil.hpp"
37 #include "vktTestGroupUtil.hpp"
38 #include "vkRef.hpp"
39 #include "vkRefUtil.hpp"
40 #include "vkBuilderUtil.hpp"
41 #include "vkPrograms.hpp"
42 #include "vkQueryUtil.hpp"
43 #include "vkMemUtil.hpp"
44 #include "vkTypeUtil.hpp"
45 #include "vkCmdUtil.hpp"
46 
47 #include <array>
48 #include <utility>
49 
50 namespace vkt
51 {
52 namespace ssbo
53 {
54 namespace
55 {
56 
57 using glu::StructType;
58 using glu::VarType;
59 using std::array;
60 using std::pair;
61 using std::string;
62 using std::vector;
63 using namespace vk;
64 
65 enum FeatureBits
66 {
67     FEATURE_VECTORS             = (1 << 0),
68     FEATURE_MATRICES            = (1 << 1),
69     FEATURE_ARRAYS              = (1 << 2),
70     FEATURE_STRUCTS             = (1 << 3),
71     FEATURE_NESTED_STRUCTS      = (1 << 4),
72     FEATURE_INSTANCE_ARRAYS     = (1 << 5),
73     FEATURE_UNUSED_VARS         = (1 << 6),
74     FEATURE_UNUSED_MEMBERS      = (1 << 7),
75     FEATURE_STD140_LAYOUT       = (1 << 8),
76     FEATURE_STD430_LAYOUT       = (1 << 9),
77     FEATURE_MATRIX_LAYOUT       = (1 << 10), //!< Matrix layout flags.
78     FEATURE_UNSIZED_ARRAYS      = (1 << 11),
79     FEATURE_ARRAYS_OF_ARRAYS    = (1 << 12),
80     FEATURE_RELAXED_LAYOUT      = (1 << 13),
81     FEATURE_16BIT_STORAGE       = (1 << 14),
82     FEATURE_8BIT_STORAGE        = (1 << 15),
83     FEATURE_SCALAR_LAYOUT       = (1 << 16),
84     FEATURE_DESCRIPTOR_INDEXING = (1 << 17),
85 };
86 
87 class RandomSSBOLayoutCase : public SSBOLayoutCase
88 {
89 public:
90     RandomSSBOLayoutCase(tcu::TestContext &testCtx, const char *name, BufferMode bufferMode, uint32_t features,
91                          uint32_t seed, bool usePhysStorageBuffer);
92 
93 private:
94     void generateBlock(de::Random &rnd, uint32_t layoutFlags);
95     void generateBufferVar(de::Random &rnd, BufferBlock &block, bool isLastMember);
96     glu::VarType generateType(de::Random &rnd, int structDepth, int arrayDepth, bool arrayOk, bool unusedArrayOk);
97 
98     uint32_t m_features;
99     int m_maxBlocks;
100     int m_maxInstances;
101     int m_maxArrayLength;
102     int m_maxArrayDepth;
103     int m_maxStructDepth;
104     int m_maxBlockMembers;
105     int m_maxStructMembers;
106     uint32_t m_seed;
107 
108     int m_blockNdx;
109     int m_bufferVarNdx;
110     int m_structNdx;
111 };
112 
RandomSSBOLayoutCase(tcu::TestContext & testCtx,const char * name,BufferMode bufferMode,uint32_t features,uint32_t seed,bool usePhysStorageBuffer)113 RandomSSBOLayoutCase::RandomSSBOLayoutCase(tcu::TestContext &testCtx, const char *name, BufferMode bufferMode,
114                                            uint32_t features, uint32_t seed, bool usePhysStorageBuffer)
115     : SSBOLayoutCase(testCtx, name, bufferMode, LOAD_FULL_MATRIX, STORE_FULL_MATRIX, usePhysStorageBuffer)
116     , m_features(features)
117     , m_maxBlocks((features & FEATURE_DESCRIPTOR_INDEXING) ? 1 : 4)
118     , m_maxInstances((features & FEATURE_INSTANCE_ARRAYS) ? 3 : 0)
119     , m_maxArrayLength((features & FEATURE_ARRAYS) ? 8 : 1)
120     , m_maxArrayDepth((features & FEATURE_ARRAYS_OF_ARRAYS) ? 2 : 0)
121     , m_maxStructDepth((features & FEATURE_STRUCTS) ? 2 : 0)
122     , m_maxBlockMembers(5)
123     , m_maxStructMembers(4)
124     , m_seed(seed)
125     , m_blockNdx(1)
126     , m_bufferVarNdx(1)
127     , m_structNdx(1)
128 {
129     de::Random rnd(m_seed);
130 
131     const int numBlocks = rnd.getInt(1, m_maxBlocks);
132 
133     for (int ndx = 0; ndx < numBlocks; ndx++)
134         generateBlock(rnd, 0);
135 
136     init();
137 }
138 
generateBlock(de::Random & rnd,uint32_t layoutFlags)139 void RandomSSBOLayoutCase::generateBlock(de::Random &rnd, uint32_t layoutFlags)
140 {
141     DE_ASSERT(m_blockNdx <= 'z' - 'a');
142 
143     const float instanceArrayWeight = 0.3f;
144     BufferBlock &block              = m_interface.allocBlock((string("Block") + (char)('A' + m_blockNdx)).c_str());
145     int numInstances = (m_maxInstances > 0 && rnd.getFloat() < instanceArrayWeight) ? rnd.getInt(0, m_maxInstances) : 0;
146     int numVars      = rnd.getInt(1, m_maxBlockMembers);
147 
148     if (m_features & FEATURE_DESCRIPTOR_INDEXING)
149         numInstances = rnd.getInt(2, 4);
150 
151     if (numInstances > 0)
152         block.setArraySize(numInstances);
153 
154     if (m_usePhysStorageBuffer || numInstances > 0 || rnd.getBool())
155         block.setInstanceName((string("block") + (char)('A' + m_blockNdx)).c_str());
156 
157     // Layout flag candidates.
158     vector<uint32_t> layoutFlagCandidates;
159 
160     if (m_features & FEATURE_STD430_LAYOUT)
161         layoutFlagCandidates.push_back(LAYOUT_STD430);
162 
163     if (m_features & FEATURE_STD140_LAYOUT)
164         layoutFlagCandidates.push_back(LAYOUT_STD140);
165 
166     if (m_features & FEATURE_RELAXED_LAYOUT)
167         layoutFlagCandidates.push_back(LAYOUT_RELAXED);
168 
169     if (m_features & FEATURE_SCALAR_LAYOUT)
170         layoutFlagCandidates.push_back(LAYOUT_SCALAR);
171 
172     if (m_features & FEATURE_16BIT_STORAGE)
173         layoutFlags |= LAYOUT_16BIT_STORAGE;
174 
175     if (m_features & FEATURE_8BIT_STORAGE)
176         layoutFlags |= LAYOUT_8BIT_STORAGE;
177 
178     if (m_features & FEATURE_DESCRIPTOR_INDEXING)
179         layoutFlags |= LAYOUT_DESCRIPTOR_INDEXING;
180 
181     DE_ASSERT(!layoutFlagCandidates.empty());
182 
183     layoutFlags |= rnd.choose<uint32_t>(layoutFlagCandidates.begin(), layoutFlagCandidates.end());
184 
185     if (m_features & FEATURE_MATRIX_LAYOUT)
186     {
187         static const uint32_t matrixCandidates[] = {0, LAYOUT_ROW_MAJOR, LAYOUT_COLUMN_MAJOR};
188         layoutFlags |=
189             rnd.choose<uint32_t>(&matrixCandidates[0], &matrixCandidates[DE_LENGTH_OF_ARRAY(matrixCandidates)]);
190     }
191 
192     block.setFlags(layoutFlags);
193 
194     for (int ndx = 0; ndx < numVars; ndx++)
195         generateBufferVar(rnd, block, (ndx + 1 == numVars));
196 
197     if (numVars > 0)
198     {
199         const BufferVar &lastVar     = *(block.end() - 1);
200         const glu::VarType &lastType = lastVar.getType();
201         const bool isUnsizedArr = lastType.isArrayType() && (lastType.getArraySize() == glu::VarType::UNSIZED_ARRAY);
202 
203         if (isUnsizedArr)
204         {
205             for (int instanceNdx = 0; instanceNdx < (numInstances ? numInstances : 1); instanceNdx++)
206             {
207                 const int arrSize = rnd.getInt(1, m_maxArrayLength);
208                 block.setLastUnsizedArraySize(instanceNdx, arrSize);
209             }
210         }
211     }
212 
213     m_blockNdx += 1;
214 }
215 
genName(char first,char last,int ndx)216 static std::string genName(char first, char last, int ndx)
217 {
218     std::string str = "";
219     int alphabetLen = last - first + 1;
220 
221     while (ndx > alphabetLen)
222     {
223         str.insert(str.begin(), (char)(first + ((ndx - 1) % alphabetLen)));
224         ndx = ((ndx - 1) / alphabetLen);
225     }
226 
227     str.insert(str.begin(), (char)(first + (ndx % (alphabetLen + 1)) - 1));
228 
229     return str;
230 }
231 
generateBufferVar(de::Random & rnd,BufferBlock & block,bool isLastMember)232 void RandomSSBOLayoutCase::generateBufferVar(de::Random &rnd, BufferBlock &block, bool isLastMember)
233 {
234     const float readWeight   = 0.7f;
235     const float writeWeight  = 0.7f;
236     const float accessWeight = 0.85f;
237     const bool unusedOk      = (m_features & FEATURE_UNUSED_VARS) != 0;
238     const std::string name   = genName('a', 'z', m_bufferVarNdx);
239     const glu::VarType type  = generateType(rnd, 0, 0, true, isLastMember && (m_features & FEATURE_UNSIZED_ARRAYS));
240     const bool access        = !unusedOk || (rnd.getFloat() < accessWeight);
241     const bool read          = access ? (rnd.getFloat() < readWeight) : false;
242     const bool write         = access ? (!read || (rnd.getFloat() < writeWeight)) : false;
243     const uint32_t flags     = (read ? ACCESS_READ : 0) | (write ? ACCESS_WRITE : 0);
244 
245     block.addMember(BufferVar(name.c_str(), type, flags));
246 
247     m_bufferVarNdx += 1;
248 }
249 
generateType(de::Random & rnd,int structDepth,int arrayDepth,bool arrayOk,bool unsizedArrayOk)250 glu::VarType RandomSSBOLayoutCase::generateType(de::Random &rnd, int structDepth, int arrayDepth, bool arrayOk,
251                                                 bool unsizedArrayOk)
252 {
253     const float structWeight       = 0.1f;
254     const float arrayWeight        = 0.1f;
255     const float unsizedArrayWeight = 0.8f;
256 
257     DE_ASSERT(arrayOk || !unsizedArrayOk);
258 
259     if (unsizedArrayOk && (rnd.getFloat() < unsizedArrayWeight))
260     {
261         const bool childArrayOk = ((m_features & FEATURE_ARRAYS_OF_ARRAYS) != 0) && (arrayDepth < m_maxArrayDepth);
262         const glu::VarType elementType = generateType(rnd, structDepth, arrayDepth + 1, childArrayOk, false);
263         return glu::VarType(elementType, glu::VarType::UNSIZED_ARRAY);
264     }
265     else if (structDepth < m_maxStructDepth && rnd.getFloat() < structWeight)
266     {
267         vector<glu::VarType> memberTypes;
268         int numMembers = rnd.getInt(1, m_maxStructMembers);
269 
270         // Generate members first so nested struct declarations are in correct order.
271         for (int ndx = 0; ndx < numMembers; ndx++)
272             memberTypes.push_back(
273                 generateType(rnd, structDepth + 1, arrayDepth, (arrayDepth < m_maxArrayDepth), false));
274 
275         glu::StructType &structType = m_interface.allocStruct((string("s") + genName('A', 'Z', m_structNdx)).c_str());
276         m_structNdx += 1;
277 
278         DE_ASSERT(numMembers <= 'Z' - 'A');
279         for (int ndx = 0; ndx < numMembers; ndx++)
280         {
281             structType.addMember((string("m") + (char)('A' + ndx)).c_str(), memberTypes[ndx]);
282         }
283 
284         return glu::VarType(&structType);
285     }
286     else if (m_maxArrayLength > 0 && arrayOk && rnd.getFloat() < arrayWeight)
287     {
288         const int arrayLength   = rnd.getInt(1, m_maxArrayLength);
289         const bool childArrayOk = ((m_features & FEATURE_ARRAYS_OF_ARRAYS) != 0) && (arrayDepth < m_maxArrayDepth);
290         const glu::VarType elementType = generateType(rnd, structDepth, arrayDepth + 1, childArrayOk, false);
291 
292         return glu::VarType(elementType, arrayLength);
293     }
294     else
295     {
296         vector<glu::DataType> typeCandidates;
297 
298         typeCandidates.push_back(glu::TYPE_FLOAT);
299         typeCandidates.push_back(glu::TYPE_INT);
300         typeCandidates.push_back(glu::TYPE_UINT);
301         typeCandidates.push_back(glu::TYPE_BOOL);
302 
303         if (m_features & FEATURE_16BIT_STORAGE)
304         {
305             typeCandidates.push_back(glu::TYPE_UINT16);
306             typeCandidates.push_back(glu::TYPE_INT16);
307             typeCandidates.push_back(glu::TYPE_FLOAT16);
308         }
309 
310         if (m_features & FEATURE_8BIT_STORAGE)
311         {
312             typeCandidates.push_back(glu::TYPE_UINT8);
313             typeCandidates.push_back(glu::TYPE_INT8);
314         }
315 
316         if (m_features & FEATURE_VECTORS)
317         {
318             typeCandidates.push_back(glu::TYPE_FLOAT_VEC2);
319             typeCandidates.push_back(glu::TYPE_FLOAT_VEC3);
320             typeCandidates.push_back(glu::TYPE_FLOAT_VEC4);
321             typeCandidates.push_back(glu::TYPE_INT_VEC2);
322             typeCandidates.push_back(glu::TYPE_INT_VEC3);
323             typeCandidates.push_back(glu::TYPE_INT_VEC4);
324             typeCandidates.push_back(glu::TYPE_UINT_VEC2);
325             typeCandidates.push_back(glu::TYPE_UINT_VEC3);
326             typeCandidates.push_back(glu::TYPE_UINT_VEC4);
327             typeCandidates.push_back(glu::TYPE_BOOL_VEC2);
328             typeCandidates.push_back(glu::TYPE_BOOL_VEC3);
329             typeCandidates.push_back(glu::TYPE_BOOL_VEC4);
330             if (m_features & FEATURE_16BIT_STORAGE)
331             {
332                 typeCandidates.push_back(glu::TYPE_FLOAT16_VEC2);
333                 typeCandidates.push_back(glu::TYPE_FLOAT16_VEC3);
334                 typeCandidates.push_back(glu::TYPE_FLOAT16_VEC4);
335                 typeCandidates.push_back(glu::TYPE_INT16_VEC2);
336                 typeCandidates.push_back(glu::TYPE_INT16_VEC3);
337                 typeCandidates.push_back(glu::TYPE_INT16_VEC4);
338                 typeCandidates.push_back(glu::TYPE_UINT16_VEC2);
339                 typeCandidates.push_back(glu::TYPE_UINT16_VEC3);
340                 typeCandidates.push_back(glu::TYPE_UINT16_VEC4);
341             }
342             if (m_features & FEATURE_8BIT_STORAGE)
343             {
344                 typeCandidates.push_back(glu::TYPE_INT8_VEC2);
345                 typeCandidates.push_back(glu::TYPE_INT8_VEC3);
346                 typeCandidates.push_back(glu::TYPE_INT8_VEC4);
347                 typeCandidates.push_back(glu::TYPE_UINT8_VEC2);
348                 typeCandidates.push_back(glu::TYPE_UINT8_VEC3);
349                 typeCandidates.push_back(glu::TYPE_UINT8_VEC4);
350             }
351         }
352 
353         if (m_features & FEATURE_MATRICES)
354         {
355             typeCandidates.push_back(glu::TYPE_FLOAT_MAT2);
356             typeCandidates.push_back(glu::TYPE_FLOAT_MAT2X3);
357             typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X2);
358             typeCandidates.push_back(glu::TYPE_FLOAT_MAT3);
359             typeCandidates.push_back(glu::TYPE_FLOAT_MAT3X4);
360             typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X2);
361             typeCandidates.push_back(glu::TYPE_FLOAT_MAT4X3);
362             typeCandidates.push_back(glu::TYPE_FLOAT_MAT4);
363         }
364 
365         glu::DataType type = rnd.choose<glu::DataType>(typeCandidates.begin(), typeCandidates.end());
366         glu::Precision precision;
367 
368         if (glu::dataTypeSupportsPrecisionModifier(type))
369         {
370             // Precision.
371             static const glu::Precision precisionCandidates[] = {glu::PRECISION_LOWP, glu::PRECISION_MEDIUMP,
372                                                                  glu::PRECISION_HIGHP};
373             precision                                         = rnd.choose<glu::Precision>(&precisionCandidates[0],
374                                                    &precisionCandidates[DE_LENGTH_OF_ARRAY(precisionCandidates)]);
375         }
376         else
377             precision = glu::PRECISION_LAST;
378 
379         return glu::VarType(type, precision);
380     }
381 }
382 
383 class BlockBasicTypeCase : public SSBOLayoutCase
384 {
385 public:
BlockBasicTypeCase(tcu::TestContext & testCtx,const char * name,const VarType & type,uint32_t layoutFlags,int numInstances,MatrixLoadFlags matrixLoadFlag,MatrixStoreFlags matrixStoreFlag,bool usePhysStorageBuffer,bool readonly)386     BlockBasicTypeCase(tcu::TestContext &testCtx, const char *name, const VarType &type, uint32_t layoutFlags,
387                        int numInstances, MatrixLoadFlags matrixLoadFlag, MatrixStoreFlags matrixStoreFlag,
388                        bool usePhysStorageBuffer, bool readonly)
389         : SSBOLayoutCase(testCtx, name, BUFFERMODE_PER_BLOCK, matrixLoadFlag, matrixStoreFlag, usePhysStorageBuffer)
390     {
391         VarType tempType = type;
392         while (tempType.isArrayType())
393         {
394             tempType = tempType.getElementType();
395         }
396         if (getDataTypeScalarType(tempType.getBasicType()) == glu::TYPE_UINT16 ||
397             getDataTypeScalarType(tempType.getBasicType()) == glu::TYPE_INT16 ||
398             getDataTypeScalarType(tempType.getBasicType()) == glu::TYPE_FLOAT16)
399         {
400             layoutFlags |= LAYOUT_16BIT_STORAGE;
401         }
402         if (getDataTypeScalarType(tempType.getBasicType()) == glu::TYPE_UINT8 ||
403             getDataTypeScalarType(tempType.getBasicType()) == glu::TYPE_INT8)
404         {
405             layoutFlags |= LAYOUT_8BIT_STORAGE;
406         }
407 
408         BufferBlock &block = m_interface.allocBlock("Block");
409         // For scalar layout tests with non-scalar types, add a scalar padding variable
410         // before "var", to make var only be scalar aligned.
411         if ((layoutFlags & LAYOUT_SCALAR) && !(type.isBasicType() && isDataTypeScalar(type.getBasicType())))
412         {
413             block.addMember(BufferVar("padding",
414                                       VarType(getDataTypeScalarType(tempType.getBasicType()), glu::PRECISION_LAST),
415                                       ACCESS_READ | (readonly ? 0 : ACCESS_WRITE)));
416         }
417         block.addMember(BufferVar("var", type, ACCESS_READ | (readonly ? 0 : ACCESS_WRITE)));
418 
419         block.setFlags(layoutFlags);
420 
421         if (m_usePhysStorageBuffer || numInstances > 0)
422         {
423             block.setArraySize(numInstances);
424             block.setInstanceName("block");
425         }
426 
427         init();
428     }
429 };
430 
431 class BlockBasicUnsizedArrayCase : public SSBOLayoutCase
432 {
433 public:
BlockBasicUnsizedArrayCase(tcu::TestContext & testCtx,const char * name,const VarType & elementType,int arraySize,uint32_t layoutFlags,MatrixLoadFlags matrixLoadFlag,MatrixStoreFlags matrixStoreFlag,bool usePhysStorageBuffer,bool readonly)434     BlockBasicUnsizedArrayCase(tcu::TestContext &testCtx, const char *name, const VarType &elementType, int arraySize,
435                                uint32_t layoutFlags, MatrixLoadFlags matrixLoadFlag, MatrixStoreFlags matrixStoreFlag,
436                                bool usePhysStorageBuffer, bool readonly)
437         : SSBOLayoutCase(testCtx, name, BUFFERMODE_PER_BLOCK, matrixLoadFlag, matrixStoreFlag, usePhysStorageBuffer)
438     {
439         BufferBlock &block = m_interface.allocBlock("Block");
440         block.addMember(BufferVar("var", VarType(elementType, VarType::UNSIZED_ARRAY),
441                                   ACCESS_READ | (readonly ? 0 : ACCESS_WRITE)));
442 
443         VarType tempType = elementType;
444         while (tempType.isArrayType())
445         {
446             tempType = tempType.getElementType();
447         }
448         if (getDataTypeScalarType(tempType.getBasicType()) == glu::TYPE_UINT16 ||
449             getDataTypeScalarType(tempType.getBasicType()) == glu::TYPE_INT16 ||
450             getDataTypeScalarType(tempType.getBasicType()) == glu::TYPE_FLOAT16)
451         {
452             layoutFlags |= LAYOUT_16BIT_STORAGE;
453         }
454         if (getDataTypeScalarType(tempType.getBasicType()) == glu::TYPE_UINT8 ||
455             getDataTypeScalarType(tempType.getBasicType()) == glu::TYPE_INT8)
456         {
457             layoutFlags |= LAYOUT_8BIT_STORAGE;
458         }
459 
460         block.setFlags(layoutFlags);
461 
462         block.setLastUnsizedArraySize(0, arraySize);
463 
464         if (m_usePhysStorageBuffer)
465         {
466             block.setInstanceName("block");
467         }
468 
469         init();
470     }
471 };
472 
createRandomCaseGroup(tcu::TestCaseGroup * parentGroup,tcu::TestContext & testCtx,const char * groupName,SSBOLayoutCase::BufferMode bufferMode,uint32_t features,int numCases,uint32_t baseSeed,bool usePhysStorageBuffer)473 static void createRandomCaseGroup(tcu::TestCaseGroup *parentGroup, tcu::TestContext &testCtx, const char *groupName,
474                                   SSBOLayoutCase::BufferMode bufferMode, uint32_t features, int numCases,
475                                   uint32_t baseSeed, bool usePhysStorageBuffer)
476 {
477     tcu::TestCaseGroup *group = new tcu::TestCaseGroup(testCtx, groupName);
478     parentGroup->addChild(group);
479 
480     baseSeed += (uint32_t)testCtx.getCommandLine().getBaseSeed();
481 
482     for (int ndx = 0; ndx < numCases; ndx++)
483         group->addChild(new RandomSSBOLayoutCase(testCtx, de::toString(ndx).c_str(), bufferMode, features,
484                                                  (uint32_t)ndx + baseSeed, usePhysStorageBuffer));
485 }
486 
487 class BlockSingleStructCase : public SSBOLayoutCase
488 {
489 public:
BlockSingleStructCase(tcu::TestContext & testCtx,const char * name,uint32_t layoutFlags,BufferMode bufferMode,int numInstances,MatrixLoadFlags matrixLoadFlag,MatrixStoreFlags matrixStoreFlag,bool usePhysStorageBuffer,bool readonly)490     BlockSingleStructCase(tcu::TestContext &testCtx, const char *name, uint32_t layoutFlags, BufferMode bufferMode,
491                           int numInstances, MatrixLoadFlags matrixLoadFlag, MatrixStoreFlags matrixStoreFlag,
492                           bool usePhysStorageBuffer, bool readonly)
493         : SSBOLayoutCase(testCtx, name, bufferMode, matrixLoadFlag, matrixStoreFlag, usePhysStorageBuffer)
494         , m_layoutFlags(layoutFlags)
495         , m_numInstances(numInstances)
496     {
497         StructType &typeS = m_interface.allocStruct("S");
498         typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, glu::PRECISION_HIGHP)); // \todo [pyry] First member is unused.
499         typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, glu::PRECISION_MEDIUMP), 4));
500         typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP));
501 
502         BufferBlock &block = m_interface.allocBlock("Block");
503         block.addMember(BufferVar("s", VarType(&typeS), ACCESS_READ | (readonly ? 0 : ACCESS_WRITE)));
504         block.setFlags(m_layoutFlags);
505 
506         if (m_usePhysStorageBuffer || m_numInstances > 0)
507         {
508             block.setInstanceName("block");
509             block.setArraySize(m_numInstances);
510         }
511 
512         init();
513     }
514 
515 private:
516     uint32_t m_layoutFlags;
517     int m_numInstances;
518 };
519 
520 class BlockSingleStructArrayCase : public SSBOLayoutCase
521 {
522 public:
BlockSingleStructArrayCase(tcu::TestContext & testCtx,const char * name,uint32_t layoutFlags,BufferMode bufferMode,int numInstances,MatrixLoadFlags matrixLoadFlag,MatrixStoreFlags matrixStoreFlag,bool usePhysStorageBuffer)523     BlockSingleStructArrayCase(tcu::TestContext &testCtx, const char *name, uint32_t layoutFlags, BufferMode bufferMode,
524                                int numInstances, MatrixLoadFlags matrixLoadFlag, MatrixStoreFlags matrixStoreFlag,
525                                bool usePhysStorageBuffer)
526         : SSBOLayoutCase(testCtx, name, bufferMode, matrixLoadFlag, matrixStoreFlag, usePhysStorageBuffer)
527         , m_layoutFlags(layoutFlags)
528         , m_numInstances(numInstances)
529     {
530         StructType &typeS = m_interface.allocStruct("S");
531         typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, glu::PRECISION_HIGHP)); // \todo [pyry] UNUSED
532         typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, glu::PRECISION_MEDIUMP), 4));
533         typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP));
534 
535         BufferBlock &block = m_interface.allocBlock("Block");
536         block.addMember(BufferVar("u", VarType(glu::TYPE_UINT, glu::PRECISION_LOWP), 0 /* no access */));
537         block.addMember(BufferVar("s", VarType(VarType(&typeS), 3), ACCESS_READ | ACCESS_WRITE));
538         block.addMember(BufferVar("v", VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_MEDIUMP), ACCESS_WRITE));
539         block.setFlags(m_layoutFlags);
540 
541         if (m_usePhysStorageBuffer || m_numInstances > 0)
542         {
543             block.setInstanceName("block");
544             block.setArraySize(m_numInstances);
545         }
546 
547         init();
548     }
549 
550 private:
551     uint32_t m_layoutFlags;
552     int m_numInstances;
553 };
554 
555 class BlockSingleNestedStructCase : public SSBOLayoutCase
556 {
557 public:
BlockSingleNestedStructCase(tcu::TestContext & testCtx,const char * name,uint32_t layoutFlags,BufferMode bufferMode,int numInstances,MatrixLoadFlags matrixLoadFlag,MatrixStoreFlags matrixStoreFlag,bool usePhysStorageBuffer)558     BlockSingleNestedStructCase(tcu::TestContext &testCtx, const char *name, uint32_t layoutFlags,
559                                 BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag,
560                                 MatrixStoreFlags matrixStoreFlag, bool usePhysStorageBuffer)
561         : SSBOLayoutCase(testCtx, name, bufferMode, matrixLoadFlag, matrixStoreFlag, usePhysStorageBuffer)
562         , m_layoutFlags(layoutFlags)
563         , m_numInstances(numInstances)
564     {
565         StructType &typeS = m_interface.allocStruct("S");
566         typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, glu::PRECISION_HIGHP));
567         typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT3, glu::PRECISION_MEDIUMP), 4));
568         typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)); // \todo [pyry] UNUSED
569 
570         StructType &typeT = m_interface.allocStruct("T");
571         typeT.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, glu::PRECISION_MEDIUMP));
572         typeT.addMember("b", VarType(&typeS));
573 
574         BufferBlock &block = m_interface.allocBlock("Block");
575         block.addMember(BufferVar("s", VarType(&typeS), ACCESS_READ));
576         block.addMember(BufferVar("v", VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_LOWP), 0 /* no access */));
577         block.addMember(BufferVar("t", VarType(&typeT), ACCESS_READ | ACCESS_WRITE));
578         block.addMember(BufferVar("u", VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP), ACCESS_WRITE));
579         block.setFlags(m_layoutFlags);
580 
581         if (m_usePhysStorageBuffer || m_numInstances > 0)
582         {
583             block.setInstanceName("block");
584             block.setArraySize(m_numInstances);
585         }
586 
587         init();
588     }
589 
590 private:
591     uint32_t m_layoutFlags;
592     int m_numInstances;
593 };
594 
595 class BlockSingleNestedStructArrayCase : public SSBOLayoutCase
596 {
597 public:
BlockSingleNestedStructArrayCase(tcu::TestContext & testCtx,const char * name,uint32_t layoutFlags,BufferMode bufferMode,int numInstances,MatrixLoadFlags matrixLoadFlag,MatrixStoreFlags matrixStoreFlag,bool usePhysStorageBuffer)598     BlockSingleNestedStructArrayCase(tcu::TestContext &testCtx, const char *name, uint32_t layoutFlags,
599                                      BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag,
600                                      MatrixStoreFlags matrixStoreFlag, bool usePhysStorageBuffer)
601         : SSBOLayoutCase(testCtx, name, bufferMode, matrixLoadFlag, matrixStoreFlag, usePhysStorageBuffer)
602         , m_layoutFlags(layoutFlags)
603         , m_numInstances(numInstances)
604     {
605         StructType &typeS = m_interface.allocStruct("S");
606         typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, glu::PRECISION_HIGHP));
607         typeS.addMember("b", VarType(VarType(glu::TYPE_INT_VEC2, glu::PRECISION_MEDIUMP), 4));
608         typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)); // \todo [pyry] UNUSED
609 
610         StructType &typeT = m_interface.allocStruct("T");
611         typeT.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, glu::PRECISION_MEDIUMP));
612         typeT.addMember("b", VarType(VarType(&typeS), 3));
613 
614         BufferBlock &block = m_interface.allocBlock("Block");
615         block.addMember(BufferVar("s", VarType(&typeS), ACCESS_WRITE));
616         block.addMember(BufferVar("v", VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_LOWP), 0 /* no access */));
617         block.addMember(BufferVar("t", VarType(VarType(&typeT), 2), ACCESS_READ));
618         block.addMember(BufferVar("u", VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP), ACCESS_READ | ACCESS_WRITE));
619         block.setFlags(m_layoutFlags);
620 
621         if (m_usePhysStorageBuffer || m_numInstances > 0)
622         {
623             block.setInstanceName("block");
624             block.setArraySize(m_numInstances);
625         }
626 
627         init();
628     }
629 
630 private:
631     uint32_t m_layoutFlags;
632     int m_numInstances;
633 };
634 
635 class BlockUnsizedStructArrayCase : public SSBOLayoutCase
636 {
637 public:
BlockUnsizedStructArrayCase(tcu::TestContext & testCtx,const char * name,uint32_t layoutFlags,BufferMode bufferMode,int numInstances,MatrixLoadFlags matrixLoadFlag,MatrixStoreFlags matrixStoreFlag,bool usePhysStorageBuffer)638     BlockUnsizedStructArrayCase(tcu::TestContext &testCtx, const char *name, uint32_t layoutFlags,
639                                 BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag,
640                                 MatrixStoreFlags matrixStoreFlag, bool usePhysStorageBuffer)
641         : SSBOLayoutCase(testCtx, name, bufferMode, matrixLoadFlag, matrixStoreFlag, usePhysStorageBuffer)
642         , m_layoutFlags(layoutFlags)
643         , m_numInstances(numInstances)
644     {
645         StructType &typeS = m_interface.allocStruct("S");
646         typeS.addMember("a", VarType(glu::TYPE_UINT_VEC2, glu::PRECISION_HIGHP)); // \todo [pyry] UNUSED
647         typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_MAT2X4, glu::PRECISION_MEDIUMP), 4));
648         typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC3, glu::PRECISION_HIGHP));
649 
650         BufferBlock &block = m_interface.allocBlock("Block");
651         block.addMember(BufferVar("u", VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_LOWP), 0 /* no access */));
652         block.addMember(BufferVar("v", VarType(glu::TYPE_UINT, glu::PRECISION_MEDIUMP), ACCESS_WRITE));
653         block.addMember(BufferVar("s", VarType(VarType(&typeS), VarType::UNSIZED_ARRAY), ACCESS_READ | ACCESS_WRITE));
654         block.setFlags(m_layoutFlags);
655 
656         if (m_usePhysStorageBuffer || m_numInstances > 0)
657         {
658             block.setInstanceName("block");
659             block.setArraySize(m_numInstances);
660         }
661 
662         {
663             de::Random rnd(246);
664             for (int ndx = 0; ndx < (m_numInstances ? m_numInstances : 1); ndx++)
665             {
666                 const int lastArrayLen = rnd.getInt(1, 5);
667                 block.setLastUnsizedArraySize(ndx, lastArrayLen);
668             }
669         }
670 
671         init();
672     }
673 
674 private:
675     uint32_t m_layoutFlags;
676     int m_numInstances;
677 };
678 
679 class Block2LevelUnsizedStructArrayCase : public SSBOLayoutCase
680 {
681 public:
Block2LevelUnsizedStructArrayCase(tcu::TestContext & testCtx,const char * name,uint32_t layoutFlags,BufferMode bufferMode,int numInstances,MatrixLoadFlags matrixLoadFlag,MatrixStoreFlags matrixStoreFlag,bool usePhysStorageBuffer)682     Block2LevelUnsizedStructArrayCase(tcu::TestContext &testCtx, const char *name, uint32_t layoutFlags,
683                                       BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag,
684                                       MatrixStoreFlags matrixStoreFlag, bool usePhysStorageBuffer)
685         : SSBOLayoutCase(testCtx, name, bufferMode, matrixLoadFlag, matrixStoreFlag, usePhysStorageBuffer)
686         , m_layoutFlags(layoutFlags)
687         , m_numInstances(numInstances)
688     {
689         StructType &typeS = m_interface.allocStruct("S");
690         typeS.addMember("a", VarType(glu::TYPE_INT_VEC3, glu::PRECISION_HIGHP));
691         typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP));
692 
693         BufferBlock &block = m_interface.allocBlock("Block");
694         block.addMember(BufferVar("u", VarType(glu::TYPE_UINT, glu::PRECISION_LOWP), 0 /* no access */));
695         block.addMember(BufferVar("v", VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_MEDIUMP), ACCESS_WRITE));
696         block.addMember(
697             BufferVar("s", VarType(VarType(VarType(&typeS), 2), VarType::UNSIZED_ARRAY), ACCESS_READ | ACCESS_WRITE));
698         block.setFlags(m_layoutFlags);
699 
700         if (m_usePhysStorageBuffer || m_numInstances > 0)
701         {
702             block.setInstanceName("block");
703             block.setArraySize(m_numInstances);
704         }
705 
706         {
707             de::Random rnd(2344);
708             for (int ndx = 0; ndx < (m_numInstances ? m_numInstances : 1); ndx++)
709             {
710                 const int lastArrayLen = rnd.getInt(1, 5);
711                 block.setLastUnsizedArraySize(ndx, lastArrayLen);
712             }
713         }
714 
715         init();
716     }
717 
718 private:
719     uint32_t m_layoutFlags;
720     int m_numInstances;
721 };
722 
723 class BlockUnsizedNestedStructArrayCase : public SSBOLayoutCase
724 {
725 public:
BlockUnsizedNestedStructArrayCase(tcu::TestContext & testCtx,const char * name,uint32_t layoutFlags,BufferMode bufferMode,int numInstances,MatrixLoadFlags matrixLoadFlag,MatrixStoreFlags matrixStoreFlag,bool usePhysStorageBuffer)726     BlockUnsizedNestedStructArrayCase(tcu::TestContext &testCtx, const char *name, uint32_t layoutFlags,
727                                       BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag,
728                                       MatrixStoreFlags matrixStoreFlag, bool usePhysStorageBuffer)
729         : SSBOLayoutCase(testCtx, name, bufferMode, matrixLoadFlag, matrixStoreFlag, usePhysStorageBuffer)
730         , m_layoutFlags(layoutFlags)
731         , m_numInstances(numInstances)
732     {
733         StructType &typeS = m_interface.allocStruct("S");
734         typeS.addMember("a", VarType(glu::TYPE_UINT_VEC3, glu::PRECISION_HIGHP));
735         typeS.addMember("b", VarType(VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_MEDIUMP), 4));
736         typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)); // \todo [pyry] UNUSED
737 
738         StructType &typeT = m_interface.allocStruct("T");
739         typeT.addMember("a", VarType(glu::TYPE_FLOAT_MAT4X3, glu::PRECISION_MEDIUMP));
740         typeT.addMember("b", VarType(VarType(&typeS), 3));
741         typeT.addMember("c", VarType(glu::TYPE_INT, glu::PRECISION_HIGHP));
742 
743         BufferBlock &block = m_interface.allocBlock("Block");
744         block.addMember(BufferVar("s", VarType(&typeS), ACCESS_WRITE));
745         block.addMember(BufferVar("v", VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_LOWP), 0 /* no access */));
746         block.addMember(BufferVar("u", VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP), ACCESS_READ | ACCESS_WRITE));
747         block.addMember(BufferVar("t", VarType(VarType(&typeT), VarType::UNSIZED_ARRAY), ACCESS_READ));
748         block.setFlags(m_layoutFlags);
749 
750         if (m_usePhysStorageBuffer || m_numInstances > 0)
751         {
752             block.setInstanceName("block");
753             block.setArraySize(m_numInstances);
754         }
755 
756         {
757             de::Random rnd(7921);
758             for (int ndx = 0; ndx < (m_numInstances ? m_numInstances : 1); ndx++)
759             {
760                 const int lastArrayLen = rnd.getInt(1, 5);
761                 block.setLastUnsizedArraySize(ndx, lastArrayLen);
762             }
763         }
764 
765         init();
766     }
767 
768 private:
769     uint32_t m_layoutFlags;
770     int m_numInstances;
771 };
772 
773 class BlockMultiBasicTypesCase : public SSBOLayoutCase
774 {
775 public:
BlockMultiBasicTypesCase(tcu::TestContext & testCtx,const char * name,uint32_t flagsA,uint32_t flagsB,BufferMode bufferMode,int numInstances,MatrixLoadFlags matrixLoadFlag,MatrixStoreFlags matrixStoreFlag,bool usePhysStorageBuffer)776     BlockMultiBasicTypesCase(tcu::TestContext &testCtx, const char *name, uint32_t flagsA, uint32_t flagsB,
777                              BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag,
778                              MatrixStoreFlags matrixStoreFlag, bool usePhysStorageBuffer)
779         : SSBOLayoutCase(testCtx, name, bufferMode, matrixLoadFlag, matrixStoreFlag, usePhysStorageBuffer)
780         , m_flagsA(flagsA)
781         , m_flagsB(flagsB)
782         , m_numInstances(numInstances)
783     {
784         BufferBlock &blockA = m_interface.allocBlock("BlockA");
785         blockA.addMember(BufferVar("a", VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP), ACCESS_READ | ACCESS_WRITE));
786         blockA.addMember(BufferVar("b", VarType(glu::TYPE_UINT_VEC3, glu::PRECISION_LOWP), 0 /* no access */));
787         blockA.addMember(BufferVar("c", VarType(glu::TYPE_FLOAT_MAT2, glu::PRECISION_MEDIUMP), ACCESS_READ));
788         blockA.setInstanceName("blockA");
789         blockA.setFlags(m_flagsA);
790 
791         BufferBlock &blockB = m_interface.allocBlock("BlockB");
792         blockB.addMember(BufferVar("a", VarType(glu::TYPE_FLOAT_MAT3, glu::PRECISION_MEDIUMP), ACCESS_WRITE));
793         blockB.addMember(BufferVar("b", VarType(glu::TYPE_INT_VEC2, glu::PRECISION_LOWP), ACCESS_READ));
794         blockB.addMember(BufferVar("c", VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP), 0 /* no access */));
795         blockB.addMember(BufferVar("d", VarType(glu::TYPE_BOOL, glu::PRECISION_LAST), ACCESS_READ | ACCESS_WRITE));
796         blockB.setInstanceName("blockB");
797         blockB.setFlags(m_flagsB);
798 
799         if (m_numInstances > 0)
800         {
801             blockA.setArraySize(m_numInstances);
802             blockB.setArraySize(m_numInstances);
803         }
804 
805         init();
806     }
807 
808 private:
809     uint32_t m_flagsA;
810     uint32_t m_flagsB;
811     int m_numInstances;
812 };
813 
814 class BlockMultiNestedStructCase : public SSBOLayoutCase
815 {
816 public:
BlockMultiNestedStructCase(tcu::TestContext & testCtx,const char * name,uint32_t flagsA,uint32_t flagsB,BufferMode bufferMode,int numInstances,MatrixLoadFlags matrixLoadFlag,MatrixStoreFlags matrixStoreFlag,bool usePhysStorageBuffer)817     BlockMultiNestedStructCase(tcu::TestContext &testCtx, const char *name, uint32_t flagsA, uint32_t flagsB,
818                                BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag,
819                                MatrixStoreFlags matrixStoreFlag, bool usePhysStorageBuffer)
820         : SSBOLayoutCase(testCtx, name, bufferMode, matrixLoadFlag, matrixStoreFlag, usePhysStorageBuffer)
821         , m_flagsA(flagsA)
822         , m_flagsB(flagsB)
823         , m_numInstances(numInstances)
824     {
825         StructType &typeS = m_interface.allocStruct("S");
826         typeS.addMember("a", VarType(glu::TYPE_FLOAT_MAT3, glu::PRECISION_LOWP));
827         typeS.addMember("b", VarType(VarType(glu::TYPE_INT_VEC2, glu::PRECISION_MEDIUMP), 4));
828         typeS.addMember("c", VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP));
829 
830         StructType &typeT = m_interface.allocStruct("T");
831         typeT.addMember("a", VarType(glu::TYPE_UINT, glu::PRECISION_MEDIUMP)); // \todo [pyry] UNUSED
832         typeT.addMember("b", VarType(&typeS));
833         typeT.addMember("c", VarType(glu::TYPE_BOOL_VEC4, glu::PRECISION_LAST));
834 
835         BufferBlock &blockA = m_interface.allocBlock("BlockA");
836         blockA.addMember(BufferVar("a", VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP), ACCESS_READ | ACCESS_WRITE));
837         blockA.addMember(BufferVar("b", VarType(&typeS), ACCESS_WRITE));
838         blockA.addMember(BufferVar("c", VarType(glu::TYPE_UINT_VEC3, glu::PRECISION_LOWP), 0 /* no access */));
839         blockA.setInstanceName("blockA");
840         blockA.setFlags(m_flagsA);
841 
842         BufferBlock &blockB = m_interface.allocBlock("BlockB");
843         blockB.addMember(BufferVar("a", VarType(glu::TYPE_FLOAT_MAT2, glu::PRECISION_MEDIUMP), ACCESS_WRITE));
844         blockB.addMember(BufferVar("b", VarType(&typeT), ACCESS_READ | ACCESS_WRITE));
845         blockB.addMember(BufferVar("c", VarType(glu::TYPE_BOOL_VEC4, glu::PRECISION_LAST), 0 /* no access */));
846         blockB.addMember(BufferVar("d", VarType(glu::TYPE_BOOL, glu::PRECISION_LAST), ACCESS_READ | ACCESS_WRITE));
847         blockB.setInstanceName("blockB");
848         blockB.setFlags(m_flagsB);
849 
850         if (m_numInstances > 0)
851         {
852             blockA.setArraySize(m_numInstances);
853             blockB.setArraySize(m_numInstances);
854         }
855 
856         init();
857     }
858 
859 private:
860     uint32_t m_flagsA;
861     uint32_t m_flagsB;
862     int m_numInstances;
863 };
864 
865 // unsized_array_length
866 
867 struct UnsizedArrayCaseParams
868 {
869     int elementSize;
870     vk::VkDeviceSize bufferSize;
871     bool useMinBufferOffset;
872     vk::VkDeviceSize bufferBindLength;
873     const char *name;
874 };
875 
createUnsizedArrayLengthProgs(SourceCollections & dst,UnsizedArrayCaseParams)876 void createUnsizedArrayLengthProgs(SourceCollections &dst, UnsizedArrayCaseParams)
877 {
878     dst.glslSources.add("comp") << glu::ComputeSource("#version 310 es\n"
879                                                       "layout(set=0, binding=0, std430) readonly buffer x {\n"
880                                                       "   int xs[];\n"
881                                                       "};\n"
882                                                       "layout(set=0, binding=1, std430) writeonly buffer y {\n"
883                                                       "   int observed_size;\n"
884                                                       "};\n"
885                                                       "layout(local_size_x=1) in;\n"
886                                                       "void main (void) {\n"
887                                                       "   observed_size = xs.length();\n"
888                                                       "}\n");
889 }
890 
ssboUnsizedArrayLengthTest(Context & context,UnsizedArrayCaseParams params)891 tcu::TestStatus ssboUnsizedArrayLengthTest(Context &context, UnsizedArrayCaseParams params)
892 {
893     const DeviceInterface &vk = context.getDeviceInterface();
894     const VkDevice device     = context.getDevice();
895     const VkQueue queue       = context.getUniversalQueue();
896     Allocator &allocator      = context.getDefaultAllocator();
897 
898     DescriptorSetLayoutBuilder builder;
899     builder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT); // input buffer
900     builder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT); // result buffer
901 
902     const Unique<VkDescriptorSetLayout> descriptorSetLayout(builder.build(vk, device));
903     const Unique<VkDescriptorPool> descriptorPool(
904         vk::DescriptorPoolBuilder()
905             .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2u)
906             .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1));
907 
908     const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
909         VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
910         DE_NULL,
911         (VkPipelineLayoutCreateFlags)0,
912         1,                          // setLayoutCount,
913         &descriptorSetLayout.get(), // pSetLayouts
914         0,                          // pushConstantRangeCount
915         DE_NULL,                    // pPushConstantRanges
916     };
917     const Unique<VkPipelineLayout> pipelineLayout(createPipelineLayout(vk, device, &pipelineLayoutCreateInfo));
918 
919     const Unique<VkShaderModule> computeModule(
920         createShaderModule(vk, device, context.getBinaryCollection().get("comp"), (VkShaderModuleCreateFlags)0u));
921 
922     const VkPipelineShaderStageCreateInfo shaderCreateInfo = {
923         VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
924         DE_NULL,
925         (VkPipelineShaderStageCreateFlags)0,
926         VK_SHADER_STAGE_COMPUTE_BIT, // stage
927         *computeModule,              // shader
928         "main",
929         DE_NULL, // pSpecializationInfo
930     };
931 
932     const VkComputePipelineCreateInfo pipelineCreateInfo = {
933         VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
934         DE_NULL,
935         0u,                // flags
936         shaderCreateInfo,  // cs
937         *pipelineLayout,   // layout
938         (vk::VkPipeline)0, // basePipelineHandle
939         0u,                // basePipelineIndex
940     };
941 
942     const Unique<VkPipeline> pipeline(createComputePipeline(vk, device, (VkPipelineCache)0u, &pipelineCreateInfo));
943 
944     // Input buffer
945     const VkBufferCreateInfo inputBufferCreateInfo = {
946         VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
947         DE_NULL,
948         0,                                  // flags
949         (VkDeviceSize)params.bufferSize,    // size
950         VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, // usage TODO: also test _DYNAMIC case.
951         VK_SHARING_MODE_EXCLUSIVE,
952         0u,      // queueFamilyCount
953         DE_NULL, // pQueueFamilyIndices
954     };
955     const Unique<VkBuffer> inputBuffer(createBuffer(vk, device, &inputBufferCreateInfo));
956     const VkMemoryRequirements inputBufferRequirements = getBufferMemoryRequirements(vk, device, *inputBuffer);
957     const de::MovePtr<Allocation> inputBufferMemory =
958         allocator.allocate(inputBufferRequirements, MemoryRequirement::HostVisible);
959 
960     VK_CHECK(vk.bindBufferMemory(device, *inputBuffer, inputBufferMemory->getMemory(), inputBufferMemory->getOffset()));
961     // Note: don't care about the contents of the input buffer -- we only determine a size.
962 
963     // Output buffer
964     const VkBufferCreateInfo outputBufferCreateInfo = {
965         VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
966         DE_NULL,
967         0,
968         (VkDeviceSize)4,
969         VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
970         VK_SHARING_MODE_EXCLUSIVE,
971         0u,
972         DE_NULL,
973     };
974     const Unique<VkBuffer> outputBuffer(createBuffer(vk, device, &outputBufferCreateInfo));
975     const VkMemoryRequirements outputBufferRequirements = getBufferMemoryRequirements(vk, device, *outputBuffer);
976     const de::MovePtr<Allocation> outputBufferMemory =
977         allocator.allocate(outputBufferRequirements, MemoryRequirement::HostVisible);
978 
979     VK_CHECK(
980         vk.bindBufferMemory(device, *outputBuffer, outputBufferMemory->getMemory(), outputBufferMemory->getOffset()));
981 
982     // Initialize output buffer contents
983     const VkMappedMemoryRange range = {
984         VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, // sType
985         DE_NULL,                               // pNext
986         outputBufferMemory->getMemory(),       // memory
987         0,                                     // offset
988         VK_WHOLE_SIZE,                         // size
989     };
990     int *outputBufferPtr = (int *)outputBufferMemory->getHostPtr();
991     *outputBufferPtr     = -1;
992     VK_CHECK(vk.flushMappedMemoryRanges(device, 1u, &range));
993 
994     // Build descriptor set
995     vk::VkDeviceSize bufferBindOffset = 0;
996     if (params.useMinBufferOffset)
997     {
998         const VkPhysicalDeviceLimits deviceLimits =
999             getPhysicalDeviceProperties(context.getInstanceInterface(), context.getPhysicalDevice()).limits;
1000         bufferBindOffset = deviceLimits.minStorageBufferOffsetAlignment;
1001     }
1002 
1003     const VkDescriptorBufferInfo inputBufferDesc =
1004         makeDescriptorBufferInfo(*inputBuffer, bufferBindOffset, params.bufferBindLength);
1005     const VkDescriptorBufferInfo outputBufferDesc = makeDescriptorBufferInfo(*outputBuffer, 0u, VK_WHOLE_SIZE);
1006 
1007     const VkDescriptorSetAllocateInfo descAllocInfo = {
1008         VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
1009         DE_NULL,
1010         *descriptorPool,            // pool
1011         1u,                         // setLayoutCount
1012         &descriptorSetLayout.get(), // pSetLayouts
1013     };
1014     const Unique<VkDescriptorSet> descSet(allocateDescriptorSet(vk, device, &descAllocInfo));
1015 
1016     DescriptorSetUpdateBuilder()
1017         .writeSingle(*descSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
1018                      &inputBufferDesc)
1019         .writeSingle(*descSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
1020                      &outputBufferDesc)
1021         .update(vk, device);
1022 
1023     const VkCommandPoolCreateInfo cmdPoolParams = {
1024         VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,      // sType
1025         DE_NULL,                                         // pNext
1026         VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, // flags
1027         context.getUniversalQueueFamilyIndex(),          // queueFamilyIndex
1028     };
1029     const Unique<VkCommandPool> cmdPool(createCommandPool(vk, device, &cmdPoolParams));
1030 
1031     // Command buffer
1032     const VkCommandBufferAllocateInfo cmdBufParams = {
1033         VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // sType
1034         DE_NULL,                                        // pNext
1035         *cmdPool,                                       // pool
1036         VK_COMMAND_BUFFER_LEVEL_PRIMARY,                // level
1037         1u,                                             // bufferCount
1038     };
1039     const Unique<VkCommandBuffer> cmdBuf(allocateCommandBuffer(vk, device, &cmdBufParams));
1040 
1041     // Record commands
1042     beginCommandBuffer(vk, *cmdBuf);
1043 
1044     vk.cmdBindPipeline(*cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
1045     vk.cmdBindDescriptorSets(*cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descSet.get(), 0u,
1046                              DE_NULL);
1047     vk.cmdDispatch(*cmdBuf, 1, 1, 1);
1048 
1049     const VkMemoryBarrier barrier = {
1050         VK_STRUCTURE_TYPE_MEMORY_BARRIER, // sType
1051         DE_NULL,                          // pNext
1052         VK_ACCESS_SHADER_WRITE_BIT,       // srcAccessMask
1053         VK_ACCESS_HOST_READ_BIT,          // dstAccessMask
1054     };
1055     vk.cmdPipelineBarrier(*cmdBuf, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0,
1056                           1, &barrier, 0, DE_NULL, 0, DE_NULL);
1057 
1058     endCommandBuffer(vk, *cmdBuf);
1059 
1060     submitCommandsAndWait(vk, device, queue, cmdBuf.get());
1061 
1062     // Read back output buffer contents
1063     VK_CHECK(vk.invalidateMappedMemoryRanges(device, 1, &range));
1064 
1065     // Expected number of elements in array at end of storage buffer
1066     const VkDeviceSize boundLength =
1067         params.bufferBindLength == VK_WHOLE_SIZE ? params.bufferSize - bufferBindOffset : params.bufferBindLength;
1068     const int expectedResult = (int)(boundLength / params.elementSize);
1069     const int actualResult   = *outputBufferPtr;
1070 
1071     context.getTestContext().getLog() << tcu::TestLog::Message << "Buffer size " << params.bufferSize << " offset "
1072                                       << bufferBindOffset << " length " << params.bufferBindLength << " element size "
1073                                       << params.elementSize << " expected array size: " << expectedResult
1074                                       << " actual array size: " << actualResult << tcu::TestLog::EndMessage;
1075 
1076     if (expectedResult == actualResult)
1077         return tcu::TestStatus::pass("Got expected array size");
1078     else
1079         return tcu::TestStatus::fail("Mismatch array size");
1080 }
1081 
1082 class SSBOLayoutTests : public tcu::TestCaseGroup
1083 {
1084 public:
1085     SSBOLayoutTests(tcu::TestContext &testCtx, bool usePhysStorageBuffer, bool readonly);
1086     ~SSBOLayoutTests(void);
1087 
1088     void init(void);
1089 
1090 private:
1091     SSBOLayoutTests(const SSBOLayoutTests &other);
1092     SSBOLayoutTests &operator=(const SSBOLayoutTests &other);
1093 
1094     bool m_usePhysStorageBuffer;
1095     bool m_readonly;
1096 };
1097 
SSBOLayoutTests(tcu::TestContext & testCtx,bool usePhysStorageBuffer,bool readonly)1098 SSBOLayoutTests::SSBOLayoutTests(tcu::TestContext &testCtx, bool usePhysStorageBuffer, bool readonly)
1099     : TestCaseGroup(testCtx, "layout")
1100     , m_usePhysStorageBuffer(usePhysStorageBuffer)
1101     , m_readonly(readonly)
1102 {
1103 }
1104 
~SSBOLayoutTests(void)1105 SSBOLayoutTests::~SSBOLayoutTests(void)
1106 {
1107 }
1108 
init(void)1109 void SSBOLayoutTests::init(void)
1110 {
1111     static const glu::DataType basicTypes[] = {
1112         glu::TYPE_FLOAT,        glu::TYPE_FLOAT_VEC2,   glu::TYPE_FLOAT_VEC3,   glu::TYPE_FLOAT_VEC4,
1113         glu::TYPE_INT,          glu::TYPE_INT_VEC2,     glu::TYPE_INT_VEC3,     glu::TYPE_INT_VEC4,
1114         glu::TYPE_UINT,         glu::TYPE_UINT_VEC2,    glu::TYPE_UINT_VEC3,    glu::TYPE_UINT_VEC4,
1115         glu::TYPE_BOOL,         glu::TYPE_BOOL_VEC2,    glu::TYPE_BOOL_VEC3,    glu::TYPE_BOOL_VEC4,
1116         glu::TYPE_FLOAT_MAT2,   glu::TYPE_FLOAT_MAT3,   glu::TYPE_FLOAT_MAT4,   glu::TYPE_FLOAT_MAT2X3,
1117         glu::TYPE_FLOAT_MAT2X4, glu::TYPE_FLOAT_MAT3X2, glu::TYPE_FLOAT_MAT3X4, glu::TYPE_FLOAT_MAT4X2,
1118         glu::TYPE_FLOAT_MAT4X3, glu::TYPE_UINT8,        glu::TYPE_UINT8_VEC2,   glu::TYPE_UINT8_VEC3,
1119         glu::TYPE_UINT8_VEC4,   glu::TYPE_INT8,         glu::TYPE_INT8_VEC2,    glu::TYPE_INT8_VEC3,
1120         glu::TYPE_INT8_VEC4,    glu::TYPE_UINT16,       glu::TYPE_UINT16_VEC2,  glu::TYPE_UINT16_VEC3,
1121         glu::TYPE_UINT16_VEC4,  glu::TYPE_INT16,        glu::TYPE_INT16_VEC2,   glu::TYPE_INT16_VEC3,
1122         glu::TYPE_INT16_VEC4,   glu::TYPE_FLOAT16,      glu::TYPE_FLOAT16_VEC2, glu::TYPE_FLOAT16_VEC3,
1123         glu::TYPE_FLOAT16_VEC4,
1124     };
1125 
1126     static const struct
1127     {
1128         const char *name;
1129         uint32_t flags;
1130     } layoutFlags[] = {
1131         {"std140", LAYOUT_STD140},
1132         {"std430", LAYOUT_STD430},
1133         {"scalar", LAYOUT_SCALAR},
1134     };
1135 
1136     static const struct
1137     {
1138         const char *name;
1139         uint32_t flags;
1140     } matrixFlags[] = {{"row_major", LAYOUT_ROW_MAJOR}, {"column_major", LAYOUT_COLUMN_MAJOR}};
1141 
1142     static const struct
1143     {
1144         const char *name;
1145         SSBOLayoutCase::BufferMode mode;
1146     } bufferModes[] = {{"per_block_buffer", SSBOLayoutCase::BUFFERMODE_PER_BLOCK},
1147                        {"single_buffer", SSBOLayoutCase::BUFFERMODE_SINGLE}};
1148 
1149     using SuffixLoadFlag  = pair<string, MatrixLoadFlags>;
1150     using SuffixStoreFlag = pair<string, MatrixStoreFlags>;
1151 
1152     static const array<SuffixLoadFlag, 2> matrixLoadTypes = {{
1153         SuffixLoadFlag("", LOAD_FULL_MATRIX),
1154         SuffixLoadFlag("_comp_access", LOAD_MATRIX_COMPONENTS),
1155     }};
1156 
1157     static const array<SuffixStoreFlag, 2> matrixStoreTypes = {{
1158         SuffixStoreFlag("", STORE_FULL_MATRIX),
1159         SuffixStoreFlag("_store_cols", STORE_MATRIX_COLUMNS),
1160     }};
1161 
1162     // ssbo.single_basic_type
1163     {
1164         tcu::TestCaseGroup *singleBasicTypeGroup = new tcu::TestCaseGroup(m_testCtx, "single_basic_type");
1165         addChild(singleBasicTypeGroup);
1166 
1167         for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1168         {
1169             tcu::TestCaseGroup *layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name);
1170             singleBasicTypeGroup->addChild(layoutGroup);
1171 
1172             for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
1173             {
1174                 glu::DataType type   = basicTypes[basicTypeNdx];
1175                 const char *typeName = glu::getDataTypeName(type);
1176 
1177                 if (!glu::dataTypeSupportsPrecisionModifier(type))
1178                     layoutGroup->addChild(new BlockBasicTypeCase(
1179                         m_testCtx, typeName, VarType(type, glu::PRECISION_LAST), layoutFlags[layoutFlagNdx].flags, 0,
1180                         LOAD_FULL_MATRIX, STORE_FULL_MATRIX, m_usePhysStorageBuffer, m_readonly));
1181                 else
1182                 {
1183                     for (int precNdx = 0; precNdx < glu::PRECISION_LAST; precNdx++)
1184                     {
1185                         const glu::Precision precision = glu::Precision(precNdx);
1186                         const string caseName          = string(glu::getPrecisionName(precision)) + "_" + typeName;
1187 
1188                         layoutGroup->addChild(new BlockBasicTypeCase(
1189                             m_testCtx, caseName.c_str(), VarType(type, precision), layoutFlags[layoutFlagNdx].flags, 0,
1190                             LOAD_FULL_MATRIX, STORE_FULL_MATRIX, m_usePhysStorageBuffer, m_readonly));
1191                     }
1192                 }
1193 
1194                 if (glu::isDataTypeMatrix(type))
1195                 {
1196                     for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
1197                     {
1198                         for (int precNdx = 0; precNdx < glu::PRECISION_LAST; precNdx++)
1199                         {
1200                             const glu::Precision precision = glu::Precision(precNdx);
1201                             const string caseName          = string(matrixFlags[matFlagNdx].name) + "_" +
1202                                                     string(glu::getPrecisionName(precision)) + "_" + typeName;
1203 
1204                             for (const auto &loadType : matrixLoadTypes)
1205                                 for (const auto &storeType : matrixStoreTypes)
1206                                     layoutGroup->addChild(new BlockBasicTypeCase(
1207                                         m_testCtx, (caseName + loadType.first + storeType.first).c_str(),
1208                                         glu::VarType(type, precision),
1209                                         layoutFlags[layoutFlagNdx].flags | matrixFlags[matFlagNdx].flags, 0,
1210                                         loadType.second, storeType.second, m_usePhysStorageBuffer, m_readonly));
1211                         }
1212                     }
1213                 }
1214             }
1215         }
1216     }
1217 
1218     // ssbo.single_basic_array
1219     {
1220         tcu::TestCaseGroup *singleBasicArrayGroup = new tcu::TestCaseGroup(m_testCtx, "single_basic_array");
1221         addChild(singleBasicArrayGroup);
1222 
1223         for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1224         {
1225             tcu::TestCaseGroup *layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name);
1226             singleBasicArrayGroup->addChild(layoutGroup);
1227 
1228             for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
1229             {
1230                 glu::DataType type   = basicTypes[basicTypeNdx];
1231                 const char *typeName = glu::getDataTypeName(type);
1232                 const int arraySize  = 3;
1233 
1234                 layoutGroup->addChild(new BlockBasicTypeCase(
1235                     m_testCtx, typeName,
1236                     VarType(VarType(type, !glu::dataTypeSupportsPrecisionModifier(type) ? glu::PRECISION_LAST :
1237                                                                                           glu::PRECISION_HIGHP),
1238                             arraySize),
1239                     layoutFlags[layoutFlagNdx].flags, 0, LOAD_FULL_MATRIX, STORE_FULL_MATRIX, m_usePhysStorageBuffer,
1240                     m_readonly));
1241 
1242                 if (glu::isDataTypeMatrix(type))
1243                 {
1244                     for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
1245                     {
1246                         for (const auto &loadType : matrixLoadTypes)
1247                             for (const auto &storeType : matrixStoreTypes)
1248                                 layoutGroup->addChild(new BlockBasicTypeCase(
1249                                     m_testCtx,
1250                                     (string(matrixFlags[matFlagNdx].name) + "_" + typeName + loadType.first +
1251                                      storeType.first)
1252                                         .c_str(),
1253                                     VarType(VarType(type, glu::PRECISION_HIGHP), arraySize),
1254                                     layoutFlags[layoutFlagNdx].flags | matrixFlags[matFlagNdx].flags, 0,
1255                                     loadType.second, storeType.second, m_usePhysStorageBuffer, m_readonly));
1256                     }
1257                 }
1258             }
1259         }
1260     }
1261 
1262     // ssbo.basic_unsized_array
1263     {
1264         tcu::TestCaseGroup *basicUnsizedArray = new tcu::TestCaseGroup(m_testCtx, "basic_unsized_array");
1265         addChild(basicUnsizedArray);
1266 
1267         for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1268         {
1269             tcu::TestCaseGroup *layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name);
1270             basicUnsizedArray->addChild(layoutGroup);
1271 
1272             for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
1273             {
1274                 glu::DataType type   = basicTypes[basicTypeNdx];
1275                 const char *typeName = glu::getDataTypeName(type);
1276                 const int arraySize  = 19;
1277 
1278                 layoutGroup->addChild(new BlockBasicUnsizedArrayCase(
1279                     m_testCtx, typeName,
1280                     VarType(type,
1281                             !glu::dataTypeSupportsPrecisionModifier(type) ? glu::PRECISION_LAST : glu::PRECISION_HIGHP),
1282                     arraySize, layoutFlags[layoutFlagNdx].flags, LOAD_FULL_MATRIX, STORE_FULL_MATRIX,
1283                     m_usePhysStorageBuffer, m_readonly));
1284 
1285                 if (glu::isDataTypeMatrix(type))
1286                 {
1287                     for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
1288                     {
1289                         for (const auto &loadType : matrixLoadTypes)
1290                             for (const auto &storeType : matrixStoreTypes)
1291                                 layoutGroup->addChild(new BlockBasicUnsizedArrayCase(
1292                                     m_testCtx,
1293                                     (string(matrixFlags[matFlagNdx].name) + "_" + typeName + loadType.first +
1294                                      storeType.first)
1295                                         .c_str(),
1296                                     VarType(type, glu::PRECISION_HIGHP), arraySize,
1297                                     layoutFlags[layoutFlagNdx].flags | matrixFlags[matFlagNdx].flags, loadType.second,
1298                                     storeType.second, m_usePhysStorageBuffer, m_readonly));
1299                     }
1300                 }
1301             }
1302         }
1303     }
1304 
1305     // ssbo.2_level_array
1306     if (!m_readonly)
1307     {
1308         tcu::TestCaseGroup *nestedArrayGroup = new tcu::TestCaseGroup(m_testCtx, "2_level_array");
1309         addChild(nestedArrayGroup);
1310 
1311         for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1312         {
1313             tcu::TestCaseGroup *layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name);
1314             nestedArrayGroup->addChild(layoutGroup);
1315 
1316             for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
1317             {
1318                 glu::DataType type   = basicTypes[basicTypeNdx];
1319                 const char *typeName = glu::getDataTypeName(type);
1320                 const int childSize  = 3;
1321                 const int parentSize = 4;
1322                 const VarType childType(VarType(type, !glu::dataTypeSupportsPrecisionModifier(type) ?
1323                                                           glu::PRECISION_LAST :
1324                                                           glu::PRECISION_HIGHP),
1325                                         childSize);
1326                 const VarType fullType(childType, parentSize);
1327 
1328                 layoutGroup->addChild(new BlockBasicTypeCase(m_testCtx, typeName, fullType,
1329                                                              layoutFlags[layoutFlagNdx].flags, 0, LOAD_FULL_MATRIX,
1330                                                              STORE_FULL_MATRIX, m_usePhysStorageBuffer, m_readonly));
1331 
1332                 if (glu::isDataTypeMatrix(type))
1333                 {
1334                     for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
1335                     {
1336                         for (const auto &loadType : matrixLoadTypes)
1337                             for (const auto &storeType : matrixStoreTypes)
1338                                 layoutGroup->addChild(new BlockBasicTypeCase(
1339                                     m_testCtx,
1340                                     (string(matrixFlags[matFlagNdx].name) + "_" + typeName + loadType.first +
1341                                      storeType.first)
1342                                         .c_str(),
1343                                     fullType, layoutFlags[layoutFlagNdx].flags | matrixFlags[matFlagNdx].flags, 0,
1344                                     loadType.second, storeType.second, m_usePhysStorageBuffer, m_readonly));
1345                     }
1346                 }
1347             }
1348         }
1349     }
1350 
1351     // ssbo.3_level_array
1352     if (!m_readonly)
1353     {
1354         tcu::TestCaseGroup *nestedArrayGroup = new tcu::TestCaseGroup(m_testCtx, "3_level_array");
1355         addChild(nestedArrayGroup);
1356 
1357         for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1358         {
1359             tcu::TestCaseGroup *layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name);
1360             nestedArrayGroup->addChild(layoutGroup);
1361 
1362             for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
1363             {
1364                 glu::DataType type   = basicTypes[basicTypeNdx];
1365                 const char *typeName = glu::getDataTypeName(type);
1366                 const int childSize0 = 3;
1367                 const int childSize1 = 2;
1368                 const int parentSize = 4;
1369                 const VarType childType0(VarType(type, !glu::dataTypeSupportsPrecisionModifier(type) ?
1370                                                            glu::PRECISION_LAST :
1371                                                            glu::PRECISION_HIGHP),
1372                                          childSize0);
1373                 const VarType childType1(childType0, childSize1);
1374                 const VarType fullType(childType1, parentSize);
1375 
1376                 layoutGroup->addChild(new BlockBasicTypeCase(m_testCtx, typeName, fullType,
1377                                                              layoutFlags[layoutFlagNdx].flags, 0, LOAD_FULL_MATRIX,
1378                                                              STORE_FULL_MATRIX, m_usePhysStorageBuffer, m_readonly));
1379 
1380                 if (glu::isDataTypeMatrix(type))
1381                 {
1382                     for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
1383                     {
1384                         for (const auto &loadType : matrixLoadTypes)
1385                             for (const auto &storeType : matrixStoreTypes)
1386                                 layoutGroup->addChild(new BlockBasicTypeCase(
1387                                     m_testCtx,
1388                                     (string(matrixFlags[matFlagNdx].name) + "_" + typeName + loadType.first +
1389                                      storeType.first)
1390                                         .c_str(),
1391                                     fullType, layoutFlags[layoutFlagNdx].flags | matrixFlags[matFlagNdx].flags, 0,
1392                                     loadType.second, storeType.second, m_usePhysStorageBuffer, m_readonly));
1393                     }
1394                 }
1395             }
1396         }
1397     }
1398 
1399     // ssbo.3_level_unsized_array
1400     if (!m_readonly)
1401     {
1402         // 3-level nested array, top-level array unsized
1403         tcu::TestCaseGroup *nestedArrayGroup = new tcu::TestCaseGroup(m_testCtx, "3_level_unsized_array");
1404         addChild(nestedArrayGroup);
1405 
1406         for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1407         {
1408             tcu::TestCaseGroup *layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name);
1409             nestedArrayGroup->addChild(layoutGroup);
1410 
1411             for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
1412             {
1413                 glu::DataType type   = basicTypes[basicTypeNdx];
1414                 const char *typeName = glu::getDataTypeName(type);
1415                 const int childSize0 = 2;
1416                 const int childSize1 = 4;
1417                 const int parentSize = 3;
1418                 const VarType childType0(VarType(type, !glu::dataTypeSupportsPrecisionModifier(type) ?
1419                                                            glu::PRECISION_LAST :
1420                                                            glu::PRECISION_HIGHP),
1421                                          childSize0);
1422                 const VarType childType1(childType0, childSize1);
1423 
1424                 layoutGroup->addChild(new BlockBasicUnsizedArrayCase(
1425                     m_testCtx, typeName, childType1, parentSize, layoutFlags[layoutFlagNdx].flags, LOAD_FULL_MATRIX,
1426                     STORE_FULL_MATRIX, m_usePhysStorageBuffer, m_readonly));
1427 
1428                 if (glu::isDataTypeMatrix(type))
1429                 {
1430                     for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
1431                     {
1432                         for (const auto &loadType : matrixLoadTypes)
1433                             for (const auto &storeType : matrixStoreTypes)
1434                                 layoutGroup->addChild(new BlockBasicUnsizedArrayCase(
1435                                     m_testCtx,
1436                                     (string(matrixFlags[matFlagNdx].name) + "_" + typeName + loadType.first +
1437                                      storeType.first)
1438                                         .c_str(),
1439                                     childType1, parentSize,
1440                                     layoutFlags[layoutFlagNdx].flags | matrixFlags[matFlagNdx].flags, loadType.second,
1441                                     storeType.second, m_usePhysStorageBuffer, m_readonly));
1442                     }
1443                 }
1444             }
1445         }
1446     }
1447 
1448     // ssbo.single_struct
1449     {
1450         tcu::TestCaseGroup *singleStructGroup = new tcu::TestCaseGroup(m_testCtx, "single_struct");
1451         addChild(singleStructGroup);
1452 
1453         for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1454         {
1455             tcu::TestCaseGroup *modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name);
1456             singleStructGroup->addChild(modeGroup);
1457 
1458             for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1459             {
1460                 for (int isArray = 0; isArray < 2; isArray++)
1461                 {
1462                     const uint32_t caseFlags = layoutFlags[layoutFlagNdx].flags;
1463                     string caseName          = layoutFlags[layoutFlagNdx].name;
1464 
1465                     if (bufferModes[modeNdx].mode == SSBOLayoutCase::BUFFERMODE_SINGLE && isArray == 0)
1466                         continue; // Doesn't make sense to add this variant.
1467 
1468                     if (isArray)
1469                         caseName += "_instance_array";
1470 
1471                     for (const auto &loadType : matrixLoadTypes)
1472                         for (const auto &storeType : matrixStoreTypes)
1473                             modeGroup->addChild(new BlockSingleStructCase(
1474                                 m_testCtx, (caseName + loadType.first + storeType.first).c_str(), caseFlags,
1475                                 bufferModes[modeNdx].mode, isArray ? 3 : 0, loadType.second, storeType.second,
1476                                 m_usePhysStorageBuffer, m_readonly));
1477                 }
1478             }
1479         }
1480     }
1481 
1482     // ssbo.single_struct_array
1483     if (!m_readonly)
1484     {
1485         tcu::TestCaseGroup *singleStructArrayGroup = new tcu::TestCaseGroup(m_testCtx, "single_struct_array");
1486         addChild(singleStructArrayGroup);
1487 
1488         for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1489         {
1490             tcu::TestCaseGroup *modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name);
1491             singleStructArrayGroup->addChild(modeGroup);
1492 
1493             for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1494             {
1495                 for (int isArray = 0; isArray < 2; isArray++)
1496                 {
1497                     std::string baseName = layoutFlags[layoutFlagNdx].name;
1498                     uint32_t baseFlags   = layoutFlags[layoutFlagNdx].flags;
1499 
1500                     if (bufferModes[modeNdx].mode == SSBOLayoutCase::BUFFERMODE_SINGLE && isArray == 0)
1501                         continue; // Doesn't make sense to add this variant.
1502 
1503                     if (isArray)
1504                         baseName += "_instance_array";
1505 
1506                     for (const auto &loadType : matrixLoadTypes)
1507                         for (const auto &storeType : matrixStoreTypes)
1508                             modeGroup->addChild(new BlockSingleStructArrayCase(
1509                                 m_testCtx, (baseName + loadType.first + storeType.first).c_str(), baseFlags,
1510                                 bufferModes[modeNdx].mode, isArray ? 3 : 0, loadType.second, storeType.second,
1511                                 m_usePhysStorageBuffer));
1512                 }
1513             }
1514         }
1515     }
1516 
1517     // ssbo.single_nested_struct
1518     if (!m_readonly)
1519     {
1520         tcu::TestCaseGroup *singleNestedStructGroup = new tcu::TestCaseGroup(m_testCtx, "single_nested_struct");
1521         addChild(singleNestedStructGroup);
1522 
1523         for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1524         {
1525             tcu::TestCaseGroup *modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name);
1526             singleNestedStructGroup->addChild(modeGroup);
1527 
1528             for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1529             {
1530                 for (int isArray = 0; isArray < 2; isArray++)
1531                 {
1532                     std::string baseName = layoutFlags[layoutFlagNdx].name;
1533                     uint32_t baseFlags   = layoutFlags[layoutFlagNdx].flags;
1534 
1535                     if (bufferModes[modeNdx].mode == SSBOLayoutCase::BUFFERMODE_SINGLE && isArray == 0)
1536                         continue; // Doesn't make sense to add this variant.
1537 
1538                     if (isArray)
1539                         baseName += "_instance_array";
1540 
1541                     for (const auto &loadType : matrixLoadTypes)
1542                         for (const auto &storeType : matrixStoreTypes)
1543                             modeGroup->addChild(new BlockSingleNestedStructCase(
1544                                 m_testCtx, (baseName + loadType.first + storeType.first).c_str(), baseFlags,
1545                                 bufferModes[modeNdx].mode, isArray ? 3 : 0, loadType.second, storeType.second,
1546                                 m_usePhysStorageBuffer));
1547                 }
1548             }
1549         }
1550     }
1551 
1552     // ssbo.single_nested_struct_array
1553     if (!m_readonly)
1554     {
1555         tcu::TestCaseGroup *singleNestedStructArrayGroup =
1556             new tcu::TestCaseGroup(m_testCtx, "single_nested_struct_array");
1557         addChild(singleNestedStructArrayGroup);
1558 
1559         for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1560         {
1561             tcu::TestCaseGroup *modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name);
1562             singleNestedStructArrayGroup->addChild(modeGroup);
1563 
1564             for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1565             {
1566                 for (int isArray = 0; isArray < 2; isArray++)
1567                 {
1568                     std::string baseName = layoutFlags[layoutFlagNdx].name;
1569                     uint32_t baseFlags   = layoutFlags[layoutFlagNdx].flags;
1570 
1571                     if (bufferModes[modeNdx].mode == SSBOLayoutCase::BUFFERMODE_SINGLE && isArray == 0)
1572                         continue; // Doesn't make sense to add this variant.
1573 
1574                     if (isArray)
1575                         baseName += "_instance_array";
1576 
1577                     for (const auto &loadType : matrixLoadTypes)
1578                         for (const auto &storeType : matrixStoreTypes)
1579                             modeGroup->addChild(new BlockSingleNestedStructArrayCase(
1580                                 m_testCtx, (baseName + loadType.first + storeType.first).c_str(), baseFlags,
1581                                 bufferModes[modeNdx].mode, isArray ? 3 : 0, loadType.second, storeType.second,
1582                                 m_usePhysStorageBuffer));
1583                 }
1584             }
1585         }
1586     }
1587 
1588     // ssbo.unsized_struct_array
1589     if (!m_readonly)
1590     {
1591         tcu::TestCaseGroup *singleStructArrayGroup = new tcu::TestCaseGroup(m_testCtx, "unsized_struct_array");
1592         addChild(singleStructArrayGroup);
1593 
1594         for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1595         {
1596             tcu::TestCaseGroup *modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name);
1597             singleStructArrayGroup->addChild(modeGroup);
1598 
1599             for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1600             {
1601                 for (int isArray = 0; isArray < 2; isArray++)
1602                 {
1603                     std::string baseName = layoutFlags[layoutFlagNdx].name;
1604                     uint32_t baseFlags   = layoutFlags[layoutFlagNdx].flags;
1605 
1606                     if (bufferModes[modeNdx].mode == SSBOLayoutCase::BUFFERMODE_SINGLE && isArray == 0)
1607                         continue; // Doesn't make sense to add this variant.
1608 
1609                     if (isArray)
1610                         baseName += "_instance_array";
1611 
1612                     for (const auto &loadType : matrixLoadTypes)
1613                         for (const auto &storeType : matrixStoreTypes)
1614                             modeGroup->addChild(new BlockUnsizedStructArrayCase(
1615                                 m_testCtx, (baseName + loadType.first + storeType.first).c_str(), baseFlags,
1616                                 bufferModes[modeNdx].mode, isArray ? 3 : 0, loadType.second, storeType.second,
1617                                 m_usePhysStorageBuffer));
1618                 }
1619             }
1620         }
1621     }
1622 
1623     // ssbo.2_level_unsized_struct_array
1624     if (!m_readonly)
1625     {
1626         tcu::TestCaseGroup *structArrayGroup = new tcu::TestCaseGroup(m_testCtx, "2_level_unsized_struct_array");
1627         addChild(structArrayGroup);
1628 
1629         for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1630         {
1631             tcu::TestCaseGroup *modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name);
1632             structArrayGroup->addChild(modeGroup);
1633 
1634             for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1635             {
1636                 for (int isArray = 0; isArray < 2; isArray++)
1637                 {
1638                     std::string baseName = layoutFlags[layoutFlagNdx].name;
1639                     uint32_t baseFlags   = layoutFlags[layoutFlagNdx].flags;
1640 
1641                     if (bufferModes[modeNdx].mode == SSBOLayoutCase::BUFFERMODE_SINGLE && isArray == 0)
1642                         continue; // Doesn't make sense to add this variant.
1643 
1644                     if (isArray)
1645                         baseName += "_instance_array";
1646 
1647                     for (const auto &loadType : matrixLoadTypes)
1648                         for (const auto &storeType : matrixStoreTypes)
1649                             modeGroup->addChild(new Block2LevelUnsizedStructArrayCase(
1650                                 m_testCtx, (baseName + loadType.first + storeType.first).c_str(), baseFlags,
1651                                 bufferModes[modeNdx].mode, isArray ? 3 : 0, loadType.second, storeType.second,
1652                                 m_usePhysStorageBuffer));
1653                 }
1654             }
1655         }
1656     }
1657 
1658     // ssbo.unsized_nested_struct_array
1659     if (!m_readonly)
1660     {
1661         tcu::TestCaseGroup *singleNestedStructArrayGroup =
1662             new tcu::TestCaseGroup(m_testCtx, "unsized_nested_struct_array");
1663         addChild(singleNestedStructArrayGroup);
1664 
1665         for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1666         {
1667             tcu::TestCaseGroup *modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name);
1668             singleNestedStructArrayGroup->addChild(modeGroup);
1669 
1670             for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1671             {
1672                 for (int isArray = 0; isArray < 2; isArray++)
1673                 {
1674                     std::string baseName = layoutFlags[layoutFlagNdx].name;
1675                     uint32_t baseFlags   = layoutFlags[layoutFlagNdx].flags;
1676 
1677                     if (bufferModes[modeNdx].mode == SSBOLayoutCase::BUFFERMODE_SINGLE && isArray == 0)
1678                         continue; // Doesn't make sense to add this variant.
1679 
1680                     if (isArray)
1681                         baseName += "_instance_array";
1682 
1683                     for (const auto &loadType : matrixLoadTypes)
1684                         for (const auto &storeType : matrixStoreTypes)
1685                             modeGroup->addChild(new BlockUnsizedNestedStructArrayCase(
1686                                 m_testCtx, (baseName + loadType.first + storeType.first).c_str(), baseFlags,
1687                                 bufferModes[modeNdx].mode, isArray ? 3 : 0, loadType.second, storeType.second,
1688                                 m_usePhysStorageBuffer));
1689                 }
1690             }
1691         }
1692     }
1693 
1694     // ssbo.instance_array_basic_type
1695     if (!m_readonly)
1696     {
1697         tcu::TestCaseGroup *instanceArrayBasicTypeGroup =
1698             new tcu::TestCaseGroup(m_testCtx, "instance_array_basic_type");
1699         addChild(instanceArrayBasicTypeGroup);
1700 
1701         for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1702         {
1703             tcu::TestCaseGroup *layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name);
1704             instanceArrayBasicTypeGroup->addChild(layoutGroup);
1705 
1706             for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
1707             {
1708                 glu::DataType type     = basicTypes[basicTypeNdx];
1709                 const char *typeName   = glu::getDataTypeName(type);
1710                 const int numInstances = 3;
1711 
1712                 layoutGroup->addChild(new BlockBasicTypeCase(
1713                     m_testCtx, typeName,
1714                     VarType(type,
1715                             !glu::dataTypeSupportsPrecisionModifier(type) ? glu::PRECISION_LAST : glu::PRECISION_HIGHP),
1716                     layoutFlags[layoutFlagNdx].flags, numInstances, LOAD_FULL_MATRIX, STORE_FULL_MATRIX,
1717                     m_usePhysStorageBuffer, m_readonly));
1718 
1719                 if (glu::isDataTypeMatrix(type))
1720                 {
1721                     for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
1722                     {
1723                         for (const auto &loadType : matrixLoadTypes)
1724                             for (const auto &storeType : matrixStoreTypes)
1725                                 layoutGroup->addChild(new BlockBasicTypeCase(
1726                                     m_testCtx,
1727                                     (string(matrixFlags[matFlagNdx].name) + "_" + typeName + loadType.first +
1728                                      storeType.first)
1729                                         .c_str(),
1730                                     VarType(type, glu::PRECISION_HIGHP),
1731                                     layoutFlags[layoutFlagNdx].flags | matrixFlags[matFlagNdx].flags, numInstances,
1732                                     loadType.second, storeType.second, m_usePhysStorageBuffer, m_readonly));
1733                     }
1734                 }
1735             }
1736         }
1737     }
1738 
1739     // ssbo.multi_basic_types
1740     if (!m_readonly)
1741     {
1742         tcu::TestCaseGroup *multiBasicTypesGroup = new tcu::TestCaseGroup(m_testCtx, "multi_basic_types");
1743         addChild(multiBasicTypesGroup);
1744 
1745         for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1746         {
1747             tcu::TestCaseGroup *modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name);
1748             multiBasicTypesGroup->addChild(modeGroup);
1749 
1750             for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1751             {
1752                 for (int isArray = 0; isArray < 2; isArray++)
1753                 {
1754                     std::string baseName = layoutFlags[layoutFlagNdx].name;
1755                     uint32_t baseFlags   = layoutFlags[layoutFlagNdx].flags;
1756 
1757                     if (isArray)
1758                         baseName += "_instance_array";
1759 
1760                     for (const auto &loadType : matrixLoadTypes)
1761                         for (const auto &storeType : matrixStoreTypes)
1762                             modeGroup->addChild(new BlockMultiBasicTypesCase(
1763                                 m_testCtx, (baseName + loadType.first + storeType.first).c_str(), baseFlags, baseFlags,
1764                                 bufferModes[modeNdx].mode, isArray ? 3 : 0, loadType.second, storeType.second,
1765                                 m_usePhysStorageBuffer));
1766                 }
1767             }
1768 
1769             for (int isArray = 0; isArray < 2; isArray++)
1770             {
1771                 std::string baseName = "relaxed_block";
1772                 uint32_t baseFlags   = LAYOUT_RELAXED;
1773 
1774                 if (isArray)
1775                     baseName += "_instance_array";
1776 
1777                 for (const auto &loadType : matrixLoadTypes)
1778                     for (const auto &storeType : matrixStoreTypes)
1779                         modeGroup->addChild(new BlockMultiBasicTypesCase(
1780                             m_testCtx, (baseName + loadType.first + storeType.first).c_str(), baseFlags, baseFlags,
1781                             bufferModes[modeNdx].mode, isArray ? 3 : 0, loadType.second, storeType.second,
1782                             m_usePhysStorageBuffer));
1783             }
1784         }
1785     }
1786 
1787     // ssbo.multi_nested_struct
1788     if (!m_readonly)
1789     {
1790         tcu::TestCaseGroup *multiNestedStructGroup = new tcu::TestCaseGroup(m_testCtx, "multi_nested_struct");
1791         addChild(multiNestedStructGroup);
1792 
1793         for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1794         {
1795             tcu::TestCaseGroup *modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name);
1796             multiNestedStructGroup->addChild(modeGroup);
1797 
1798             for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1799             {
1800                 for (int isArray = 0; isArray < 2; isArray++)
1801                 {
1802                     std::string baseName = layoutFlags[layoutFlagNdx].name;
1803                     uint32_t baseFlags   = layoutFlags[layoutFlagNdx].flags;
1804 
1805                     if (isArray)
1806                         baseName += "_instance_array";
1807 
1808                     for (const auto &loadType : matrixLoadTypes)
1809                         for (const auto &storeType : matrixStoreTypes)
1810                             modeGroup->addChild(new BlockMultiNestedStructCase(
1811                                 m_testCtx, (baseName + loadType.first + storeType.first).c_str(), baseFlags, baseFlags,
1812                                 bufferModes[modeNdx].mode, isArray ? 3 : 0, loadType.second, storeType.second,
1813                                 m_usePhysStorageBuffer));
1814                 }
1815             }
1816         }
1817     }
1818 
1819     // ssbo.random
1820     if (!m_readonly)
1821     {
1822         const uint32_t allStdLayouts = FEATURE_STD140_LAYOUT | FEATURE_STD430_LAYOUT;
1823         const uint32_t allBasicTypes = FEATURE_VECTORS | FEATURE_MATRICES;
1824         const uint32_t unused        = FEATURE_UNUSED_MEMBERS | FEATURE_UNUSED_VARS;
1825         const uint32_t unsized       = FEATURE_UNSIZED_ARRAYS;
1826         const uint32_t matFlags      = FEATURE_MATRIX_LAYOUT;
1827         const uint32_t allButRelaxed = ~FEATURE_RELAXED_LAYOUT & ~FEATURE_16BIT_STORAGE & ~FEATURE_8BIT_STORAGE &
1828                                        ~FEATURE_SCALAR_LAYOUT & ~FEATURE_DESCRIPTOR_INDEXING;
1829         const uint32_t allRelaxed = FEATURE_VECTORS | FEATURE_RELAXED_LAYOUT | FEATURE_INSTANCE_ARRAYS;
1830         const uint32_t allScalar  = ~FEATURE_RELAXED_LAYOUT & ~allStdLayouts & ~FEATURE_16BIT_STORAGE &
1831                                    ~FEATURE_8BIT_STORAGE & ~FEATURE_DESCRIPTOR_INDEXING;
1832         const uint32_t descriptorIndexing = allStdLayouts | FEATURE_RELAXED_LAYOUT | FEATURE_SCALAR_LAYOUT |
1833                                             FEATURE_DESCRIPTOR_INDEXING | allBasicTypes | unused | matFlags;
1834 
1835         tcu::TestCaseGroup *randomGroup = new tcu::TestCaseGroup(m_testCtx, "random");
1836         addChild(randomGroup);
1837 
1838         for (int i = 0; i < 3; ++i)
1839         {
1840 
1841             tcu::TestCaseGroup *group = randomGroup;
1842             if (i == 1)
1843             {
1844                 group = new tcu::TestCaseGroup(m_testCtx, "16bit");
1845                 randomGroup->addChild(group);
1846             }
1847             else if (i == 2)
1848             {
1849                 group = new tcu::TestCaseGroup(m_testCtx, "8bit");
1850                 randomGroup->addChild(group);
1851             }
1852             const uint32_t use16BitStorage = i == 1 ? FEATURE_16BIT_STORAGE : 0;
1853             const uint32_t use8BitStorage  = i == 2 ? FEATURE_8BIT_STORAGE : 0;
1854 
1855             // Basic types.
1856             // Scalar types only, per-block buffers
1857             createRandomCaseGroup(group, m_testCtx, "scalar_types", SSBOLayoutCase::BUFFERMODE_PER_BLOCK,
1858                                   use8BitStorage | use16BitStorage | allStdLayouts | unused, 25, 0,
1859                                   m_usePhysStorageBuffer);
1860             // Scalar and vector types only, per-block buffers
1861             createRandomCaseGroup(group, m_testCtx, "vector_types", SSBOLayoutCase::BUFFERMODE_PER_BLOCK,
1862                                   use8BitStorage | use16BitStorage | allStdLayouts | unused | FEATURE_VECTORS, 25, 25,
1863                                   m_usePhysStorageBuffer);
1864             // All basic types, per-block buffers
1865             createRandomCaseGroup(group, m_testCtx, "basic_types", SSBOLayoutCase::BUFFERMODE_PER_BLOCK,
1866                                   use8BitStorage | use16BitStorage | allStdLayouts | unused | allBasicTypes | matFlags,
1867                                   25, 50, m_usePhysStorageBuffer);
1868             // Arrays, per-block buffers
1869             createRandomCaseGroup(group, m_testCtx, "basic_arrays", SSBOLayoutCase::BUFFERMODE_PER_BLOCK,
1870                                   use8BitStorage | use16BitStorage | allStdLayouts | unused | allBasicTypes | matFlags |
1871                                       FEATURE_ARRAYS,
1872                                   25, 50, m_usePhysStorageBuffer);
1873             // Unsized arrays, per-block buffers
1874             createRandomCaseGroup(group, m_testCtx, "unsized_arrays", SSBOLayoutCase::BUFFERMODE_PER_BLOCK,
1875                                   use8BitStorage | use16BitStorage | allStdLayouts | unused | allBasicTypes | matFlags |
1876                                       unsized | FEATURE_ARRAYS,
1877                                   25, 50, m_usePhysStorageBuffer);
1878             // Arrays of arrays, per-block buffers
1879             createRandomCaseGroup(group, m_testCtx, "arrays_of_arrays", SSBOLayoutCase::BUFFERMODE_PER_BLOCK,
1880                                   use8BitStorage | use16BitStorage | allStdLayouts | unused | allBasicTypes | matFlags |
1881                                       unsized | FEATURE_ARRAYS | FEATURE_ARRAYS_OF_ARRAYS,
1882                                   25, 950, m_usePhysStorageBuffer);
1883 
1884             // Basic instance arrays, per-block buffers
1885             createRandomCaseGroup(group, m_testCtx, "basic_instance_arrays", SSBOLayoutCase::BUFFERMODE_PER_BLOCK,
1886                                   use8BitStorage | use16BitStorage | allStdLayouts | unused | allBasicTypes | matFlags |
1887                                       unsized | FEATURE_INSTANCE_ARRAYS,
1888                                   25, 75, m_usePhysStorageBuffer);
1889             // Nested structs, per-block buffers
1890             createRandomCaseGroup(group, m_testCtx, "nested_structs", SSBOLayoutCase::BUFFERMODE_PER_BLOCK,
1891                                   use8BitStorage | use16BitStorage | allStdLayouts | unused | allBasicTypes | matFlags |
1892                                       unsized | FEATURE_STRUCTS,
1893                                   25, 100, m_usePhysStorageBuffer);
1894             // Nested structs, arrays, per-block buffers
1895             createRandomCaseGroup(group, m_testCtx, "nested_structs_arrays", SSBOLayoutCase::BUFFERMODE_PER_BLOCK,
1896                                   use8BitStorage | use16BitStorage | allStdLayouts | unused | allBasicTypes | matFlags |
1897                                       unsized | FEATURE_STRUCTS | FEATURE_ARRAYS | FEATURE_ARRAYS_OF_ARRAYS,
1898                                   25, 150, m_usePhysStorageBuffer);
1899             // Nested structs, instance arrays, per-block buffers
1900             createRandomCaseGroup(group, m_testCtx, "nested_structs_instance_arrays",
1901                                   SSBOLayoutCase::BUFFERMODE_PER_BLOCK,
1902                                   use8BitStorage | use16BitStorage | allStdLayouts | unused | allBasicTypes | matFlags |
1903                                       unsized | FEATURE_STRUCTS | FEATURE_INSTANCE_ARRAYS,
1904                                   25, 125, m_usePhysStorageBuffer);
1905             // Nested structs, instance arrays, per-block buffers
1906             createRandomCaseGroup(
1907                 group, m_testCtx, "nested_structs_arrays_instance_arrays", SSBOLayoutCase::BUFFERMODE_PER_BLOCK,
1908                 use8BitStorage | use16BitStorage | allStdLayouts | unused | allBasicTypes | matFlags | unsized |
1909                     FEATURE_STRUCTS | FEATURE_ARRAYS | FEATURE_ARRAYS_OF_ARRAYS | FEATURE_INSTANCE_ARRAYS,
1910                 25, 175, m_usePhysStorageBuffer);
1911             // All random features, per-block buffers
1912             createRandomCaseGroup(group, m_testCtx, "all_per_block_buffers", SSBOLayoutCase::BUFFERMODE_PER_BLOCK,
1913                                   use8BitStorage | use16BitStorage | allButRelaxed, 50, 200, m_usePhysStorageBuffer);
1914             // All random features, shared buffer
1915             createRandomCaseGroup(group, m_testCtx, "all_shared_buffer", SSBOLayoutCase::BUFFERMODE_SINGLE,
1916                                   use8BitStorage | use16BitStorage | allButRelaxed, 50, 250, m_usePhysStorageBuffer);
1917 
1918             // VK_KHR_relaxed_block_layout
1919             createRandomCaseGroup(group, m_testCtx, "relaxed", SSBOLayoutCase::BUFFERMODE_SINGLE,
1920                                   use8BitStorage | use16BitStorage | allRelaxed, 100, deInt32Hash(313),
1921                                   m_usePhysStorageBuffer);
1922             // VK_EXT_scalar_block_layout
1923             createRandomCaseGroup(group, m_testCtx, "scalar", SSBOLayoutCase::BUFFERMODE_SINGLE,
1924                                   use8BitStorage | use16BitStorage | allScalar, 100, deInt32Hash(313),
1925                                   m_usePhysStorageBuffer);
1926             // VK_EXT_descriptor_indexing
1927             createRandomCaseGroup(group, m_testCtx, "descriptor_indexing", SSBOLayoutCase::BUFFERMODE_SINGLE,
1928                                   use8BitStorage | use16BitStorage | descriptorIndexing, 50, 123,
1929                                   m_usePhysStorageBuffer);
1930         }
1931     }
1932 }
1933 
createUnsizedArrayTests(tcu::TestCaseGroup * testGroup)1934 void createUnsizedArrayTests(tcu::TestCaseGroup *testGroup)
1935 {
1936     const UnsizedArrayCaseParams subcases[] = {
1937         {4, 256, false, 256, "float_no_offset_explicit_size"},
1938         {4, 256, false, VK_WHOLE_SIZE, "float_no_offset_whole_size"},
1939         {4, 512, true, 32, "float_offset_explicit_size"},
1940         {4, 512, true, VK_WHOLE_SIZE, "float_offset_whole_size"},
1941     };
1942 
1943     for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(subcases); ndx++)
1944     {
1945         const UnsizedArrayCaseParams &params = subcases[ndx];
1946         addFunctionCaseWithPrograms<UnsizedArrayCaseParams>(testGroup, params.name, createUnsizedArrayLengthProgs,
1947                                                             ssboUnsizedArrayLengthTest, params);
1948     }
1949 }
1950 
1951 } // namespace
1952 
createTests(tcu::TestContext & testCtx,const std::string & name)1953 tcu::TestCaseGroup *createTests(tcu::TestContext &testCtx, const std::string &name)
1954 {
1955     de::MovePtr<tcu::TestCaseGroup> ssboTestGroup(new tcu::TestCaseGroup(testCtx, name.c_str()));
1956 
1957     ssboTestGroup->addChild(new SSBOLayoutTests(testCtx, false, false));
1958     // SSBO unsized array length tests
1959     addTestGroup(ssboTestGroup.get(), "unsized_array_length", createUnsizedArrayTests);
1960 
1961     // Readonly Shader Storage Buffer Tests
1962     de::MovePtr<tcu::TestCaseGroup> readonlyGroup(new tcu::TestCaseGroup(testCtx, "readonly"));
1963     readonlyGroup->addChild(new SSBOLayoutTests(testCtx, false, true));
1964     ssboTestGroup->addChild(readonlyGroup.release());
1965 
1966     de::MovePtr<tcu::TestCaseGroup> physGroup(new tcu::TestCaseGroup(testCtx, "phys"));
1967     physGroup->addChild(new SSBOLayoutTests(testCtx, true, false));
1968     ssboTestGroup->addChild(physGroup.release());
1969 
1970     ssboTestGroup->addChild(createSSBOCornerCaseTests(testCtx));
1971 
1972     return ssboTestGroup.release();
1973 }
1974 
1975 } // namespace ssbo
1976 } // namespace vkt
1977