1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.1 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief SSBO layout case.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es31fSSBOLayoutCase.hpp"
25 #include "gluRenderContext.hpp"
26 #include "gluShaderProgram.hpp"
27 #include "gluPixelTransfer.hpp"
28 #include "gluContextInfo.hpp"
29 #include "gluRenderContext.hpp"
30 #include "gluProgramInterfaceQuery.hpp"
31 #include "gluObjectWrapper.hpp"
32 #include "gluVarTypeUtil.hpp"
33 #include "glwFunctions.hpp"
34 #include "glwEnums.hpp"
35 #include "tcuTestLog.hpp"
36 #include "tcuSurface.hpp"
37 #include "tcuRenderTarget.hpp"
38 #include "deRandom.hpp"
39 #include "deStringUtil.hpp"
40 #include "deMemory.h"
41 #include "deString.h"
42 #include "deMath.h"
43 
44 #include <algorithm>
45 #include <map>
46 
47 using tcu::TestLog;
48 using std::string;
49 using std::vector;
50 using std::map;
51 
52 namespace deqp
53 {
54 namespace gles31
55 {
56 
57 using glu::VarType;
58 using glu::StructType;
59 using glu::StructMember;
60 
61 namespace bb
62 {
63 
64 struct LayoutFlagsFmt
65 {
66 	deUint32 flags;
LayoutFlagsFmtdeqp::gles31::bb::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_SHARED,		"shared"		},
79 		{ LAYOUT_PACKED,		"packed"		},
80 		{ LAYOUT_STD140,		"std140"		},
81 		{ LAYOUT_STD430,		"std430"		},
82 		{ LAYOUT_ROW_MAJOR,		"row_major"		},
83 		{ LAYOUT_COLUMN_MAJOR,	"column_major"	}
84 	};
85 
86 	deUint32 remBits = fmt.flags;
87 	for (int descNdx = 0; descNdx < DE_LENGTH_OF_ARRAY(bitDesc); descNdx++)
88 	{
89 		if (remBits & bitDesc[descNdx].bit)
90 		{
91 			if (remBits != fmt.flags)
92 				str << ", ";
93 			str << bitDesc[descNdx].token;
94 			remBits &= ~bitDesc[descNdx].bit;
95 		}
96 	}
97 	DE_ASSERT(remBits == 0);
98 	return str;
99 }
100 
101 // BufferVar implementation.
102 
BufferVar(const char * name,const VarType & type,deUint32 flags)103 BufferVar::BufferVar (const char* name, const VarType& type, deUint32 flags)
104 	: m_name	(name)
105 	, m_type	(type)
106 	, m_flags	(flags)
107 {
108 }
109 
110 // BufferBlock implementation.
111 
BufferBlock(const char * blockName)112 BufferBlock::BufferBlock (const char* blockName)
113 	: m_blockName	(blockName)
114 	, m_arraySize	(-1)
115 	, m_flags		(0)
116 {
117 	setArraySize(0);
118 }
119 
setArraySize(int arraySize)120 void BufferBlock::setArraySize (int arraySize)
121 {
122 	DE_ASSERT(arraySize >= 0);
123 	m_lastUnsizedArraySizes.resize(arraySize == 0 ? 1 : arraySize, 0);
124 	m_arraySize = arraySize;
125 }
126 
127 struct BlockLayoutEntry
128 {
BlockLayoutEntrydeqp::gles31::bb::BlockLayoutEntry129 	BlockLayoutEntry (void)
130 		: size(0)
131 	{
132 	}
133 
134 	std::string			name;
135 	int					size;
136 	std::vector<int>	activeVarIndices;
137 };
138 
operator <<(std::ostream & stream,const BlockLayoutEntry & entry)139 std::ostream& operator<< (std::ostream& stream, const BlockLayoutEntry& entry)
140 {
141 	stream << entry.name << " { name = " << entry.name
142 		   << ", size = " << entry.size
143 		   << ", activeVarIndices = [";
144 
145 	for (vector<int>::const_iterator i = entry.activeVarIndices.begin(); i != entry.activeVarIndices.end(); i++)
146 	{
147 		if (i != entry.activeVarIndices.begin())
148 			stream << ", ";
149 		stream << *i;
150 	}
151 
152 	stream << "] }";
153 	return stream;
154 }
155 
156 struct BufferVarLayoutEntry
157 {
BufferVarLayoutEntrydeqp::gles31::bb::BufferVarLayoutEntry158 	BufferVarLayoutEntry (void)
159 		: type					(glu::TYPE_LAST)
160 		, blockNdx				(-1)
161 		, offset				(-1)
162 		, arraySize				(-1)
163 		, arrayStride			(-1)
164 		, matrixStride			(-1)
165 		, topLevelArraySize		(-1)
166 		, topLevelArrayStride	(-1)
167 		, isRowMajor			(false)
168 	{
169 	}
170 
171 	std::string			name;
172 	glu::DataType		type;
173 	int					blockNdx;
174 	int					offset;
175 	int					arraySize;
176 	int					arrayStride;
177 	int					matrixStride;
178 	int					topLevelArraySize;
179 	int					topLevelArrayStride;
180 	bool				isRowMajor;
181 };
182 
isUnsizedArray(const BufferVarLayoutEntry & entry)183 static bool isUnsizedArray (const BufferVarLayoutEntry& entry)
184 {
185 	DE_ASSERT(entry.arraySize != 0 || entry.topLevelArraySize != 0);
186 	return entry.arraySize == 0 || entry.topLevelArraySize == 0;
187 }
188 
operator <<(std::ostream & stream,const BufferVarLayoutEntry & entry)189 std::ostream& operator<< (std::ostream& stream, const BufferVarLayoutEntry& entry)
190 {
191 	stream << entry.name << " { type = " << glu::getDataTypeName(entry.type)
192 		   << ", blockNdx = " << entry.blockNdx
193 		   << ", offset = " << entry.offset
194 		   << ", arraySize = " << entry.arraySize
195 		   << ", arrayStride = " << entry.arrayStride
196 		   << ", matrixStride = " << entry.matrixStride
197 		   << ", topLevelArraySize = " << entry.topLevelArraySize
198 		   << ", topLevelArrayStride = " << entry.topLevelArrayStride
199 		   << ", isRowMajor = " << (entry.isRowMajor ? "true" : "false")
200 		   << " }";
201 	return stream;
202 }
203 
204 class BufferLayout
205 {
206 public:
207 	std::vector<BlockLayoutEntry>		blocks;
208 	std::vector<BufferVarLayoutEntry>	bufferVars;
209 
210 	int									getVariableIndex		(const string& name) const;
211 	int									getBlockIndex			(const string& name) const;
212 };
213 
214 // \todo [2012-01-24 pyry] Speed up lookups using hash.
215 
getVariableIndex(const string & name) const216 int BufferLayout::getVariableIndex (const string& name) const
217 {
218 	for (int ndx = 0; ndx < (int)bufferVars.size(); ndx++)
219 	{
220 		if (bufferVars[ndx].name == name)
221 			return ndx;
222 	}
223 	return -1;
224 }
225 
getBlockIndex(const string & name) const226 int BufferLayout::getBlockIndex (const string& name) const
227 {
228 	for (int ndx = 0; ndx < (int)blocks.size(); ndx++)
229 	{
230 		if (blocks[ndx].name == name)
231 			return ndx;
232 	}
233 	return -1;
234 }
235 
236 // ShaderInterface implementation.
237 
ShaderInterface(void)238 ShaderInterface::ShaderInterface (void)
239 {
240 }
241 
~ShaderInterface(void)242 ShaderInterface::~ShaderInterface (void)
243 {
244 	for (std::vector<StructType*>::iterator i = m_structs.begin(); i != m_structs.end(); i++)
245 		delete *i;
246 
247 	for (std::vector<BufferBlock*>::iterator i = m_bufferBlocks.begin(); i != m_bufferBlocks.end(); i++)
248 		delete *i;
249 }
250 
allocStruct(const char * name)251 StructType& ShaderInterface::allocStruct (const char* name)
252 {
253 	m_structs.reserve(m_structs.size()+1);
254 	m_structs.push_back(new StructType(name));
255 	return *m_structs.back();
256 }
257 
258 struct StructNameEquals
259 {
260 	std::string name;
261 
StructNameEqualsdeqp::gles31::bb::StructNameEquals262 	StructNameEquals (const char* name_) : name(name_) {}
263 
operator ()deqp::gles31::bb::StructNameEquals264 	bool operator() (const StructType* type) const
265 	{
266 		return type->getTypeName() && name == type->getTypeName();
267 	}
268 };
269 
findStruct(const char * name) const270 const StructType* ShaderInterface::findStruct (const char* name) const
271 {
272 	std::vector<StructType*>::const_iterator pos = std::find_if(m_structs.begin(), m_structs.end(), StructNameEquals(name));
273 	return pos != m_structs.end() ? *pos : DE_NULL;
274 }
275 
getNamedStructs(std::vector<const StructType * > & structs) const276 void ShaderInterface::getNamedStructs (std::vector<const StructType*>& structs) const
277 {
278 	for (std::vector<StructType*>::const_iterator i = m_structs.begin(); i != m_structs.end(); i++)
279 	{
280 		if ((*i)->getTypeName() != DE_NULL)
281 			structs.push_back(*i);
282 	}
283 }
284 
allocBlock(const char * name)285 BufferBlock& ShaderInterface::allocBlock (const char* name)
286 {
287 	m_bufferBlocks.reserve(m_bufferBlocks.size()+1);
288 	m_bufferBlocks.push_back(new BufferBlock(name));
289 	return *m_bufferBlocks.back();
290 }
291 
292 // BlockDataPtr
293 
294 struct BlockDataPtr
295 {
296 	void*		ptr;
297 	int			size;						//!< Redundant, for debugging purposes.
298 	int			lastUnsizedArraySize;
299 
BlockDataPtrdeqp::gles31::bb::BlockDataPtr300 	BlockDataPtr (void* ptr_, int size_, int lastUnsizedArraySize_)
301 		: ptr					(ptr_)
302 		, size					(size_)
303 		, lastUnsizedArraySize	(lastUnsizedArraySize_)
304 	{
305 	}
306 
BlockDataPtrdeqp::gles31::bb::BlockDataPtr307 	BlockDataPtr (void)
308 		: ptr					(DE_NULL)
309 		, size					(0)
310 		, lastUnsizedArraySize	(0)
311 	{
312 	}
313 };
314 
315 namespace // Utilities
316 {
317 
findBlockIndex(const BufferLayout & layout,const string & name)318 int findBlockIndex (const BufferLayout& layout, const string& name)
319 {
320 	for (int ndx = 0; ndx < (int)layout.blocks.size(); ndx++)
321 	{
322 		if (layout.blocks[ndx].name == name)
323 			return ndx;
324 	}
325 	return -1;
326 }
327 
328 // Layout computation.
329 
getDataTypeByteSize(glu::DataType type)330 int getDataTypeByteSize (glu::DataType type)
331 {
332 	return glu::getDataTypeScalarSize(type)*(int)sizeof(deUint32);
333 }
334 
getDataTypeByteAlignment(glu::DataType type)335 int getDataTypeByteAlignment (glu::DataType type)
336 {
337 	switch (type)
338 	{
339 		case glu::TYPE_FLOAT:
340 		case glu::TYPE_INT:
341 		case glu::TYPE_UINT:
342 		case glu::TYPE_BOOL:		return 1*(int)sizeof(deUint32);
343 
344 		case glu::TYPE_FLOAT_VEC2:
345 		case glu::TYPE_INT_VEC2:
346 		case glu::TYPE_UINT_VEC2:
347 		case glu::TYPE_BOOL_VEC2:	return 2*(int)sizeof(deUint32);
348 
349 		case glu::TYPE_FLOAT_VEC3:
350 		case glu::TYPE_INT_VEC3:
351 		case glu::TYPE_UINT_VEC3:
352 		case glu::TYPE_BOOL_VEC3:	// Fall-through to vec4
353 
354 		case glu::TYPE_FLOAT_VEC4:
355 		case glu::TYPE_INT_VEC4:
356 		case glu::TYPE_UINT_VEC4:
357 		case glu::TYPE_BOOL_VEC4:	return 4*(int)sizeof(deUint32);
358 
359 		default:
360 			DE_ASSERT(false);
361 			return 0;
362 	}
363 }
364 
deRoundUp32(int a,int b)365 static inline int deRoundUp32 (int a, int b)
366 {
367 	int d = a/b;
368 	return d*b == a ? a : (d+1)*b;
369 }
370 
computeStd140BaseAlignment(const VarType & type,deUint32 layoutFlags)371 int computeStd140BaseAlignment (const VarType& type, deUint32 layoutFlags)
372 {
373 	const int vec4Alignment = (int)sizeof(deUint32)*4;
374 
375 	if (type.isBasicType())
376 	{
377 		glu::DataType basicType = type.getBasicType();
378 
379 		if (glu::isDataTypeMatrix(basicType))
380 		{
381 			const bool	isRowMajor	= !!(layoutFlags & LAYOUT_ROW_MAJOR);
382 			const int	vecSize		= isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType)
383 												 : glu::getDataTypeMatrixNumRows(basicType);
384 			const int	vecAlign	= deAlign32(getDataTypeByteAlignment(glu::getDataTypeFloatVec(vecSize)), vec4Alignment);
385 
386 			return vecAlign;
387 		}
388 		else
389 			return getDataTypeByteAlignment(basicType);
390 	}
391 	else if (type.isArrayType())
392 	{
393 		int elemAlignment = computeStd140BaseAlignment(type.getElementType(), layoutFlags);
394 
395 		// Round up to alignment of vec4
396 		return deAlign32(elemAlignment, vec4Alignment);
397 	}
398 	else
399 	{
400 		DE_ASSERT(type.isStructType());
401 
402 		int maxBaseAlignment = 0;
403 
404 		for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++)
405 			maxBaseAlignment = de::max(maxBaseAlignment, computeStd140BaseAlignment(memberIter->getType(), layoutFlags));
406 
407 		return deAlign32(maxBaseAlignment, vec4Alignment);
408 	}
409 }
410 
computeStd430BaseAlignment(const VarType & type,deUint32 layoutFlags)411 int computeStd430BaseAlignment (const VarType& type, deUint32 layoutFlags)
412 {
413 	// Otherwise identical to std140 except that alignment of structures and arrays
414 	// are not rounded up to alignment of vec4.
415 
416 	if (type.isBasicType())
417 	{
418 		glu::DataType basicType = type.getBasicType();
419 
420 		if (glu::isDataTypeMatrix(basicType))
421 		{
422 			const bool	isRowMajor	= !!(layoutFlags & LAYOUT_ROW_MAJOR);
423 			const int	vecSize		= isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType)
424 												 : glu::getDataTypeMatrixNumRows(basicType);
425 			const int	vecAlign	= getDataTypeByteAlignment(glu::getDataTypeFloatVec(vecSize));
426 
427 			return vecAlign;
428 		}
429 		else
430 			return getDataTypeByteAlignment(basicType);
431 	}
432 	else if (type.isArrayType())
433 	{
434 		return computeStd430BaseAlignment(type.getElementType(), layoutFlags);
435 	}
436 	else
437 	{
438 		DE_ASSERT(type.isStructType());
439 
440 		int maxBaseAlignment = 0;
441 
442 		for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++)
443 			maxBaseAlignment = de::max(maxBaseAlignment, computeStd430BaseAlignment(memberIter->getType(), layoutFlags));
444 
445 		return maxBaseAlignment;
446 	}
447 }
448 
mergeLayoutFlags(deUint32 prevFlags,deUint32 newFlags)449 inline deUint32 mergeLayoutFlags (deUint32 prevFlags, deUint32 newFlags)
450 {
451 	const deUint32	packingMask		= LAYOUT_PACKED|LAYOUT_SHARED|LAYOUT_STD140|LAYOUT_STD430;
452 	const deUint32	matrixMask		= LAYOUT_ROW_MAJOR|LAYOUT_COLUMN_MAJOR;
453 
454 	deUint32 mergedFlags = 0;
455 
456 	mergedFlags |= ((newFlags & packingMask)	? newFlags : prevFlags) & packingMask;
457 	mergedFlags |= ((newFlags & matrixMask)		? newFlags : prevFlags) & matrixMask;
458 
459 	return mergedFlags;
460 }
461 
462 //! 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)463 int computeReferenceLayout (
464 	BufferLayout&		layout,
465 	int					curBlockNdx,
466 	int					baseOffset,
467 	const std::string&	curPrefix,
468 	const VarType&		type,
469 	deUint32			layoutFlags)
470 {
471 	// Reference layout uses std430 rules by default. std140 rules are
472 	// choosen only for blocks that have std140 layout.
473 	const bool	isStd140			= (layoutFlags & LAYOUT_STD140) != 0;
474 	const int	baseAlignment		= isStd140 ? computeStd140BaseAlignment(type, layoutFlags)
475 											   : computeStd430BaseAlignment(type, layoutFlags);
476 	int			curOffset			= deAlign32(baseOffset, baseAlignment);
477 	const int	topLevelArraySize	= 1; // Default values
478 	const int	topLevelArrayStride	= 0;
479 
480 	if (type.isBasicType())
481 	{
482 		const glu::DataType		basicType	= type.getBasicType();
483 		BufferVarLayoutEntry	entry;
484 
485 		entry.name					= curPrefix;
486 		entry.type					= basicType;
487 		entry.arraySize				= 1;
488 		entry.arrayStride			= 0;
489 		entry.matrixStride			= 0;
490 		entry.topLevelArraySize		= topLevelArraySize;
491 		entry.topLevelArrayStride	= topLevelArrayStride;
492 		entry.blockNdx				= curBlockNdx;
493 
494 		if (glu::isDataTypeMatrix(basicType))
495 		{
496 			// Array of vectors as specified in rules 5 & 7.
497 			const bool	isRowMajor			= !!(layoutFlags & LAYOUT_ROW_MAJOR);
498 			const int	numVecs				= isRowMajor ? glu::getDataTypeMatrixNumRows(basicType)
499 														 : glu::getDataTypeMatrixNumColumns(basicType);
500 
501 			entry.offset		= curOffset;
502 			entry.matrixStride	= baseAlignment;
503 			entry.isRowMajor	= isRowMajor;
504 
505 			curOffset += numVecs*baseAlignment;
506 		}
507 		else
508 		{
509 			// Scalar or vector.
510 			entry.offset = curOffset;
511 
512 			curOffset += getDataTypeByteSize(basicType);
513 		}
514 
515 		layout.bufferVars.push_back(entry);
516 	}
517 	else if (type.isArrayType())
518 	{
519 		const VarType&	elemType	= type.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				stride			= baseAlignment;
526 			BufferVarLayoutEntry	entry;
527 
528 			entry.name					= curPrefix + "[0]"; // Array variables are always postfixed with [0]
529 			entry.type					= elemBasicType;
530 			entry.blockNdx				= curBlockNdx;
531 			entry.offset				= curOffset;
532 			entry.arraySize				= type.getArraySize();
533 			entry.arrayStride			= stride;
534 			entry.matrixStride			= 0;
535 			entry.topLevelArraySize		= topLevelArraySize;
536 			entry.topLevelArrayStride	= topLevelArrayStride;
537 
538 			curOffset += stride*type.getArraySize();
539 
540 			layout.bufferVars.push_back(entry);
541 		}
542 		else if (elemType.isBasicType() && glu::isDataTypeMatrix(elemType.getBasicType()))
543 		{
544 			// Array of matrices.
545 			const glu::DataType			elemBasicType	= elemType.getBasicType();
546 			const bool					isRowMajor		= !!(layoutFlags & LAYOUT_ROW_MAJOR);
547 			const int					numVecs			= isRowMajor ? glu::getDataTypeMatrixNumRows(elemBasicType)
548 																	 : glu::getDataTypeMatrixNumColumns(elemBasicType);
549 			const int					vecStride		= baseAlignment;
550 			BufferVarLayoutEntry		entry;
551 
552 			entry.name					= curPrefix + "[0]"; // Array variables are always postfixed with [0]
553 			entry.type					= elemBasicType;
554 			entry.blockNdx				= curBlockNdx;
555 			entry.offset				= curOffset;
556 			entry.arraySize				= type.getArraySize();
557 			entry.arrayStride			= vecStride*numVecs;
558 			entry.matrixStride			= vecStride;
559 			entry.isRowMajor			= isRowMajor;
560 			entry.topLevelArraySize		= topLevelArraySize;
561 			entry.topLevelArrayStride	= topLevelArrayStride;
562 
563 			curOffset += numVecs*vecStride*type.getArraySize();
564 
565 			layout.bufferVars.push_back(entry);
566 		}
567 		else
568 		{
569 			DE_ASSERT(elemType.isStructType() || elemType.isArrayType());
570 
571 			for (int elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++)
572 				curOffset += computeReferenceLayout(layout, curBlockNdx, curOffset, curPrefix + "[" + de::toString(elemNdx) + "]", type.getElementType(), layoutFlags);
573 		}
574 	}
575 	else
576 	{
577 		DE_ASSERT(type.isStructType());
578 
579 		for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++)
580 			curOffset += computeReferenceLayout(layout, curBlockNdx, curOffset, curPrefix + "." + memberIter->getName(), memberIter->getType(), layoutFlags);
581 
582 		curOffset = deAlign32(curOffset, baseAlignment);
583 	}
584 
585 	return curOffset-baseOffset;
586 }
587 
588 //! 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)589 int computeReferenceLayout (BufferLayout& layout, int curBlockNdx, const std::string& blockPrefix, int baseOffset, const BufferVar& bufVar, deUint32 blockLayoutFlags)
590 {
591 	const VarType&	varType			= bufVar.getType();
592 	const deUint32	combinedFlags	= mergeLayoutFlags(blockLayoutFlags, bufVar.getFlags());
593 
594 	if (varType.isArrayType())
595 	{
596 		// Top-level arrays need special care.
597 		const int		topLevelArraySize	= varType.getArraySize() == VarType::UNSIZED_ARRAY ? 0 : varType.getArraySize();
598 		const string	prefix				= blockPrefix + bufVar.getName() + "[0]";
599 		const bool		isStd140			= (blockLayoutFlags & LAYOUT_STD140) != 0;
600 		const int		vec4Align			= (int)sizeof(deUint32)*4;
601 		const int		baseAlignment		= isStd140 ? computeStd140BaseAlignment(varType, combinedFlags)
602 													   : computeStd430BaseAlignment(varType, combinedFlags);
603 		int				curOffset			= deAlign32(baseOffset, baseAlignment);
604 		const VarType&	elemType			= varType.getElementType();
605 
606 		if (elemType.isBasicType() && !glu::isDataTypeMatrix(elemType.getBasicType()))
607 		{
608 			// Array of scalars or vectors.
609 			const glu::DataType		elemBasicType	= elemType.getBasicType();
610 			const int				elemBaseAlign	= getDataTypeByteAlignment(elemBasicType);
611 			const int				stride			= isStd140 ? deAlign32(elemBaseAlign, vec4Align) : elemBaseAlign;
612 			BufferVarLayoutEntry	entry;
613 
614 			entry.name					= prefix;
615 			entry.topLevelArraySize		= 1;
616 			entry.topLevelArrayStride	= 0;
617 			entry.type					= elemBasicType;
618 			entry.blockNdx				= curBlockNdx;
619 			entry.offset				= curOffset;
620 			entry.arraySize				= topLevelArraySize;
621 			entry.arrayStride			= stride;
622 			entry.matrixStride			= 0;
623 
624 			layout.bufferVars.push_back(entry);
625 
626 			curOffset += stride*topLevelArraySize;
627 		}
628 		else if (elemType.isBasicType() && glu::isDataTypeMatrix(elemType.getBasicType()))
629 		{
630 			// Array of matrices.
631 			const glu::DataType		elemBasicType	= elemType.getBasicType();
632 			const bool				isRowMajor		= !!(combinedFlags & LAYOUT_ROW_MAJOR);
633 			const int				vecSize			= isRowMajor ? glu::getDataTypeMatrixNumColumns(elemBasicType)
634 																 : glu::getDataTypeMatrixNumRows(elemBasicType);
635 			const int				numVecs			= isRowMajor ? glu::getDataTypeMatrixNumRows(elemBasicType)
636 																 : glu::getDataTypeMatrixNumColumns(elemBasicType);
637 			const glu::DataType		vecType			= glu::getDataTypeFloatVec(vecSize);
638 			const int				vecBaseAlign	= getDataTypeByteAlignment(vecType);
639 			const int				stride			= isStd140 ? deAlign32(vecBaseAlign, vec4Align) : vecBaseAlign;
640 			BufferVarLayoutEntry	entry;
641 
642 			entry.name					= prefix;
643 			entry.topLevelArraySize		= 1;
644 			entry.topLevelArrayStride	= 0;
645 			entry.type					= elemBasicType;
646 			entry.blockNdx				= curBlockNdx;
647 			entry.offset				= curOffset;
648 			entry.arraySize				= topLevelArraySize;
649 			entry.arrayStride			= stride*numVecs;
650 			entry.matrixStride			= stride;
651 			entry.isRowMajor			= isRowMajor;
652 
653 			layout.bufferVars.push_back(entry);
654 
655 			curOffset += stride*numVecs*topLevelArraySize;
656 		}
657 		else
658 		{
659 			DE_ASSERT(elemType.isStructType() || elemType.isArrayType());
660 
661 			// Struct base alignment is not added multiple times as curOffset supplied to computeReferenceLayout
662 			// was already aligned correctly. Thus computeReferenceLayout should not add any extra padding
663 			// before struct. Padding after struct will be added as it should.
664 			//
665 			// Stride could be computed prior to creating child elements, but it would essentially require running
666 			// the layout computation twice. Instead we fix stride to child elements afterwards.
667 
668 			const int	firstChildNdx	= (int)layout.bufferVars.size();
669 			const int	stride			= computeReferenceLayout(layout, curBlockNdx, curOffset, prefix, varType.getElementType(), combinedFlags);
670 
671 			for (int childNdx = firstChildNdx; childNdx < (int)layout.bufferVars.size(); childNdx++)
672 			{
673 				layout.bufferVars[childNdx].topLevelArraySize	= topLevelArraySize;
674 				layout.bufferVars[childNdx].topLevelArrayStride	= stride;
675 			}
676 
677 			curOffset += stride*topLevelArraySize;
678 		}
679 
680 		return curOffset-baseOffset;
681 	}
682 	else
683 		return computeReferenceLayout(layout, curBlockNdx, baseOffset, blockPrefix + bufVar.getName(), varType, combinedFlags);
684 }
685 
computeReferenceLayout(BufferLayout & layout,const ShaderInterface & interface)686 void computeReferenceLayout (BufferLayout& layout, const ShaderInterface& interface)
687 {
688 	int numBlocks = interface.getNumBlocks();
689 
690 	for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
691 	{
692 		const BufferBlock&	block			= interface.getBlock(blockNdx);
693 		bool				hasInstanceName	= block.getInstanceName() != DE_NULL;
694 		std::string			blockPrefix		= hasInstanceName ? (std::string(block.getBlockName()) + ".") : std::string("");
695 		int					curOffset		= 0;
696 		int					activeBlockNdx	= (int)layout.blocks.size();
697 		int					firstVarNdx		= (int)layout.bufferVars.size();
698 
699 		for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++)
700 		{
701 			const BufferVar& bufVar = *varIter;
702 			curOffset += computeReferenceLayout(layout, activeBlockNdx,  blockPrefix, curOffset, bufVar, block.getFlags());
703 		}
704 
705 		int	varIndicesEnd	= (int)layout.bufferVars.size();
706 		int	blockSize		= curOffset;
707 		int	numInstances	= block.isArray() ? block.getArraySize() : 1;
708 
709 		// Create block layout entries for each instance.
710 		for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
711 		{
712 			// Allocate entry for instance.
713 			layout.blocks.push_back(BlockLayoutEntry());
714 			BlockLayoutEntry& blockEntry = layout.blocks.back();
715 
716 			blockEntry.name = block.getBlockName();
717 			blockEntry.size = blockSize;
718 
719 			// Compute active variable set for block.
720 			for (int varNdx = firstVarNdx; varNdx < varIndicesEnd; varNdx++)
721 				blockEntry.activeVarIndices.push_back(varNdx);
722 
723 			if (block.isArray())
724 				blockEntry.name += "[" + de::toString(instanceNdx) + "]";
725 		}
726 	}
727 }
728 
729 // Value generator.
730 
generateValue(const BufferVarLayoutEntry & entry,int unsizedArraySize,void * basePtr,de::Random & rnd)731 void generateValue (const BufferVarLayoutEntry& entry, int unsizedArraySize, void* basePtr, de::Random& rnd)
732 {
733 	const glu::DataType	scalarType		= glu::getDataTypeScalarType(entry.type);
734 	const int			scalarSize		= glu::getDataTypeScalarSize(entry.type);
735 	const int			arraySize		= entry.arraySize == 0 ? unsizedArraySize : entry.arraySize;
736 	const int			arrayStride		= entry.arrayStride;
737 	const int			topLevelSize	= entry.topLevelArraySize == 0 ? unsizedArraySize : entry.topLevelArraySize;
738 	const int			topLevelStride	= entry.topLevelArrayStride;
739 	const bool			isMatrix		= glu::isDataTypeMatrix(entry.type);
740 	const int			numVecs			= isMatrix ? (entry.isRowMajor ? glu::getDataTypeMatrixNumRows(entry.type) : glu::getDataTypeMatrixNumColumns(entry.type)) : 1;
741 	const int			vecSize			= scalarSize / numVecs;
742 	const int			compSize		= sizeof(deUint32);
743 
744 	DE_ASSERT(scalarSize%numVecs == 0);
745 	DE_ASSERT(topLevelSize >= 0);
746 	DE_ASSERT(arraySize >= 0);
747 
748 	for (int topElemNdx = 0; topElemNdx < topLevelSize; topElemNdx++)
749 	{
750 		deUint8* const topElemPtr = (deUint8*)basePtr + entry.offset + topElemNdx*topLevelStride;
751 
752 		for (int elemNdx = 0; elemNdx < arraySize; elemNdx++)
753 		{
754 			deUint8* const elemPtr = topElemPtr + elemNdx*arrayStride;
755 
756 			for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
757 			{
758 				deUint8* const vecPtr = elemPtr + (isMatrix ? vecNdx*entry.matrixStride : 0);
759 
760 				for (int compNdx = 0; compNdx < vecSize; compNdx++)
761 				{
762 					deUint8* const compPtr = vecPtr + compSize*compNdx;
763 
764 					switch (scalarType)
765 					{
766 						case glu::TYPE_FLOAT:	*((float*)compPtr)		= (float)rnd.getInt(-9, 9);						break;
767 						case glu::TYPE_INT:		*((int*)compPtr)		= rnd.getInt(-9, 9);							break;
768 						case glu::TYPE_UINT:	*((deUint32*)compPtr)	= (deUint32)rnd.getInt(0, 9);					break;
769 						// \note Random bit pattern is used for true values. Spec states that all non-zero values are
770 						//       interpreted as true but some implementations fail this.
771 						case glu::TYPE_BOOL:	*((deUint32*)compPtr)	= rnd.getBool() ? rnd.getUint32()|1u : 0u;		break;
772 						default:
773 							DE_ASSERT(false);
774 					}
775 				}
776 			}
777 		}
778 	}
779 }
780 
generateValues(const BufferLayout & layout,const vector<BlockDataPtr> & blockPointers,deUint32 seed)781 void generateValues (const BufferLayout& layout, const vector<BlockDataPtr>& blockPointers, deUint32 seed)
782 {
783 	de::Random	rnd			(seed);
784 	const int	numBlocks	= (int)layout.blocks.size();
785 
786 	DE_ASSERT(numBlocks == (int)blockPointers.size());
787 
788 	for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
789 	{
790 		const BlockLayoutEntry&	blockLayout	= layout.blocks[blockNdx];
791 		const BlockDataPtr&		blockPtr	= blockPointers[blockNdx];
792 		const int				numEntries	= (int)layout.blocks[blockNdx].activeVarIndices.size();
793 
794 		for (int entryNdx = 0; entryNdx < numEntries; entryNdx++)
795 		{
796 			const int					varNdx		= blockLayout.activeVarIndices[entryNdx];
797 			const BufferVarLayoutEntry&	varEntry	= layout.bufferVars[varNdx];
798 
799 			generateValue(varEntry, blockPtr.lastUnsizedArraySize, blockPtr.ptr, rnd);
800 		}
801 	}
802 }
803 
804 // Shader generator.
805 
getCompareFuncForType(glu::DataType type)806 const char* getCompareFuncForType (glu::DataType type)
807 {
808 	switch (type)
809 	{
810 		case glu::TYPE_FLOAT:			return "bool compare_float    (highp float a, highp float b)  { return abs(a - b) < 0.05; }\n";
811 		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";
812 		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";
813 		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";
814 		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";
815 		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";
816 		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";
817 		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";
818 		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";
819 		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";
820 		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";
821 		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";
822 		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";
823 		case glu::TYPE_INT:				return "bool compare_int      (highp int a, highp int b)      { return a == b; }\n";
824 		case glu::TYPE_INT_VEC2:		return "bool compare_ivec2    (highp ivec2 a, highp ivec2 b)  { return a == b; }\n";
825 		case glu::TYPE_INT_VEC3:		return "bool compare_ivec3    (highp ivec3 a, highp ivec3 b)  { return a == b; }\n";
826 		case glu::TYPE_INT_VEC4:		return "bool compare_ivec4    (highp ivec4 a, highp ivec4 b)  { return a == b; }\n";
827 		case glu::TYPE_UINT:			return "bool compare_uint     (highp uint a, highp uint b)    { return a == b; }\n";
828 		case glu::TYPE_UINT_VEC2:		return "bool compare_uvec2    (highp uvec2 a, highp uvec2 b)  { return a == b; }\n";
829 		case glu::TYPE_UINT_VEC3:		return "bool compare_uvec3    (highp uvec3 a, highp uvec3 b)  { return a == b; }\n";
830 		case glu::TYPE_UINT_VEC4:		return "bool compare_uvec4    (highp uvec4 a, highp uvec4 b)  { return a == b; }\n";
831 		case glu::TYPE_BOOL:			return "bool compare_bool     (bool a, bool b)                { return a == b; }\n";
832 		case glu::TYPE_BOOL_VEC2:		return "bool compare_bvec2    (bvec2 a, bvec2 b)              { return a == b; }\n";
833 		case glu::TYPE_BOOL_VEC3:		return "bool compare_bvec3    (bvec3 a, bvec3 b)              { return a == b; }\n";
834 		case glu::TYPE_BOOL_VEC4:		return "bool compare_bvec4    (bvec4 a, bvec4 b)              { return a == b; }\n";
835 		default:
836 			DE_ASSERT(false);
837 			return DE_NULL;
838 	}
839 }
840 
getCompareDependencies(std::set<glu::DataType> & compareFuncs,glu::DataType basicType)841 void getCompareDependencies (std::set<glu::DataType>& compareFuncs, glu::DataType basicType)
842 {
843 	switch (basicType)
844 	{
845 		case glu::TYPE_FLOAT_VEC2:
846 		case glu::TYPE_FLOAT_VEC3:
847 		case glu::TYPE_FLOAT_VEC4:
848 			compareFuncs.insert(glu::TYPE_FLOAT);
849 			compareFuncs.insert(basicType);
850 			break;
851 
852 		case glu::TYPE_FLOAT_MAT2:
853 		case glu::TYPE_FLOAT_MAT2X3:
854 		case glu::TYPE_FLOAT_MAT2X4:
855 		case glu::TYPE_FLOAT_MAT3X2:
856 		case glu::TYPE_FLOAT_MAT3:
857 		case glu::TYPE_FLOAT_MAT3X4:
858 		case glu::TYPE_FLOAT_MAT4X2:
859 		case glu::TYPE_FLOAT_MAT4X3:
860 		case glu::TYPE_FLOAT_MAT4:
861 			compareFuncs.insert(glu::TYPE_FLOAT);
862 			compareFuncs.insert(glu::getDataTypeFloatVec(glu::getDataTypeMatrixNumRows(basicType)));
863 			compareFuncs.insert(basicType);
864 			break;
865 
866 		default:
867 			compareFuncs.insert(basicType);
868 			break;
869 	}
870 }
871 
collectUniqueBasicTypes(std::set<glu::DataType> & basicTypes,const VarType & type)872 void collectUniqueBasicTypes (std::set<glu::DataType>& basicTypes, const VarType& type)
873 {
874 	if (type.isStructType())
875 	{
876 		for (StructType::ConstIterator iter = type.getStructPtr()->begin(); iter != type.getStructPtr()->end(); ++iter)
877 			collectUniqueBasicTypes(basicTypes, iter->getType());
878 	}
879 	else if (type.isArrayType())
880 		collectUniqueBasicTypes(basicTypes, type.getElementType());
881 	else
882 	{
883 		DE_ASSERT(type.isBasicType());
884 		basicTypes.insert(type.getBasicType());
885 	}
886 }
887 
collectUniqueBasicTypes(std::set<glu::DataType> & basicTypes,const BufferBlock & bufferBlock)888 void collectUniqueBasicTypes (std::set<glu::DataType>& basicTypes, const BufferBlock& bufferBlock)
889 {
890 	for (BufferBlock::const_iterator iter = bufferBlock.begin(); iter != bufferBlock.end(); ++iter)
891 		collectUniqueBasicTypes(basicTypes, iter->getType());
892 }
893 
collectUniqueBasicTypes(std::set<glu::DataType> & basicTypes,const ShaderInterface & interface)894 void collectUniqueBasicTypes (std::set<glu::DataType>& basicTypes, const ShaderInterface& interface)
895 {
896 	for (int ndx = 0; ndx < interface.getNumBlocks(); ++ndx)
897 		collectUniqueBasicTypes(basicTypes, interface.getBlock(ndx));
898 }
899 
generateCompareFuncs(std::ostream & str,const ShaderInterface & interface)900 void generateCompareFuncs (std::ostream& str, const ShaderInterface& interface)
901 {
902 	std::set<glu::DataType> types;
903 	std::set<glu::DataType> compareFuncs;
904 
905 	// Collect unique basic types
906 	collectUniqueBasicTypes(types, interface);
907 
908 	// Set of compare functions required
909 	for (std::set<glu::DataType>::const_iterator iter = types.begin(); iter != types.end(); ++iter)
910 	{
911 		getCompareDependencies(compareFuncs, *iter);
912 	}
913 
914 	for (int type = 0; type < glu::TYPE_LAST; ++type)
915 	{
916 		if (compareFuncs.find(glu::DataType(type)) != compareFuncs.end())
917 			str << getCompareFuncForType(glu::DataType(type));
918 	}
919 }
920 
921 struct Indent
922 {
923 	int level;
Indentdeqp::gles31::bb::__anon69309db60211::Indent924 	Indent (int level_) : level(level_) {}
925 };
926 
operator <<(std::ostream & str,const Indent & indent)927 std::ostream& operator<< (std::ostream& str, const Indent& indent)
928 {
929 	for (int i = 0; i < indent.level; i++)
930 		str << "\t";
931 	return str;
932 }
933 
generateDeclaration(std::ostream & src,const BufferVar & bufferVar,int indentLevel)934 void generateDeclaration (std::ostream& src, const BufferVar& bufferVar, int indentLevel)
935 {
936 	// \todo [pyry] Qualifiers
937 
938 	if ((bufferVar.getFlags() & LAYOUT_MASK) != 0)
939 		src << "layout(" << LayoutFlagsFmt(bufferVar.getFlags() & LAYOUT_MASK) << ") ";
940 
941 	src << glu::declare(bufferVar.getType(), bufferVar.getName(), indentLevel);
942 }
943 
generateDeclaration(std::ostream & src,const BufferBlock & block,int bindingPoint)944 void generateDeclaration (std::ostream& src, const BufferBlock& block, int bindingPoint)
945 {
946 	src << "layout(";
947 
948 	if ((block.getFlags() & LAYOUT_MASK) != 0)
949 		src << LayoutFlagsFmt(block.getFlags() & LAYOUT_MASK) << ", ";
950 
951 	src << "binding = " << bindingPoint;
952 
953 	src << ") ";
954 
955 	src << "buffer " << block.getBlockName();
956 	src << "\n{\n";
957 
958 	for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++)
959 	{
960 		src << Indent(1);
961 		generateDeclaration(src, *varIter, 1 /* indent level */);
962 		src << ";\n";
963 	}
964 
965 	src << "}";
966 
967 	if (block.getInstanceName() != DE_NULL)
968 	{
969 		src << " " << block.getInstanceName();
970 		if (block.isArray())
971 			src << "[" << block.getArraySize() << "]";
972 	}
973 	else
974 		DE_ASSERT(!block.isArray());
975 
976 	src << ";\n";
977 }
978 
generateImmMatrixSrc(std::ostream & src,glu::DataType basicType,int matrixStride,bool isRowMajor,const void * valuePtr)979 void generateImmMatrixSrc (std::ostream& src, glu::DataType basicType, int matrixStride, bool isRowMajor, const void* valuePtr)
980 {
981 	DE_ASSERT(glu::isDataTypeMatrix(basicType));
982 
983 	const int		compSize		= sizeof(deUint32);
984 	const int		numRows			= glu::getDataTypeMatrixNumRows(basicType);
985 	const int		numCols			= glu::getDataTypeMatrixNumColumns(basicType);
986 
987 	src << glu::getDataTypeName(basicType) << "(";
988 
989 	// Constructed in column-wise order.
990 	for (int colNdx = 0; colNdx < numCols; colNdx++)
991 	{
992 		for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
993 		{
994 			const deUint8*	compPtr	= (const deUint8*)valuePtr + (isRowMajor ? rowNdx*matrixStride + colNdx*compSize
995 																				: colNdx*matrixStride + rowNdx*compSize);
996 
997 			if (colNdx > 0 || rowNdx > 0)
998 				src << ", ";
999 
1000 			src << de::floatToString(*((const float*)compPtr), 1);
1001 		}
1002 	}
1003 
1004 	src << ")";
1005 }
1006 
generateImmScalarVectorSrc(std::ostream & src,glu::DataType basicType,const void * valuePtr)1007 void generateImmScalarVectorSrc (std::ostream& src, glu::DataType basicType, const void* valuePtr)
1008 {
1009 	DE_ASSERT(glu::isDataTypeFloatOrVec(basicType)	||
1010 			  glu::isDataTypeIntOrIVec(basicType)	||
1011 			  glu::isDataTypeUintOrUVec(basicType)	||
1012 			  glu::isDataTypeBoolOrBVec(basicType));
1013 
1014 	const glu::DataType		scalarType		= glu::getDataTypeScalarType(basicType);
1015 	const int				scalarSize		= glu::getDataTypeScalarSize(basicType);
1016 	const int				compSize		= sizeof(deUint32);
1017 
1018 	if (scalarSize > 1)
1019 		src << glu::getDataTypeName(basicType) << "(";
1020 
1021 	for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
1022 	{
1023 		const deUint8* compPtr = (const deUint8*)valuePtr + scalarNdx*compSize;
1024 
1025 		if (scalarNdx > 0)
1026 			src << ", ";
1027 
1028 		switch (scalarType)
1029 		{
1030 			case glu::TYPE_FLOAT:	src << de::floatToString(*((const float*)compPtr), 1);			break;
1031 			case glu::TYPE_INT:		src << *((const int*)compPtr);									break;
1032 			case glu::TYPE_UINT:	src << *((const deUint32*)compPtr) << "u";						break;
1033 			case glu::TYPE_BOOL:	src << (*((const deUint32*)compPtr) != 0u ? "true" : "false");	break;
1034 			default:
1035 				DE_ASSERT(false);
1036 		}
1037 	}
1038 
1039 	if (scalarSize > 1)
1040 		src << ")";
1041 }
1042 
getAPIName(const BufferBlock & block,const BufferVar & var,const glu::TypeComponentVector & accessPath)1043 string getAPIName (const BufferBlock& block, const BufferVar& var, const glu::TypeComponentVector& accessPath)
1044 {
1045 	std::ostringstream name;
1046 
1047 	if (block.getInstanceName())
1048 		name << block.getBlockName() << ".";
1049 
1050 	name << var.getName();
1051 
1052 	for (glu::TypeComponentVector::const_iterator pathComp = accessPath.begin(); pathComp != accessPath.end(); pathComp++)
1053 	{
1054 		if (pathComp->type == glu::VarTypeComponent::STRUCT_MEMBER)
1055 		{
1056 			const VarType		curType		= glu::getVarType(var.getType(), accessPath.begin(), pathComp);
1057 			const StructType*	structPtr	= curType.getStructPtr();
1058 
1059 			name << "." << structPtr->getMember(pathComp->index).getName();
1060 		}
1061 		else if (pathComp->type == glu::VarTypeComponent::ARRAY_ELEMENT)
1062 		{
1063 			if (pathComp == accessPath.begin() || (pathComp+1) == accessPath.end())
1064 				name << "[0]"; // Top- / bottom-level array
1065 			else
1066 				name << "[" << pathComp->index << "]";
1067 		}
1068 		else
1069 			DE_ASSERT(false);
1070 	}
1071 
1072 	return name.str();
1073 }
1074 
getShaderName(const BufferBlock & block,int instanceNdx,const BufferVar & var,const glu::TypeComponentVector & accessPath)1075 string getShaderName (const BufferBlock& block, int instanceNdx, const BufferVar& var, const glu::TypeComponentVector& accessPath)
1076 {
1077 	std::ostringstream name;
1078 
1079 	if (block.getInstanceName())
1080 	{
1081 		name << block.getInstanceName();
1082 
1083 		if (block.isArray())
1084 			name << "[" << instanceNdx << "]";
1085 
1086 		name << ".";
1087 	}
1088 	else
1089 		DE_ASSERT(instanceNdx == 0);
1090 
1091 	name << var.getName();
1092 
1093 	for (glu::TypeComponentVector::const_iterator pathComp = accessPath.begin(); pathComp != accessPath.end(); pathComp++)
1094 	{
1095 		if (pathComp->type == glu::VarTypeComponent::STRUCT_MEMBER)
1096 		{
1097 			const VarType		curType		= glu::getVarType(var.getType(), accessPath.begin(), pathComp);
1098 			const StructType*	structPtr	= curType.getStructPtr();
1099 
1100 			name << "." << structPtr->getMember(pathComp->index).getName();
1101 		}
1102 		else if (pathComp->type == glu::VarTypeComponent::ARRAY_ELEMENT)
1103 			name << "[" << pathComp->index << "]";
1104 		else
1105 			DE_ASSERT(false);
1106 	}
1107 
1108 	return name.str();
1109 }
1110 
computeOffset(const BufferVarLayoutEntry & varLayout,const glu::TypeComponentVector & accessPath)1111 int computeOffset (const BufferVarLayoutEntry& varLayout, const glu::TypeComponentVector& accessPath)
1112 {
1113 	const int	topLevelNdx		= (accessPath.size() > 1 && accessPath.front().type == glu::VarTypeComponent::ARRAY_ELEMENT) ? accessPath.front().index : 0;
1114 	const int	bottomLevelNdx	= (!accessPath.empty() && accessPath.back().type == glu::VarTypeComponent::ARRAY_ELEMENT) ? accessPath.back().index : 0;
1115 
1116 	return varLayout.offset + varLayout.topLevelArrayStride*topLevelNdx + varLayout.arrayStride*bottomLevelNdx;
1117 }
1118 
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)1119 void generateCompareSrc (
1120 	std::ostream&				src,
1121 	const char*					resultVar,
1122 	const BufferLayout&			bufferLayout,
1123 	const BufferBlock&			block,
1124 	int							instanceNdx,
1125 	const BlockDataPtr&			blockPtr,
1126 	const BufferVar&			bufVar,
1127 	const glu::SubTypeAccess&	accessPath)
1128 {
1129 	const VarType curType = accessPath.getType();
1130 
1131 	if (curType.isArrayType())
1132 	{
1133 		const int arraySize = curType.getArraySize() == VarType::UNSIZED_ARRAY ? block.getLastUnsizedArraySize(instanceNdx) : curType.getArraySize();
1134 
1135 		for (int elemNdx = 0; elemNdx < arraySize; elemNdx++)
1136 			generateCompareSrc(src, resultVar, bufferLayout, block, instanceNdx, blockPtr, bufVar, accessPath.element(elemNdx));
1137 	}
1138 	else if (curType.isStructType())
1139 	{
1140 		const int numMembers = curType.getStructPtr()->getNumMembers();
1141 
1142 		for (int memberNdx = 0; memberNdx < numMembers; memberNdx++)
1143 			generateCompareSrc(src, resultVar, bufferLayout, block, instanceNdx, blockPtr, bufVar, accessPath.member(memberNdx));
1144 	}
1145 	else
1146 	{
1147 		DE_ASSERT(curType.isBasicType());
1148 
1149 		const string	apiName	= getAPIName(block, bufVar, accessPath.getPath());
1150 		const int		varNdx	= bufferLayout.getVariableIndex(apiName);
1151 
1152 		DE_ASSERT(varNdx >= 0);
1153 		{
1154 			const BufferVarLayoutEntry&	varLayout		= bufferLayout.bufferVars[varNdx];
1155 			const string				shaderName		= getShaderName(block, instanceNdx, bufVar, accessPath.getPath());
1156 			const glu::DataType			basicType		= curType.getBasicType();
1157 			const bool					isMatrix		= glu::isDataTypeMatrix(basicType);
1158 			const char*					typeName		= glu::getDataTypeName(basicType);
1159 			const void*					valuePtr		= (const deUint8*)blockPtr.ptr + computeOffset(varLayout, accessPath.getPath());
1160 
1161 			src << "\t" << resultVar << " = " << resultVar << " && compare_" << typeName << "(" << shaderName << ", ";
1162 
1163 			if (isMatrix)
1164 				generateImmMatrixSrc(src, basicType, varLayout.matrixStride, varLayout.isRowMajor, valuePtr);
1165 			else
1166 				generateImmScalarVectorSrc(src, basicType, valuePtr);
1167 
1168 			src << ");\n";
1169 		}
1170 	}
1171 }
1172 
generateCompareSrc(std::ostream & src,const char * resultVar,const ShaderInterface & interface,const BufferLayout & layout,const vector<BlockDataPtr> & blockPointers)1173 void generateCompareSrc (std::ostream& src, const char* resultVar, const ShaderInterface& interface, const BufferLayout& layout, const vector<BlockDataPtr>& blockPointers)
1174 {
1175 	for (int declNdx = 0; declNdx < interface.getNumBlocks(); declNdx++)
1176 	{
1177 		const BufferBlock&	block			= interface.getBlock(declNdx);
1178 		const bool			isArray			= block.isArray();
1179 		const int			numInstances	= isArray ? block.getArraySize() : 1;
1180 
1181 		DE_ASSERT(!isArray || block.getInstanceName());
1182 
1183 		for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1184 		{
1185 			const string		instanceName	= block.getBlockName() + (isArray ? "[" + de::toString(instanceNdx) + "]" : string(""));
1186 			const int			blockNdx		= layout.getBlockIndex(instanceName);
1187 			const BlockDataPtr&	blockPtr		= blockPointers[blockNdx];
1188 
1189 			for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++)
1190 			{
1191 				const BufferVar& bufVar = *varIter;
1192 
1193 				if ((bufVar.getFlags() & ACCESS_READ) == 0)
1194 					continue; // Don't read from that variable.
1195 
1196 				generateCompareSrc(src, resultVar, layout, block, instanceNdx, blockPtr, bufVar, glu::SubTypeAccess(bufVar.getType()));
1197 			}
1198 		}
1199 	}
1200 }
1201 
1202 // \todo [2013-10-14 pyry] Almost identical to generateCompareSrc - unify?
1203 
generateWriteSrc(std::ostream & src,const BufferLayout & bufferLayout,const BufferBlock & block,int instanceNdx,const BlockDataPtr & blockPtr,const BufferVar & bufVar,const glu::SubTypeAccess & accessPath)1204 void generateWriteSrc (
1205 	std::ostream&				src,
1206 	const BufferLayout&			bufferLayout,
1207 	const BufferBlock&			block,
1208 	int							instanceNdx,
1209 	const BlockDataPtr&			blockPtr,
1210 	const BufferVar&			bufVar,
1211 	const glu::SubTypeAccess&	accessPath)
1212 {
1213 	const VarType curType = accessPath.getType();
1214 
1215 	if (curType.isArrayType())
1216 	{
1217 		const int arraySize = curType.getArraySize() == VarType::UNSIZED_ARRAY ? block.getLastUnsizedArraySize(instanceNdx) : curType.getArraySize();
1218 
1219 		for (int elemNdx = 0; elemNdx < arraySize; elemNdx++)
1220 			generateWriteSrc(src, bufferLayout, block, instanceNdx, blockPtr, bufVar, accessPath.element(elemNdx));
1221 	}
1222 	else if (curType.isStructType())
1223 	{
1224 		const int numMembers = curType.getStructPtr()->getNumMembers();
1225 
1226 		for (int memberNdx = 0; memberNdx < numMembers; memberNdx++)
1227 			generateWriteSrc(src, bufferLayout, block, instanceNdx, blockPtr, bufVar, accessPath.member(memberNdx));
1228 	}
1229 	else
1230 	{
1231 		DE_ASSERT(curType.isBasicType());
1232 
1233 		const string	apiName	= getAPIName(block, bufVar, accessPath.getPath());
1234 		const int		varNdx	= bufferLayout.getVariableIndex(apiName);
1235 
1236 		DE_ASSERT(varNdx >= 0);
1237 		{
1238 			const BufferVarLayoutEntry&	varLayout		= bufferLayout.bufferVars[varNdx];
1239 			const string				shaderName		= getShaderName(block, instanceNdx, bufVar, accessPath.getPath());
1240 			const glu::DataType			basicType		= curType.getBasicType();
1241 			const bool					isMatrix		= glu::isDataTypeMatrix(basicType);
1242 			const void*					valuePtr		= (const deUint8*)blockPtr.ptr + computeOffset(varLayout, accessPath.getPath());
1243 
1244 			src << "\t" << shaderName << " = ";
1245 
1246 			if (isMatrix)
1247 				generateImmMatrixSrc(src, basicType, varLayout.matrixStride, varLayout.isRowMajor, valuePtr);
1248 			else
1249 				generateImmScalarVectorSrc(src, basicType, valuePtr);
1250 
1251 			src << ";\n";
1252 		}
1253 	}
1254 }
1255 
generateWriteSrc(std::ostream & src,const ShaderInterface & interface,const BufferLayout & layout,const vector<BlockDataPtr> & blockPointers)1256 void generateWriteSrc (std::ostream& src, const ShaderInterface& interface, const BufferLayout& layout, const vector<BlockDataPtr>& blockPointers)
1257 {
1258 	for (int declNdx = 0; declNdx < interface.getNumBlocks(); declNdx++)
1259 	{
1260 		const BufferBlock&	block			= interface.getBlock(declNdx);
1261 		const bool			isArray			= block.isArray();
1262 		const int			numInstances	= isArray ? block.getArraySize() : 1;
1263 
1264 		DE_ASSERT(!isArray || block.getInstanceName());
1265 
1266 		for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1267 		{
1268 			const string		instanceName	= block.getBlockName() + (isArray ? "[" + de::toString(instanceNdx) + "]" : string(""));
1269 			const int			blockNdx		= layout.getBlockIndex(instanceName);
1270 			const BlockDataPtr&	blockPtr		= blockPointers[blockNdx];
1271 
1272 			for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++)
1273 			{
1274 				const BufferVar& bufVar = *varIter;
1275 
1276 				if ((bufVar.getFlags() & ACCESS_WRITE) == 0)
1277 					continue; // Don't write to that variable.
1278 
1279 				generateWriteSrc(src, layout, block, instanceNdx, blockPtr, bufVar, glu::SubTypeAccess(bufVar.getType()));
1280 			}
1281 		}
1282 	}
1283 }
1284 
generateComputeShader(const glw::Functions & gl,glu::GLSLVersion glslVersion,const ShaderInterface & interface,const BufferLayout & layout,const vector<BlockDataPtr> & comparePtrs,const vector<BlockDataPtr> & writePtrs)1285 string generateComputeShader (const glw::Functions& gl, glu::GLSLVersion glslVersion, const ShaderInterface& interface, const BufferLayout& layout, const vector<BlockDataPtr>& comparePtrs, const vector<BlockDataPtr>& writePtrs)
1286 {
1287 	std::ostringstream src;
1288 	glw::GLint maxShaderStorageBufferBindings;
1289 	glw::GLint maxComputeShaderStorageBlocks;
1290 
1291 	DE_ASSERT(glslVersion == glu::GLSL_VERSION_310_ES || glslVersion == glu::GLSL_VERSION_430);
1292 
1293 	gl.getIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, &maxShaderStorageBufferBindings);
1294 	gl.getIntegerv(GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS, &maxComputeShaderStorageBlocks);
1295 
1296 	src << glu::getGLSLVersionDeclaration(glslVersion) << "\n";
1297 	src << "layout(local_size_x = 1) in;\n";
1298 	src << "\n";
1299 
1300 	std::vector<const StructType*> namedStructs;
1301 	interface.getNamedStructs(namedStructs);
1302 	for (std::vector<const StructType*>::const_iterator structIter = namedStructs.begin(); structIter != namedStructs.end(); structIter++)
1303 		src << glu::declare(*structIter) << ";\n";
1304 
1305 	{
1306 		int bindingPoint = 0;
1307 
1308 		for (int blockNdx = 0; blockNdx < interface.getNumBlocks(); blockNdx++)
1309 		{
1310 			const BufferBlock& block = interface.getBlock(blockNdx);
1311 			generateDeclaration(src, block, bindingPoint);
1312 
1313 			bindingPoint += block.isArray() ? block.getArraySize() : 1;
1314 		}
1315 
1316 		if (bindingPoint > maxShaderStorageBufferBindings)
1317 		{
1318 			throw tcu::NotSupportedError("Test requires support for more SSBO bindings than implementation exposes");
1319 		}
1320 		if (bindingPoint > maxComputeShaderStorageBlocks)
1321 		{
1322 			throw tcu::NotSupportedError("Test requires support for more compute shader storage blocks than implementation exposes");
1323 		}
1324 	}
1325 
1326 	// Atomic counter for counting passed invocations.
1327 	src << "\nlayout(binding = 0) uniform atomic_uint ac_numPassed;\n";
1328 
1329 	// Comparison utilities.
1330 	src << "\n";
1331 	generateCompareFuncs(src, interface);
1332 
1333 	src << "\n"
1334 		   "void main (void)\n"
1335 		   "{\n"
1336 		   "	bool allOk = true;\n";
1337 
1338 	// Value compare.
1339 	generateCompareSrc(src, "allOk", interface, layout, comparePtrs);
1340 
1341 	src << "	if (allOk)\n"
1342 		<< "		atomicCounterIncrement(ac_numPassed);\n"
1343 		<< "\n";
1344 
1345 	// Value write.
1346 	generateWriteSrc(src, interface, layout, writePtrs);
1347 
1348 	src << "}\n";
1349 
1350 	return src.str();
1351 }
1352 
getGLBufferLayout(const glw::Functions & gl,BufferLayout & layout,deUint32 program)1353 void getGLBufferLayout (const glw::Functions& gl, BufferLayout& layout, deUint32 program)
1354 {
1355 	int		numActiveBufferVars	= 0;
1356 	int		numActiveBlocks		= 0;
1357 
1358 	gl.getProgramInterfaceiv(program, GL_BUFFER_VARIABLE,		GL_ACTIVE_RESOURCES,	&numActiveBufferVars);
1359 	gl.getProgramInterfaceiv(program, GL_SHADER_STORAGE_BLOCK,	GL_ACTIVE_RESOURCES,	&numActiveBlocks);
1360 
1361 	GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to get number of buffer variables and buffer blocks");
1362 
1363 	// Block entries.
1364 	layout.blocks.resize(numActiveBlocks);
1365 	for (int blockNdx = 0; blockNdx < numActiveBlocks; blockNdx++)
1366 	{
1367 		BlockLayoutEntry&	entry				= layout.blocks[blockNdx];
1368 		const deUint32		queryParams[]		= { GL_BUFFER_DATA_SIZE, GL_NUM_ACTIVE_VARIABLES, GL_NAME_LENGTH };
1369 		int					returnValues[]		= { 0, 0, 0 };
1370 
1371 		DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(queryParams) == DE_LENGTH_OF_ARRAY(returnValues));
1372 
1373 		{
1374 			int returnLength = 0;
1375 			gl.getProgramResourceiv(program, GL_SHADER_STORAGE_BLOCK, (deUint32)blockNdx, DE_LENGTH_OF_ARRAY(queryParams), &queryParams[0], DE_LENGTH_OF_ARRAY(returnValues), &returnLength, &returnValues[0]);
1376 			GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceiv(GL_SHADER_STORAGE_BLOCK) failed");
1377 
1378 			if (returnLength != DE_LENGTH_OF_ARRAY(returnValues))
1379 				throw tcu::TestError("glGetProgramResourceiv(GL_SHADER_STORAGE_BLOCK) returned wrong number of values");
1380 		}
1381 
1382 		entry.size = returnValues[0];
1383 
1384 		// Query active variables
1385 		if (returnValues[1] > 0)
1386 		{
1387 			const int		numBlockVars	= returnValues[1];
1388 			const deUint32	queryArg		= GL_ACTIVE_VARIABLES;
1389 			int				retLength		= 0;
1390 
1391 			entry.activeVarIndices.resize(numBlockVars);
1392 			gl.getProgramResourceiv(program, GL_SHADER_STORAGE_BLOCK, (deUint32)blockNdx, 1, &queryArg, numBlockVars, &retLength, &entry.activeVarIndices[0]);
1393 			GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceiv(GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_VARIABLES) failed");
1394 
1395 			if (retLength != numBlockVars)
1396 				throw tcu::TestError("glGetProgramResourceiv(GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_VARIABLES) returned wrong number of values");
1397 		}
1398 
1399 		// Query name
1400 		if (returnValues[2] > 0)
1401 		{
1402 			const int		nameLen		= returnValues[2];
1403 			int				retLen		= 0;
1404 			vector<char>	name		(nameLen);
1405 
1406 			gl.getProgramResourceName(program, GL_SHADER_STORAGE_BLOCK, (deUint32)blockNdx, (glw::GLsizei)name.size(), &retLen, &name[0]);
1407 			GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceName(GL_SHADER_STORAGE_BLOCK) failed");
1408 
1409 			if (retLen+1 != nameLen)
1410 				throw tcu::TestError("glGetProgramResourceName(GL_SHADER_STORAGE_BLOCK) returned invalid name. Number of characters written is inconsistent with NAME_LENGTH property.");
1411 			if (name[nameLen-1] != 0)
1412 				throw tcu::TestError("glGetProgramResourceName(GL_SHADER_STORAGE_BLOCK) returned invalid name. Expected null terminator at index " + de::toString(nameLen-1));
1413 
1414 			entry.name = &name[0];
1415 		}
1416 		else
1417 			throw tcu::TestError("glGetProgramResourceiv() returned invalid GL_NAME_LENGTH");
1418 	}
1419 
1420 	layout.bufferVars.resize(numActiveBufferVars);
1421 	for (int bufVarNdx = 0; bufVarNdx < numActiveBufferVars; bufVarNdx++)
1422 	{
1423 		BufferVarLayoutEntry&	entry				= layout.bufferVars[bufVarNdx];
1424 		const deUint32			queryParams[] =
1425 		{
1426 			GL_BLOCK_INDEX,					// 0
1427 			GL_TYPE,						// 1
1428 			GL_OFFSET,						// 2
1429 			GL_ARRAY_SIZE,					// 3
1430 			GL_ARRAY_STRIDE,				// 4
1431 			GL_MATRIX_STRIDE,				// 5
1432 			GL_TOP_LEVEL_ARRAY_SIZE,		// 6
1433 			GL_TOP_LEVEL_ARRAY_STRIDE,		// 7
1434 			GL_IS_ROW_MAJOR,				// 8
1435 			GL_NAME_LENGTH					// 9
1436 		};
1437 		int returnValues[DE_LENGTH_OF_ARRAY(queryParams)];
1438 
1439 		DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(queryParams) == DE_LENGTH_OF_ARRAY(returnValues));
1440 
1441 		{
1442 			int returnLength = 0;
1443 			gl.getProgramResourceiv(program, GL_BUFFER_VARIABLE, (deUint32)bufVarNdx, DE_LENGTH_OF_ARRAY(queryParams), &queryParams[0], DE_LENGTH_OF_ARRAY(returnValues), &returnLength, &returnValues[0]);
1444 			GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceiv(GL_BUFFER_VARIABLE) failed");
1445 
1446 			if (returnLength != DE_LENGTH_OF_ARRAY(returnValues))
1447 				throw tcu::TestError("glGetProgramResourceiv(GL_BUFFER_VARIABLE) returned wrong number of values");
1448 		}
1449 
1450 		// Map values
1451 		entry.blockNdx				= returnValues[0];
1452 		entry.type					= glu::getDataTypeFromGLType(returnValues[1]);
1453 		entry.offset				= returnValues[2];
1454 		entry.arraySize				= returnValues[3];
1455 		entry.arrayStride			= returnValues[4];
1456 		entry.matrixStride			= returnValues[5];
1457 		entry.topLevelArraySize		= returnValues[6];
1458 		entry.topLevelArrayStride	= returnValues[7];
1459 		entry.isRowMajor			= returnValues[8] != 0;
1460 
1461 		// Query name
1462 		DE_ASSERT(queryParams[9] == GL_NAME_LENGTH);
1463 		if (returnValues[9] > 0)
1464 		{
1465 			const int		nameLen		= returnValues[9];
1466 			int				retLen		= 0;
1467 			vector<char>	name		(nameLen);
1468 
1469 			gl.getProgramResourceName(program, GL_BUFFER_VARIABLE, (deUint32)bufVarNdx, (glw::GLsizei)name.size(), &retLen, &name[0]);
1470 			GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceName(GL_BUFFER_VARIABLE) failed");
1471 
1472 			if (retLen+1 != nameLen)
1473 				throw tcu::TestError("glGetProgramResourceName(GL_BUFFER_VARIABLE) returned invalid name. Number of characters written is inconsistent with NAME_LENGTH property.");
1474 			if (name[nameLen-1] != 0)
1475 				throw tcu::TestError("glGetProgramResourceName(GL_BUFFER_VARIABLE) returned invalid name. Expected null terminator at index " + de::toString(nameLen-1));
1476 
1477 			entry.name = &name[0];
1478 		}
1479 		else
1480 			throw tcu::TestError("glGetProgramResourceiv() returned invalid GL_NAME_LENGTH");
1481 	}
1482 }
1483 
copyBufferVarData(const BufferVarLayoutEntry & dstEntry,const BlockDataPtr & dstBlockPtr,const BufferVarLayoutEntry & srcEntry,const BlockDataPtr & srcBlockPtr)1484 void copyBufferVarData (const BufferVarLayoutEntry& dstEntry, const BlockDataPtr& dstBlockPtr, const BufferVarLayoutEntry& srcEntry, const BlockDataPtr& srcBlockPtr)
1485 {
1486 	DE_ASSERT(dstEntry.arraySize <= srcEntry.arraySize);
1487 	DE_ASSERT(dstEntry.topLevelArraySize <= srcEntry.topLevelArraySize);
1488 	DE_ASSERT(dstBlockPtr.lastUnsizedArraySize <= srcBlockPtr.lastUnsizedArraySize);
1489 	DE_ASSERT(dstEntry.type == srcEntry.type);
1490 
1491 	deUint8* const			dstBasePtr			= (deUint8*)dstBlockPtr.ptr + dstEntry.offset;
1492 	const deUint8* const	srcBasePtr			= (const deUint8*)srcBlockPtr.ptr + srcEntry.offset;
1493 	const int				scalarSize			= glu::getDataTypeScalarSize(dstEntry.type);
1494 	const bool				isMatrix			= glu::isDataTypeMatrix(dstEntry.type);
1495 	const int				compSize			= sizeof(deUint32);
1496 	const int				dstArraySize		= dstEntry.arraySize == 0 ? dstBlockPtr.lastUnsizedArraySize : dstEntry.arraySize;
1497 	const int				dstArrayStride		= dstEntry.arrayStride;
1498 	const int				dstTopLevelSize		= dstEntry.topLevelArraySize == 0 ? dstBlockPtr.lastUnsizedArraySize : dstEntry.topLevelArraySize;
1499 	const int				dstTopLevelStride	= dstEntry.topLevelArrayStride;
1500 	const int				srcArraySize		= srcEntry.arraySize == 0 ? srcBlockPtr.lastUnsizedArraySize : srcEntry.arraySize;
1501 	const int				srcArrayStride		= srcEntry.arrayStride;
1502 	const int				srcTopLevelSize		= srcEntry.topLevelArraySize == 0 ? srcBlockPtr.lastUnsizedArraySize : srcEntry.topLevelArraySize;
1503 	const int				srcTopLevelStride	= srcEntry.topLevelArrayStride;
1504 
1505 	DE_ASSERT(dstArraySize <= srcArraySize && dstTopLevelSize <= srcTopLevelSize);
1506 	DE_UNREF(srcArraySize && srcTopLevelSize);
1507 
1508 	for (int topElemNdx = 0; topElemNdx < dstTopLevelSize; topElemNdx++)
1509 	{
1510 		deUint8* const			dstTopPtr	= dstBasePtr + topElemNdx*dstTopLevelStride;
1511 		const deUint8* const	srcTopPtr	= srcBasePtr + topElemNdx*srcTopLevelStride;
1512 
1513 		for (int elementNdx = 0; elementNdx < dstArraySize; elementNdx++)
1514 		{
1515 			deUint8* const			dstElemPtr	= dstTopPtr + elementNdx*dstArrayStride;
1516 			const deUint8* const	srcElemPtr	= srcTopPtr + elementNdx*srcArrayStride;
1517 
1518 			if (isMatrix)
1519 			{
1520 				const int	numRows	= glu::getDataTypeMatrixNumRows(dstEntry.type);
1521 				const int	numCols	= glu::getDataTypeMatrixNumColumns(dstEntry.type);
1522 
1523 				for (int colNdx = 0; colNdx < numCols; colNdx++)
1524 				{
1525 					for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
1526 					{
1527 						deUint8*		dstCompPtr	= dstElemPtr + (dstEntry.isRowMajor ? rowNdx*dstEntry.matrixStride + colNdx*compSize
1528 																						: colNdx*dstEntry.matrixStride + rowNdx*compSize);
1529 						const deUint8*	srcCompPtr	= srcElemPtr + (srcEntry.isRowMajor ? rowNdx*srcEntry.matrixStride + colNdx*compSize
1530 																						: colNdx*srcEntry.matrixStride + rowNdx*compSize);
1531 
1532 						DE_ASSERT((deIntptr)(srcCompPtr + compSize) - (deIntptr)srcBlockPtr.ptr <= (deIntptr)srcBlockPtr.size);
1533 						DE_ASSERT((deIntptr)(dstCompPtr + compSize) - (deIntptr)dstBlockPtr.ptr <= (deIntptr)dstBlockPtr.size);
1534 						deMemcpy(dstCompPtr, srcCompPtr, compSize);
1535 					}
1536 				}
1537 			}
1538 			else
1539 			{
1540 				DE_ASSERT((deIntptr)(srcElemPtr + scalarSize*compSize) - (deIntptr)srcBlockPtr.ptr <= (deIntptr)srcBlockPtr.size);
1541 				DE_ASSERT((deIntptr)(dstElemPtr + scalarSize*compSize) - (deIntptr)dstBlockPtr.ptr <= (deIntptr)dstBlockPtr.size);
1542 				deMemcpy(dstElemPtr, srcElemPtr, scalarSize*compSize);
1543 			}
1544 		}
1545 	}
1546 }
1547 
copyData(const BufferLayout & dstLayout,const vector<BlockDataPtr> & dstBlockPointers,const BufferLayout & srcLayout,const vector<BlockDataPtr> & srcBlockPointers)1548 void copyData (const BufferLayout& dstLayout, const vector<BlockDataPtr>& dstBlockPointers, const BufferLayout& srcLayout, const vector<BlockDataPtr>& srcBlockPointers)
1549 {
1550 	// \note Src layout is used as reference in case of activeVarIndices happens to be incorrect in dstLayout blocks.
1551 	int numBlocks = (int)srcLayout.blocks.size();
1552 
1553 	for (int srcBlockNdx = 0; srcBlockNdx < numBlocks; srcBlockNdx++)
1554 	{
1555 		const BlockLayoutEntry&		srcBlock	= srcLayout.blocks[srcBlockNdx];
1556 		const BlockDataPtr&			srcBlockPtr	= srcBlockPointers[srcBlockNdx];
1557 		int							dstBlockNdx	= dstLayout.getBlockIndex(srcBlock.name.c_str());
1558 
1559 		if (dstBlockNdx >= 0)
1560 		{
1561 			DE_ASSERT(de::inBounds(dstBlockNdx, 0, (int)dstBlockPointers.size()));
1562 
1563 			const BlockDataPtr& dstBlockPtr = dstBlockPointers[dstBlockNdx];
1564 
1565 			for (vector<int>::const_iterator srcVarNdxIter = srcBlock.activeVarIndices.begin(); srcVarNdxIter != srcBlock.activeVarIndices.end(); srcVarNdxIter++)
1566 			{
1567 				const BufferVarLayoutEntry&	srcEntry	= srcLayout.bufferVars[*srcVarNdxIter];
1568 				int							dstVarNdx	= dstLayout.getVariableIndex(srcEntry.name.c_str());
1569 
1570 				if (dstVarNdx >= 0)
1571 					copyBufferVarData(dstLayout.bufferVars[dstVarNdx], dstBlockPtr, srcEntry, srcBlockPtr);
1572 			}
1573 		}
1574 	}
1575 }
1576 
copyNonWrittenData(const BufferLayout & layout,const BufferBlock & block,int instanceNdx,const BlockDataPtr & srcBlockPtr,const BlockDataPtr & dstBlockPtr,const BufferVar & bufVar,const glu::SubTypeAccess & accessPath)1577 void copyNonWrittenData (
1578 	const BufferLayout&			layout,
1579 	const BufferBlock&			block,
1580 	int							instanceNdx,
1581 	const BlockDataPtr&			srcBlockPtr,
1582 	const BlockDataPtr&			dstBlockPtr,
1583 	const BufferVar&			bufVar,
1584 	const glu::SubTypeAccess&	accessPath)
1585 {
1586 	const VarType curType = accessPath.getType();
1587 
1588 	if (curType.isArrayType())
1589 	{
1590 		const int arraySize = curType.getArraySize() == VarType::UNSIZED_ARRAY ? block.getLastUnsizedArraySize(instanceNdx) : curType.getArraySize();
1591 
1592 		for (int elemNdx = 0; elemNdx < arraySize; elemNdx++)
1593 			copyNonWrittenData(layout, block, instanceNdx, srcBlockPtr, dstBlockPtr, bufVar, accessPath.element(elemNdx));
1594 	}
1595 	else if (curType.isStructType())
1596 	{
1597 		const int numMembers = curType.getStructPtr()->getNumMembers();
1598 
1599 		for (int memberNdx = 0; memberNdx < numMembers; memberNdx++)
1600 			copyNonWrittenData(layout, block, instanceNdx, srcBlockPtr, dstBlockPtr, bufVar, accessPath.member(memberNdx));
1601 	}
1602 	else
1603 	{
1604 		DE_ASSERT(curType.isBasicType());
1605 
1606 		const string	apiName	= getAPIName(block, bufVar, accessPath.getPath());
1607 		const int		varNdx	= layout.getVariableIndex(apiName);
1608 
1609 		DE_ASSERT(varNdx >= 0);
1610 		{
1611 			const BufferVarLayoutEntry& varLayout = layout.bufferVars[varNdx];
1612 			copyBufferVarData(varLayout, dstBlockPtr, varLayout, srcBlockPtr);
1613 		}
1614 	}
1615 }
1616 
copyNonWrittenData(const ShaderInterface & interface,const BufferLayout & layout,const vector<BlockDataPtr> & srcPtrs,const vector<BlockDataPtr> & dstPtrs)1617 void copyNonWrittenData (const ShaderInterface& interface, const BufferLayout& layout, const vector<BlockDataPtr>& srcPtrs, const vector<BlockDataPtr>& dstPtrs)
1618 {
1619 	for (int declNdx = 0; declNdx < interface.getNumBlocks(); declNdx++)
1620 	{
1621 		const BufferBlock&	block			= interface.getBlock(declNdx);
1622 		const bool			isArray			= block.isArray();
1623 		const int			numInstances	= isArray ? block.getArraySize() : 1;
1624 
1625 		DE_ASSERT(!isArray || block.getInstanceName());
1626 
1627 		for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1628 		{
1629 			const string		instanceName	= block.getBlockName() + (isArray ? "[" + de::toString(instanceNdx) + "]" : string(""));
1630 			const int			blockNdx		= layout.getBlockIndex(instanceName);
1631 			const BlockDataPtr&	srcBlockPtr		= srcPtrs[blockNdx];
1632 			const BlockDataPtr&	dstBlockPtr		= dstPtrs[blockNdx];
1633 
1634 			for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++)
1635 			{
1636 				const BufferVar& bufVar = *varIter;
1637 
1638 				if (bufVar.getFlags() & ACCESS_WRITE)
1639 					continue;
1640 
1641 				copyNonWrittenData(layout, block, instanceNdx, srcBlockPtr, dstBlockPtr, bufVar, glu::SubTypeAccess(bufVar.getType()));
1642 			}
1643 		}
1644 	}
1645 }
1646 
compareComponents(glu::DataType scalarType,const void * ref,const void * res,int numComps)1647 bool compareComponents (glu::DataType scalarType, const void* ref, const void* res, int numComps)
1648 {
1649 	if (scalarType == glu::TYPE_FLOAT)
1650 	{
1651 		const float threshold = 0.05f; // Same as used in shaders - should be fine for values being used.
1652 
1653 		for (int ndx = 0; ndx < numComps; ndx++)
1654 		{
1655 			const float		refVal		= *((const float*)ref + ndx);
1656 			const float		resVal		= *((const float*)res + ndx);
1657 
1658 			if (!(deFloatAbs(resVal - refVal) <= threshold))
1659 				return false;
1660 		}
1661 	}
1662 	else if (scalarType == glu::TYPE_BOOL)
1663 	{
1664 		for (int ndx = 0; ndx < numComps; ndx++)
1665 		{
1666 			const deUint32	refVal		= *((const deUint32*)ref + ndx);
1667 			const deUint32	resVal		= *((const deUint32*)res + ndx);
1668 
1669 			if ((refVal != 0) != (resVal != 0))
1670 				return false;
1671 		}
1672 	}
1673 	else
1674 	{
1675 		DE_ASSERT(scalarType == glu::TYPE_INT || scalarType == glu::TYPE_UINT);
1676 
1677 		for (int ndx = 0; ndx < numComps; ndx++)
1678 		{
1679 			const deUint32	refVal		= *((const deUint32*)ref + ndx);
1680 			const deUint32	resVal		= *((const deUint32*)res + ndx);
1681 
1682 			if (refVal != resVal)
1683 				return false;
1684 		}
1685 	}
1686 
1687 	return true;
1688 }
1689 
compareBufferVarData(tcu::TestLog & log,const BufferVarLayoutEntry & refEntry,const BlockDataPtr & refBlockPtr,const BufferVarLayoutEntry & resEntry,const BlockDataPtr & resBlockPtr)1690 bool compareBufferVarData (tcu::TestLog& log, const BufferVarLayoutEntry& refEntry, const BlockDataPtr& refBlockPtr, const BufferVarLayoutEntry& resEntry, const BlockDataPtr& resBlockPtr)
1691 {
1692 	DE_ASSERT(resEntry.arraySize <= refEntry.arraySize);
1693 	DE_ASSERT(resEntry.topLevelArraySize <= refEntry.topLevelArraySize);
1694 	DE_ASSERT(resBlockPtr.lastUnsizedArraySize <= refBlockPtr.lastUnsizedArraySize);
1695 	DE_ASSERT(resEntry.type == refEntry.type);
1696 
1697 	deUint8* const			resBasePtr			= (deUint8*)resBlockPtr.ptr + resEntry.offset;
1698 	const deUint8* const	refBasePtr			= (const deUint8*)refBlockPtr.ptr + refEntry.offset;
1699 	const glu::DataType		scalarType			= glu::getDataTypeScalarType(refEntry.type);
1700 	const int				scalarSize			= glu::getDataTypeScalarSize(resEntry.type);
1701 	const bool				isMatrix			= glu::isDataTypeMatrix(resEntry.type);
1702 	const int				compSize			= sizeof(deUint32);
1703 	const int				maxPrints			= 3;
1704 	int						numFailed			= 0;
1705 
1706 	const int				resArraySize		= resEntry.arraySize == 0 ? resBlockPtr.lastUnsizedArraySize : resEntry.arraySize;
1707 	const int				resArrayStride		= resEntry.arrayStride;
1708 	const int				resTopLevelSize		= resEntry.topLevelArraySize == 0 ? resBlockPtr.lastUnsizedArraySize : resEntry.topLevelArraySize;
1709 	const int				resTopLevelStride	= resEntry.topLevelArrayStride;
1710 	const int				refArraySize		= refEntry.arraySize == 0 ? refBlockPtr.lastUnsizedArraySize : refEntry.arraySize;
1711 	const int				refArrayStride		= refEntry.arrayStride;
1712 	const int				refTopLevelSize		= refEntry.topLevelArraySize == 0 ? refBlockPtr.lastUnsizedArraySize : refEntry.topLevelArraySize;
1713 	const int				refTopLevelStride	= refEntry.topLevelArrayStride;
1714 
1715 	DE_ASSERT(resArraySize <= refArraySize && resTopLevelSize <= refTopLevelSize);
1716 	DE_UNREF(refArraySize && refTopLevelSize);
1717 
1718 	for (int topElemNdx = 0; topElemNdx < resTopLevelSize; topElemNdx++)
1719 	{
1720 		deUint8* const			resTopPtr	= resBasePtr + topElemNdx*resTopLevelStride;
1721 		const deUint8* const	refTopPtr	= refBasePtr + topElemNdx*refTopLevelStride;
1722 
1723 		for (int elementNdx = 0; elementNdx < resArraySize; elementNdx++)
1724 		{
1725 			deUint8* const			resElemPtr	= resTopPtr + elementNdx*resArrayStride;
1726 			const deUint8* const	refElemPtr	= refTopPtr + elementNdx*refArrayStride;
1727 
1728 			if (isMatrix)
1729 			{
1730 				const int	numRows	= glu::getDataTypeMatrixNumRows(resEntry.type);
1731 				const int	numCols	= glu::getDataTypeMatrixNumColumns(resEntry.type);
1732 				bool		isOk	= true;
1733 
1734 				for (int colNdx = 0; colNdx < numCols; colNdx++)
1735 				{
1736 					for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
1737 					{
1738 						deUint8*		resCompPtr	= resElemPtr + (resEntry.isRowMajor ? rowNdx*resEntry.matrixStride + colNdx*compSize
1739 																						: colNdx*resEntry.matrixStride + rowNdx*compSize);
1740 						const deUint8*	refCompPtr	= refElemPtr + (refEntry.isRowMajor ? rowNdx*refEntry.matrixStride + colNdx*compSize
1741 																						: colNdx*refEntry.matrixStride + rowNdx*compSize);
1742 
1743 						DE_ASSERT((deIntptr)(refCompPtr + compSize) - (deIntptr)refBlockPtr.ptr <= (deIntptr)refBlockPtr.size);
1744 						DE_ASSERT((deIntptr)(resCompPtr + compSize) - (deIntptr)resBlockPtr.ptr <= (deIntptr)resBlockPtr.size);
1745 
1746 						isOk = isOk && compareComponents(scalarType, resCompPtr, refCompPtr, 1);
1747 					}
1748 				}
1749 
1750 				if (!isOk)
1751 				{
1752 					numFailed += 1;
1753 					if (numFailed < maxPrints)
1754 					{
1755 						std::ostringstream expected, got;
1756 						generateImmMatrixSrc(expected, refEntry.type, refEntry.matrixStride, refEntry.isRowMajor, refElemPtr);
1757 						generateImmMatrixSrc(got, resEntry.type, resEntry.matrixStride, resEntry.isRowMajor, resElemPtr);
1758 						log << TestLog::Message << "ERROR: mismatch in " << refEntry.name << ", top-level ndx " << topElemNdx << ", bottom-level ndx " << elementNdx << ":\n"
1759 												<< "  expected " << expected.str() << "\n"
1760 												<< "  got " << got.str()
1761 							<< TestLog::EndMessage;
1762 					}
1763 				}
1764 			}
1765 			else
1766 			{
1767 				DE_ASSERT((deIntptr)(refElemPtr + scalarSize*compSize) - (deIntptr)refBlockPtr.ptr <= (deIntptr)refBlockPtr.size);
1768 				DE_ASSERT((deIntptr)(resElemPtr + scalarSize*compSize) - (deIntptr)resBlockPtr.ptr <= (deIntptr)resBlockPtr.size);
1769 
1770 				const bool isOk = compareComponents(scalarType, resElemPtr, refElemPtr, scalarSize);
1771 
1772 				if (!isOk)
1773 				{
1774 					numFailed += 1;
1775 					if (numFailed < maxPrints)
1776 					{
1777 						std::ostringstream expected, got;
1778 						generateImmScalarVectorSrc(expected, refEntry.type, refElemPtr);
1779 						generateImmScalarVectorSrc(got, resEntry.type, resElemPtr);
1780 						log << TestLog::Message << "ERROR: mismatch in " << refEntry.name << ", top-level ndx " << topElemNdx << ", bottom-level ndx " << elementNdx << ":\n"
1781 												<< "  expected " << expected.str() << "\n"
1782 												<< "  got " << got.str()
1783 							<< TestLog::EndMessage;
1784 					}
1785 				}
1786 			}
1787 		}
1788 	}
1789 
1790 	if (numFailed >= maxPrints)
1791 		log << TestLog::Message << "... (" << numFailed << " failures for " << refEntry.name << " in total)" << TestLog::EndMessage;
1792 
1793 	return numFailed == 0;
1794 }
1795 
compareData(tcu::TestLog & log,const BufferLayout & refLayout,const vector<BlockDataPtr> & refBlockPointers,const BufferLayout & resLayout,const vector<BlockDataPtr> & resBlockPointers)1796 bool compareData (tcu::TestLog& log, const BufferLayout& refLayout, const vector<BlockDataPtr>& refBlockPointers, const BufferLayout& resLayout, const vector<BlockDataPtr>& resBlockPointers)
1797 {
1798 	const int	numBlocks	= (int)refLayout.blocks.size();
1799 	bool		allOk		= true;
1800 
1801 	for (int refBlockNdx = 0; refBlockNdx < numBlocks; refBlockNdx++)
1802 	{
1803 		const BlockLayoutEntry&		refBlock	= refLayout.blocks[refBlockNdx];
1804 		const BlockDataPtr&			refBlockPtr	= refBlockPointers[refBlockNdx];
1805 		int							resBlockNdx	= resLayout.getBlockIndex(refBlock.name.c_str());
1806 
1807 		if (resBlockNdx >= 0)
1808 		{
1809 			DE_ASSERT(de::inBounds(resBlockNdx, 0, (int)resBlockPointers.size()));
1810 
1811 			const BlockDataPtr& resBlockPtr = resBlockPointers[resBlockNdx];
1812 
1813 			for (vector<int>::const_iterator refVarNdxIter = refBlock.activeVarIndices.begin(); refVarNdxIter != refBlock.activeVarIndices.end(); refVarNdxIter++)
1814 			{
1815 				const BufferVarLayoutEntry&	refEntry	= refLayout.bufferVars[*refVarNdxIter];
1816 				int							resVarNdx	= resLayout.getVariableIndex(refEntry.name.c_str());
1817 
1818 				if (resVarNdx >= 0)
1819 				{
1820 					const BufferVarLayoutEntry& resEntry = resLayout.bufferVars[resVarNdx];
1821 					allOk = compareBufferVarData(log, refEntry, refBlockPtr, resEntry, resBlockPtr) && allOk;
1822 				}
1823 			}
1824 		}
1825 	}
1826 
1827 	return allOk;
1828 }
1829 
getBlockAPIName(const BufferBlock & block,int instanceNdx)1830 string getBlockAPIName (const BufferBlock& block, int instanceNdx)
1831 {
1832 	DE_ASSERT(block.isArray() || instanceNdx == 0);
1833 	return block.getBlockName() + (block.isArray() ? ("[" + de::toString(instanceNdx) + "]") : string());
1834 }
1835 
1836 // \note Some implementations don't report block members in the order they are declared.
1837 //		 For checking whether size has to be adjusted by some top-level array actual size,
1838 //		 we only need to know a) whether there is a unsized top-level array, and b)
1839 //		 what is stride of that array.
1840 
hasUnsizedArray(const BufferLayout & layout,const BlockLayoutEntry & entry)1841 static bool hasUnsizedArray (const BufferLayout& layout, const BlockLayoutEntry& entry)
1842 {
1843 	for (vector<int>::const_iterator varNdx = entry.activeVarIndices.begin(); varNdx != entry.activeVarIndices.end(); ++varNdx)
1844 	{
1845 		if (isUnsizedArray(layout.bufferVars[*varNdx]))
1846 			return true;
1847 	}
1848 
1849 	return false;
1850 }
1851 
getUnsizedArrayStride(const BufferLayout & layout,const BlockLayoutEntry & entry)1852 static int getUnsizedArrayStride (const BufferLayout& layout, const BlockLayoutEntry& entry)
1853 {
1854 	for (vector<int>::const_iterator varNdx = entry.activeVarIndices.begin(); varNdx != entry.activeVarIndices.end(); ++varNdx)
1855 	{
1856 		const BufferVarLayoutEntry& varEntry = layout.bufferVars[*varNdx];
1857 
1858 		if (varEntry.arraySize == 0)
1859 			return varEntry.arrayStride;
1860 		else if (varEntry.topLevelArraySize == 0)
1861 			return varEntry.topLevelArrayStride;
1862 	}
1863 
1864 	return 0;
1865 }
1866 
computeBufferSizes(const ShaderInterface & interface,const BufferLayout & layout)1867 vector<int> computeBufferSizes (const ShaderInterface& interface, const BufferLayout& layout)
1868 {
1869 	vector<int> sizes(layout.blocks.size());
1870 
1871 	for (int declNdx = 0; declNdx < interface.getNumBlocks(); declNdx++)
1872 	{
1873 		const BufferBlock&	block			= interface.getBlock(declNdx);
1874 		const bool			isArray			= block.isArray();
1875 		const int			numInstances	= isArray ? block.getArraySize() : 1;
1876 
1877 		for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1878 		{
1879 			const string	apiName		= getBlockAPIName(block, instanceNdx);
1880 			const int		blockNdx	= layout.getBlockIndex(apiName);
1881 
1882 			if (blockNdx >= 0)
1883 			{
1884 				const BlockLayoutEntry&		blockLayout		= layout.blocks[blockNdx];
1885 				const int					baseSize		= blockLayout.size;
1886 				const bool					isLastUnsized	= hasUnsizedArray(layout, blockLayout);
1887 				const int					lastArraySize	= isLastUnsized ? block.getLastUnsizedArraySize(instanceNdx) : 0;
1888 				const int					stride			= isLastUnsized ? getUnsizedArrayStride(layout, blockLayout) : 0;
1889 
1890 				sizes[blockNdx] = baseSize + lastArraySize*stride;
1891 			}
1892 		}
1893 	}
1894 
1895 	return sizes;
1896 }
1897 
getBlockDataPtr(const BufferLayout & layout,const BlockLayoutEntry & blockLayout,void * ptr,int bufferSize)1898 BlockDataPtr getBlockDataPtr (const BufferLayout& layout, const BlockLayoutEntry& blockLayout, void* ptr, int bufferSize)
1899 {
1900 	const bool	isLastUnsized	= hasUnsizedArray(layout, blockLayout);
1901 	const int	baseSize		= blockLayout.size;
1902 
1903 	if (isLastUnsized)
1904 	{
1905 		const int		lastArrayStride	= getUnsizedArrayStride(layout, blockLayout);
1906 		const int		lastArraySize	= (bufferSize-baseSize) / (lastArrayStride ? lastArrayStride : 1);
1907 
1908 		DE_ASSERT(baseSize + lastArraySize*lastArrayStride == bufferSize);
1909 
1910 		return BlockDataPtr(ptr, bufferSize, lastArraySize);
1911 	}
1912 	else
1913 		return BlockDataPtr(ptr, bufferSize, 0);
1914 }
1915 
1916 struct RefDataStorage
1917 {
1918 	vector<deUint8>			data;
1919 	vector<BlockDataPtr>	pointers;
1920 };
1921 
1922 struct Buffer
1923 {
1924 	deUint32				buffer;
1925 	int						size;
1926 
Bufferdeqp::gles31::bb::__anon69309db60211::Buffer1927 	Buffer (deUint32 buffer_, int size_) : buffer(buffer_), size(size_) {}
Bufferdeqp::gles31::bb::__anon69309db60211::Buffer1928 	Buffer (void) : buffer(0), size(0) {}
1929 };
1930 
1931 struct BlockLocation
1932 {
1933 	int						index;
1934 	int						offset;
1935 	int						size;
1936 
BlockLocationdeqp::gles31::bb::__anon69309db60211::BlockLocation1937 	BlockLocation (int index_, int offset_, int size_) : index(index_), offset(offset_), size(size_) {}
BlockLocationdeqp::gles31::bb::__anon69309db60211::BlockLocation1938 	BlockLocation (void) : index(0), offset(0), size(0) {}
1939 };
1940 
initRefDataStorage(const ShaderInterface & interface,const BufferLayout & layout,RefDataStorage & storage)1941 void initRefDataStorage (const ShaderInterface& interface, const BufferLayout& layout, RefDataStorage& storage)
1942 {
1943 	DE_ASSERT(storage.data.empty() && storage.pointers.empty());
1944 
1945 	const vector<int>	bufferSizes = computeBufferSizes(interface, layout);
1946 	int					totalSize	= 0;
1947 
1948 	for (vector<int>::const_iterator sizeIter = bufferSizes.begin(); sizeIter != bufferSizes.end(); ++sizeIter)
1949 		totalSize += *sizeIter;
1950 
1951 	storage.data.resize(totalSize);
1952 
1953 	// Pointers for each block.
1954 	{
1955 		deUint8*	basePtr		= storage.data.empty() ? DE_NULL : &storage.data[0];
1956 		int			curOffset	= 0;
1957 
1958 		DE_ASSERT(bufferSizes.size() == layout.blocks.size());
1959 		DE_ASSERT(totalSize == 0 || basePtr);
1960 
1961 		storage.pointers.resize(layout.blocks.size());
1962 
1963 		for (int blockNdx = 0; blockNdx < (int)layout.blocks.size(); blockNdx++)
1964 		{
1965 			const BlockLayoutEntry&	blockLayout		= layout.blocks[blockNdx];
1966 			const int				bufferSize		= bufferSizes[blockNdx];
1967 
1968 			storage.pointers[blockNdx] = getBlockDataPtr(layout, blockLayout, basePtr + curOffset, bufferSize);
1969 
1970 			curOffset += bufferSize;
1971 		}
1972 	}
1973 }
1974 
blockLocationsToPtrs(const BufferLayout & layout,const vector<BlockLocation> & blockLocations,const vector<void * > & bufPtrs)1975 vector<BlockDataPtr> blockLocationsToPtrs (const BufferLayout& layout, const vector<BlockLocation>& blockLocations, const vector<void*>& bufPtrs)
1976 {
1977 	vector<BlockDataPtr> blockPtrs(blockLocations.size());
1978 
1979 	DE_ASSERT(layout.blocks.size() == blockLocations.size());
1980 
1981 	for (int blockNdx = 0; blockNdx < (int)layout.blocks.size(); blockNdx++)
1982 	{
1983 		const BlockLayoutEntry&	blockLayout		= layout.blocks[blockNdx];
1984 		const BlockLocation&	location		= blockLocations[blockNdx];
1985 
1986 		blockPtrs[blockNdx] = getBlockDataPtr(layout, blockLayout, (deUint8*)bufPtrs[location.index] + location.offset, location.size);
1987 	}
1988 
1989 	return blockPtrs;
1990 }
1991 
mapBuffers(const glw::Functions & gl,const vector<Buffer> & buffers,deUint32 access)1992 vector<void*> mapBuffers (const glw::Functions& gl, const vector<Buffer>& buffers, deUint32 access)
1993 {
1994 	vector<void*> mapPtrs(buffers.size(), DE_NULL);
1995 
1996 	try
1997 	{
1998 		for (int ndx = 0; ndx < (int)buffers.size(); ndx++)
1999 		{
2000 			if (buffers[ndx].size > 0)
2001 			{
2002 				gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, buffers[ndx].buffer);
2003 				mapPtrs[ndx] = gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, buffers[ndx].size, access);
2004 				GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to map buffer");
2005 				TCU_CHECK(mapPtrs[ndx]);
2006 			}
2007 			else
2008 				mapPtrs[ndx] = DE_NULL;
2009 		}
2010 
2011 		return mapPtrs;
2012 	}
2013 	catch (...)
2014 	{
2015 		for (int ndx = 0; ndx < (int)buffers.size(); ndx++)
2016 		{
2017 			if (mapPtrs[ndx])
2018 			{
2019 				gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, buffers[ndx].buffer);
2020 				gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
2021 			}
2022 		}
2023 
2024 		throw;
2025 	}
2026 }
2027 
unmapBuffers(const glw::Functions & gl,const vector<Buffer> & buffers)2028 void unmapBuffers (const glw::Functions& gl, const vector<Buffer>& buffers)
2029 {
2030 	for (int ndx = 0; ndx < (int)buffers.size(); ndx++)
2031 	{
2032 		if (buffers[ndx].size > 0)
2033 		{
2034 			gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, buffers[ndx].buffer);
2035 			gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
2036 		}
2037 	}
2038 
2039 	GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to unmap buffer");
2040 }
2041 
2042 } // anonymous (utilities)
2043 
2044 class BufferManager
2045 {
2046 public:
2047 								BufferManager	(const glu::RenderContext& renderCtx);
2048 								~BufferManager	(void);
2049 
2050 	deUint32					allocBuffer		(void);
2051 
2052 private:
2053 								BufferManager	(const BufferManager& other);
2054 	BufferManager&				operator=		(const BufferManager& other);
2055 
2056 	const glu::RenderContext&	m_renderCtx;
2057 	std::vector<deUint32>		m_buffers;
2058 };
2059 
BufferManager(const glu::RenderContext & renderCtx)2060 BufferManager::BufferManager (const glu::RenderContext& renderCtx)
2061 	: m_renderCtx(renderCtx)
2062 {
2063 }
2064 
~BufferManager(void)2065 BufferManager::~BufferManager (void)
2066 {
2067 	if (!m_buffers.empty())
2068 		m_renderCtx.getFunctions().deleteBuffers((glw::GLsizei)m_buffers.size(), &m_buffers[0]);
2069 }
2070 
allocBuffer(void)2071 deUint32 BufferManager::allocBuffer (void)
2072 {
2073 	deUint32 buf = 0;
2074 
2075 	m_buffers.reserve(m_buffers.size()+1);
2076 	m_renderCtx.getFunctions().genBuffers(1, &buf);
2077 	GLU_EXPECT_NO_ERROR(m_renderCtx.getFunctions().getError(), "Failed to allocate buffer");
2078 	m_buffers.push_back(buf);
2079 
2080 	return buf;
2081 }
2082 
2083 } // bb
2084 
2085 using namespace bb;
2086 
2087 // SSBOLayoutCase.
2088 
SSBOLayoutCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * description,glu::GLSLVersion glslVersion,BufferMode bufferMode)2089 SSBOLayoutCase::SSBOLayoutCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* description, glu::GLSLVersion glslVersion, BufferMode bufferMode)
2090 	: TestCase		(testCtx, name, description)
2091 	, m_renderCtx	(renderCtx)
2092 	, m_glslVersion	(glslVersion)
2093 	, m_bufferMode	(bufferMode)
2094 {
2095 	DE_ASSERT(glslVersion == glu::GLSL_VERSION_310_ES || glslVersion == glu::GLSL_VERSION_430);
2096 }
2097 
~SSBOLayoutCase(void)2098 SSBOLayoutCase::~SSBOLayoutCase (void)
2099 {
2100 }
2101 
iterate(void)2102 SSBOLayoutCase::IterateResult SSBOLayoutCase::iterate (void)
2103 {
2104 	TestLog&					log				= m_testCtx.getLog();
2105 	const glw::Functions&		gl				= m_renderCtx.getFunctions();
2106 
2107 	BufferLayout				refLayout;		// std140 / std430 layout.
2108 	BufferLayout				glLayout;		// Layout reported by GL.
2109 	RefDataStorage				initialData;	// Initial data stored in buffer.
2110 	RefDataStorage				writeData;		// Data written by compute shader.
2111 
2112 	BufferManager				bufferManager	(m_renderCtx);
2113 	vector<Buffer>				buffers;		// Buffers allocated for storage
2114 	vector<BlockLocation>		blockLocations;	// Block locations in storage (index, offset)
2115 
2116 	// Initialize result to pass.
2117 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2118 
2119 	computeReferenceLayout	(refLayout, m_interface);
2120 	initRefDataStorage		(m_interface, refLayout, initialData);
2121 	initRefDataStorage		(m_interface, refLayout, writeData);
2122 	generateValues			(refLayout, initialData.pointers, deStringHash(getName()) ^ 0xad2f7214);
2123 	generateValues			(refLayout, writeData.pointers, deStringHash(getName()) ^ 0x25ca4e7);
2124 	copyNonWrittenData		(m_interface, refLayout, initialData.pointers, writeData.pointers);
2125 
2126 	const glu::ShaderProgram program(m_renderCtx, glu::ProgramSources() << glu::ComputeSource(generateComputeShader(gl, m_glslVersion, m_interface, refLayout, initialData.pointers, writeData.pointers)));
2127 	log << program;
2128 
2129 	if (!program.isOk())
2130 	{
2131 		// Compile failed.
2132 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compile failed");
2133 		return STOP;
2134 	}
2135 
2136 	// Query layout from GL.
2137 	getGLBufferLayout(gl, glLayout, program.getProgram());
2138 
2139 	// Print layout to log.
2140 	{
2141 		tcu::ScopedLogSection section(log, "ActiveBufferBlocks", "Active Buffer Blocks");
2142 		for (int blockNdx = 0; blockNdx < (int)glLayout.blocks.size(); blockNdx++)
2143 			log << TestLog::Message << blockNdx << ": " << glLayout.blocks[blockNdx] << TestLog::EndMessage;
2144 	}
2145 
2146 	{
2147 		tcu::ScopedLogSection section(log, "ActiveBufferVars", "Active Buffer Variables");
2148 		for (int varNdx = 0; varNdx < (int)glLayout.bufferVars.size(); varNdx++)
2149 			log << TestLog::Message << varNdx << ": " << glLayout.bufferVars[varNdx] << TestLog::EndMessage;
2150 	}
2151 
2152 	// Verify layouts.
2153 	{
2154 		if (!checkLayoutIndices(glLayout) || !checkLayoutBounds(glLayout) || !compareTypes(refLayout, glLayout))
2155 		{
2156 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid layout");
2157 			return STOP; // It is not safe to use the given layout.
2158 		}
2159 
2160 		if (!compareStdBlocks(refLayout, glLayout))
2161 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid std140 or std430 layout");
2162 
2163 		if (!compareSharedBlocks(refLayout, glLayout))
2164 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid shared layout");
2165 
2166 		if (!checkIndexQueries(program.getProgram(), glLayout))
2167 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Inconsintent block index query results");
2168 	}
2169 
2170 	// Allocate GL buffers & compute placement.
2171 	{
2172 		const int			numBlocks		= (int)glLayout.blocks.size();
2173 		const vector<int>	bufferSizes		= computeBufferSizes(m_interface, glLayout);
2174 
2175 		DE_ASSERT(bufferSizes.size() == glLayout.blocks.size());
2176 
2177 		blockLocations.resize(numBlocks);
2178 
2179 		if (m_bufferMode == BUFFERMODE_PER_BLOCK)
2180 		{
2181 			buffers.resize(numBlocks);
2182 
2183 			for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
2184 			{
2185 				const int bufferSize = bufferSizes[blockNdx];
2186 
2187 				buffers[blockNdx].size = bufferSize;
2188 				blockLocations[blockNdx] = BlockLocation(blockNdx, 0, bufferSize);
2189 			}
2190 		}
2191 		else
2192 		{
2193 			DE_ASSERT(m_bufferMode == BUFFERMODE_SINGLE);
2194 
2195 			int		bindingAlignment	= 0;
2196 			int		totalSize			= 0;
2197 
2198 			gl.getIntegerv(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &bindingAlignment);
2199 
2200 			{
2201 				int curOffset = 0;
2202 				DE_ASSERT(bufferSizes.size() == glLayout.blocks.size());
2203 				for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
2204 				{
2205 					const int bufferSize = bufferSizes[blockNdx];
2206 
2207 					if (bindingAlignment > 0)
2208 						curOffset = deRoundUp32(curOffset, bindingAlignment);
2209 
2210 					blockLocations[blockNdx] = BlockLocation(0, curOffset, bufferSize);
2211 					curOffset += bufferSize;
2212 				}
2213 				totalSize = curOffset;
2214 			}
2215 
2216 			buffers.resize(1);
2217 			buffers[0].size = totalSize;
2218 		}
2219 
2220 		for (int bufNdx = 0; bufNdx < (int)buffers.size(); bufNdx++)
2221 		{
2222 			const int		bufferSize	= buffers[bufNdx].size;
2223 			const deUint32	buffer		= bufferManager.allocBuffer();
2224 
2225 			gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, buffer);
2226 			gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_STATIC_DRAW);
2227 			GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to allocate buffer");
2228 
2229 			buffers[bufNdx].buffer = buffer;
2230 		}
2231 	}
2232 
2233 	{
2234 		const vector<void*>			mapPtrs			= mapBuffers(gl, buffers, GL_MAP_WRITE_BIT);
2235 		const vector<BlockDataPtr>	mappedBlockPtrs	= blockLocationsToPtrs(glLayout, blockLocations, mapPtrs);
2236 
2237 		copyData(glLayout, mappedBlockPtrs, refLayout, initialData.pointers);
2238 
2239 		unmapBuffers(gl, buffers);
2240 	}
2241 
2242 	{
2243 		int bindingPoint = 0;
2244 
2245 		for (int blockDeclNdx = 0; blockDeclNdx < m_interface.getNumBlocks(); blockDeclNdx++)
2246 		{
2247 			const BufferBlock&	block		= m_interface.getBlock(blockDeclNdx);
2248 			const int			numInst		= block.isArray() ? block.getArraySize() : 1;
2249 
2250 			for (int instNdx = 0; instNdx < numInst; instNdx++)
2251 			{
2252 				const string	instName	= getBlockAPIName(block, instNdx);
2253 				const int		layoutNdx	= findBlockIndex(glLayout, instName);
2254 
2255 				if (layoutNdx >= 0)
2256 				{
2257 					const BlockLocation& blockLoc = blockLocations[layoutNdx];
2258 
2259 					if (blockLoc.size > 0)
2260 						gl.bindBufferRange(GL_SHADER_STORAGE_BUFFER, bindingPoint, buffers[blockLoc.index].buffer, blockLoc.offset, blockLoc.size);
2261 				}
2262 
2263 				bindingPoint += 1;
2264 			}
2265 		}
2266 	}
2267 
2268 	GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to bind buffers");
2269 
2270 	{
2271 		const bool execOk = execute(program.getProgram());
2272 
2273 		if (execOk)
2274 		{
2275 			const vector<void*>			mapPtrs			= mapBuffers(gl, buffers, GL_MAP_READ_BIT);
2276 			const vector<BlockDataPtr>	mappedBlockPtrs	= blockLocationsToPtrs(glLayout, blockLocations, mapPtrs);
2277 
2278 			const bool					compareOk		= compareData(m_testCtx.getLog(), refLayout, writeData.pointers, glLayout, mappedBlockPtrs);
2279 
2280 			unmapBuffers(gl, buffers);
2281 
2282 			if (!compareOk)
2283 				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Result comparison failed");
2284 		}
2285 		else
2286 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader execution failed");
2287 	}
2288 
2289 	return STOP;
2290 }
2291 
compareStdBlocks(const BufferLayout & refLayout,const BufferLayout & cmpLayout) const2292 bool SSBOLayoutCase::compareStdBlocks (const BufferLayout& refLayout, const BufferLayout& cmpLayout) const
2293 {
2294 	TestLog&	log			= m_testCtx.getLog();
2295 	bool		isOk		= true;
2296 	int			numBlocks	= m_interface.getNumBlocks();
2297 
2298 	for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
2299 	{
2300 		const BufferBlock&		block			= m_interface.getBlock(blockNdx);
2301 		bool					isArray			= block.isArray();
2302 		std::string				instanceName	= string(block.getBlockName()) + (isArray ? "[0]" : "");
2303 		int						refBlockNdx		= refLayout.getBlockIndex(instanceName.c_str());
2304 		int						cmpBlockNdx		= cmpLayout.getBlockIndex(instanceName.c_str());
2305 
2306 		if ((block.getFlags() & (LAYOUT_STD140|LAYOUT_STD430)) == 0)
2307 			continue; // Not std* layout.
2308 
2309 		DE_ASSERT(refBlockNdx >= 0);
2310 
2311 		if (cmpBlockNdx < 0)
2312 		{
2313 			// Not found.
2314 			log << TestLog::Message << "Error: Buffer block '" << instanceName << "' not found" << TestLog::EndMessage;
2315 			isOk = false;
2316 			continue;
2317 		}
2318 
2319 		const BlockLayoutEntry&		refBlockLayout	= refLayout.blocks[refBlockNdx];
2320 		const BlockLayoutEntry&		cmpBlockLayout	= cmpLayout.blocks[cmpBlockNdx];
2321 
2322 		// \todo [2012-01-24 pyry] Verify that activeVarIndices is correct.
2323 		// \todo [2012-01-24 pyry] Verify all instances.
2324 		if (refBlockLayout.activeVarIndices.size() != cmpBlockLayout.activeVarIndices.size())
2325 		{
2326 			log << TestLog::Message << "Error: Number of active variables differ in block '" << instanceName
2327 				<< "' (expected " << refBlockLayout.activeVarIndices.size()
2328 				<< ", got " << cmpBlockLayout.activeVarIndices.size()
2329 				<< ")" << TestLog::EndMessage;
2330 			isOk = false;
2331 		}
2332 
2333 		for (vector<int>::const_iterator ndxIter = refBlockLayout.activeVarIndices.begin(); ndxIter != refBlockLayout.activeVarIndices.end(); ndxIter++)
2334 		{
2335 			const BufferVarLayoutEntry&	refEntry	= refLayout.bufferVars[*ndxIter];
2336 			int							cmpEntryNdx	= cmpLayout.getVariableIndex(refEntry.name.c_str());
2337 
2338 			if (cmpEntryNdx < 0)
2339 			{
2340 				log << TestLog::Message << "Error: Buffer variable '" << refEntry.name << "' not found" << TestLog::EndMessage;
2341 				isOk = false;
2342 				continue;
2343 			}
2344 
2345 			const BufferVarLayoutEntry&	cmpEntry	= cmpLayout.bufferVars[cmpEntryNdx];
2346 
2347 			if (refEntry.type					!= cmpEntry.type				||
2348 				refEntry.arraySize				!= cmpEntry.arraySize			||
2349 				refEntry.offset					!= cmpEntry.offset				||
2350 				refEntry.arrayStride			!= cmpEntry.arrayStride			||
2351 				refEntry.matrixStride			!= cmpEntry.matrixStride		||
2352 				refEntry.topLevelArraySize		!= cmpEntry.topLevelArraySize	||
2353 				refEntry.topLevelArrayStride	!= cmpEntry.topLevelArrayStride	||
2354 				refEntry.isRowMajor				!= cmpEntry.isRowMajor)
2355 			{
2356 				log << TestLog::Message << "Error: Layout mismatch in '" << refEntry.name << "':\n"
2357 					<< "  expected: " << refEntry << "\n"
2358 					<< "  got: " << cmpEntry
2359 					<< TestLog::EndMessage;
2360 				isOk = false;
2361 			}
2362 		}
2363 	}
2364 
2365 	return isOk;
2366 }
2367 
compareSharedBlocks(const BufferLayout & refLayout,const BufferLayout & cmpLayout) const2368 bool SSBOLayoutCase::compareSharedBlocks (const BufferLayout& refLayout, const BufferLayout& cmpLayout) const
2369 {
2370 	TestLog&	log			= m_testCtx.getLog();
2371 	bool		isOk		= true;
2372 	int			numBlocks	= m_interface.getNumBlocks();
2373 
2374 	for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
2375 	{
2376 		const BufferBlock&		block			= m_interface.getBlock(blockNdx);
2377 		bool					isArray			= block.isArray();
2378 		std::string				instanceName	= string(block.getBlockName()) + (isArray ? "[0]" : "");
2379 		int						refBlockNdx		= refLayout.getBlockIndex(instanceName.c_str());
2380 		int						cmpBlockNdx		= cmpLayout.getBlockIndex(instanceName.c_str());
2381 
2382 		if ((block.getFlags() & LAYOUT_SHARED) == 0)
2383 			continue; // Not shared layout.
2384 
2385 		DE_ASSERT(refBlockNdx >= 0);
2386 
2387 		if (cmpBlockNdx < 0)
2388 		{
2389 			// Not found, should it?
2390 			log << TestLog::Message << "Error: Buffer block '" << instanceName << "' not found" << TestLog::EndMessage;
2391 			isOk = false;
2392 			continue;
2393 		}
2394 
2395 		const BlockLayoutEntry&		refBlockLayout	= refLayout.blocks[refBlockNdx];
2396 		const BlockLayoutEntry&		cmpBlockLayout	= cmpLayout.blocks[cmpBlockNdx];
2397 
2398 		if (refBlockLayout.activeVarIndices.size() != cmpBlockLayout.activeVarIndices.size())
2399 		{
2400 			log << TestLog::Message << "Error: Number of active variables differ in block '" << instanceName
2401 				<< "' (expected " << refBlockLayout.activeVarIndices.size()
2402 				<< ", got " << cmpBlockLayout.activeVarIndices.size()
2403 				<< ")" << TestLog::EndMessage;
2404 			isOk = false;
2405 		}
2406 
2407 		for (vector<int>::const_iterator ndxIter = refBlockLayout.activeVarIndices.begin(); ndxIter != refBlockLayout.activeVarIndices.end(); ndxIter++)
2408 		{
2409 			const BufferVarLayoutEntry&	refEntry	= refLayout.bufferVars[*ndxIter];
2410 			int							cmpEntryNdx	= cmpLayout.getVariableIndex(refEntry.name.c_str());
2411 
2412 			if (cmpEntryNdx < 0)
2413 			{
2414 				log << TestLog::Message << "Error: Buffer variable '" << refEntry.name << "' not found" << TestLog::EndMessage;
2415 				isOk = false;
2416 				continue;
2417 			}
2418 
2419 			const BufferVarLayoutEntry&	cmpEntry	= cmpLayout.bufferVars[cmpEntryNdx];
2420 
2421 			if (refEntry.type				!= cmpEntry.type				||
2422 				refEntry.arraySize			!= cmpEntry.arraySize			||
2423 				refEntry.topLevelArraySize	!= cmpEntry.topLevelArraySize	||
2424 				refEntry.isRowMajor	!= cmpEntry.isRowMajor)
2425 			{
2426 				log << TestLog::Message << "Error: Type / array size mismatch in '" << refEntry.name << "':\n"
2427 					<< "  expected: " << refEntry << "\n"
2428 					<< "  got: " << cmpEntry
2429 					<< TestLog::EndMessage;
2430 				isOk = false;
2431 			}
2432 		}
2433 	}
2434 
2435 	return isOk;
2436 }
2437 
compareTypes(const BufferLayout & refLayout,const BufferLayout & cmpLayout) const2438 bool SSBOLayoutCase::compareTypes (const BufferLayout& refLayout, const BufferLayout& cmpLayout) const
2439 {
2440 	TestLog&	log			= m_testCtx.getLog();
2441 	bool		isOk		= true;
2442 	int			numBlocks	= m_interface.getNumBlocks();
2443 
2444 	for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
2445 	{
2446 		const BufferBlock&		block			= m_interface.getBlock(blockNdx);
2447 		bool					isArray			= block.isArray();
2448 		int						numInstances	= isArray ? block.getArraySize() : 1;
2449 
2450 		for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
2451 		{
2452 			std::ostringstream instanceName;
2453 
2454 			instanceName << block.getBlockName();
2455 			if (isArray)
2456 				instanceName << "[" << instanceNdx << "]";
2457 
2458 			int cmpBlockNdx = cmpLayout.getBlockIndex(instanceName.str().c_str());
2459 
2460 			if (cmpBlockNdx < 0)
2461 				continue;
2462 
2463 			const BlockLayoutEntry& cmpBlockLayout = cmpLayout.blocks[cmpBlockNdx];
2464 
2465 			for (vector<int>::const_iterator ndxIter = cmpBlockLayout.activeVarIndices.begin(); ndxIter != cmpBlockLayout.activeVarIndices.end(); ndxIter++)
2466 			{
2467 				const BufferVarLayoutEntry&	cmpEntry	= cmpLayout.bufferVars[*ndxIter];
2468 				int							refEntryNdx	= refLayout.getVariableIndex(cmpEntry.name.c_str());
2469 
2470 				if (refEntryNdx < 0)
2471 				{
2472 					log << TestLog::Message << "Error: Buffer variable '" << cmpEntry.name << "' not found in reference layout" << TestLog::EndMessage;
2473 					isOk = false;
2474 					continue;
2475 				}
2476 
2477 				const BufferVarLayoutEntry&	refEntry	= refLayout.bufferVars[refEntryNdx];
2478 
2479 				if (refEntry.type != cmpEntry.type)
2480 				{
2481 					log << TestLog::Message << "Error: Buffer variable type mismatch in '" << refEntry.name << "':\n"
2482 						<< "  expected: " << glu::getDataTypeName(refEntry.type) << "\n"
2483 						<< "  got: " << glu::getDataTypeName(cmpEntry.type)
2484 						<< TestLog::EndMessage;
2485 					isOk = false;
2486 				}
2487 
2488 				if (refEntry.arraySize < cmpEntry.arraySize)
2489 				{
2490 					log << TestLog::Message << "Error: Invalid array size in '" << refEntry.name << "': expected <= " << refEntry.arraySize << TestLog::EndMessage;
2491 					isOk = false;
2492 				}
2493 
2494 				if (refEntry.topLevelArraySize < cmpEntry.topLevelArraySize)
2495 				{
2496 					log << TestLog::Message << "Error: Invalid top-level array size in '" << refEntry.name << "': expected <= " << refEntry.topLevelArraySize << TestLog::EndMessage;
2497 					isOk = false;
2498 				}
2499 			}
2500 		}
2501 	}
2502 
2503 	return isOk;
2504 }
2505 
checkLayoutIndices(const BufferLayout & layout) const2506 bool SSBOLayoutCase::checkLayoutIndices (const BufferLayout& layout) const
2507 {
2508 	TestLog&	log			= m_testCtx.getLog();
2509 	int			numVars		= (int)layout.bufferVars.size();
2510 	int			numBlocks	= (int)layout.blocks.size();
2511 	bool		isOk		= true;
2512 
2513 	// Check variable block indices.
2514 	for (int varNdx = 0; varNdx < numVars; varNdx++)
2515 	{
2516 		const BufferVarLayoutEntry& bufVar = layout.bufferVars[varNdx];
2517 
2518 		if (bufVar.blockNdx < 0 || !deInBounds32(bufVar.blockNdx, 0, numBlocks))
2519 		{
2520 			log << TestLog::Message << "Error: Invalid block index in buffer variable '" << bufVar.name << "'" << TestLog::EndMessage;
2521 			isOk = false;
2522 		}
2523 	}
2524 
2525 	// Check active variables.
2526 	for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
2527 	{
2528 		const BlockLayoutEntry& block = layout.blocks[blockNdx];
2529 
2530 		for (vector<int>::const_iterator varNdxIter = block.activeVarIndices.begin(); varNdxIter != block.activeVarIndices.end(); varNdxIter++)
2531 		{
2532 			if (!deInBounds32(*varNdxIter, 0, numVars))
2533 			{
2534 				log << TestLog::Message << "Error: Invalid active variable index " << *varNdxIter << " in block '" << block.name << "'" << TestLog::EndMessage;
2535 				isOk = false;
2536 			}
2537 		}
2538 	}
2539 
2540 	return isOk;
2541 }
2542 
checkLayoutBounds(const BufferLayout & layout) const2543 bool SSBOLayoutCase::checkLayoutBounds (const BufferLayout& layout) const
2544 {
2545 	TestLog&	log			= m_testCtx.getLog();
2546 	const int	numVars		= (int)layout.bufferVars.size();
2547 	bool		isOk		= true;
2548 
2549 	for (int varNdx = 0; varNdx < numVars; varNdx++)
2550 	{
2551 		const BufferVarLayoutEntry& var = layout.bufferVars[varNdx];
2552 
2553 		if (var.blockNdx < 0 || isUnsizedArray(var))
2554 			continue;
2555 
2556 		const BlockLayoutEntry&		block			= layout.blocks[var.blockNdx];
2557 		const bool					isMatrix		= glu::isDataTypeMatrix(var.type);
2558 		const int					numVecs			= isMatrix ? (var.isRowMajor ? glu::getDataTypeMatrixNumRows(var.type) : glu::getDataTypeMatrixNumColumns(var.type)) : 1;
2559 		const int					numComps		= isMatrix ? (var.isRowMajor ? glu::getDataTypeMatrixNumColumns(var.type) : glu::getDataTypeMatrixNumRows(var.type)) : glu::getDataTypeScalarSize(var.type);
2560 		const int					numElements		= var.arraySize;
2561 		const int					topLevelSize	= var.topLevelArraySize;
2562 		const int					arrayStride		= var.arrayStride;
2563 		const int					topLevelStride	= var.topLevelArrayStride;
2564 		const int					compSize		= sizeof(deUint32);
2565 		const int					vecSize			= numComps*compSize;
2566 
2567 		int							minOffset		= 0;
2568 		int							maxOffset		= 0;
2569 
2570 		// For negative strides.
2571 		minOffset	= de::min(minOffset, (numVecs-1)*var.matrixStride);
2572 		minOffset	= de::min(minOffset, (numElements-1)*arrayStride);
2573 		minOffset	= de::min(minOffset, (topLevelSize-1)*topLevelStride + (numElements-1)*arrayStride + (numVecs-1)*var.matrixStride);
2574 
2575 		maxOffset	= de::max(maxOffset, vecSize);
2576 		maxOffset	= de::max(maxOffset, (numVecs-1)*var.matrixStride + vecSize);
2577 		maxOffset	= de::max(maxOffset, (numElements-1)*arrayStride + vecSize);
2578 		maxOffset	= de::max(maxOffset, (topLevelSize-1)*topLevelStride + (numElements-1)*arrayStride + vecSize);
2579 		maxOffset	= de::max(maxOffset, (topLevelSize-1)*topLevelStride + (numElements-1)*arrayStride + (numVecs-1)*var.matrixStride + vecSize);
2580 
2581 		if (var.offset+minOffset < 0 || var.offset+maxOffset > block.size)
2582 		{
2583 			log << TestLog::Message << "Error: Variable '" << var.name << "' out of block bounds" << TestLog::EndMessage;
2584 			isOk = false;
2585 		}
2586 	}
2587 
2588 	return isOk;
2589 }
2590 
checkIndexQueries(deUint32 program,const BufferLayout & layout) const2591 bool SSBOLayoutCase::checkIndexQueries (deUint32 program, const BufferLayout& layout) const
2592 {
2593 	tcu::TestLog&				log			= m_testCtx.getLog();
2594 	const glw::Functions&		gl			= m_renderCtx.getFunctions();
2595 	bool						allOk		= true;
2596 
2597 	// \note Spec mandates that buffer blocks are assigned consecutive locations from 0.
2598 	//		 BlockLayoutEntries are stored in that order in UniformLayout.
2599 	for (int blockNdx = 0; blockNdx < (int)layout.blocks.size(); blockNdx++)
2600 	{
2601 		const BlockLayoutEntry&		block		= layout.blocks[blockNdx];
2602 		const int					queriedNdx	= gl.getProgramResourceIndex(program, GL_SHADER_STORAGE_BLOCK, block.name.c_str());
2603 
2604 		if (queriedNdx != blockNdx)
2605 		{
2606 			log << TestLog::Message << "ERROR: glGetProgramResourceIndex(" << block.name << ") returned " << queriedNdx << ", expected " << blockNdx << "!" << TestLog::EndMessage;
2607 			allOk = false;
2608 		}
2609 
2610 		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformBlockIndex()");
2611 	}
2612 
2613 	return allOk;
2614 }
2615 
execute(deUint32 program)2616 bool SSBOLayoutCase::execute (deUint32 program)
2617 {
2618 	const glw::Functions&				gl				= m_renderCtx.getFunctions();
2619 	const deUint32						numPassedLoc	= gl.getProgramResourceIndex(program, GL_UNIFORM, "ac_numPassed");
2620 	const glu::InterfaceVariableInfo	acVarInfo		= numPassedLoc != GL_INVALID_INDEX ? glu::getProgramInterfaceVariableInfo(gl, program, GL_UNIFORM, numPassedLoc)
2621 																						   : glu::InterfaceVariableInfo();
2622 	const glu::InterfaceBlockInfo		acBufferInfo	= acVarInfo.atomicCounterBufferIndex != GL_INVALID_INDEX ? glu::getProgramInterfaceBlockInfo(gl, program, GL_ATOMIC_COUNTER_BUFFER, acVarInfo.atomicCounterBufferIndex)
2623 																												 : glu::InterfaceBlockInfo();
2624 	const glu::Buffer					acBuffer		(m_renderCtx);
2625 	bool								isOk			= true;
2626 
2627 	if (numPassedLoc == GL_INVALID_INDEX)
2628 		throw tcu::TestError("No location for ac_numPassed found");
2629 
2630 	if (acBufferInfo.index == GL_INVALID_INDEX)
2631 		throw tcu::TestError("ac_numPassed buffer index is GL_INVALID_INDEX");
2632 
2633 	if (acBufferInfo.dataSize == 0)
2634 		throw tcu::TestError("ac_numPassed buffer size = 0");
2635 
2636 	// Initialize atomic counter buffer.
2637 	{
2638 		vector<deUint8> emptyData(acBufferInfo.dataSize, 0);
2639 
2640 		gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, *acBuffer);
2641 		gl.bufferData(GL_ATOMIC_COUNTER_BUFFER, (glw::GLsizeiptr)emptyData.size(), &emptyData[0], GL_STATIC_READ);
2642 		gl.bindBufferBase(GL_ATOMIC_COUNTER_BUFFER, acBufferInfo.index, *acBuffer);
2643 		GLU_EXPECT_NO_ERROR(gl.getError(), "Setting up buffer for ac_numPassed failed");
2644 	}
2645 
2646 	gl.useProgram(program);
2647 	gl.dispatchCompute(1, 1, 1);
2648 	GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute() failed");
2649 
2650 	// Read back ac_numPassed data.
2651 	{
2652 		const void*	mapPtr		= gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, acBufferInfo.dataSize, GL_MAP_READ_BIT);
2653 		const int	refCount	= 1;
2654 		int			resCount	= 0;
2655 
2656 		GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER) failed");
2657 		TCU_CHECK(mapPtr);
2658 
2659 		resCount = *(const int*)((const deUint8*)mapPtr + acVarInfo.offset);
2660 
2661 		gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
2662 		GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER) failed");
2663 
2664 		if (refCount != resCount)
2665 		{
2666 			m_testCtx.getLog() << TestLog::Message << "ERROR: ac_numPassed = " << resCount << ", expected " << refCount << TestLog::EndMessage;
2667 			isOk = false;
2668 		}
2669 	}
2670 
2671 	GLU_EXPECT_NO_ERROR(gl.getError(), "Shader execution failed");
2672 
2673 	return isOk;
2674 }
2675 
2676 } // gles31
2677 } // deqp
2678