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