• 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 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