• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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