• 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 case.
24  *//*--------------------------------------------------------------------*/
25 
26 #include "vktSSBOLayoutCase.hpp"
27 #include "gluShaderProgram.hpp"
28 #include "gluContextInfo.hpp"
29 #include "gluShaderUtil.hpp"
30 #include "gluVarType.hpp"
31 #include "gluVarTypeUtil.hpp"
32 #include "tcuTestLog.hpp"
33 #include "deRandom.hpp"
34 #include "deStringUtil.hpp"
35 #include "deMemory.h"
36 #include "deString.h"
37 #include "deMath.h"
38 #include "deSharedPtr.hpp"
39 
40 #include <algorithm>
41 #include <map>
42 
43 #include "vkBuilderUtil.hpp"
44 #include "vkMemUtil.hpp"
45 #include "vkPrograms.hpp"
46 #include "vkQueryUtil.hpp"
47 #include "vkRef.hpp"
48 #include "vkRefUtil.hpp"
49 #include "vkTypeUtil.hpp"
50 
51 namespace vkt
52 {
53 namespace ssbo
54 {
55 
56 using tcu::TestLog;
57 using std::string;
58 using std::vector;
59 using std::map;
60 using glu::VarType;
61 using glu::StructType;
62 using glu::StructMember;
63 
64 struct LayoutFlagsFmt
65 {
66 	deUint32 flags;
LayoutFlagsFmtvkt::ssbo::LayoutFlagsFmt67 	LayoutFlagsFmt (deUint32 flags_) : flags(flags_) {}
68 };
69 
operator <<(std::ostream & str,const LayoutFlagsFmt & fmt)70 std::ostream& operator<< (std::ostream& str, const LayoutFlagsFmt& fmt)
71 {
72 	static const struct
73 	{
74 		deUint32	bit;
75 		const char*	token;
76 	} bitDesc[] =
77 	{
78 		{ LAYOUT_STD140,		"std140"		},
79 		{ LAYOUT_STD430,		"std430"		},
80 		{ LAYOUT_ROW_MAJOR,		"row_major"		},
81 		{ LAYOUT_COLUMN_MAJOR,	"column_major"	}
82 	};
83 
84 	deUint32 remBits = fmt.flags;
85 	for (int descNdx = 0; descNdx < DE_LENGTH_OF_ARRAY(bitDesc); descNdx++)
86 	{
87 		if (remBits & bitDesc[descNdx].bit)
88 		{
89 			if (remBits != fmt.flags)
90 				str << ", ";
91 			str << bitDesc[descNdx].token;
92 			remBits &= ~bitDesc[descNdx].bit;
93 		}
94 	}
95 	DE_ASSERT(remBits == 0);
96 	return str;
97 }
98 
99 // BufferVar implementation.
100 
BufferVar(const char * name,const VarType & type,deUint32 flags)101 BufferVar::BufferVar (const char* name, const VarType& type, deUint32 flags)
102 	: m_name	(name)
103 	, m_type	(type)
104 	, m_flags	(flags)
105 {
106 }
107 
108 // BufferBlock implementation.
109 
BufferBlock(const char * blockName)110 BufferBlock::BufferBlock (const char* blockName)
111 	: m_blockName	(blockName)
112 	, m_arraySize	(-1)
113 	, m_flags		(0)
114 {
115 	setArraySize(0);
116 }
117 
setArraySize(int arraySize)118 void BufferBlock::setArraySize (int arraySize)
119 {
120 	DE_ASSERT(arraySize >= 0);
121 	m_lastUnsizedArraySizes.resize(arraySize == 0 ? 1 : arraySize, 0);
122 	m_arraySize = arraySize;
123 }
124 
operator <<(std::ostream & stream,const BlockLayoutEntry & entry)125 std::ostream& operator<< (std::ostream& stream, const BlockLayoutEntry& entry)
126 {
127 	stream << entry.name << " { name = " << entry.name
128 		   << ", size = " << entry.size
129 		   << ", activeVarIndices = [";
130 
131 	for (vector<int>::const_iterator i = entry.activeVarIndices.begin(); i != entry.activeVarIndices.end(); i++)
132 	{
133 		if (i != entry.activeVarIndices.begin())
134 			stream << ", ";
135 		stream << *i;
136 	}
137 
138 	stream << "] }";
139 	return stream;
140 }
141 
isUnsizedArray(const BufferVarLayoutEntry & entry)142 static bool isUnsizedArray (const BufferVarLayoutEntry& entry)
143 {
144 	DE_ASSERT(entry.arraySize != 0 || entry.topLevelArraySize != 0);
145 	return entry.arraySize == 0 || entry.topLevelArraySize == 0;
146 }
147 
operator <<(std::ostream & stream,const BufferVarLayoutEntry & entry)148 std::ostream& operator<< (std::ostream& stream, const BufferVarLayoutEntry& entry)
149 {
150 	stream << entry.name << " { type = " << glu::getDataTypeName(entry.type)
151 		   << ", blockNdx = " << entry.blockNdx
152 		   << ", offset = " << entry.offset
153 		   << ", arraySize = " << entry.arraySize
154 		   << ", arrayStride = " << entry.arrayStride
155 		   << ", matrixStride = " << entry.matrixStride
156 		   << ", topLevelArraySize = " << entry.topLevelArraySize
157 		   << ", topLevelArrayStride = " << entry.topLevelArrayStride
158 		   << ", isRowMajor = " << (entry.isRowMajor ? "true" : "false")
159 		   << " }";
160 	return stream;
161 }
162 
163 // \todo [2012-01-24 pyry] Speed up lookups using hash.
164 
getVariableIndex(const string & name) const165 int BufferLayout::getVariableIndex (const string& name) const
166 {
167 	for (int ndx = 0; ndx < (int)bufferVars.size(); ndx++)
168 	{
169 		if (bufferVars[ndx].name == name)
170 			return ndx;
171 	}
172 	return -1;
173 }
174 
getBlockIndex(const string & name) const175 int BufferLayout::getBlockIndex (const string& name) const
176 {
177 	for (int ndx = 0; ndx < (int)blocks.size(); ndx++)
178 	{
179 		if (blocks[ndx].name == name)
180 			return ndx;
181 	}
182 	return -1;
183 }
184 
185 // ShaderInterface implementation.
186 
ShaderInterface(void)187 ShaderInterface::ShaderInterface (void)
188 {
189 }
190 
~ShaderInterface(void)191 ShaderInterface::~ShaderInterface (void)
192 {
193 	for (std::vector<StructType*>::iterator i = m_structs.begin(); i != m_structs.end(); i++)
194 		delete *i;
195 
196 	for (std::vector<BufferBlock*>::iterator i = m_bufferBlocks.begin(); i != m_bufferBlocks.end(); i++)
197 		delete *i;
198 }
199 
allocStruct(const char * name)200 StructType& ShaderInterface::allocStruct (const char* name)
201 {
202 	m_structs.reserve(m_structs.size()+1);
203 	m_structs.push_back(new StructType(name));
204 	return *m_structs.back();
205 }
206 
207 struct StructNameEquals
208 {
209 	std::string name;
210 
StructNameEqualsvkt::ssbo::StructNameEquals211 	StructNameEquals (const char* name_) : name(name_) {}
212 
operator ()vkt::ssbo::StructNameEquals213 	bool operator() (const StructType* type) const
214 	{
215 		return type->getTypeName() && name == type->getTypeName();
216 	}
217 };
218 
findStruct(const char * name) const219 const StructType* ShaderInterface::findStruct (const char* name) const
220 {
221 	std::vector<StructType*>::const_iterator pos = std::find_if(m_structs.begin(), m_structs.end(), StructNameEquals(name));
222 	return pos != m_structs.end() ? *pos : DE_NULL;
223 }
224 
getNamedStructs(std::vector<const StructType * > & structs) const225 void ShaderInterface::getNamedStructs (std::vector<const StructType*>& structs) const
226 {
227 	for (std::vector<StructType*>::const_iterator i = m_structs.begin(); i != m_structs.end(); i++)
228 	{
229 		if ((*i)->getTypeName() != DE_NULL)
230 			structs.push_back(*i);
231 	}
232 }
233 
allocBlock(const char * name)234 BufferBlock& ShaderInterface::allocBlock (const char* name)
235 {
236 	m_bufferBlocks.reserve(m_bufferBlocks.size()+1);
237 	m_bufferBlocks.push_back(new BufferBlock(name));
238 	return *m_bufferBlocks.back();
239 }
240 
241 namespace // Utilities
242 {
243 // Layout computation.
244 
getDataTypeByteSize(glu::DataType type)245 int getDataTypeByteSize (glu::DataType type)
246 {
247 	return glu::getDataTypeScalarSize(type)*(int)sizeof(deUint32);
248 }
249 
getDataTypeByteAlignment(glu::DataType type)250 int getDataTypeByteAlignment (glu::DataType type)
251 {
252 	switch (type)
253 	{
254 		case glu::TYPE_FLOAT:
255 		case glu::TYPE_INT:
256 		case glu::TYPE_UINT:
257 		case glu::TYPE_BOOL:		return 1*(int)sizeof(deUint32);
258 
259 		case glu::TYPE_FLOAT_VEC2:
260 		case glu::TYPE_INT_VEC2:
261 		case glu::TYPE_UINT_VEC2:
262 		case glu::TYPE_BOOL_VEC2:	return 2*(int)sizeof(deUint32);
263 
264 		case glu::TYPE_FLOAT_VEC3:
265 		case glu::TYPE_INT_VEC3:
266 		case glu::TYPE_UINT_VEC3:
267 		case glu::TYPE_BOOL_VEC3:	// Fall-through to vec4
268 
269 		case glu::TYPE_FLOAT_VEC4:
270 		case glu::TYPE_INT_VEC4:
271 		case glu::TYPE_UINT_VEC4:
272 		case glu::TYPE_BOOL_VEC4:	return 4*(int)sizeof(deUint32);
273 
274 		default:
275 			DE_ASSERT(false);
276 			return 0;
277 	}
278 }
279 
deRoundUp32(int a,int b)280 static inline int deRoundUp32 (int a, int b)
281 {
282 	int d = a/b;
283 	return d*b == a ? a : (d+1)*b;
284 }
285 
computeStd140BaseAlignment(const VarType & type,deUint32 layoutFlags)286 int computeStd140BaseAlignment (const VarType& type, deUint32 layoutFlags)
287 {
288 	const int vec4Alignment = (int)sizeof(deUint32)*4;
289 
290 	if (type.isBasicType())
291 	{
292 		glu::DataType basicType = type.getBasicType();
293 
294 		if (glu::isDataTypeMatrix(basicType))
295 		{
296 			const bool	isRowMajor	= !!(layoutFlags & LAYOUT_ROW_MAJOR);
297 			const int	vecSize		= isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType)
298 												 : glu::getDataTypeMatrixNumRows(basicType);
299 			const int	vecAlign	= deAlign32(getDataTypeByteAlignment(glu::getDataTypeFloatVec(vecSize)), vec4Alignment);
300 
301 			return vecAlign;
302 		}
303 		else
304 			return getDataTypeByteAlignment(basicType);
305 	}
306 	else if (type.isArrayType())
307 	{
308 		int elemAlignment = computeStd140BaseAlignment(type.getElementType(), layoutFlags);
309 
310 		// Round up to alignment of vec4
311 		return deAlign32(elemAlignment, vec4Alignment);
312 	}
313 	else
314 	{
315 		DE_ASSERT(type.isStructType());
316 
317 		int maxBaseAlignment = 0;
318 
319 		for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++)
320 			maxBaseAlignment = de::max(maxBaseAlignment, computeStd140BaseAlignment(memberIter->getType(), layoutFlags));
321 
322 		return deAlign32(maxBaseAlignment, vec4Alignment);
323 	}
324 }
325 
computeStd430BaseAlignment(const VarType & type,deUint32 layoutFlags)326 int computeStd430BaseAlignment (const VarType& type, deUint32 layoutFlags)
327 {
328 	// Otherwise identical to std140 except that alignment of structures and arrays
329 	// are not rounded up to alignment of vec4.
330 
331 	if (type.isBasicType())
332 	{
333 		glu::DataType basicType = type.getBasicType();
334 
335 		if (glu::isDataTypeMatrix(basicType))
336 		{
337 			const bool	isRowMajor	= !!(layoutFlags & LAYOUT_ROW_MAJOR);
338 			const int	vecSize		= isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType)
339 												 : glu::getDataTypeMatrixNumRows(basicType);
340 			const int	vecAlign	= getDataTypeByteAlignment(glu::getDataTypeFloatVec(vecSize));
341 
342 			return vecAlign;
343 		}
344 		else
345 			return getDataTypeByteAlignment(basicType);
346 	}
347 	else if (type.isArrayType())
348 	{
349 		return computeStd430BaseAlignment(type.getElementType(), layoutFlags);
350 	}
351 	else
352 	{
353 		DE_ASSERT(type.isStructType());
354 
355 		int maxBaseAlignment = 0;
356 
357 		for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++)
358 			maxBaseAlignment = de::max(maxBaseAlignment, computeStd430BaseAlignment(memberIter->getType(), layoutFlags));
359 
360 		return maxBaseAlignment;
361 	}
362 }
363 
mergeLayoutFlags(deUint32 prevFlags,deUint32 newFlags)364 inline deUint32 mergeLayoutFlags (deUint32 prevFlags, deUint32 newFlags)
365 {
366 	const deUint32	packingMask		= LAYOUT_STD430|LAYOUT_STD140;
367 	const deUint32	matrixMask		= LAYOUT_ROW_MAJOR|LAYOUT_COLUMN_MAJOR;
368 
369 	deUint32 mergedFlags = 0;
370 
371 	mergedFlags |= ((newFlags & packingMask)	? newFlags : prevFlags) & packingMask;
372 	mergedFlags |= ((newFlags & matrixMask)		? newFlags : prevFlags) & matrixMask;
373 
374 	return mergedFlags;
375 }
376 
377 //! Appends all child elements to layout, returns value that should be appended to offset.
computeReferenceLayout(BufferLayout & layout,int curBlockNdx,int baseOffset,const std::string & curPrefix,const VarType & type,deUint32 layoutFlags)378 int computeReferenceLayout (
379 	BufferLayout&		layout,
380 	int					curBlockNdx,
381 	int					baseOffset,
382 	const std::string&	curPrefix,
383 	const VarType&		type,
384 	deUint32			layoutFlags)
385 {
386 	// Reference layout uses std430 rules by default. std140 rules are
387 	// choosen only for blocks that have std140 layout.
388 	const bool	isStd140			= (layoutFlags & LAYOUT_STD140) != 0;
389 	const int	baseAlignment		= isStd140 ? computeStd140BaseAlignment(type, layoutFlags)
390 											   : computeStd430BaseAlignment(type, layoutFlags);
391 	int			curOffset			= deAlign32(baseOffset, baseAlignment);
392 	const int	topLevelArraySize	= 1; // Default values
393 	const int	topLevelArrayStride	= 0;
394 
395 	if (type.isBasicType())
396 	{
397 		const glu::DataType		basicType	= type.getBasicType();
398 		BufferVarLayoutEntry	entry;
399 
400 		entry.name					= curPrefix;
401 		entry.type					= basicType;
402 		entry.arraySize				= 1;
403 		entry.arrayStride			= 0;
404 		entry.matrixStride			= 0;
405 		entry.topLevelArraySize		= topLevelArraySize;
406 		entry.topLevelArrayStride	= topLevelArrayStride;
407 		entry.blockNdx				= curBlockNdx;
408 
409 		if (glu::isDataTypeMatrix(basicType))
410 		{
411 			// Array of vectors as specified in rules 5 & 7.
412 			const bool	isRowMajor			= !!(layoutFlags & LAYOUT_ROW_MAJOR);
413 			const int	numVecs				= isRowMajor ? glu::getDataTypeMatrixNumRows(basicType)
414 														 : glu::getDataTypeMatrixNumColumns(basicType);
415 
416 			entry.offset		= curOffset;
417 			entry.matrixStride	= baseAlignment;
418 			entry.isRowMajor	= isRowMajor;
419 
420 			curOffset += numVecs*baseAlignment;
421 		}
422 		else
423 		{
424 			// Scalar or vector.
425 			entry.offset = curOffset;
426 
427 			curOffset += getDataTypeByteSize(basicType);
428 		}
429 
430 		layout.bufferVars.push_back(entry);
431 	}
432 	else if (type.isArrayType())
433 	{
434 		const VarType&	elemType	= type.getElementType();
435 
436 		if (elemType.isBasicType() && !glu::isDataTypeMatrix(elemType.getBasicType()))
437 		{
438 			// Array of scalars or vectors.
439 			const glu::DataType		elemBasicType	= elemType.getBasicType();
440 			const int				stride			= baseAlignment;
441 			BufferVarLayoutEntry	entry;
442 
443 			entry.name					= curPrefix + "[0]"; // Array variables are always postfixed with [0]
444 			entry.type					= elemBasicType;
445 			entry.blockNdx				= curBlockNdx;
446 			entry.offset				= curOffset;
447 			entry.arraySize				= type.getArraySize();
448 			entry.arrayStride			= stride;
449 			entry.matrixStride			= 0;
450 			entry.topLevelArraySize		= topLevelArraySize;
451 			entry.topLevelArrayStride	= topLevelArrayStride;
452 
453 			curOffset += stride*type.getArraySize();
454 
455 			layout.bufferVars.push_back(entry);
456 		}
457 		else if (elemType.isBasicType() && glu::isDataTypeMatrix(elemType.getBasicType()))
458 		{
459 			// Array of matrices.
460 			const glu::DataType			elemBasicType	= elemType.getBasicType();
461 			const bool					isRowMajor		= !!(layoutFlags & LAYOUT_ROW_MAJOR);
462 			const int					numVecs			= isRowMajor ? glu::getDataTypeMatrixNumRows(elemBasicType)
463 																	 : glu::getDataTypeMatrixNumColumns(elemBasicType);
464 			const int					vecStride		= baseAlignment;
465 			BufferVarLayoutEntry		entry;
466 
467 			entry.name					= curPrefix + "[0]"; // Array variables are always postfixed with [0]
468 			entry.type					= elemBasicType;
469 			entry.blockNdx				= curBlockNdx;
470 			entry.offset				= curOffset;
471 			entry.arraySize				= type.getArraySize();
472 			entry.arrayStride			= vecStride*numVecs;
473 			entry.matrixStride			= vecStride;
474 			entry.isRowMajor			= isRowMajor;
475 			entry.topLevelArraySize		= topLevelArraySize;
476 			entry.topLevelArrayStride	= topLevelArrayStride;
477 
478 			curOffset += numVecs*vecStride*type.getArraySize();
479 
480 			layout.bufferVars.push_back(entry);
481 		}
482 		else
483 		{
484 			DE_ASSERT(elemType.isStructType() || elemType.isArrayType());
485 
486 			for (int elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++)
487 				curOffset += computeReferenceLayout(layout, curBlockNdx, curOffset, curPrefix + "[" + de::toString(elemNdx) + "]", type.getElementType(), layoutFlags);
488 		}
489 	}
490 	else
491 	{
492 		DE_ASSERT(type.isStructType());
493 
494 		for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++)
495 			curOffset += computeReferenceLayout(layout, curBlockNdx, curOffset, curPrefix + "." + memberIter->getName(), memberIter->getType(), layoutFlags);
496 
497 		curOffset = deAlign32(curOffset, baseAlignment);
498 	}
499 
500 	return curOffset-baseOffset;
501 }
502 
503 //! Appends all child elements to layout, returns offset increment.
computeReferenceLayout(BufferLayout & layout,int curBlockNdx,const std::string & blockPrefix,int baseOffset,const BufferVar & bufVar,deUint32 blockLayoutFlags)504 int computeReferenceLayout (BufferLayout& layout, int curBlockNdx, const std::string& blockPrefix, int baseOffset, const BufferVar& bufVar, deUint32 blockLayoutFlags)
505 {
506 	const VarType&	varType			= bufVar.getType();
507 	const deUint32	combinedFlags	= mergeLayoutFlags(blockLayoutFlags, bufVar.getFlags());
508 
509 	if (varType.isArrayType())
510 	{
511 		// Top-level arrays need special care.
512 		const int		topLevelArraySize	= varType.getArraySize() == VarType::UNSIZED_ARRAY ? 0 : varType.getArraySize();
513 		const string	prefix				= blockPrefix + bufVar.getName() + "[0]";
514 		const bool		isStd140			= (blockLayoutFlags & LAYOUT_STD140) != 0;
515 		const int		vec4Align			= (int)sizeof(deUint32)*4;
516 		const int		baseAlignment		= isStd140 ? computeStd140BaseAlignment(varType, combinedFlags)
517 													   : computeStd430BaseAlignment(varType, combinedFlags);
518 		int				curOffset			= deAlign32(baseOffset, baseAlignment);
519 		const VarType&	elemType			= varType.getElementType();
520 
521 		if (elemType.isBasicType() && !glu::isDataTypeMatrix(elemType.getBasicType()))
522 		{
523 			// Array of scalars or vectors.
524 			const glu::DataType		elemBasicType	= elemType.getBasicType();
525 			const int				elemBaseAlign	= getDataTypeByteAlignment(elemBasicType);
526 			const int				stride			= isStd140 ? deAlign32(elemBaseAlign, vec4Align) : elemBaseAlign;
527 			BufferVarLayoutEntry	entry;
528 
529 			entry.name					= prefix;
530 			entry.topLevelArraySize		= 1;
531 			entry.topLevelArrayStride	= 0;
532 			entry.type					= elemBasicType;
533 			entry.blockNdx				= curBlockNdx;
534 			entry.offset				= curOffset;
535 			entry.arraySize				= topLevelArraySize;
536 			entry.arrayStride			= stride;
537 			entry.matrixStride			= 0;
538 
539 			layout.bufferVars.push_back(entry);
540 
541 			curOffset += stride*topLevelArraySize;
542 		}
543 		else if (elemType.isBasicType() && glu::isDataTypeMatrix(elemType.getBasicType()))
544 		{
545 			// Array of matrices.
546 			const glu::DataType		elemBasicType	= elemType.getBasicType();
547 			const bool				isRowMajor		= !!(combinedFlags & LAYOUT_ROW_MAJOR);
548 			const int				vecSize			= isRowMajor ? glu::getDataTypeMatrixNumColumns(elemBasicType)
549 																 : glu::getDataTypeMatrixNumRows(elemBasicType);
550 			const int				numVecs			= isRowMajor ? glu::getDataTypeMatrixNumRows(elemBasicType)
551 																 : glu::getDataTypeMatrixNumColumns(elemBasicType);
552 			const glu::DataType		vecType			= glu::getDataTypeFloatVec(vecSize);
553 			const int				vecBaseAlign	= getDataTypeByteAlignment(vecType);
554 			const int				stride			= isStd140 ? deAlign32(vecBaseAlign, vec4Align) : vecBaseAlign;
555 			BufferVarLayoutEntry	entry;
556 
557 			entry.name					= prefix;
558 			entry.topLevelArraySize		= 1;
559 			entry.topLevelArrayStride	= 0;
560 			entry.type					= elemBasicType;
561 			entry.blockNdx				= curBlockNdx;
562 			entry.offset				= curOffset;
563 			entry.arraySize				= topLevelArraySize;
564 			entry.arrayStride			= stride*numVecs;
565 			entry.matrixStride			= stride;
566 			entry.isRowMajor			= isRowMajor;
567 
568 			layout.bufferVars.push_back(entry);
569 
570 			curOffset += stride*numVecs*topLevelArraySize;
571 		}
572 		else
573 		{
574 			DE_ASSERT(elemType.isStructType() || elemType.isArrayType());
575 
576 			// Struct base alignment is not added multiple times as curOffset supplied to computeReferenceLayout
577 			// was already aligned correctly. Thus computeReferenceLayout should not add any extra padding
578 			// before struct. Padding after struct will be added as it should.
579 			//
580 			// Stride could be computed prior to creating child elements, but it would essentially require running
581 			// the layout computation twice. Instead we fix stride to child elements afterwards.
582 
583 			const int	firstChildNdx	= (int)layout.bufferVars.size();
584 			const int	stride			= computeReferenceLayout(layout, curBlockNdx, curOffset, prefix, varType.getElementType(), combinedFlags);
585 
586 			for (int childNdx = firstChildNdx; childNdx < (int)layout.bufferVars.size(); childNdx++)
587 			{
588 				layout.bufferVars[childNdx].topLevelArraySize	= topLevelArraySize;
589 				layout.bufferVars[childNdx].topLevelArrayStride	= stride;
590 			}
591 
592 			curOffset += stride*topLevelArraySize;
593 		}
594 
595 		return curOffset-baseOffset;
596 	}
597 	else
598 		return computeReferenceLayout(layout, curBlockNdx, baseOffset, blockPrefix + bufVar.getName(), varType, combinedFlags);
599 }
600 
computeReferenceLayout(BufferLayout & layout,const ShaderInterface & interface)601 void computeReferenceLayout (BufferLayout& layout, const ShaderInterface& interface)
602 {
603 	int numBlocks = interface.getNumBlocks();
604 
605 	for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
606 	{
607 		const BufferBlock&	block			= interface.getBlock(blockNdx);
608 		bool				hasInstanceName	= block.getInstanceName() != DE_NULL;
609 		std::string			blockPrefix		= hasInstanceName ? (std::string(block.getBlockName()) + ".") : std::string("");
610 		int					curOffset		= 0;
611 		int					activeBlockNdx	= (int)layout.blocks.size();
612 		int					firstVarNdx		= (int)layout.bufferVars.size();
613 
614 		for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++)
615 		{
616 			const BufferVar& bufVar = *varIter;
617 			curOffset += computeReferenceLayout(layout, activeBlockNdx,  blockPrefix, curOffset, bufVar, block.getFlags());
618 		}
619 
620 		int	varIndicesEnd	= (int)layout.bufferVars.size();
621 		int	blockSize		= curOffset;
622 		int	numInstances	= block.isArray() ? block.getArraySize() : 1;
623 
624 		// Create block layout entries for each instance.
625 		for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
626 		{
627 			// Allocate entry for instance.
628 			layout.blocks.push_back(BlockLayoutEntry());
629 			BlockLayoutEntry& blockEntry = layout.blocks.back();
630 
631 			blockEntry.name = block.getBlockName();
632 			blockEntry.size = blockSize;
633 
634 			// Compute active variable set for block.
635 			for (int varNdx = firstVarNdx; varNdx < varIndicesEnd; varNdx++)
636 				blockEntry.activeVarIndices.push_back(varNdx);
637 
638 			if (block.isArray())
639 				blockEntry.name += "[" + de::toString(instanceNdx) + "]";
640 		}
641 	}
642 }
643 
644 // Value generator.
645 
generateValue(const BufferVarLayoutEntry & entry,int unsizedArraySize,void * basePtr,de::Random & rnd)646 void generateValue (const BufferVarLayoutEntry& entry, int unsizedArraySize, void* basePtr, de::Random& rnd)
647 {
648 	const glu::DataType	scalarType		= glu::getDataTypeScalarType(entry.type);
649 	const int			scalarSize		= glu::getDataTypeScalarSize(entry.type);
650 	const int			arraySize		= entry.arraySize == 0 ? unsizedArraySize : entry.arraySize;
651 	const int			arrayStride		= entry.arrayStride;
652 	const int			topLevelSize	= entry.topLevelArraySize == 0 ? unsizedArraySize : entry.topLevelArraySize;
653 	const int			topLevelStride	= entry.topLevelArrayStride;
654 	const bool			isMatrix		= glu::isDataTypeMatrix(entry.type);
655 	const int			numVecs			= isMatrix ? (entry.isRowMajor ? glu::getDataTypeMatrixNumRows(entry.type) : glu::getDataTypeMatrixNumColumns(entry.type)) : 1;
656 	const int			vecSize			= scalarSize / numVecs;
657 	const int			compSize		= sizeof(deUint32);
658 
659 	DE_ASSERT(scalarSize%numVecs == 0);
660 	DE_ASSERT(topLevelSize >= 0);
661 	DE_ASSERT(arraySize >= 0);
662 
663 	for (int topElemNdx = 0; topElemNdx < topLevelSize; topElemNdx++)
664 	{
665 		deUint8* const topElemPtr = (deUint8*)basePtr + entry.offset + topElemNdx*topLevelStride;
666 
667 		for (int elemNdx = 0; elemNdx < arraySize; elemNdx++)
668 		{
669 			deUint8* const elemPtr = topElemPtr + elemNdx*arrayStride;
670 
671 			for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
672 			{
673 				deUint8* const vecPtr = elemPtr + (isMatrix ? vecNdx*entry.matrixStride : 0);
674 
675 				for (int compNdx = 0; compNdx < vecSize; compNdx++)
676 				{
677 					deUint8* const compPtr = vecPtr + compSize*compNdx;
678 
679 					switch (scalarType)
680 					{
681 						case glu::TYPE_FLOAT:	*((float*)compPtr)		= (float)rnd.getInt(-9, 9);						break;
682 						case glu::TYPE_INT:		*((int*)compPtr)		= rnd.getInt(-9, 9);							break;
683 						case glu::TYPE_UINT:	*((deUint32*)compPtr)	= (deUint32)rnd.getInt(0, 9);					break;
684 						// \note Random bit pattern is used for true values. Spec states that all non-zero values are
685 						//       interpreted as true but some implementations fail this.
686 						case glu::TYPE_BOOL:	*((deUint32*)compPtr)	= rnd.getBool() ? rnd.getUint32()|1u : 0u;		break;
687 						default:
688 							DE_ASSERT(false);
689 					}
690 				}
691 			}
692 		}
693 	}
694 }
695 
generateValues(const BufferLayout & layout,const vector<BlockDataPtr> & blockPointers,deUint32 seed)696 void generateValues (const BufferLayout& layout, const vector<BlockDataPtr>& blockPointers, deUint32 seed)
697 {
698 	de::Random	rnd			(seed);
699 	const int	numBlocks	= (int)layout.blocks.size();
700 
701 	DE_ASSERT(numBlocks == (int)blockPointers.size());
702 
703 	for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
704 	{
705 		const BlockLayoutEntry&	blockLayout	= layout.blocks[blockNdx];
706 		const BlockDataPtr&		blockPtr	= blockPointers[blockNdx];
707 		const int				numEntries	= (int)layout.blocks[blockNdx].activeVarIndices.size();
708 
709 		for (int entryNdx = 0; entryNdx < numEntries; entryNdx++)
710 		{
711 			const int					varNdx		= blockLayout.activeVarIndices[entryNdx];
712 			const BufferVarLayoutEntry&	varEntry	= layout.bufferVars[varNdx];
713 
714 			generateValue(varEntry, blockPtr.lastUnsizedArraySize, blockPtr.ptr, rnd);
715 		}
716 	}
717 }
718 
719 // Shader generator.
720 
getCompareFuncForType(glu::DataType type)721 const char* getCompareFuncForType (glu::DataType type)
722 {
723 	switch (type)
724 	{
725 		case glu::TYPE_FLOAT:			return "bool compare_float    (highp float a, highp float b)  { return abs(a - b) < 0.05; }\n";
726 		case glu::TYPE_FLOAT_VEC2:		return "bool compare_vec2     (highp vec2 a, highp vec2 b)    { return compare_float(a.x, b.x)&&compare_float(a.y, b.y); }\n";
727 		case glu::TYPE_FLOAT_VEC3:		return "bool compare_vec3     (highp vec3 a, highp vec3 b)    { return compare_float(a.x, b.x)&&compare_float(a.y, b.y)&&compare_float(a.z, b.z); }\n";
728 		case glu::TYPE_FLOAT_VEC4:		return "bool compare_vec4     (highp vec4 a, highp vec4 b)    { return compare_float(a.x, b.x)&&compare_float(a.y, b.y)&&compare_float(a.z, b.z)&&compare_float(a.w, b.w); }\n";
729 		case glu::TYPE_FLOAT_MAT2:		return "bool compare_mat2     (highp mat2 a, highp mat2 b)    { return compare_vec2(a[0], b[0])&&compare_vec2(a[1], b[1]); }\n";
730 		case glu::TYPE_FLOAT_MAT2X3:	return "bool compare_mat2x3   (highp mat2x3 a, highp mat2x3 b){ return compare_vec3(a[0], b[0])&&compare_vec3(a[1], b[1]); }\n";
731 		case glu::TYPE_FLOAT_MAT2X4:	return "bool compare_mat2x4   (highp mat2x4 a, highp mat2x4 b){ return compare_vec4(a[0], b[0])&&compare_vec4(a[1], b[1]); }\n";
732 		case glu::TYPE_FLOAT_MAT3X2:	return "bool compare_mat3x2   (highp mat3x2 a, highp mat3x2 b){ return compare_vec2(a[0], b[0])&&compare_vec2(a[1], b[1])&&compare_vec2(a[2], b[2]); }\n";
733 		case glu::TYPE_FLOAT_MAT3:		return "bool compare_mat3     (highp mat3 a, highp mat3 b)    { return compare_vec3(a[0], b[0])&&compare_vec3(a[1], b[1])&&compare_vec3(a[2], b[2]); }\n";
734 		case glu::TYPE_FLOAT_MAT3X4:	return "bool compare_mat3x4   (highp mat3x4 a, highp mat3x4 b){ return compare_vec4(a[0], b[0])&&compare_vec4(a[1], b[1])&&compare_vec4(a[2], b[2]); }\n";
735 		case glu::TYPE_FLOAT_MAT4X2:	return "bool compare_mat4x2   (highp mat4x2 a, highp mat4x2 b){ return compare_vec2(a[0], b[0])&&compare_vec2(a[1], b[1])&&compare_vec2(a[2], b[2])&&compare_vec2(a[3], b[3]); }\n";
736 		case glu::TYPE_FLOAT_MAT4X3:	return "bool compare_mat4x3   (highp mat4x3 a, highp mat4x3 b){ return compare_vec3(a[0], b[0])&&compare_vec3(a[1], b[1])&&compare_vec3(a[2], b[2])&&compare_vec3(a[3], b[3]); }\n";
737 		case glu::TYPE_FLOAT_MAT4:		return "bool compare_mat4     (highp mat4 a, highp mat4 b)    { return compare_vec4(a[0], b[0])&&compare_vec4(a[1], b[1])&&compare_vec4(a[2], b[2])&&compare_vec4(a[3], b[3]); }\n";
738 		case glu::TYPE_INT:				return "bool compare_int      (highp int a, highp int b)      { return a == b; }\n";
739 		case glu::TYPE_INT_VEC2:		return "bool compare_ivec2    (highp ivec2 a, highp ivec2 b)  { return a == b; }\n";
740 		case glu::TYPE_INT_VEC3:		return "bool compare_ivec3    (highp ivec3 a, highp ivec3 b)  { return a == b; }\n";
741 		case glu::TYPE_INT_VEC4:		return "bool compare_ivec4    (highp ivec4 a, highp ivec4 b)  { return a == b; }\n";
742 		case glu::TYPE_UINT:			return "bool compare_uint     (highp uint a, highp uint b)    { return a == b; }\n";
743 		case glu::TYPE_UINT_VEC2:		return "bool compare_uvec2    (highp uvec2 a, highp uvec2 b)  { return a == b; }\n";
744 		case glu::TYPE_UINT_VEC3:		return "bool compare_uvec3    (highp uvec3 a, highp uvec3 b)  { return a == b; }\n";
745 		case glu::TYPE_UINT_VEC4:		return "bool compare_uvec4    (highp uvec4 a, highp uvec4 b)  { return a == b; }\n";
746 		case glu::TYPE_BOOL:			return "bool compare_bool     (bool a, bool b)                { return a == b; }\n";
747 		case glu::TYPE_BOOL_VEC2:		return "bool compare_bvec2    (bvec2 a, bvec2 b)              { return a == b; }\n";
748 		case glu::TYPE_BOOL_VEC3:		return "bool compare_bvec3    (bvec3 a, bvec3 b)              { return a == b; }\n";
749 		case glu::TYPE_BOOL_VEC4:		return "bool compare_bvec4    (bvec4 a, bvec4 b)              { return a == b; }\n";
750 		default:
751 			DE_ASSERT(false);
752 			return DE_NULL;
753 	}
754 }
755 
getCompareDependencies(std::set<glu::DataType> & compareFuncs,glu::DataType basicType)756 void getCompareDependencies (std::set<glu::DataType>& compareFuncs, glu::DataType basicType)
757 {
758 	switch (basicType)
759 	{
760 		case glu::TYPE_FLOAT_VEC2:
761 		case glu::TYPE_FLOAT_VEC3:
762 		case glu::TYPE_FLOAT_VEC4:
763 			compareFuncs.insert(glu::TYPE_FLOAT);
764 			compareFuncs.insert(basicType);
765 			break;
766 
767 		case glu::TYPE_FLOAT_MAT2:
768 		case glu::TYPE_FLOAT_MAT2X3:
769 		case glu::TYPE_FLOAT_MAT2X4:
770 		case glu::TYPE_FLOAT_MAT3X2:
771 		case glu::TYPE_FLOAT_MAT3:
772 		case glu::TYPE_FLOAT_MAT3X4:
773 		case glu::TYPE_FLOAT_MAT4X2:
774 		case glu::TYPE_FLOAT_MAT4X3:
775 		case glu::TYPE_FLOAT_MAT4:
776 			compareFuncs.insert(glu::TYPE_FLOAT);
777 			compareFuncs.insert(glu::getDataTypeFloatVec(glu::getDataTypeMatrixNumRows(basicType)));
778 			compareFuncs.insert(basicType);
779 			break;
780 
781 		default:
782 			compareFuncs.insert(basicType);
783 			break;
784 	}
785 }
786 
collectUniqueBasicTypes(std::set<glu::DataType> & basicTypes,const VarType & type)787 void collectUniqueBasicTypes (std::set<glu::DataType>& basicTypes, const VarType& type)
788 {
789 	if (type.isStructType())
790 	{
791 		for (StructType::ConstIterator iter = type.getStructPtr()->begin(); iter != type.getStructPtr()->end(); ++iter)
792 			collectUniqueBasicTypes(basicTypes, iter->getType());
793 	}
794 	else if (type.isArrayType())
795 		collectUniqueBasicTypes(basicTypes, type.getElementType());
796 	else
797 	{
798 		DE_ASSERT(type.isBasicType());
799 		basicTypes.insert(type.getBasicType());
800 	}
801 }
802 
collectUniqueBasicTypes(std::set<glu::DataType> & basicTypes,const BufferBlock & bufferBlock)803 void collectUniqueBasicTypes (std::set<glu::DataType>& basicTypes, const BufferBlock& bufferBlock)
804 {
805 	for (BufferBlock::const_iterator iter = bufferBlock.begin(); iter != bufferBlock.end(); ++iter)
806 		collectUniqueBasicTypes(basicTypes, iter->getType());
807 }
808 
collectUniqueBasicTypes(std::set<glu::DataType> & basicTypes,const ShaderInterface & interface)809 void collectUniqueBasicTypes (std::set<glu::DataType>& basicTypes, const ShaderInterface& interface)
810 {
811 	for (int ndx = 0; ndx < interface.getNumBlocks(); ++ndx)
812 		collectUniqueBasicTypes(basicTypes, interface.getBlock(ndx));
813 }
814 
generateCompareFuncs(std::ostream & str,const ShaderInterface & interface)815 void generateCompareFuncs (std::ostream& str, const ShaderInterface& interface)
816 {
817 	std::set<glu::DataType> types;
818 	std::set<glu::DataType> compareFuncs;
819 
820 	// Collect unique basic types
821 	collectUniqueBasicTypes(types, interface);
822 
823 	// Set of compare functions required
824 	for (std::set<glu::DataType>::const_iterator iter = types.begin(); iter != types.end(); ++iter)
825 	{
826 		getCompareDependencies(compareFuncs, *iter);
827 	}
828 
829 	for (int type = 0; type < glu::TYPE_LAST; ++type)
830 	{
831 		if (compareFuncs.find(glu::DataType(type)) != compareFuncs.end())
832 			str << getCompareFuncForType(glu::DataType(type));
833 	}
834 }
835 
836 struct Indent
837 {
838 	int level;
Indentvkt::ssbo::__anonfd4a4c8c0211::Indent839 	Indent (int level_) : level(level_) {}
840 };
841 
operator <<(std::ostream & str,const Indent & indent)842 std::ostream& operator<< (std::ostream& str, const Indent& indent)
843 {
844 	for (int i = 0; i < indent.level; i++)
845 		str << "\t";
846 	return str;
847 }
848 
generateDeclaration(std::ostream & src,const BufferVar & bufferVar,int indentLevel)849 void generateDeclaration (std::ostream& src, const BufferVar& bufferVar, int indentLevel)
850 {
851 	// \todo [pyry] Qualifiers
852 
853 	if ((bufferVar.getFlags() & LAYOUT_MASK) != 0)
854 		src << "layout(" << LayoutFlagsFmt(bufferVar.getFlags() & LAYOUT_MASK) << ") ";
855 
856 	src << glu::declare(bufferVar.getType(), bufferVar.getName(), indentLevel);
857 }
858 
generateDeclaration(std::ostream & src,const BufferBlock & block,int bindingPoint)859 void generateDeclaration (std::ostream& src, const BufferBlock& block, int bindingPoint)
860 {
861 	src << "layout(";
862 
863 	if ((block.getFlags() & LAYOUT_MASK) != 0)
864 		src << LayoutFlagsFmt(block.getFlags() & LAYOUT_MASK) << ", ";
865 
866 	src << "binding = " << bindingPoint;
867 
868 	src << ") ";
869 
870 	src << "buffer " << block.getBlockName();
871 	src << "\n{\n";
872 
873 	for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++)
874 	{
875 		src << Indent(1);
876 		generateDeclaration(src, *varIter, 1 /* indent level */);
877 		src << ";\n";
878 	}
879 
880 	src << "}";
881 
882 	if (block.getInstanceName() != DE_NULL)
883 	{
884 		src << " " << block.getInstanceName();
885 		if (block.isArray())
886 			src << "[" << block.getArraySize() << "]";
887 	}
888 	else
889 		DE_ASSERT(!block.isArray());
890 
891 	src << ";\n";
892 }
893 
generateImmMatrixSrc(std::ostream & src,glu::DataType basicType,int matrixStride,bool isRowMajor,const void * valuePtr)894 void generateImmMatrixSrc (std::ostream& src, glu::DataType basicType, int matrixStride, bool isRowMajor, const void* valuePtr)
895 {
896 	DE_ASSERT(glu::isDataTypeMatrix(basicType));
897 
898 	const int		compSize		= sizeof(deUint32);
899 	const int		numRows			= glu::getDataTypeMatrixNumRows(basicType);
900 	const int		numCols			= glu::getDataTypeMatrixNumColumns(basicType);
901 
902 	src << glu::getDataTypeName(basicType) << "(";
903 
904 	// Constructed in column-wise order.
905 	for (int colNdx = 0; colNdx < numCols; colNdx++)
906 	{
907 		for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
908 		{
909 			const deUint8*	compPtr	= (const deUint8*)valuePtr + (isRowMajor ? rowNdx*matrixStride + colNdx*compSize
910 																				: colNdx*matrixStride + rowNdx*compSize);
911 
912 			if (colNdx > 0 || rowNdx > 0)
913 				src << ", ";
914 
915 			src << de::floatToString(*((const float*)compPtr), 1);
916 		}
917 	}
918 
919 	src << ")";
920 }
921 
generateImmScalarVectorSrc(std::ostream & src,glu::DataType basicType,const void * valuePtr)922 void generateImmScalarVectorSrc (std::ostream& src, glu::DataType basicType, const void* valuePtr)
923 {
924 	DE_ASSERT(glu::isDataTypeFloatOrVec(basicType)	||
925 			  glu::isDataTypeIntOrIVec(basicType)	||
926 			  glu::isDataTypeUintOrUVec(basicType)	||
927 			  glu::isDataTypeBoolOrBVec(basicType));
928 
929 	const glu::DataType		scalarType		= glu::getDataTypeScalarType(basicType);
930 	const int				scalarSize		= glu::getDataTypeScalarSize(basicType);
931 	const int				compSize		= sizeof(deUint32);
932 
933 	if (scalarSize > 1)
934 		src << glu::getDataTypeName(basicType) << "(";
935 
936 	for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
937 	{
938 		const deUint8* compPtr = (const deUint8*)valuePtr + scalarNdx*compSize;
939 
940 		if (scalarNdx > 0)
941 			src << ", ";
942 
943 		switch (scalarType)
944 		{
945 			case glu::TYPE_FLOAT:	src << de::floatToString(*((const float*)compPtr), 1);			break;
946 			case glu::TYPE_INT:		src << *((const int*)compPtr);									break;
947 			case glu::TYPE_UINT:	src << *((const deUint32*)compPtr) << "u";						break;
948 			case glu::TYPE_BOOL:	src << (*((const deUint32*)compPtr) != 0u ? "true" : "false");	break;
949 			default:
950 				DE_ASSERT(false);
951 		}
952 	}
953 
954 	if (scalarSize > 1)
955 		src << ")";
956 }
957 
getAPIName(const BufferBlock & block,const BufferVar & var,const glu::TypeComponentVector & accessPath)958 string getAPIName (const BufferBlock& block, const BufferVar& var, const glu::TypeComponentVector& accessPath)
959 {
960 	std::ostringstream name;
961 
962 	if (block.getInstanceName())
963 		name << block.getBlockName() << ".";
964 
965 	name << var.getName();
966 
967 	for (glu::TypeComponentVector::const_iterator pathComp = accessPath.begin(); pathComp != accessPath.end(); pathComp++)
968 	{
969 		if (pathComp->type == glu::VarTypeComponent::STRUCT_MEMBER)
970 		{
971 			const VarType		curType		= glu::getVarType(var.getType(), accessPath.begin(), pathComp);
972 			const StructType*	structPtr	= curType.getStructPtr();
973 
974 			name << "." << structPtr->getMember(pathComp->index).getName();
975 		}
976 		else if (pathComp->type == glu::VarTypeComponent::ARRAY_ELEMENT)
977 		{
978 			if (pathComp == accessPath.begin() || (pathComp+1) == accessPath.end())
979 				name << "[0]"; // Top- / bottom-level array
980 			else
981 				name << "[" << pathComp->index << "]";
982 		}
983 		else
984 			DE_ASSERT(false);
985 	}
986 
987 	return name.str();
988 }
989 
getShaderName(const BufferBlock & block,int instanceNdx,const BufferVar & var,const glu::TypeComponentVector & accessPath)990 string getShaderName (const BufferBlock& block, int instanceNdx, const BufferVar& var, const glu::TypeComponentVector& accessPath)
991 {
992 	std::ostringstream name;
993 
994 	if (block.getInstanceName())
995 	{
996 		name << block.getInstanceName();
997 
998 		if (block.isArray())
999 			name << "[" << instanceNdx << "]";
1000 
1001 		name << ".";
1002 	}
1003 	else
1004 		DE_ASSERT(instanceNdx == 0);
1005 
1006 	name << var.getName();
1007 
1008 	for (glu::TypeComponentVector::const_iterator pathComp = accessPath.begin(); pathComp != accessPath.end(); pathComp++)
1009 	{
1010 		if (pathComp->type == glu::VarTypeComponent::STRUCT_MEMBER)
1011 		{
1012 			const VarType		curType		= glu::getVarType(var.getType(), accessPath.begin(), pathComp);
1013 			const StructType*	structPtr	= curType.getStructPtr();
1014 
1015 			name << "." << structPtr->getMember(pathComp->index).getName();
1016 		}
1017 		else if (pathComp->type == glu::VarTypeComponent::ARRAY_ELEMENT)
1018 			name << "[" << pathComp->index << "]";
1019 		else
1020 			DE_ASSERT(false);
1021 	}
1022 
1023 	return name.str();
1024 }
1025 
computeOffset(const BufferVarLayoutEntry & varLayout,const glu::TypeComponentVector & accessPath)1026 int computeOffset (const BufferVarLayoutEntry& varLayout, const glu::TypeComponentVector& accessPath)
1027 {
1028 	const int	topLevelNdx		= (accessPath.size() > 1 && accessPath.front().type == glu::VarTypeComponent::ARRAY_ELEMENT) ? accessPath.front().index : 0;
1029 	const int	bottomLevelNdx	= (!accessPath.empty() && accessPath.back().type == glu::VarTypeComponent::ARRAY_ELEMENT) ? accessPath.back().index : 0;
1030 
1031 	return varLayout.offset + varLayout.topLevelArrayStride*topLevelNdx + varLayout.arrayStride*bottomLevelNdx;
1032 }
1033 
generateCompareSrc(std::ostream & src,const char * resultVar,const BufferLayout & bufferLayout,const BufferBlock & block,int instanceNdx,const BlockDataPtr & blockPtr,const BufferVar & bufVar,const glu::SubTypeAccess & accessPath)1034 void generateCompareSrc (
1035 	std::ostream&				src,
1036 	const char*					resultVar,
1037 	const BufferLayout&			bufferLayout,
1038 	const BufferBlock&			block,
1039 	int							instanceNdx,
1040 	const BlockDataPtr&			blockPtr,
1041 	const BufferVar&			bufVar,
1042 	const glu::SubTypeAccess&	accessPath)
1043 {
1044 	const VarType curType = accessPath.getType();
1045 
1046 	if (curType.isArrayType())
1047 	{
1048 		const int arraySize = curType.getArraySize() == VarType::UNSIZED_ARRAY ? block.getLastUnsizedArraySize(instanceNdx) : curType.getArraySize();
1049 
1050 		for (int elemNdx = 0; elemNdx < arraySize; elemNdx++)
1051 			generateCompareSrc(src, resultVar, bufferLayout, block, instanceNdx, blockPtr, bufVar, accessPath.element(elemNdx));
1052 	}
1053 	else if (curType.isStructType())
1054 	{
1055 		const int numMembers = curType.getStructPtr()->getNumMembers();
1056 
1057 		for (int memberNdx = 0; memberNdx < numMembers; memberNdx++)
1058 			generateCompareSrc(src, resultVar, bufferLayout, block, instanceNdx, blockPtr, bufVar, accessPath.member(memberNdx));
1059 	}
1060 	else
1061 	{
1062 		DE_ASSERT(curType.isBasicType());
1063 
1064 		const string	apiName	= getAPIName(block, bufVar, accessPath.getPath());
1065 		const int		varNdx	= bufferLayout.getVariableIndex(apiName);
1066 
1067 		DE_ASSERT(varNdx >= 0);
1068 		{
1069 			const BufferVarLayoutEntry&	varLayout		= bufferLayout.bufferVars[varNdx];
1070 			const string				shaderName		= getShaderName(block, instanceNdx, bufVar, accessPath.getPath());
1071 			const glu::DataType			basicType		= curType.getBasicType();
1072 			const bool					isMatrix		= glu::isDataTypeMatrix(basicType);
1073 			const char*					typeName		= glu::getDataTypeName(basicType);
1074 			const void*					valuePtr		= (const deUint8*)blockPtr.ptr + computeOffset(varLayout, accessPath.getPath());
1075 
1076 			src << "\t" << resultVar << " = " << resultVar << " && compare_" << typeName << "(" << shaderName << ", ";
1077 
1078 			if (isMatrix)
1079 				generateImmMatrixSrc(src, basicType, varLayout.matrixStride, varLayout.isRowMajor, valuePtr);
1080 			else
1081 				generateImmScalarVectorSrc(src, basicType, valuePtr);
1082 
1083 			src << ");\n";
1084 		}
1085 	}
1086 }
1087 
generateCompareSrc(std::ostream & src,const char * resultVar,const ShaderInterface & interface,const BufferLayout & layout,const vector<BlockDataPtr> & blockPointers)1088 void generateCompareSrc (std::ostream& src, const char* resultVar, const ShaderInterface& interface, const BufferLayout& layout, const vector<BlockDataPtr>& blockPointers)
1089 {
1090 	for (int declNdx = 0; declNdx < interface.getNumBlocks(); declNdx++)
1091 	{
1092 		const BufferBlock&	block			= interface.getBlock(declNdx);
1093 		const bool			isArray			= block.isArray();
1094 		const int			numInstances	= isArray ? block.getArraySize() : 1;
1095 
1096 		DE_ASSERT(!isArray || block.getInstanceName());
1097 
1098 		for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1099 		{
1100 			const string		instanceName	= block.getBlockName() + (isArray ? "[" + de::toString(instanceNdx) + "]" : string(""));
1101 			const int			blockNdx		= layout.getBlockIndex(instanceName);
1102 			const BlockDataPtr&	blockPtr		= blockPointers[blockNdx];
1103 
1104 			for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++)
1105 			{
1106 				const BufferVar& bufVar = *varIter;
1107 
1108 				if ((bufVar.getFlags() & ACCESS_READ) == 0)
1109 					continue; // Don't read from that variable.
1110 
1111 				generateCompareSrc(src, resultVar, layout, block, instanceNdx, blockPtr, bufVar, glu::SubTypeAccess(bufVar.getType()));
1112 			}
1113 		}
1114 	}
1115 }
1116 
1117 // \todo [2013-10-14 pyry] Almost identical to generateCompareSrc - unify?
1118 
generateWriteSrc(std::ostream & src,const BufferLayout & bufferLayout,const BufferBlock & block,int instanceNdx,const BlockDataPtr & blockPtr,const BufferVar & bufVar,const glu::SubTypeAccess & accessPath)1119 void generateWriteSrc (
1120 	std::ostream&				src,
1121 	const BufferLayout&			bufferLayout,
1122 	const BufferBlock&			block,
1123 	int							instanceNdx,
1124 	const BlockDataPtr&			blockPtr,
1125 	const BufferVar&			bufVar,
1126 	const glu::SubTypeAccess&	accessPath)
1127 {
1128 	const VarType curType = accessPath.getType();
1129 
1130 	if (curType.isArrayType())
1131 	{
1132 		const int arraySize = curType.getArraySize() == VarType::UNSIZED_ARRAY ? block.getLastUnsizedArraySize(instanceNdx) : curType.getArraySize();
1133 
1134 		for (int elemNdx = 0; elemNdx < arraySize; elemNdx++)
1135 			generateWriteSrc(src, bufferLayout, block, instanceNdx, blockPtr, bufVar, accessPath.element(elemNdx));
1136 	}
1137 	else if (curType.isStructType())
1138 	{
1139 		const int numMembers = curType.getStructPtr()->getNumMembers();
1140 
1141 		for (int memberNdx = 0; memberNdx < numMembers; memberNdx++)
1142 			generateWriteSrc(src, bufferLayout, block, instanceNdx, blockPtr, bufVar, accessPath.member(memberNdx));
1143 	}
1144 	else
1145 	{
1146 		DE_ASSERT(curType.isBasicType());
1147 
1148 		const string	apiName	= getAPIName(block, bufVar, accessPath.getPath());
1149 		const int		varNdx	= bufferLayout.getVariableIndex(apiName);
1150 
1151 		DE_ASSERT(varNdx >= 0);
1152 		{
1153 			const BufferVarLayoutEntry&	varLayout		= bufferLayout.bufferVars[varNdx];
1154 			const string				shaderName		= getShaderName(block, instanceNdx, bufVar, accessPath.getPath());
1155 			const glu::DataType			basicType		= curType.getBasicType();
1156 			const bool					isMatrix		= glu::isDataTypeMatrix(basicType);
1157 			const void*					valuePtr		= (const deUint8*)blockPtr.ptr + computeOffset(varLayout, accessPath.getPath());
1158 
1159 			src << "\t" << shaderName << " = ";
1160 
1161 			if (isMatrix)
1162 				generateImmMatrixSrc(src, basicType, varLayout.matrixStride, varLayout.isRowMajor, valuePtr);
1163 			else
1164 				generateImmScalarVectorSrc(src, basicType, valuePtr);
1165 
1166 			src << ";\n";
1167 		}
1168 	}
1169 }
1170 
generateWriteSrc(std::ostream & src,const ShaderInterface & interface,const BufferLayout & layout,const vector<BlockDataPtr> & blockPointers)1171 void generateWriteSrc (std::ostream& src, const ShaderInterface& interface, const BufferLayout& layout, const vector<BlockDataPtr>& blockPointers)
1172 {
1173 	for (int declNdx = 0; declNdx < interface.getNumBlocks(); declNdx++)
1174 	{
1175 		const BufferBlock&	block			= interface.getBlock(declNdx);
1176 		const bool			isArray			= block.isArray();
1177 		const int			numInstances	= isArray ? block.getArraySize() : 1;
1178 
1179 		DE_ASSERT(!isArray || block.getInstanceName());
1180 
1181 		for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1182 		{
1183 			const string		instanceName	= block.getBlockName() + (isArray ? "[" + de::toString(instanceNdx) + "]" : string(""));
1184 			const int			blockNdx		= layout.getBlockIndex(instanceName);
1185 			const BlockDataPtr&	blockPtr		= blockPointers[blockNdx];
1186 
1187 			for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++)
1188 			{
1189 				const BufferVar& bufVar = *varIter;
1190 
1191 				if ((bufVar.getFlags() & ACCESS_WRITE) == 0)
1192 					continue; // Don't write to that variable.
1193 
1194 				generateWriteSrc(src, layout, block, instanceNdx, blockPtr, bufVar, glu::SubTypeAccess(bufVar.getType()));
1195 			}
1196 		}
1197 	}
1198 }
1199 
generateComputeShader(const ShaderInterface & interface,const BufferLayout & layout,const vector<BlockDataPtr> & comparePtrs,const vector<BlockDataPtr> & writePtrs)1200 string generateComputeShader (const ShaderInterface& interface, const BufferLayout& layout, const vector<BlockDataPtr>& comparePtrs, const vector<BlockDataPtr>& writePtrs)
1201 {
1202 	std::ostringstream src;
1203 
1204 	src << "#version 310 es\n";
1205 	src << "layout(local_size_x = 1) in;\n";
1206 	src << "\n";
1207 
1208 	// Atomic counter for counting passed invocations.
1209 	src << "layout(std140, binding = 0) buffer AcBlock { highp uint ac_numPassed; };\n\n";
1210 
1211 	std::vector<const StructType*> namedStructs;
1212 	interface.getNamedStructs(namedStructs);
1213 	for (std::vector<const StructType*>::const_iterator structIter = namedStructs.begin(); structIter != namedStructs.end(); structIter++)
1214 		src << glu::declare(*structIter) << ";\n";
1215 
1216 	{
1217 		for (int blockNdx = 0; blockNdx < interface.getNumBlocks(); blockNdx++)
1218 		{
1219 			const BufferBlock& block = interface.getBlock(blockNdx);
1220 			generateDeclaration(src, block, 1 + blockNdx);
1221 		}
1222 	}
1223 
1224 	// Comparison utilities.
1225 	src << "\n";
1226 	generateCompareFuncs(src, interface);
1227 
1228 	src << "\n"
1229 		   "void main (void)\n"
1230 		   "{\n"
1231 		   "	bool allOk = true;\n";
1232 
1233 	// Value compare.
1234 	generateCompareSrc(src, "allOk", interface, layout, comparePtrs);
1235 
1236 	src << "	if (allOk)\n"
1237 		<< "		ac_numPassed++;\n"
1238 		<< "\n";
1239 
1240 	// Value write.
1241 	generateWriteSrc(src, interface, layout, writePtrs);
1242 
1243 	src << "}\n";
1244 
1245 	return src.str();
1246 }
1247 
copyBufferVarData(const BufferVarLayoutEntry & dstEntry,const BlockDataPtr & dstBlockPtr,const BufferVarLayoutEntry & srcEntry,const BlockDataPtr & srcBlockPtr)1248 void copyBufferVarData (const BufferVarLayoutEntry& dstEntry, const BlockDataPtr& dstBlockPtr, const BufferVarLayoutEntry& srcEntry, const BlockDataPtr& srcBlockPtr)
1249 {
1250 	DE_ASSERT(dstEntry.arraySize <= srcEntry.arraySize);
1251 	DE_ASSERT(dstEntry.topLevelArraySize <= srcEntry.topLevelArraySize);
1252 	DE_ASSERT(dstBlockPtr.lastUnsizedArraySize <= srcBlockPtr.lastUnsizedArraySize);
1253 	DE_ASSERT(dstEntry.type == srcEntry.type);
1254 
1255 	deUint8* const			dstBasePtr			= (deUint8*)dstBlockPtr.ptr + dstEntry.offset;
1256 	const deUint8* const	srcBasePtr			= (const deUint8*)srcBlockPtr.ptr + srcEntry.offset;
1257 	const int				scalarSize			= glu::getDataTypeScalarSize(dstEntry.type);
1258 	const bool				isMatrix			= glu::isDataTypeMatrix(dstEntry.type);
1259 	const int				compSize			= sizeof(deUint32);
1260 	const int				dstArraySize		= dstEntry.arraySize == 0 ? dstBlockPtr.lastUnsizedArraySize : dstEntry.arraySize;
1261 	const int				dstArrayStride		= dstEntry.arrayStride;
1262 	const int				dstTopLevelSize		= dstEntry.topLevelArraySize == 0 ? dstBlockPtr.lastUnsizedArraySize : dstEntry.topLevelArraySize;
1263 	const int				dstTopLevelStride	= dstEntry.topLevelArrayStride;
1264 	const int				srcArraySize		= srcEntry.arraySize == 0 ? srcBlockPtr.lastUnsizedArraySize : srcEntry.arraySize;
1265 	const int				srcArrayStride		= srcEntry.arrayStride;
1266 	const int				srcTopLevelSize		= srcEntry.topLevelArraySize == 0 ? srcBlockPtr.lastUnsizedArraySize : srcEntry.topLevelArraySize;
1267 	const int				srcTopLevelStride	= srcEntry.topLevelArrayStride;
1268 
1269 	DE_ASSERT(dstArraySize <= srcArraySize && dstTopLevelSize <= srcTopLevelSize);
1270 	DE_UNREF(srcArraySize && srcTopLevelSize);
1271 
1272 	for (int topElemNdx = 0; topElemNdx < dstTopLevelSize; topElemNdx++)
1273 	{
1274 		deUint8* const			dstTopPtr	= dstBasePtr + topElemNdx*dstTopLevelStride;
1275 		const deUint8* const	srcTopPtr	= srcBasePtr + topElemNdx*srcTopLevelStride;
1276 
1277 		for (int elementNdx = 0; elementNdx < dstArraySize; elementNdx++)
1278 		{
1279 			deUint8* const			dstElemPtr	= dstTopPtr + elementNdx*dstArrayStride;
1280 			const deUint8* const	srcElemPtr	= srcTopPtr + elementNdx*srcArrayStride;
1281 
1282 			if (isMatrix)
1283 			{
1284 				const int	numRows	= glu::getDataTypeMatrixNumRows(dstEntry.type);
1285 				const int	numCols	= glu::getDataTypeMatrixNumColumns(dstEntry.type);
1286 
1287 				for (int colNdx = 0; colNdx < numCols; colNdx++)
1288 				{
1289 					for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
1290 					{
1291 						deUint8*		dstCompPtr	= dstElemPtr + (dstEntry.isRowMajor ? rowNdx*dstEntry.matrixStride + colNdx*compSize
1292 																						: colNdx*dstEntry.matrixStride + rowNdx*compSize);
1293 						const deUint8*	srcCompPtr	= srcElemPtr + (srcEntry.isRowMajor ? rowNdx*srcEntry.matrixStride + colNdx*compSize
1294 																						: colNdx*srcEntry.matrixStride + rowNdx*compSize);
1295 
1296 						DE_ASSERT((deIntptr)(srcCompPtr + compSize) - (deIntptr)srcBlockPtr.ptr <= (deIntptr)srcBlockPtr.size);
1297 						DE_ASSERT((deIntptr)(dstCompPtr + compSize) - (deIntptr)dstBlockPtr.ptr <= (deIntptr)dstBlockPtr.size);
1298 						deMemcpy(dstCompPtr, srcCompPtr, compSize);
1299 					}
1300 				}
1301 			}
1302 			else
1303 			{
1304 				DE_ASSERT((deIntptr)(srcElemPtr + scalarSize*compSize) - (deIntptr)srcBlockPtr.ptr <= (deIntptr)srcBlockPtr.size);
1305 				DE_ASSERT((deIntptr)(dstElemPtr + scalarSize*compSize) - (deIntptr)dstBlockPtr.ptr <= (deIntptr)dstBlockPtr.size);
1306 				deMemcpy(dstElemPtr, srcElemPtr, scalarSize*compSize);
1307 			}
1308 		}
1309 	}
1310 }
1311 
copyData(const BufferLayout & dstLayout,const vector<BlockDataPtr> & dstBlockPointers,const BufferLayout & srcLayout,const vector<BlockDataPtr> & srcBlockPointers)1312 void copyData (const BufferLayout& dstLayout, const vector<BlockDataPtr>& dstBlockPointers, const BufferLayout& srcLayout, const vector<BlockDataPtr>& srcBlockPointers)
1313 {
1314 	// \note Src layout is used as reference in case of activeVarIndices happens to be incorrect in dstLayout blocks.
1315 	int numBlocks = (int)srcLayout.blocks.size();
1316 
1317 	for (int srcBlockNdx = 0; srcBlockNdx < numBlocks; srcBlockNdx++)
1318 	{
1319 		const BlockLayoutEntry&		srcBlock	= srcLayout.blocks[srcBlockNdx];
1320 		const BlockDataPtr&			srcBlockPtr	= srcBlockPointers[srcBlockNdx];
1321 		int							dstBlockNdx	= dstLayout.getBlockIndex(srcBlock.name.c_str());
1322 
1323 		if (dstBlockNdx >= 0)
1324 		{
1325 			DE_ASSERT(de::inBounds(dstBlockNdx, 0, (int)dstBlockPointers.size()));
1326 
1327 			const BlockDataPtr& dstBlockPtr = dstBlockPointers[dstBlockNdx];
1328 
1329 			for (vector<int>::const_iterator srcVarNdxIter = srcBlock.activeVarIndices.begin(); srcVarNdxIter != srcBlock.activeVarIndices.end(); srcVarNdxIter++)
1330 			{
1331 				const BufferVarLayoutEntry&	srcEntry	= srcLayout.bufferVars[*srcVarNdxIter];
1332 				int							dstVarNdx	= dstLayout.getVariableIndex(srcEntry.name.c_str());
1333 
1334 				if (dstVarNdx >= 0)
1335 					copyBufferVarData(dstLayout.bufferVars[dstVarNdx], dstBlockPtr, srcEntry, srcBlockPtr);
1336 			}
1337 		}
1338 	}
1339 }
1340 
copyNonWrittenData(const BufferLayout & layout,const BufferBlock & block,int instanceNdx,const BlockDataPtr & srcBlockPtr,const BlockDataPtr & dstBlockPtr,const BufferVar & bufVar,const glu::SubTypeAccess & accessPath)1341 void copyNonWrittenData (
1342 	const BufferLayout&			layout,
1343 	const BufferBlock&			block,
1344 	int							instanceNdx,
1345 	const BlockDataPtr&			srcBlockPtr,
1346 	const BlockDataPtr&			dstBlockPtr,
1347 	const BufferVar&			bufVar,
1348 	const glu::SubTypeAccess&	accessPath)
1349 {
1350 	const VarType curType = accessPath.getType();
1351 
1352 	if (curType.isArrayType())
1353 	{
1354 		const int arraySize = curType.getArraySize() == VarType::UNSIZED_ARRAY ? block.getLastUnsizedArraySize(instanceNdx) : curType.getArraySize();
1355 
1356 		for (int elemNdx = 0; elemNdx < arraySize; elemNdx++)
1357 			copyNonWrittenData(layout, block, instanceNdx, srcBlockPtr, dstBlockPtr, bufVar, accessPath.element(elemNdx));
1358 	}
1359 	else if (curType.isStructType())
1360 	{
1361 		const int numMembers = curType.getStructPtr()->getNumMembers();
1362 
1363 		for (int memberNdx = 0; memberNdx < numMembers; memberNdx++)
1364 			copyNonWrittenData(layout, block, instanceNdx, srcBlockPtr, dstBlockPtr, bufVar, accessPath.member(memberNdx));
1365 	}
1366 	else
1367 	{
1368 		DE_ASSERT(curType.isBasicType());
1369 
1370 		const string	apiName	= getAPIName(block, bufVar, accessPath.getPath());
1371 		const int		varNdx	= layout.getVariableIndex(apiName);
1372 
1373 		DE_ASSERT(varNdx >= 0);
1374 		{
1375 			const BufferVarLayoutEntry& varLayout = layout.bufferVars[varNdx];
1376 			copyBufferVarData(varLayout, dstBlockPtr, varLayout, srcBlockPtr);
1377 		}
1378 	}
1379 }
1380 
copyNonWrittenData(const ShaderInterface & interface,const BufferLayout & layout,const vector<BlockDataPtr> & srcPtrs,const vector<BlockDataPtr> & dstPtrs)1381 void copyNonWrittenData (const ShaderInterface& interface, const BufferLayout& layout, const vector<BlockDataPtr>& srcPtrs, const vector<BlockDataPtr>& dstPtrs)
1382 {
1383 	for (int declNdx = 0; declNdx < interface.getNumBlocks(); declNdx++)
1384 	{
1385 		const BufferBlock&	block			= interface.getBlock(declNdx);
1386 		const bool			isArray			= block.isArray();
1387 		const int			numInstances	= isArray ? block.getArraySize() : 1;
1388 
1389 		DE_ASSERT(!isArray || block.getInstanceName());
1390 
1391 		for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1392 		{
1393 			const string		instanceName	= block.getBlockName() + (isArray ? "[" + de::toString(instanceNdx) + "]" : string(""));
1394 			const int			blockNdx		= layout.getBlockIndex(instanceName);
1395 			const BlockDataPtr&	srcBlockPtr		= srcPtrs[blockNdx];
1396 			const BlockDataPtr&	dstBlockPtr		= dstPtrs[blockNdx];
1397 
1398 			for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++)
1399 			{
1400 				const BufferVar& bufVar = *varIter;
1401 
1402 				if (bufVar.getFlags() & ACCESS_WRITE)
1403 					continue;
1404 
1405 				copyNonWrittenData(layout, block, instanceNdx, srcBlockPtr, dstBlockPtr, bufVar, glu::SubTypeAccess(bufVar.getType()));
1406 			}
1407 		}
1408 	}
1409 }
1410 
compareComponents(glu::DataType scalarType,const void * ref,const void * res,int numComps)1411 bool compareComponents (glu::DataType scalarType, const void* ref, const void* res, int numComps)
1412 {
1413 	if (scalarType == glu::TYPE_FLOAT)
1414 	{
1415 		const float threshold = 0.05f; // Same as used in shaders - should be fine for values being used.
1416 
1417 		for (int ndx = 0; ndx < numComps; ndx++)
1418 		{
1419 			const float		refVal		= *((const float*)ref + ndx);
1420 			const float		resVal		= *((const float*)res + ndx);
1421 
1422 			if (deFloatAbs(resVal - refVal) >= threshold)
1423 				return false;
1424 		}
1425 	}
1426 	else if (scalarType == glu::TYPE_BOOL)
1427 	{
1428 		for (int ndx = 0; ndx < numComps; ndx++)
1429 		{
1430 			const deUint32	refVal		= *((const deUint32*)ref + ndx);
1431 			const deUint32	resVal		= *((const deUint32*)res + ndx);
1432 
1433 			if ((refVal != 0) != (resVal != 0))
1434 				return false;
1435 		}
1436 	}
1437 	else
1438 	{
1439 		DE_ASSERT(scalarType == glu::TYPE_INT || scalarType == glu::TYPE_UINT);
1440 
1441 		for (int ndx = 0; ndx < numComps; ndx++)
1442 		{
1443 			const deUint32	refVal		= *((const deUint32*)ref + ndx);
1444 			const deUint32	resVal		= *((const deUint32*)res + ndx);
1445 
1446 			if (refVal != resVal)
1447 				return false;
1448 		}
1449 	}
1450 
1451 	return true;
1452 }
1453 
compareBufferVarData(tcu::TestLog & log,const BufferVarLayoutEntry & refEntry,const BlockDataPtr & refBlockPtr,const BufferVarLayoutEntry & resEntry,const BlockDataPtr & resBlockPtr)1454 bool compareBufferVarData (tcu::TestLog& log, const BufferVarLayoutEntry& refEntry, const BlockDataPtr& refBlockPtr, const BufferVarLayoutEntry& resEntry, const BlockDataPtr& resBlockPtr)
1455 {
1456 	DE_ASSERT(resEntry.arraySize <= refEntry.arraySize);
1457 	DE_ASSERT(resEntry.topLevelArraySize <= refEntry.topLevelArraySize);
1458 	DE_ASSERT(resBlockPtr.lastUnsizedArraySize <= refBlockPtr.lastUnsizedArraySize);
1459 	DE_ASSERT(resEntry.type == refEntry.type);
1460 
1461 	deUint8* const			resBasePtr			= (deUint8*)resBlockPtr.ptr + resEntry.offset;
1462 	const deUint8* const	refBasePtr			= (const deUint8*)refBlockPtr.ptr + refEntry.offset;
1463 	const glu::DataType		scalarType			= glu::getDataTypeScalarType(refEntry.type);
1464 	const int				scalarSize			= glu::getDataTypeScalarSize(resEntry.type);
1465 	const bool				isMatrix			= glu::isDataTypeMatrix(resEntry.type);
1466 	const int				compSize			= sizeof(deUint32);
1467 	const int				maxPrints			= 3;
1468 	int						numFailed			= 0;
1469 
1470 	const int				resArraySize		= resEntry.arraySize == 0 ? resBlockPtr.lastUnsizedArraySize : resEntry.arraySize;
1471 	const int				resArrayStride		= resEntry.arrayStride;
1472 	const int				resTopLevelSize		= resEntry.topLevelArraySize == 0 ? resBlockPtr.lastUnsizedArraySize : resEntry.topLevelArraySize;
1473 	const int				resTopLevelStride	= resEntry.topLevelArrayStride;
1474 	const int				refArraySize		= refEntry.arraySize == 0 ? refBlockPtr.lastUnsizedArraySize : refEntry.arraySize;
1475 	const int				refArrayStride		= refEntry.arrayStride;
1476 	const int				refTopLevelSize		= refEntry.topLevelArraySize == 0 ? refBlockPtr.lastUnsizedArraySize : refEntry.topLevelArraySize;
1477 	const int				refTopLevelStride	= refEntry.topLevelArrayStride;
1478 
1479 	DE_ASSERT(resArraySize <= refArraySize && resTopLevelSize <= refTopLevelSize);
1480 	DE_UNREF(refArraySize && refTopLevelSize);
1481 
1482 	for (int topElemNdx = 0; topElemNdx < resTopLevelSize; topElemNdx++)
1483 	{
1484 		deUint8* const			resTopPtr	= resBasePtr + topElemNdx*resTopLevelStride;
1485 		const deUint8* const	refTopPtr	= refBasePtr + topElemNdx*refTopLevelStride;
1486 
1487 		for (int elementNdx = 0; elementNdx < resArraySize; elementNdx++)
1488 		{
1489 			deUint8* const			resElemPtr	= resTopPtr + elementNdx*resArrayStride;
1490 			const deUint8* const	refElemPtr	= refTopPtr + elementNdx*refArrayStride;
1491 
1492 			if (isMatrix)
1493 			{
1494 				const int	numRows	= glu::getDataTypeMatrixNumRows(resEntry.type);
1495 				const int	numCols	= glu::getDataTypeMatrixNumColumns(resEntry.type);
1496 				bool		isOk	= true;
1497 
1498 				for (int colNdx = 0; colNdx < numCols; colNdx++)
1499 				{
1500 					for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
1501 					{
1502 						deUint8*		resCompPtr	= resElemPtr + (resEntry.isRowMajor ? rowNdx*resEntry.matrixStride + colNdx*compSize
1503 																						: colNdx*resEntry.matrixStride + rowNdx*compSize);
1504 						const deUint8*	refCompPtr	= refElemPtr + (refEntry.isRowMajor ? rowNdx*refEntry.matrixStride + colNdx*compSize
1505 																						: colNdx*refEntry.matrixStride + rowNdx*compSize);
1506 
1507 						DE_ASSERT((deIntptr)(refCompPtr + compSize) - (deIntptr)refBlockPtr.ptr <= (deIntptr)refBlockPtr.size);
1508 						DE_ASSERT((deIntptr)(resCompPtr + compSize) - (deIntptr)resBlockPtr.ptr <= (deIntptr)resBlockPtr.size);
1509 
1510 						isOk = isOk && compareComponents(scalarType, resCompPtr, refCompPtr, 1);
1511 					}
1512 				}
1513 
1514 				if (!isOk)
1515 				{
1516 					numFailed += 1;
1517 					if (numFailed < maxPrints)
1518 					{
1519 						std::ostringstream expected, got;
1520 						generateImmMatrixSrc(expected, refEntry.type, refEntry.matrixStride, refEntry.isRowMajor, refElemPtr);
1521 						generateImmMatrixSrc(got, resEntry.type, resEntry.matrixStride, resEntry.isRowMajor, resElemPtr);
1522 						log << TestLog::Message << "ERROR: mismatch in " << refEntry.name << ", top-level ndx " << topElemNdx << ", bottom-level ndx " << elementNdx << ":\n"
1523 												<< "  expected " << expected.str() << "\n"
1524 												<< "  got " << got.str()
1525 							<< TestLog::EndMessage;
1526 					}
1527 				}
1528 			}
1529 			else
1530 			{
1531 				DE_ASSERT((deIntptr)(refElemPtr + scalarSize*compSize) - (deIntptr)refBlockPtr.ptr <= (deIntptr)refBlockPtr.size);
1532 				DE_ASSERT((deIntptr)(resElemPtr + scalarSize*compSize) - (deIntptr)resBlockPtr.ptr <= (deIntptr)resBlockPtr.size);
1533 
1534 				const bool isOk = compareComponents(scalarType, resElemPtr, refElemPtr, scalarSize);
1535 
1536 				if (!isOk)
1537 				{
1538 					numFailed += 1;
1539 					if (numFailed < maxPrints)
1540 					{
1541 						std::ostringstream expected, got;
1542 						generateImmScalarVectorSrc(expected, refEntry.type, refElemPtr);
1543 						generateImmScalarVectorSrc(got, resEntry.type, resElemPtr);
1544 						log << TestLog::Message << "ERROR: mismatch in " << refEntry.name << ", top-level ndx " << topElemNdx << ", bottom-level ndx " << elementNdx << ":\n"
1545 												<< "  expected " << expected.str() << "\n"
1546 												<< "  got " << got.str()
1547 							<< TestLog::EndMessage;
1548 					}
1549 				}
1550 			}
1551 		}
1552 	}
1553 
1554 	if (numFailed >= maxPrints)
1555 		log << TestLog::Message << "... (" << numFailed << " failures for " << refEntry.name << " in total)" << TestLog::EndMessage;
1556 
1557 	return numFailed == 0;
1558 }
1559 
compareData(tcu::TestLog & log,const BufferLayout & refLayout,const vector<BlockDataPtr> & refBlockPointers,const BufferLayout & resLayout,const vector<BlockDataPtr> & resBlockPointers)1560 bool compareData (tcu::TestLog& log, const BufferLayout& refLayout, const vector<BlockDataPtr>& refBlockPointers, const BufferLayout& resLayout, const vector<BlockDataPtr>& resBlockPointers)
1561 {
1562 	const int	numBlocks	= (int)refLayout.blocks.size();
1563 	bool		allOk		= true;
1564 
1565 	for (int refBlockNdx = 0; refBlockNdx < numBlocks; refBlockNdx++)
1566 	{
1567 		const BlockLayoutEntry&		refBlock	= refLayout.blocks[refBlockNdx];
1568 		const BlockDataPtr&			refBlockPtr	= refBlockPointers[refBlockNdx];
1569 		int							resBlockNdx	= resLayout.getBlockIndex(refBlock.name.c_str());
1570 
1571 		if (resBlockNdx >= 0)
1572 		{
1573 			DE_ASSERT(de::inBounds(resBlockNdx, 0, (int)resBlockPointers.size()));
1574 
1575 			const BlockDataPtr& resBlockPtr = resBlockPointers[resBlockNdx];
1576 
1577 			for (vector<int>::const_iterator refVarNdxIter = refBlock.activeVarIndices.begin(); refVarNdxIter != refBlock.activeVarIndices.end(); refVarNdxIter++)
1578 			{
1579 				const BufferVarLayoutEntry&	refEntry	= refLayout.bufferVars[*refVarNdxIter];
1580 				int							resVarNdx	= resLayout.getVariableIndex(refEntry.name.c_str());
1581 
1582 				if (resVarNdx >= 0)
1583 				{
1584 					const BufferVarLayoutEntry& resEntry = resLayout.bufferVars[resVarNdx];
1585 					allOk = compareBufferVarData(log, refEntry, refBlockPtr, resEntry, resBlockPtr) && allOk;
1586 				}
1587 			}
1588 		}
1589 	}
1590 
1591 	return allOk;
1592 }
1593 
getBlockAPIName(const BufferBlock & block,int instanceNdx)1594 string getBlockAPIName (const BufferBlock& block, int instanceNdx)
1595 {
1596 	DE_ASSERT(block.isArray() || instanceNdx == 0);
1597 	return block.getBlockName() + (block.isArray() ? ("[" + de::toString(instanceNdx) + "]") : string());
1598 }
1599 
1600 // \note Some implementations don't report block members in the order they are declared.
1601 //		 For checking whether size has to be adjusted by some top-level array actual size,
1602 //		 we only need to know a) whether there is a unsized top-level array, and b)
1603 //		 what is stride of that array.
1604 
hasUnsizedArray(const BufferLayout & layout,const BlockLayoutEntry & entry)1605 static bool hasUnsizedArray (const BufferLayout& layout, const BlockLayoutEntry& entry)
1606 {
1607 	for (vector<int>::const_iterator varNdx = entry.activeVarIndices.begin(); varNdx != entry.activeVarIndices.end(); ++varNdx)
1608 	{
1609 		if (isUnsizedArray(layout.bufferVars[*varNdx]))
1610 			return true;
1611 	}
1612 
1613 	return false;
1614 }
1615 
getUnsizedArrayStride(const BufferLayout & layout,const BlockLayoutEntry & entry)1616 static int getUnsizedArrayStride (const BufferLayout& layout, const BlockLayoutEntry& entry)
1617 {
1618 	for (vector<int>::const_iterator varNdx = entry.activeVarIndices.begin(); varNdx != entry.activeVarIndices.end(); ++varNdx)
1619 	{
1620 		const BufferVarLayoutEntry& varEntry = layout.bufferVars[*varNdx];
1621 
1622 		if (varEntry.arraySize == 0)
1623 			return varEntry.arrayStride;
1624 		else if (varEntry.topLevelArraySize == 0)
1625 			return varEntry.topLevelArrayStride;
1626 	}
1627 
1628 	return 0;
1629 }
1630 
computeBufferSizes(const ShaderInterface & interface,const BufferLayout & layout)1631 vector<int> computeBufferSizes (const ShaderInterface& interface, const BufferLayout& layout)
1632 {
1633 	vector<int> sizes(layout.blocks.size());
1634 
1635 	for (int declNdx = 0; declNdx < interface.getNumBlocks(); declNdx++)
1636 	{
1637 		const BufferBlock&	block			= interface.getBlock(declNdx);
1638 		const bool			isArray			= block.isArray();
1639 		const int			numInstances	= isArray ? block.getArraySize() : 1;
1640 
1641 		for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1642 		{
1643 			const string	apiName		= getBlockAPIName(block, instanceNdx);
1644 			const int		blockNdx	= layout.getBlockIndex(apiName);
1645 
1646 			if (blockNdx >= 0)
1647 			{
1648 				const BlockLayoutEntry&		blockLayout		= layout.blocks[blockNdx];
1649 				const int					baseSize		= blockLayout.size;
1650 				const bool					isLastUnsized	= hasUnsizedArray(layout, blockLayout);
1651 				const int					lastArraySize	= isLastUnsized ? block.getLastUnsizedArraySize(instanceNdx) : 0;
1652 				const int					stride			= isLastUnsized ? getUnsizedArrayStride(layout, blockLayout) : 0;
1653 
1654 				sizes[blockNdx] = baseSize + lastArraySize*stride;
1655 			}
1656 		}
1657 	}
1658 
1659 	return sizes;
1660 }
1661 
getBlockDataPtr(const BufferLayout & layout,const BlockLayoutEntry & blockLayout,void * ptr,int bufferSize)1662 BlockDataPtr getBlockDataPtr (const BufferLayout& layout, const BlockLayoutEntry& blockLayout, void* ptr, int bufferSize)
1663 {
1664 	const bool	isLastUnsized	= hasUnsizedArray(layout, blockLayout);
1665 	const int	baseSize		= blockLayout.size;
1666 
1667 	if (isLastUnsized)
1668 	{
1669 		const int		lastArrayStride	= getUnsizedArrayStride(layout, blockLayout);
1670 		const int		lastArraySize	= (bufferSize-baseSize) / (lastArrayStride ? lastArrayStride : 1);
1671 
1672 		DE_ASSERT(baseSize + lastArraySize*lastArrayStride == bufferSize);
1673 
1674 		return BlockDataPtr(ptr, bufferSize, lastArraySize);
1675 	}
1676 	else
1677 		return BlockDataPtr(ptr, bufferSize, 0);
1678 }
1679 
1680 struct Buffer
1681 {
1682 	deUint32				buffer;
1683 	int						size;
1684 
Buffervkt::ssbo::__anonfd4a4c8c0211::Buffer1685 	Buffer (deUint32 buffer_, int size_) : buffer(buffer_), size(size_) {}
Buffervkt::ssbo::__anonfd4a4c8c0211::Buffer1686 	Buffer (void) : buffer(0), size(0) {}
1687 };
1688 
1689 struct BlockLocation
1690 {
1691 	int						index;
1692 	int						offset;
1693 	int						size;
1694 
BlockLocationvkt::ssbo::__anonfd4a4c8c0211::BlockLocation1695 	BlockLocation (int index_, int offset_, int size_) : index(index_), offset(offset_), size(size_) {}
BlockLocationvkt::ssbo::__anonfd4a4c8c0211::BlockLocation1696 	BlockLocation (void) : index(0), offset(0), size(0) {}
1697 };
1698 
initRefDataStorage(const ShaderInterface & interface,const BufferLayout & layout,RefDataStorage & storage)1699 void initRefDataStorage (const ShaderInterface& interface, const BufferLayout& layout, RefDataStorage& storage)
1700 {
1701 	DE_ASSERT(storage.data.empty() && storage.pointers.empty());
1702 
1703 	const vector<int>	bufferSizes = computeBufferSizes(interface, layout);
1704 	int					totalSize	= 0;
1705 
1706 	for (vector<int>::const_iterator sizeIter = bufferSizes.begin(); sizeIter != bufferSizes.end(); ++sizeIter)
1707 		totalSize += *sizeIter;
1708 
1709 	storage.data.resize(totalSize);
1710 
1711 	// Pointers for each block.
1712 	{
1713 		deUint8*	basePtr		= storage.data.empty() ? DE_NULL : &storage.data[0];
1714 		int			curOffset	= 0;
1715 
1716 		DE_ASSERT(bufferSizes.size() == layout.blocks.size());
1717 		DE_ASSERT(totalSize == 0 || basePtr);
1718 
1719 		storage.pointers.resize(layout.blocks.size());
1720 
1721 		for (int blockNdx = 0; blockNdx < (int)layout.blocks.size(); blockNdx++)
1722 		{
1723 			const BlockLayoutEntry&	blockLayout		= layout.blocks[blockNdx];
1724 			const int				bufferSize		= bufferSizes[blockNdx];
1725 
1726 			storage.pointers[blockNdx] = getBlockDataPtr(layout, blockLayout, basePtr + curOffset, bufferSize);
1727 
1728 			curOffset += bufferSize;
1729 		}
1730 	}
1731 }
1732 
1733 
blockLocationsToPtrs(const BufferLayout & layout,const vector<BlockLocation> & blockLocations,const vector<void * > & bufPtrs)1734 vector<BlockDataPtr> blockLocationsToPtrs (const BufferLayout& layout, const vector<BlockLocation>& blockLocations, const vector<void*>& bufPtrs)
1735 {
1736 	vector<BlockDataPtr> blockPtrs(blockLocations.size());
1737 
1738 	DE_ASSERT(layout.blocks.size() == blockLocations.size());
1739 
1740 	for (int blockNdx = 0; blockNdx < (int)layout.blocks.size(); blockNdx++)
1741 	{
1742 		const BlockLayoutEntry&	blockLayout		= layout.blocks[blockNdx];
1743 		const BlockLocation&	location		= blockLocations[blockNdx];
1744 
1745 		blockPtrs[blockNdx] = getBlockDataPtr(layout, blockLayout, (deUint8*)bufPtrs[location.index] + location.offset, location.size);
1746 	}
1747 
1748 	return blockPtrs;
1749 }
1750 
1751 } // anonymous (utilities)
1752 
allocateAndBindMemory(Context & context,vk::VkBuffer buffer,vk::MemoryRequirement memReqs)1753 de::MovePtr<vk::Allocation> allocateAndBindMemory (Context& context, vk::VkBuffer buffer, vk::MemoryRequirement memReqs)
1754 {
1755 	const vk::DeviceInterface&		vkd		= context.getDeviceInterface();
1756 	const vk::VkMemoryRequirements	bufReqs	= vk::getBufferMemoryRequirements(vkd, context.getDevice(), buffer);
1757 	de::MovePtr<vk::Allocation>		memory	= context.getDefaultAllocator().allocate(bufReqs, memReqs);
1758 
1759 	vkd.bindBufferMemory(context.getDevice(), buffer, memory->getMemory(), memory->getOffset());
1760 
1761 	return memory;
1762 }
1763 
createBuffer(Context & context,vk::VkDeviceSize bufferSize,vk::VkBufferUsageFlags usageFlags)1764 vk::Move<vk::VkBuffer> createBuffer (Context& context, vk::VkDeviceSize bufferSize, vk::VkBufferUsageFlags usageFlags)
1765 {
1766 	const vk::VkDevice			vkDevice			= context.getDevice();
1767 	const vk::DeviceInterface&	vk					= context.getDeviceInterface();
1768 	const deUint32			queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
1769 
1770 	const vk::VkBufferCreateInfo	bufferInfo		=
1771 	{
1772 		vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,	// VkStructureType		sType;
1773 		DE_NULL,									// const void*			pNext;
1774 		0u,											// VkBufferCreateFlags	flags;
1775 		bufferSize,									// VkDeviceSize			size;
1776 		usageFlags,									// VkBufferUsageFlags	usage;
1777 		vk::VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode		sharingMode;
1778 		1u,											// deUint32				queueFamilyCount;
1779 		&queueFamilyIndex							// const deUint32*		pQueueFamilyIndices;
1780 	};
1781 
1782 	return vk::createBuffer(vk, vkDevice, &bufferInfo);
1783 }
1784 
1785 // SSBOLayoutCaseInstance
1786 
1787 class SSBOLayoutCaseInstance : public TestInstance
1788 {
1789 public:
1790 								SSBOLayoutCaseInstance	(Context&					context,
1791 														SSBOLayoutCase::BufferMode	bufferMode,
1792 														const ShaderInterface&		interface,
1793 														const BufferLayout&			refLayout,
1794 														const RefDataStorage&		initialData,
1795 														const RefDataStorage&		writeData);
1796 	virtual						~SSBOLayoutCaseInstance	(void);
1797 	virtual tcu::TestStatus		iterate						(void);
1798 
1799 private:
1800 	SSBOLayoutCase::BufferMode	m_bufferMode;
1801 	const ShaderInterface&		m_interface;
1802 	const BufferLayout&			m_refLayout;
1803 	const RefDataStorage&		m_initialData;	// Initial data stored in buffer.
1804 	const RefDataStorage&		m_writeData;	// Data written by compute shader.
1805 
1806 
1807 	typedef de::SharedPtr<vk::Unique<vk::VkBuffer> >	VkBufferSp;
1808 	typedef de::SharedPtr<vk::Allocation>				AllocationSp;
1809 
1810 	std::vector<VkBufferSp>		m_uniformBuffers;
1811 	std::vector<AllocationSp>	m_uniformAllocs;
1812 };
1813 
SSBOLayoutCaseInstance(Context & context,SSBOLayoutCase::BufferMode bufferMode,const ShaderInterface & interface,const BufferLayout & refLayout,const RefDataStorage & initialData,const RefDataStorage & writeData)1814 SSBOLayoutCaseInstance::SSBOLayoutCaseInstance (Context&					context,
1815 												SSBOLayoutCase::BufferMode	bufferMode,
1816 												const ShaderInterface&		interface,
1817 												const BufferLayout&			refLayout,
1818 												const RefDataStorage&		initialData,
1819 												const RefDataStorage&		writeData)
1820 	: TestInstance	(context)
1821 	, m_bufferMode	(bufferMode)
1822 	, m_interface	(interface)
1823 	, m_refLayout	(refLayout)
1824 	, m_initialData	(initialData)
1825 	, m_writeData	(writeData)
1826 {
1827 }
1828 
~SSBOLayoutCaseInstance(void)1829 SSBOLayoutCaseInstance::~SSBOLayoutCaseInstance (void)
1830 {
1831 }
1832 
iterate(void)1833 tcu::TestStatus SSBOLayoutCaseInstance::iterate (void)
1834 {
1835 	// todo: add compute stage availability check
1836 	const vk::DeviceInterface&	vk					= m_context.getDeviceInterface();
1837 	const vk::VkDevice			device				= m_context.getDevice();
1838 	const vk::VkQueue			queue				= m_context.getUniversalQueue();
1839 	const deUint32				queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
1840 
1841 	// Create descriptor set
1842 	const deUint32 acBufferSize = 1024;
1843 	vk::Move<vk::VkBuffer> acBuffer (createBuffer(m_context, acBufferSize, vk:: VK_BUFFER_USAGE_STORAGE_BUFFER_BIT));
1844 	de::UniquePtr<vk::Allocation> acBufferAlloc (allocateAndBindMemory(m_context, *acBuffer, vk::MemoryRequirement::HostVisible));
1845 
1846 	deMemset(acBufferAlloc->getHostPtr(), 0, acBufferSize);
1847 	flushMappedMemoryRange(vk, device, acBufferAlloc->getMemory(), acBufferAlloc->getOffset(), acBufferSize);
1848 
1849 	vk::DescriptorSetLayoutBuilder setLayoutBuilder;
1850 	vk::DescriptorPoolBuilder poolBuilder;
1851 
1852 	setLayoutBuilder
1853 		.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT);
1854 
1855 	int numBlocks = 0;
1856 	const int numBindings = m_interface.getNumBlocks();
1857 	for (int bindingNdx = 0; bindingNdx < numBindings; bindingNdx++)
1858 	{
1859 		const BufferBlock& block = m_interface.getBlock(bindingNdx);
1860 		if (block.isArray())
1861 		{
1862 			setLayoutBuilder
1863 				.addArrayBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, block.getArraySize(), vk::VK_SHADER_STAGE_COMPUTE_BIT);
1864 			numBlocks += block.getArraySize();
1865 		}
1866 		else
1867 		{
1868 			setLayoutBuilder
1869 				.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT);
1870 			numBlocks += 1;
1871 		}
1872 	}
1873 
1874 	poolBuilder
1875 		.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, (deUint32)(1 + numBlocks));
1876 
1877 	const vk::Unique<vk::VkDescriptorSetLayout> descriptorSetLayout(setLayoutBuilder.build(vk, device));
1878 	const vk::Unique<vk::VkDescriptorPool> descriptorPool(poolBuilder.build(vk, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
1879 
1880 	const vk::VkDescriptorSetAllocateInfo allocInfo =
1881 	{
1882 		vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
1883 		DE_NULL,
1884 		*descriptorPool,
1885 		1u,
1886 		&descriptorSetLayout.get(),
1887 	};
1888 
1889 	const vk::Unique<vk::VkDescriptorSet> descriptorSet(allocateDescriptorSet(vk, device, &allocInfo));
1890 	const vk::VkDescriptorBufferInfo descriptorInfo = makeDescriptorBufferInfo(*acBuffer, 0ull, acBufferSize);
1891 
1892 	vk::DescriptorSetUpdateBuilder setUpdateBuilder;
1893 	std::vector<vk::VkDescriptorBufferInfo>	descriptors(numBlocks);
1894 
1895 	setUpdateBuilder
1896 		.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorInfo);
1897 
1898 	vector<BlockDataPtr>  mappedBlockPtrs;
1899 
1900 	// Upload base buffers
1901 	{
1902 		const std::vector<int>			bufferSizes		= computeBufferSizes(m_interface, m_refLayout);
1903 		std::vector<void*>				mapPtrs;
1904 		std::vector<BlockLocation>		blockLocations	(numBlocks);
1905 
1906 		DE_ASSERT(bufferSizes.size() == m_refLayout.blocks.size());
1907 
1908 		if (m_bufferMode == SSBOLayoutCase::BUFFERMODE_PER_BLOCK)
1909 		{
1910 			mapPtrs.resize(numBlocks);
1911 			for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1912 			{
1913 				const deUint32 bufferSize = bufferSizes[blockNdx];
1914 				DE_ASSERT(bufferSize > 0);
1915 
1916 				blockLocations[blockNdx] = BlockLocation(blockNdx, 0, bufferSize);
1917 
1918 				vk::Move<vk::VkBuffer>				buffer		= createBuffer(m_context, bufferSize, vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
1919 				de::MovePtr<vk::Allocation>			alloc		= allocateAndBindMemory(m_context, *buffer, vk::MemoryRequirement::HostVisible);
1920 
1921 				descriptors[blockNdx] = makeDescriptorBufferInfo(*buffer, 0ull, bufferSize);
1922 
1923 				mapPtrs[blockNdx] = alloc->getHostPtr();
1924 
1925 				m_uniformBuffers.push_back(VkBufferSp(new vk::Unique<vk::VkBuffer>(buffer)));
1926 				m_uniformAllocs.push_back(AllocationSp(alloc.release()));
1927 			}
1928 		}
1929 		else
1930 		{
1931 			DE_ASSERT(m_bufferMode == SSBOLayoutCase::BUFFERMODE_SINGLE);
1932 
1933 			vk::VkPhysicalDeviceProperties properties;
1934 			m_context.getInstanceInterface().getPhysicalDeviceProperties(m_context.getPhysicalDevice(), &properties);
1935 			const int	bindingAlignment	= (int)properties.limits.minStorageBufferOffsetAlignment;
1936 			int			curOffset			= 0;
1937 			for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1938 			{
1939 				const int bufferSize = bufferSizes[blockNdx];
1940 				DE_ASSERT(bufferSize > 0);
1941 
1942 				if (bindingAlignment > 0)
1943 					curOffset = deRoundUp32(curOffset, bindingAlignment);
1944 
1945 				blockLocations[blockNdx] = BlockLocation(0, curOffset, bufferSize);
1946 				curOffset += bufferSize;
1947 			}
1948 
1949 			const int						totalBufferSize = curOffset;
1950 			vk::Move<vk::VkBuffer>			buffer			= createBuffer(m_context, totalBufferSize, vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
1951 			de::MovePtr<vk::Allocation>		alloc			= allocateAndBindMemory(m_context, *buffer, vk::MemoryRequirement::HostVisible);
1952 
1953 			mapPtrs.push_back(alloc->getHostPtr());
1954 
1955 			for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1956 			{
1957 				const deUint32						bufferSize	= bufferSizes[blockNdx];
1958 				const deUint32						offset		= blockLocations[blockNdx].offset;
1959 
1960 				descriptors[blockNdx] = makeDescriptorBufferInfo(*buffer, offset, bufferSize);
1961 			}
1962 
1963 			m_uniformBuffers.push_back(VkBufferSp(new vk::Unique<vk::VkBuffer>(buffer)));
1964 			m_uniformAllocs.push_back(AllocationSp(alloc.release()));
1965 		}
1966 
1967 		// Update remaining bindings
1968 		{
1969 			int blockNdx = 0;
1970 			for (int bindingNdx = 0; bindingNdx < numBindings; ++bindingNdx)
1971 			{
1972 				const BufferBlock&	block				= m_interface.getBlock(bindingNdx);
1973 				const int			numBlocksInBinding	= (block.isArray() ? block.getArraySize() : 1);
1974 
1975 				setUpdateBuilder.writeArray(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(bindingNdx + 1),
1976 					vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, numBlocksInBinding, &descriptors[blockNdx]);
1977 
1978 				blockNdx += numBlocksInBinding;
1979 			}
1980 		}
1981 
1982 		// Copy the initial data to the storage buffers
1983 		{
1984 			mappedBlockPtrs = blockLocationsToPtrs(m_refLayout, blockLocations, mapPtrs);
1985 			copyData(m_refLayout, mappedBlockPtrs, m_refLayout, m_initialData.pointers);
1986 
1987 			if (m_bufferMode == SSBOLayoutCase::BUFFERMODE_PER_BLOCK)
1988 			{
1989 				DE_ASSERT(m_uniformAllocs.size() == bufferSizes.size());
1990 				for (size_t allocNdx = 0; allocNdx < m_uniformAllocs.size(); allocNdx++)
1991 				{
1992 					const int size = bufferSizes[allocNdx];
1993 					vk::Allocation* alloc = m_uniformAllocs[allocNdx].get();
1994 					flushMappedMemoryRange(vk, device, alloc->getMemory(), alloc->getOffset(), size);
1995 				}
1996 			}
1997 			else
1998 			{
1999 				DE_ASSERT(m_bufferMode == SSBOLayoutCase::BUFFERMODE_SINGLE);
2000 				DE_ASSERT(m_uniformAllocs.size() == 1);
2001 				int totalSize = 0;
2002 				for (size_t bufferNdx = 0; bufferNdx < bufferSizes.size(); bufferNdx++)
2003 				{
2004 					totalSize += bufferSizes[bufferNdx];
2005 				}
2006 
2007 				DE_ASSERT(totalSize > 0);
2008 				vk::Allocation* alloc = m_uniformAllocs[0].get();
2009 				flushMappedMemoryRange(vk, device, alloc->getMemory(), alloc->getOffset(), totalSize);
2010 			}
2011 		}
2012 	}
2013 
2014 	setUpdateBuilder.update(vk, device);
2015 
2016 	const vk::VkPipelineLayoutCreateInfo pipelineLayoutParams =
2017 	{
2018 		vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,	// VkStructureType				sType;
2019 		DE_NULL,											// const void*					pNext;
2020 		(vk::VkPipelineLayoutCreateFlags)0,
2021 		1u,													// deUint32						descriptorSetCount;
2022 		&*descriptorSetLayout,								// const VkDescriptorSetLayout*	pSetLayouts;
2023 		0u,													// deUint32						pushConstantRangeCount;
2024 		DE_NULL,											// const VkPushConstantRange*	pPushConstantRanges;
2025 	};
2026 	vk::Move<vk::VkPipelineLayout> pipelineLayout(createPipelineLayout(vk, device, &pipelineLayoutParams));
2027 
2028 	vk::Move<vk::VkShaderModule> shaderModule (createShaderModule(vk, device, m_context.getBinaryCollection().get("compute"), 0));
2029 	const vk::VkPipelineShaderStageCreateInfo pipelineShaderStageParams =
2030 	{
2031 		vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,// VkStructureType				sType;
2032 		DE_NULL,												// const void*					pNext;
2033 		(vk::VkPipelineShaderStageCreateFlags)0,
2034 		vk::VK_SHADER_STAGE_COMPUTE_BIT,						// VkShaderStage				stage;
2035 		*shaderModule,											// VkShader						shader;
2036 		"main",													//
2037 		DE_NULL,												// const VkSpecializationInfo*	pSpecializationInfo;
2038 	};
2039 	const vk::VkComputePipelineCreateInfo pipelineCreateInfo =
2040 	{
2041 		vk::VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,	// VkStructureType					sType;
2042 		DE_NULL,											// const void*						pNext;
2043 		0,													// VkPipelineCreateFlags			flags;
2044 		pipelineShaderStageParams,							// VkPipelineShaderStageCreateInfo	stage;
2045 		*pipelineLayout,									// VkPipelineLayout					layout;
2046 		DE_NULL,											// VkPipeline						basePipelineHandle;
2047 		0,													// deInt32							basePipelineIndex;
2048 	};
2049 	vk::Move<vk::VkPipeline> pipeline(createComputePipeline(vk, device, DE_NULL, &pipelineCreateInfo));
2050 
2051 	const vk::VkCommandPoolCreateInfo cmdPoolParams =
2052 	{
2053 		vk::VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,			// VkStructureType		sType;
2054 		DE_NULL,												// const void*			pNext;
2055 		vk::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,	// VkCmdPoolCreateFlags	flags;
2056 		queueFamilyIndex,										// deUint32				queueFamilyIndex;
2057 	};
2058 	vk::Move<vk::VkCommandPool> cmdPool (createCommandPool(vk, device, &cmdPoolParams));
2059 
2060 	const vk::VkCommandBufferAllocateInfo cmdBufParams =
2061 	{
2062 		vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,	// VkStructureType			sType;
2063 		DE_NULL,											// const void*				pNext;
2064 		*cmdPool,											// VkCmdPool				pool;
2065 		vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY,				// VkCmdBufferLevel		level;
2066 		1u,													// deUint32					bufferCount;
2067 	};
2068 	vk::Move<vk::VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vk, device, &cmdBufParams));
2069 
2070 	const vk::VkCommandBufferBeginInfo cmdBufBeginParams =
2071 	{
2072 		vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,	//	VkStructureType				sType;
2073 		DE_NULL,											//	const void*					pNext;
2074 		0u,													//	VkCmdBufferOptimizeFlags	flags;
2075 		(const vk::VkCommandBufferInheritanceInfo*)DE_NULL,
2076 	};
2077 	VK_CHECK(vk.beginCommandBuffer(*cmdBuffer, &cmdBufBeginParams));
2078 
2079 	vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
2080 	vk.cmdBindDescriptorSets(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
2081 
2082 	vk.cmdDispatch(*cmdBuffer, 1, 1, 1);
2083 
2084 	VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
2085 
2086 	const vk::VkFenceCreateInfo	fenceParams =
2087 	{
2088 		vk::VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,	// VkStructureType		sType;
2089 		DE_NULL,									// const void*			pNext;
2090 		0u,											// VkFenceCreateFlags	flags;
2091 	};
2092 	vk::Move<vk::VkFence> fence (createFence(vk, device, &fenceParams));
2093 
2094 	const vk::VkSubmitInfo  submitInfo  =
2095 	{
2096 		vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
2097 		DE_NULL,
2098 		0u,
2099 		(const vk::VkSemaphore*)DE_NULL,
2100 		(const vk::VkPipelineStageFlags*)DE_NULL,
2101 		1u,
2102 		&cmdBuffer.get(),
2103 		0u,
2104 		(const vk::VkSemaphore*)DE_NULL,
2105 	};
2106 
2107 	VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfo, *fence));
2108 	VK_CHECK(vk.waitForFences(device, 1u, &fence.get(), DE_TRUE, ~0ull));
2109 
2110 	// Read back ac_numPassed data
2111 	bool counterOk;
2112 	{
2113 		const int refCount = 1;
2114 		int resCount = 0;
2115 
2116 		resCount = *(const int*)((const deUint8*)acBufferAlloc->getHostPtr());
2117 
2118 		counterOk = (refCount == resCount);
2119 		if (!counterOk)
2120 		{
2121 			m_context.getTestContext().getLog() << TestLog::Message << "Error: ac_numPassed = " << resCount << ", expected " << refCount << TestLog::EndMessage;
2122 		}
2123 	}
2124 
2125 	// Validate result
2126 	const bool compareOk = compareData(m_context.getTestContext().getLog(), m_refLayout, m_writeData.pointers, m_refLayout, mappedBlockPtrs);
2127 
2128 	if (compareOk && counterOk)
2129 		return tcu::TestStatus::pass("Result comparison and counter values are OK");
2130 	else if (!compareOk && counterOk)
2131 		return tcu::TestStatus::fail("Result comparison failed");
2132 	else if (compareOk && !counterOk)
2133 		return tcu::TestStatus::fail("Counter value incorrect");
2134 	else
2135 		return tcu::TestStatus::fail("Result comparison and counter values are incorrect");
2136 }
2137 
2138 // SSBOLayoutCase.
2139 
SSBOLayoutCase(tcu::TestContext & testCtx,const char * name,const char * description,BufferMode bufferMode)2140 SSBOLayoutCase::SSBOLayoutCase (tcu::TestContext& testCtx, const char* name, const char* description, BufferMode bufferMode)
2141 	: TestCase		(testCtx, name, description)
2142 	, m_bufferMode	(bufferMode)
2143 {
2144 }
2145 
~SSBOLayoutCase(void)2146 SSBOLayoutCase::~SSBOLayoutCase (void)
2147 {
2148 }
2149 
initPrograms(vk::SourceCollections & programCollection) const2150 void SSBOLayoutCase::initPrograms (vk::SourceCollections& programCollection) const
2151 {
2152 	DE_ASSERT(!m_computeShaderSrc.empty());
2153 
2154 	programCollection.glslSources.add("compute") << glu::ComputeSource(m_computeShaderSrc);
2155 }
2156 
createInstance(Context & context) const2157 TestInstance* SSBOLayoutCase::createInstance (Context& context) const
2158 {
2159 	return new SSBOLayoutCaseInstance(context, m_bufferMode, m_interface, m_refLayout, m_initialData, m_writeData);
2160 }
2161 
init(void)2162 void SSBOLayoutCase::init (void)
2163 {
2164 	computeReferenceLayout	(m_refLayout, m_interface);
2165 	initRefDataStorage		(m_interface, m_refLayout, m_initialData);
2166 	initRefDataStorage		(m_interface, m_refLayout, m_writeData);
2167 	generateValues			(m_refLayout, m_initialData.pointers, deStringHash(getName()) ^ 0xad2f7214);
2168 	generateValues			(m_refLayout, m_writeData.pointers, deStringHash(getName()) ^ 0x25ca4e7);
2169 	copyNonWrittenData		(m_interface, m_refLayout, m_initialData.pointers, m_writeData.pointers);
2170 
2171 	m_computeShaderSrc = generateComputeShader(m_interface, m_refLayout, m_initialData.pointers, m_writeData.pointers);
2172 }
2173 
2174 } // ssbo
2175 } // vkt
2176