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