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