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, const char* description, 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,const char * description,BufferMode bufferMode,deUint32 features,deUint32 seed,bool usePhysStorageBuffer)113 RandomSSBOLayoutCase::RandomSSBOLayoutCase (tcu::TestContext& testCtx, const char* name, const char* description, BufferMode bufferMode, deUint32 features, deUint32 seed, bool usePhysStorageBuffer)
114 : SSBOLayoutCase (testCtx, name, description, 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 char * description,const VarType & type,deUint32 layoutFlags,int numInstances,MatrixLoadFlags matrixLoadFlag,MatrixStoreFlags matrixStoreFlag,bool usePhysStorageBuffer,bool readonly)382 BlockBasicTypeCase (tcu::TestContext& testCtx, const char* name, const char* description, const VarType& type, deUint32 layoutFlags, int numInstances, MatrixLoadFlags matrixLoadFlag, MatrixStoreFlags matrixStoreFlag, bool usePhysStorageBuffer, bool readonly)
383 : SSBOLayoutCase(testCtx, name, description, 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 char * description,const VarType & elementType,int arraySize,deUint32 layoutFlags,MatrixLoadFlags matrixLoadFlag,MatrixStoreFlags matrixStoreFlag,bool usePhysStorageBuffer,bool readonly)425 BlockBasicUnsizedArrayCase (tcu::TestContext& testCtx, const char* name, const char* description, const VarType& elementType, int arraySize, deUint32 layoutFlags, MatrixLoadFlags matrixLoadFlag, MatrixStoreFlags matrixStoreFlag, bool usePhysStorageBuffer, bool readonly)
426 : SSBOLayoutCase(testCtx, name, description, 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,const char * description,SSBOLayoutCase::BufferMode bufferMode,deUint32 features,int numCases,deUint32 baseSeed,bool usePhysStorageBuffer)461 static void createRandomCaseGroup (tcu::TestCaseGroup* parentGroup, tcu::TestContext& testCtx, const char* groupName, const char* description, SSBOLayoutCase::BufferMode bufferMode, deUint32 features, int numCases, deUint32 baseSeed, bool usePhysStorageBuffer)
462 {
463 tcu::TestCaseGroup* group = new tcu::TestCaseGroup(testCtx, groupName, description);
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,const char * description,deUint32 layoutFlags,BufferMode bufferMode,int numInstances,MatrixLoadFlags matrixLoadFlag,MatrixStoreFlags matrixStoreFlag,bool usePhysStorageBuffer,bool readonly)475 BlockSingleStructCase (tcu::TestContext& testCtx, const char* name, const char* description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag, MatrixStoreFlags matrixStoreFlag, bool usePhysStorageBuffer, bool readonly)
476 : SSBOLayoutCase (testCtx, name, description, 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,const char * description,deUint32 layoutFlags,BufferMode bufferMode,int numInstances,MatrixLoadFlags matrixLoadFlag,MatrixStoreFlags matrixStoreFlag,bool usePhysStorageBuffer)506 BlockSingleStructArrayCase (tcu::TestContext& testCtx, const char* name, const char* description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag, MatrixStoreFlags matrixStoreFlag, bool usePhysStorageBuffer)
507 : SSBOLayoutCase (testCtx, name, description, 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,const char * description,deUint32 layoutFlags,BufferMode bufferMode,int numInstances,MatrixLoadFlags matrixLoadFlag,MatrixStoreFlags matrixStoreFlag,bool usePhysStorageBuffer)539 BlockSingleNestedStructCase (tcu::TestContext& testCtx, const char* name, const char* description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag, MatrixStoreFlags matrixStoreFlag, bool usePhysStorageBuffer)
540 : SSBOLayoutCase (testCtx, name, description, 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,const char * description,deUint32 layoutFlags,BufferMode bufferMode,int numInstances,MatrixLoadFlags matrixLoadFlag,MatrixStoreFlags matrixStoreFlag,bool usePhysStorageBuffer)577 BlockSingleNestedStructArrayCase (tcu::TestContext& testCtx, const char* name, const char* description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag, MatrixStoreFlags matrixStoreFlag, bool usePhysStorageBuffer)
578 : SSBOLayoutCase (testCtx, name, description, 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,const char * description,deUint32 layoutFlags,BufferMode bufferMode,int numInstances,MatrixLoadFlags matrixLoadFlag,MatrixStoreFlags matrixStoreFlag,bool usePhysStorageBuffer)615 BlockUnsizedStructArrayCase (tcu::TestContext& testCtx, const char* name, const char* description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag, MatrixStoreFlags matrixStoreFlag, bool usePhysStorageBuffer)
616 : SSBOLayoutCase (testCtx, name, description, 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,const char * description,deUint32 layoutFlags,BufferMode bufferMode,int numInstances,MatrixLoadFlags matrixLoadFlag,MatrixStoreFlags matrixStoreFlag,bool usePhysStorageBuffer)657 Block2LevelUnsizedStructArrayCase (tcu::TestContext& testCtx, const char* name, const char* description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag, MatrixStoreFlags matrixStoreFlag, bool usePhysStorageBuffer)
658 : SSBOLayoutCase (testCtx, name, description, 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,const char * description,deUint32 layoutFlags,BufferMode bufferMode,int numInstances,MatrixLoadFlags matrixLoadFlag,MatrixStoreFlags matrixStoreFlag,bool usePhysStorageBuffer)698 BlockUnsizedNestedStructArrayCase (tcu::TestContext& testCtx, const char* name, const char* description, deUint32 layoutFlags, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag, MatrixStoreFlags matrixStoreFlag, bool usePhysStorageBuffer)
699 : SSBOLayoutCase (testCtx, name, description, 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,const char * description,deUint32 flagsA,deUint32 flagsB,BufferMode bufferMode,int numInstances,MatrixLoadFlags matrixLoadFlag,MatrixStoreFlags matrixStoreFlag,bool usePhysStorageBuffer)746 BlockMultiBasicTypesCase (tcu::TestContext& testCtx, const char* name, const char* description, deUint32 flagsA, deUint32 flagsB, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag, MatrixStoreFlags matrixStoreFlag, bool usePhysStorageBuffer)
747 : SSBOLayoutCase (testCtx, name, description, 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,const char * description,deUint32 flagsA,deUint32 flagsB,BufferMode bufferMode,int numInstances,MatrixLoadFlags matrixLoadFlag,MatrixStoreFlags matrixStoreFlag,bool usePhysStorageBuffer)785 BlockMultiNestedStructCase (tcu::TestContext& testCtx, const char* name, const char* description, deUint32 flagsA, deUint32 flagsB, BufferMode bufferMode, int numInstances, MatrixLoadFlags matrixLoadFlag, MatrixStoreFlags matrixStoreFlag, bool usePhysStorageBuffer)
786 : SSBOLayoutCase (testCtx, name, description, 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", "SSBO Layout Tests")
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", "Single basic variable in single buffer");
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", "Single basic array variable in single buffer");
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", "Basic unsized array tests");
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", "2-level nested 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", "3-level nested 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 tcu::TestCaseGroup* nestedArrayGroup = new tcu::TestCaseGroup(m_testCtx, "3_level_unsized_array", "3-level nested array, top-level array unsized");
1376 addChild(nestedArrayGroup);
1377
1378 for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1379 {
1380 tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
1381 nestedArrayGroup->addChild(layoutGroup);
1382
1383 for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
1384 {
1385 glu::DataType type = basicTypes[basicTypeNdx];
1386 const char* typeName = glu::getDataTypeName(type);
1387 const int childSize0 = 2;
1388 const int childSize1 = 4;
1389 const int parentSize = 3;
1390 const VarType childType0 (VarType(type, !glu::dataTypeSupportsPrecisionModifier(type) ? glu::PRECISION_LAST : glu::PRECISION_HIGHP), childSize0);
1391 const VarType childType1 (childType0, childSize1);
1392
1393 layoutGroup->addChild(new BlockBasicUnsizedArrayCase(m_testCtx, typeName, "", childType1, parentSize, layoutFlags[layoutFlagNdx].flags, LOAD_FULL_MATRIX, STORE_FULL_MATRIX, m_usePhysStorageBuffer, m_readonly));
1394
1395 if (glu::isDataTypeMatrix(type))
1396 {
1397 for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
1398 {
1399 for (const auto& loadType : matrixLoadTypes)
1400 for (const auto& storeType : matrixStoreTypes)
1401 layoutGroup->addChild(new BlockBasicUnsizedArrayCase(m_testCtx, (string(matrixFlags[matFlagNdx].name) + "_" + typeName + loadType.first + storeType.first).c_str(), "",
1402 childType1, parentSize,
1403 layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags, loadType.second, storeType.second, m_usePhysStorageBuffer, m_readonly));
1404 }
1405 }
1406 }
1407 }
1408 }
1409
1410 // ssbo.single_struct
1411 {
1412 tcu::TestCaseGroup* singleStructGroup = new tcu::TestCaseGroup(m_testCtx, "single_struct", "Single struct in uniform block");
1413 addChild(singleStructGroup);
1414
1415 for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1416 {
1417 tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
1418 singleStructGroup->addChild(modeGroup);
1419
1420 for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1421 {
1422 for (int isArray = 0; isArray < 2; isArray++)
1423 {
1424 const deUint32 caseFlags = layoutFlags[layoutFlagNdx].flags;
1425 string caseName = layoutFlags[layoutFlagNdx].name;
1426
1427 if (bufferModes[modeNdx].mode == SSBOLayoutCase::BUFFERMODE_SINGLE && isArray == 0)
1428 continue; // Doesn't make sense to add this variant.
1429
1430 if (isArray)
1431 caseName += "_instance_array";
1432
1433 for (const auto& loadType : matrixLoadTypes)
1434 for (const auto& storeType : matrixStoreTypes)
1435 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));
1436 }
1437 }
1438 }
1439 }
1440
1441 // ssbo.single_struct_array
1442 if (!m_readonly)
1443 {
1444 tcu::TestCaseGroup* singleStructArrayGroup = new tcu::TestCaseGroup(m_testCtx, "single_struct_array", "Struct array in one uniform block");
1445 addChild(singleStructArrayGroup);
1446
1447 for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1448 {
1449 tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
1450 singleStructArrayGroup->addChild(modeGroup);
1451
1452 for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1453 {
1454 for (int isArray = 0; isArray < 2; isArray++)
1455 {
1456 std::string baseName = layoutFlags[layoutFlagNdx].name;
1457 deUint32 baseFlags = layoutFlags[layoutFlagNdx].flags;
1458
1459 if (bufferModes[modeNdx].mode == SSBOLayoutCase::BUFFERMODE_SINGLE && isArray == 0)
1460 continue; // Doesn't make sense to add this variant.
1461
1462 if (isArray)
1463 baseName += "_instance_array";
1464
1465 for (const auto& loadType : matrixLoadTypes)
1466 for (const auto& storeType : matrixStoreTypes)
1467 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));
1468 }
1469 }
1470 }
1471 }
1472
1473 // ssbo.single_nested_struct
1474 if (!m_readonly)
1475 {
1476 tcu::TestCaseGroup* singleNestedStructGroup = new tcu::TestCaseGroup(m_testCtx, "single_nested_struct", "Nested struct in one uniform block");
1477 addChild(singleNestedStructGroup);
1478
1479 for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1480 {
1481 tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
1482 singleNestedStructGroup->addChild(modeGroup);
1483
1484 for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1485 {
1486 for (int isArray = 0; isArray < 2; isArray++)
1487 {
1488 std::string baseName = layoutFlags[layoutFlagNdx].name;
1489 deUint32 baseFlags = layoutFlags[layoutFlagNdx].flags;
1490
1491 if (bufferModes[modeNdx].mode == SSBOLayoutCase::BUFFERMODE_SINGLE && isArray == 0)
1492 continue; // Doesn't make sense to add this variant.
1493
1494 if (isArray)
1495 baseName += "_instance_array";
1496
1497 for (const auto& loadType : matrixLoadTypes)
1498 for (const auto& storeType : matrixStoreTypes)
1499 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));
1500 }
1501 }
1502 }
1503 }
1504
1505 // ssbo.single_nested_struct_array
1506 if (!m_readonly)
1507 {
1508 tcu::TestCaseGroup* singleNestedStructArrayGroup = new tcu::TestCaseGroup(m_testCtx, "single_nested_struct_array", "Nested struct array in one uniform block");
1509 addChild(singleNestedStructArrayGroup);
1510
1511 for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1512 {
1513 tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
1514 singleNestedStructArrayGroup->addChild(modeGroup);
1515
1516 for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1517 {
1518 for (int isArray = 0; isArray < 2; isArray++)
1519 {
1520 std::string baseName = layoutFlags[layoutFlagNdx].name;
1521 deUint32 baseFlags = layoutFlags[layoutFlagNdx].flags;
1522
1523 if (bufferModes[modeNdx].mode == SSBOLayoutCase::BUFFERMODE_SINGLE && isArray == 0)
1524 continue; // Doesn't make sense to add this variant.
1525
1526 if (isArray)
1527 baseName += "_instance_array";
1528
1529 for (const auto& loadType : matrixLoadTypes)
1530 for (const auto& storeType : matrixStoreTypes)
1531 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));
1532 }
1533 }
1534 }
1535 }
1536
1537 // ssbo.unsized_struct_array
1538 if (!m_readonly)
1539 {
1540 tcu::TestCaseGroup* singleStructArrayGroup = new tcu::TestCaseGroup(m_testCtx, "unsized_struct_array", "Unsized struct array in one uniform block");
1541 addChild(singleStructArrayGroup);
1542
1543 for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1544 {
1545 tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
1546 singleStructArrayGroup->addChild(modeGroup);
1547
1548 for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1549 {
1550 for (int isArray = 0; isArray < 2; isArray++)
1551 {
1552 std::string baseName = layoutFlags[layoutFlagNdx].name;
1553 deUint32 baseFlags = layoutFlags[layoutFlagNdx].flags;
1554
1555 if (bufferModes[modeNdx].mode == SSBOLayoutCase::BUFFERMODE_SINGLE && isArray == 0)
1556 continue; // Doesn't make sense to add this variant.
1557
1558 if (isArray)
1559 baseName += "_instance_array";
1560
1561 for (const auto& loadType : matrixLoadTypes)
1562 for (const auto& storeType : matrixStoreTypes)
1563 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));
1564 }
1565 }
1566 }
1567 }
1568
1569 // ssbo.2_level_unsized_struct_array
1570 if (!m_readonly)
1571 {
1572 tcu::TestCaseGroup* structArrayGroup = new tcu::TestCaseGroup(m_testCtx, "2_level_unsized_struct_array", "Unsized 2-level struct array in one uniform block");
1573 addChild(structArrayGroup);
1574
1575 for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1576 {
1577 tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
1578 structArrayGroup->addChild(modeGroup);
1579
1580 for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1581 {
1582 for (int isArray = 0; isArray < 2; isArray++)
1583 {
1584 std::string baseName = layoutFlags[layoutFlagNdx].name;
1585 deUint32 baseFlags = layoutFlags[layoutFlagNdx].flags;
1586
1587 if (bufferModes[modeNdx].mode == SSBOLayoutCase::BUFFERMODE_SINGLE && isArray == 0)
1588 continue; // Doesn't make sense to add this variant.
1589
1590 if (isArray)
1591 baseName += "_instance_array";
1592
1593 for (const auto& loadType : matrixLoadTypes)
1594 for (const auto& storeType : matrixStoreTypes)
1595 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));
1596 }
1597 }
1598 }
1599 }
1600
1601 // ssbo.unsized_nested_struct_array
1602 if (!m_readonly)
1603 {
1604 tcu::TestCaseGroup* singleNestedStructArrayGroup = new tcu::TestCaseGroup(m_testCtx, "unsized_nested_struct_array", "Unsized, nested struct array in one uniform block");
1605 addChild(singleNestedStructArrayGroup);
1606
1607 for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1608 {
1609 tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
1610 singleNestedStructArrayGroup->addChild(modeGroup);
1611
1612 for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1613 {
1614 for (int isArray = 0; isArray < 2; isArray++)
1615 {
1616 std::string baseName = layoutFlags[layoutFlagNdx].name;
1617 deUint32 baseFlags = layoutFlags[layoutFlagNdx].flags;
1618
1619 if (bufferModes[modeNdx].mode == SSBOLayoutCase::BUFFERMODE_SINGLE && isArray == 0)
1620 continue; // Doesn't make sense to add this variant.
1621
1622 if (isArray)
1623 baseName += "_instance_array";
1624
1625 for (const auto& loadType : matrixLoadTypes)
1626 for (const auto& storeType : matrixStoreTypes)
1627 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));
1628 }
1629 }
1630 }
1631 }
1632
1633 // ssbo.instance_array_basic_type
1634 if (!m_readonly)
1635 {
1636 tcu::TestCaseGroup* instanceArrayBasicTypeGroup = new tcu::TestCaseGroup(m_testCtx, "instance_array_basic_type", "Single basic variable in instance array");
1637 addChild(instanceArrayBasicTypeGroup);
1638
1639 for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1640 {
1641 tcu::TestCaseGroup* layoutGroup = new tcu::TestCaseGroup(m_testCtx, layoutFlags[layoutFlagNdx].name, "");
1642 instanceArrayBasicTypeGroup->addChild(layoutGroup);
1643
1644 for (int basicTypeNdx = 0; basicTypeNdx < DE_LENGTH_OF_ARRAY(basicTypes); basicTypeNdx++)
1645 {
1646 glu::DataType type = basicTypes[basicTypeNdx];
1647 const char* typeName = glu::getDataTypeName(type);
1648 const int numInstances = 3;
1649
1650 layoutGroup->addChild(new BlockBasicTypeCase(m_testCtx, typeName, "",
1651 VarType(type, !glu::dataTypeSupportsPrecisionModifier(type) ? glu::PRECISION_LAST : glu::PRECISION_HIGHP),
1652 layoutFlags[layoutFlagNdx].flags, numInstances, LOAD_FULL_MATRIX, STORE_FULL_MATRIX, m_usePhysStorageBuffer, m_readonly));
1653
1654 if (glu::isDataTypeMatrix(type))
1655 {
1656 for (int matFlagNdx = 0; matFlagNdx < DE_LENGTH_OF_ARRAY(matrixFlags); matFlagNdx++)
1657 {
1658 for (const auto& loadType : matrixLoadTypes)
1659 for (const auto& storeType : matrixStoreTypes)
1660 layoutGroup->addChild(new BlockBasicTypeCase(m_testCtx, (string(matrixFlags[matFlagNdx].name) + "_" + typeName + loadType.first + storeType.first).c_str(), "",
1661 VarType(type, glu::PRECISION_HIGHP), layoutFlags[layoutFlagNdx].flags|matrixFlags[matFlagNdx].flags,
1662 numInstances, loadType.second, storeType.second, m_usePhysStorageBuffer, m_readonly));
1663 }
1664 }
1665 }
1666 }
1667 }
1668
1669 // ssbo.multi_basic_types
1670 if (!m_readonly)
1671 {
1672 tcu::TestCaseGroup* multiBasicTypesGroup = new tcu::TestCaseGroup(m_testCtx, "multi_basic_types", "Multiple buffers with basic types");
1673 addChild(multiBasicTypesGroup);
1674
1675 for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1676 {
1677 tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
1678 multiBasicTypesGroup->addChild(modeGroup);
1679
1680 for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1681 {
1682 for (int isArray = 0; isArray < 2; isArray++)
1683 {
1684 std::string baseName = layoutFlags[layoutFlagNdx].name;
1685 deUint32 baseFlags = layoutFlags[layoutFlagNdx].flags;
1686
1687 if (isArray)
1688 baseName += "_instance_array";
1689
1690 for (const auto& loadType : matrixLoadTypes)
1691 for (const auto& storeType : matrixStoreTypes)
1692 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));
1693 }
1694 }
1695
1696 for (int isArray = 0; isArray < 2; isArray++)
1697 {
1698 std::string baseName = "relaxed_block";
1699 deUint32 baseFlags = LAYOUT_RELAXED;
1700
1701 if (isArray)
1702 baseName += "_instance_array";
1703
1704 for (const auto& loadType : matrixLoadTypes)
1705 for (const auto& storeType : matrixStoreTypes)
1706 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));
1707 }
1708 }
1709 }
1710
1711 // ssbo.multi_nested_struct
1712 if (!m_readonly)
1713 {
1714 tcu::TestCaseGroup* multiNestedStructGroup = new tcu::TestCaseGroup(m_testCtx, "multi_nested_struct", "Multiple buffers with nested structs");
1715 addChild(multiNestedStructGroup);
1716
1717 for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(bufferModes); modeNdx++)
1718 {
1719 tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[modeNdx].name, "");
1720 multiNestedStructGroup->addChild(modeGroup);
1721
1722 for (int layoutFlagNdx = 0; layoutFlagNdx < DE_LENGTH_OF_ARRAY(layoutFlags); layoutFlagNdx++)
1723 {
1724 for (int isArray = 0; isArray < 2; isArray++)
1725 {
1726 std::string baseName = layoutFlags[layoutFlagNdx].name;
1727 deUint32 baseFlags = layoutFlags[layoutFlagNdx].flags;
1728
1729 if (isArray)
1730 baseName += "_instance_array";
1731
1732 for (const auto& loadType : matrixLoadTypes)
1733 for (const auto& storeType : matrixStoreTypes)
1734 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));
1735 }
1736 }
1737 }
1738 }
1739
1740 // ssbo.random
1741 if (!m_readonly)
1742 {
1743 const deUint32 allStdLayouts = FEATURE_STD140_LAYOUT|FEATURE_STD430_LAYOUT;
1744 const deUint32 allBasicTypes = FEATURE_VECTORS|FEATURE_MATRICES;
1745 const deUint32 unused = FEATURE_UNUSED_MEMBERS|FEATURE_UNUSED_VARS;
1746 const deUint32 unsized = FEATURE_UNSIZED_ARRAYS;
1747 const deUint32 matFlags = FEATURE_MATRIX_LAYOUT;
1748 const deUint32 allButRelaxed = ~FEATURE_RELAXED_LAYOUT & ~FEATURE_16BIT_STORAGE & ~FEATURE_8BIT_STORAGE & ~FEATURE_SCALAR_LAYOUT & ~FEATURE_DESCRIPTOR_INDEXING;
1749 const deUint32 allRelaxed = FEATURE_VECTORS|FEATURE_RELAXED_LAYOUT|FEATURE_INSTANCE_ARRAYS;
1750 const deUint32 allScalar = ~FEATURE_RELAXED_LAYOUT & ~allStdLayouts & ~FEATURE_16BIT_STORAGE & ~FEATURE_8BIT_STORAGE & ~FEATURE_DESCRIPTOR_INDEXING;
1751 const deUint32 descriptorIndexing = allStdLayouts|FEATURE_RELAXED_LAYOUT|FEATURE_SCALAR_LAYOUT|FEATURE_DESCRIPTOR_INDEXING|allBasicTypes|unused|matFlags;
1752
1753 tcu::TestCaseGroup* randomGroup = new tcu::TestCaseGroup(m_testCtx, "random", "Random Uniform Block cases");
1754 addChild(randomGroup);
1755
1756 for (int i = 0; i < 3; ++i)
1757 {
1758
1759 tcu::TestCaseGroup* group = randomGroup;
1760 if (i == 1)
1761 {
1762 group = new tcu::TestCaseGroup(m_testCtx, "16bit", "16bit storage");
1763 randomGroup->addChild(group);
1764 }
1765 else if (i == 2)
1766 {
1767 group = new tcu::TestCaseGroup(m_testCtx, "8bit", "8bit storage");
1768 randomGroup->addChild(group);
1769 }
1770 const deUint32 use16BitStorage = i == 1 ? FEATURE_16BIT_STORAGE : 0;
1771 const deUint32 use8BitStorage = i == 2 ? FEATURE_8BIT_STORAGE : 0;
1772
1773 // Basic types.
1774 createRandomCaseGroup(group, m_testCtx, "scalar_types", "Scalar types only, per-block buffers", SSBOLayoutCase::BUFFERMODE_PER_BLOCK, use8BitStorage|use16BitStorage|allStdLayouts|unused, 25, 0, m_usePhysStorageBuffer);
1775 createRandomCaseGroup(group, m_testCtx, "vector_types", "Scalar and vector types only, per-block buffers", SSBOLayoutCase::BUFFERMODE_PER_BLOCK, use8BitStorage|use16BitStorage|allStdLayouts|unused|FEATURE_VECTORS, 25, 25, m_usePhysStorageBuffer);
1776 createRandomCaseGroup(group, m_testCtx, "basic_types", "All basic types, per-block buffers", SSBOLayoutCase::BUFFERMODE_PER_BLOCK, use8BitStorage|use16BitStorage|allStdLayouts|unused|allBasicTypes|matFlags, 25, 50, m_usePhysStorageBuffer);
1777 createRandomCaseGroup(group, m_testCtx, "basic_arrays", "Arrays, per-block buffers", SSBOLayoutCase::BUFFERMODE_PER_BLOCK, use8BitStorage|use16BitStorage|allStdLayouts|unused|allBasicTypes|matFlags|FEATURE_ARRAYS, 25, 50, m_usePhysStorageBuffer);
1778 createRandomCaseGroup(group, m_testCtx, "unsized_arrays", "Unsized arrays, per-block buffers", SSBOLayoutCase::BUFFERMODE_PER_BLOCK, use8BitStorage|use16BitStorage|allStdLayouts|unused|allBasicTypes|matFlags|unsized|FEATURE_ARRAYS, 25, 50, m_usePhysStorageBuffer);
1779 createRandomCaseGroup(group, m_testCtx, "arrays_of_arrays", "Arrays of arrays, per-block buffers", SSBOLayoutCase::BUFFERMODE_PER_BLOCK, use8BitStorage|use16BitStorage|allStdLayouts|unused|allBasicTypes|matFlags|unsized|FEATURE_ARRAYS|FEATURE_ARRAYS_OF_ARRAYS, 25, 950, m_usePhysStorageBuffer);
1780
1781 createRandomCaseGroup(group, m_testCtx, "basic_instance_arrays", "Basic instance arrays, per-block buffers", SSBOLayoutCase::BUFFERMODE_PER_BLOCK, use8BitStorage|use16BitStorage|allStdLayouts|unused|allBasicTypes|matFlags|unsized|FEATURE_INSTANCE_ARRAYS, 25, 75, m_usePhysStorageBuffer);
1782 createRandomCaseGroup(group, m_testCtx, "nested_structs", "Nested structs, per-block buffers", SSBOLayoutCase::BUFFERMODE_PER_BLOCK, use8BitStorage|use16BitStorage|allStdLayouts|unused|allBasicTypes|matFlags|unsized|FEATURE_STRUCTS, 25, 100, m_usePhysStorageBuffer);
1783 createRandomCaseGroup(group, m_testCtx, "nested_structs_arrays", "Nested structs, arrays, per-block buffers", SSBOLayoutCase::BUFFERMODE_PER_BLOCK, use8BitStorage|use16BitStorage|allStdLayouts|unused|allBasicTypes|matFlags|unsized|FEATURE_STRUCTS|FEATURE_ARRAYS|FEATURE_ARRAYS_OF_ARRAYS, 25, 150, m_usePhysStorageBuffer);
1784 createRandomCaseGroup(group, m_testCtx, "nested_structs_instance_arrays", "Nested structs, instance arrays, per-block buffers", SSBOLayoutCase::BUFFERMODE_PER_BLOCK, use8BitStorage|use16BitStorage|allStdLayouts|unused|allBasicTypes|matFlags|unsized|FEATURE_STRUCTS|FEATURE_INSTANCE_ARRAYS, 25, 125, m_usePhysStorageBuffer);
1785 createRandomCaseGroup(group, m_testCtx, "nested_structs_arrays_instance_arrays", "Nested structs, instance arrays, per-block buffers", 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);
1786 createRandomCaseGroup(group, m_testCtx, "all_per_block_buffers", "All random features, per-block buffers", SSBOLayoutCase::BUFFERMODE_PER_BLOCK, use8BitStorage|use16BitStorage|allButRelaxed, 50, 200, m_usePhysStorageBuffer);
1787 createRandomCaseGroup(group, m_testCtx, "all_shared_buffer", "All random features, shared buffer", SSBOLayoutCase::BUFFERMODE_SINGLE, use8BitStorage|use16BitStorage|allButRelaxed, 50, 250, m_usePhysStorageBuffer);
1788
1789 createRandomCaseGroup(group, m_testCtx, "relaxed", "VK_KHR_relaxed_block_layout", SSBOLayoutCase::BUFFERMODE_SINGLE, use8BitStorage|use16BitStorage|allRelaxed, 100, deInt32Hash(313), m_usePhysStorageBuffer);
1790 createRandomCaseGroup(group, m_testCtx, "scalar", "VK_EXT_scalar_block_layout", SSBOLayoutCase::BUFFERMODE_SINGLE, use8BitStorage|use16BitStorage|allScalar, 100, deInt32Hash(313), m_usePhysStorageBuffer);
1791 createRandomCaseGroup(group, m_testCtx, "descriptor_indexing", "VK_EXT_descriptor_indexing", SSBOLayoutCase::BUFFERMODE_SINGLE, use8BitStorage|use16BitStorage|descriptorIndexing, 50, 123, m_usePhysStorageBuffer);
1792 }
1793 }
1794 }
1795
createUnsizedArrayTests(tcu::TestCaseGroup * testGroup)1796 void createUnsizedArrayTests (tcu::TestCaseGroup* testGroup)
1797 {
1798 const UnsizedArrayCaseParams subcases[] =
1799 {
1800 { 4, 256, false, 256, "float_no_offset_explicit_size" },
1801 { 4, 256, false, VK_WHOLE_SIZE, "float_no_offset_whole_size" },
1802 { 4, 512, true, 32, "float_offset_explicit_size" },
1803 { 4, 512, true, VK_WHOLE_SIZE, "float_offset_whole_size" },
1804 };
1805
1806 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(subcases); ndx++)
1807 {
1808 const UnsizedArrayCaseParams& params = subcases[ndx];
1809 addFunctionCaseWithPrograms<UnsizedArrayCaseParams>(testGroup, params.name, "", createUnsizedArrayLengthProgs, ssboUnsizedArrayLengthTest, params);
1810 }
1811 }
1812
1813 } // anonymous
1814
createTests(tcu::TestContext & testCtx)1815 tcu::TestCaseGroup* createTests (tcu::TestContext& testCtx)
1816 {
1817 de::MovePtr<tcu::TestCaseGroup> ssboTestGroup (new tcu::TestCaseGroup(testCtx, "ssbo", "Shader Storage Buffer Object Tests"));
1818
1819 ssboTestGroup->addChild(new SSBOLayoutTests(testCtx, false, false));
1820 addTestGroup(ssboTestGroup.get(), "unsized_array_length", "SSBO unsized array length tests", createUnsizedArrayTests);
1821
1822 de::MovePtr<tcu::TestCaseGroup> readonlyGroup(new tcu::TestCaseGroup(testCtx, "readonly", "Readonly Shader Storage Buffer Tests"));
1823 readonlyGroup->addChild(new SSBOLayoutTests(testCtx, false, true));
1824 ssboTestGroup->addChild(readonlyGroup.release());
1825
1826 de::MovePtr<tcu::TestCaseGroup> physGroup(new tcu::TestCaseGroup(testCtx, "phys", "Physical Storage Buffer Pointer Tests"));
1827 physGroup->addChild(new SSBOLayoutTests(testCtx, true, false));
1828 ssboTestGroup->addChild(physGroup.release());
1829
1830 ssboTestGroup->addChild(createSSBOCornerCaseTests(testCtx));
1831
1832 return ssboTestGroup.release();
1833 }
1834
1835 } // ssbo
1836 } // vkt
1837