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