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 ¶ms = 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