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