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