Home | History | Annotate | Download | only in ubo
      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 Uniform block case.
     24  *//*--------------------------------------------------------------------*/
     25 
     26 #include "vktUniformBlockCase.hpp"
     27 
     28 #include "vkPrograms.hpp"
     29 
     30 #include "gluVarType.hpp"
     31 #include "tcuTestLog.hpp"
     32 #include "tcuSurface.hpp"
     33 #include "deRandom.hpp"
     34 #include "deStringUtil.hpp"
     35 
     36 #include "tcuTextureUtil.hpp"
     37 #include "deSharedPtr.hpp"
     38 #include "deFloat16.h"
     39 
     40 #include "vkMemUtil.hpp"
     41 #include "vkQueryUtil.hpp"
     42 #include "vkTypeUtil.hpp"
     43 #include "vkRef.hpp"
     44 #include "vkRefUtil.hpp"
     45 #include "vkBuilderUtil.hpp"
     46 #include "vkCmdUtil.hpp"
     47 #include "vkObjUtil.hpp"
     48 #include "vkImageUtil.hpp"
     49 
     50 #include <map>
     51 #include <set>
     52 
     53 namespace vkt
     54 {
     55 namespace ubo
     56 {
     57 
     58 using namespace vk;
     59 
     60 // VarType implementation.
     61 
     62 VarType::VarType (void)
     63 	: m_type	(TYPE_LAST)
     64 	, m_flags	(0)
     65 {
     66 }
     67 
     68 VarType::VarType (const VarType& other)
     69 	: m_type	(TYPE_LAST)
     70 	, m_flags	(0)
     71 {
     72 	*this = other;
     73 }
     74 
     75 VarType::VarType (glu::DataType basicType, deUint32 flags)
     76 	: m_type	(TYPE_BASIC)
     77 	, m_flags	(flags)
     78 {
     79 	m_data.basicType = basicType;
     80 }
     81 
     82 VarType::VarType (const VarType& elementType, int arraySize)
     83 	: m_type	(TYPE_ARRAY)
     84 	, m_flags	(0)
     85 {
     86 	m_data.array.size			= arraySize;
     87 	m_data.array.elementType	= new VarType(elementType);
     88 }
     89 
     90 VarType::VarType (const StructType* structPtr, deUint32 flags)
     91 	: m_type	(TYPE_STRUCT)
     92 	, m_flags	(flags)
     93 {
     94 	m_data.structPtr = structPtr;
     95 }
     96 
     97 VarType::~VarType (void)
     98 {
     99 	if (m_type == TYPE_ARRAY)
    100 		delete m_data.array.elementType;
    101 }
    102 
    103 VarType& VarType::operator= (const VarType& other)
    104 {
    105 	if (this == &other)
    106 		return *this; // Self-assignment.
    107 
    108 	VarType *oldElementType = m_type == TYPE_ARRAY ? m_data.array.elementType : DE_NULL;
    109 
    110 	m_type	= other.m_type;
    111 	m_flags	= other.m_flags;
    112 	m_data	= Data();
    113 
    114 	if (m_type == TYPE_ARRAY)
    115 	{
    116 		m_data.array.elementType	= new VarType(*other.m_data.array.elementType);
    117 		m_data.array.size			= other.m_data.array.size;
    118 	}
    119 	else
    120 		m_data = other.m_data;
    121 
    122 	delete oldElementType;
    123 
    124 	return *this;
    125 }
    126 
    127 // StructType implementation.
    128 
    129 void StructType::addMember (const std::string& name, const VarType& type, deUint32 flags)
    130 {
    131 	m_members.push_back(StructMember(name, type, flags));
    132 }
    133 
    134 // Uniform implementation.
    135 
    136 Uniform::Uniform (const std::string& name, const VarType& type, deUint32 flags)
    137 	: m_name	(name)
    138 	, m_type	(type)
    139 	, m_flags	(flags)
    140 {
    141 }
    142 
    143 // UniformBlock implementation.
    144 
    145 UniformBlock::UniformBlock (const std::string& blockName)
    146 	: m_blockName	(blockName)
    147 	, m_arraySize	(0)
    148 	, m_flags		(0)
    149 {
    150 }
    151 
    152 std::ostream& operator<< (std::ostream& stream, const BlockLayoutEntry& entry)
    153 {
    154 	stream << entry.name << " { name = " << entry.name
    155 		   << ", size = " << entry.size
    156 		   << ", activeUniformIndices = [";
    157 
    158 	for (std::vector<int>::const_iterator i = entry.activeUniformIndices.begin(); i != entry.activeUniformIndices.end(); i++)
    159 	{
    160 		if (i != entry.activeUniformIndices.begin())
    161 			stream << ", ";
    162 		stream << *i;
    163 	}
    164 
    165 	stream << "] }";
    166 	return stream;
    167 }
    168 
    169 std::ostream& operator<< (std::ostream& stream, const UniformLayoutEntry& entry)
    170 {
    171 	stream << entry.name << " { type = " << glu::getDataTypeName(entry.type)
    172 		   << ", size = " << entry.size
    173 		   << ", blockNdx = " << entry.blockNdx
    174 		   << ", offset = " << entry.offset
    175 		   << ", arrayStride = " << entry.arrayStride
    176 		   << ", matrixStride = " << entry.matrixStride
    177 		   << ", isRowMajor = " << (entry.isRowMajor ? "true" : "false")
    178 		   << " }";
    179 	return stream;
    180 }
    181 
    182 int UniformLayout::getUniformLayoutIndex (int blockNdx, const std::string& name) const
    183 {
    184 	for (int ndx = 0; ndx < (int)uniforms.size(); ndx++)
    185 	{
    186 		if (blocks[uniforms[ndx].blockNdx].blockDeclarationNdx == blockNdx &&
    187 			uniforms[ndx].name == name)
    188 			return ndx;
    189 	}
    190 
    191 	return -1;
    192 }
    193 
    194 int UniformLayout::getBlockLayoutIndex (int blockNdx, int instanceNdx) const
    195 {
    196 	for (int ndx = 0; ndx < (int)blocks.size(); ndx++)
    197 	{
    198 		if (blocks[ndx].blockDeclarationNdx == blockNdx &&
    199 			blocks[ndx].instanceNdx == instanceNdx)
    200 			return ndx;
    201 	}
    202 
    203 	return -1;
    204 }
    205 
    206 // ShaderInterface implementation.
    207 
    208 ShaderInterface::ShaderInterface (void)
    209 {
    210 }
    211 
    212 ShaderInterface::~ShaderInterface (void)
    213 {
    214 }
    215 
    216 StructType& ShaderInterface::allocStruct (const std::string& name)
    217 {
    218 	m_structs.push_back(StructTypeSP(new StructType(name)));
    219 	return *m_structs.back();
    220 }
    221 
    222 struct StructNameEquals
    223 {
    224 	std::string name;
    225 
    226 	StructNameEquals (const std::string& name_) : name(name_) {}
    227 
    228 	bool operator() (const StructTypeSP type) const
    229 	{
    230 		return type->hasTypeName() && name == type->getTypeName();
    231 	}
    232 };
    233 
    234 void ShaderInterface::getNamedStructs (std::vector<const StructType*>& structs) const
    235 {
    236 	for (std::vector<StructTypeSP>::const_iterator i = m_structs.begin(); i != m_structs.end(); i++)
    237 	{
    238 		if ((*i)->hasTypeName())
    239 			structs.push_back((*i).get());
    240 	}
    241 }
    242 
    243 UniformBlock& ShaderInterface::allocBlock (const std::string& name)
    244 {
    245 	m_uniformBlocks.push_back(UniformBlockSP(new UniformBlock(name)));
    246 	return *m_uniformBlocks.back();
    247 }
    248 
    249 bool ShaderInterface::usesBlockLayout (UniformFlags layoutFlag) const
    250 {
    251 	for (int i = 0, num_blocks = getNumUniformBlocks() ; i < num_blocks ; i++)
    252 	{
    253 		if (m_uniformBlocks[i]->getFlags() & layoutFlag)
    254 			return true;
    255 	}
    256 	return false;
    257 }
    258 
    259 namespace // Utilities
    260 {
    261 
    262 struct PrecisionFlagsFmt
    263 {
    264 	deUint32 flags;
    265 	PrecisionFlagsFmt (deUint32 flags_) : flags(flags_) {}
    266 };
    267 
    268 std::ostream& operator<< (std::ostream& str, const PrecisionFlagsFmt& fmt)
    269 {
    270 	// Precision.
    271 	DE_ASSERT(dePop32(fmt.flags & (PRECISION_LOW|PRECISION_MEDIUM|PRECISION_HIGH)) <= 1);
    272 	str << (fmt.flags & PRECISION_LOW		? "lowp"	:
    273 			fmt.flags & PRECISION_MEDIUM	? "mediump"	:
    274 			fmt.flags & PRECISION_HIGH		? "highp"	: "");
    275 	return str;
    276 }
    277 
    278 struct LayoutFlagsFmt
    279 {
    280 	deUint32 flags;
    281 	deUint32 offset;
    282 	LayoutFlagsFmt (deUint32 flags_, deUint32 offset_ = 0u) : flags(flags_), offset(offset_) {}
    283 };
    284 
    285 std::ostream& operator<< (std::ostream& str, const LayoutFlagsFmt& fmt)
    286 {
    287 	static const struct
    288 	{
    289 		deUint32	bit;
    290 		const char*	token;
    291 	} bitDesc[] =
    292 	{
    293 		{ LAYOUT_STD140,		"std140"		},
    294 		{ LAYOUT_STD430,		"std430"		},
    295 		{ LAYOUT_SCALAR,		"scalar"		},
    296 		{ LAYOUT_ROW_MAJOR,		"row_major"		},
    297 		{ LAYOUT_COLUMN_MAJOR,	"column_major"	},
    298 		{ LAYOUT_OFFSET,		"offset"		},
    299 	};
    300 
    301 	deUint32 remBits = fmt.flags;
    302 	for (int descNdx = 0; descNdx < DE_LENGTH_OF_ARRAY(bitDesc); descNdx++)
    303 	{
    304 		if (remBits & bitDesc[descNdx].bit)
    305 		{
    306 			if (remBits != fmt.flags)
    307 				str << ", ";
    308 			str << bitDesc[descNdx].token;
    309 			if (bitDesc[descNdx].bit == LAYOUT_OFFSET)
    310 				str << " = " << fmt.offset;
    311 			remBits &= ~bitDesc[descNdx].bit;
    312 		}
    313 	}
    314 	DE_ASSERT(remBits == 0);
    315 	return str;
    316 }
    317 
    318 // Layout computation.
    319 
    320 int getDataTypeByteSize (glu::DataType type)
    321 {
    322 	if (deInRange32(type, glu::TYPE_UINT8, glu::TYPE_UINT8_VEC4) || deInRange32(type, glu::TYPE_INT8, glu::TYPE_INT8_VEC4))
    323 	{
    324 		return glu::getDataTypeScalarSize(type)*(int)sizeof(deUint8);
    325 	}
    326 	if (deInRange32(type, glu::TYPE_UINT16, glu::TYPE_UINT16_VEC4) || deInRange32(type, glu::TYPE_INT16, glu::TYPE_INT16_VEC4) || deInRange32(type, glu::TYPE_FLOAT16, glu::TYPE_FLOAT16_VEC4))
    327 	{
    328 		return glu::getDataTypeScalarSize(type)*(int)sizeof(deUint16);
    329 	}
    330 	else
    331 	{
    332 		return glu::getDataTypeScalarSize(type)*(int)sizeof(deUint32);
    333 	}
    334 }
    335 
    336 int getDataTypeByteAlignment (glu::DataType type)
    337 {
    338 	switch (type)
    339 	{
    340 		case glu::TYPE_FLOAT:
    341 		case glu::TYPE_INT:
    342 		case glu::TYPE_UINT:
    343 		case glu::TYPE_BOOL:		return 1*(int)sizeof(deUint32);
    344 
    345 		case glu::TYPE_FLOAT_VEC2:
    346 		case glu::TYPE_INT_VEC2:
    347 		case glu::TYPE_UINT_VEC2:
    348 		case glu::TYPE_BOOL_VEC2:	return 2*(int)sizeof(deUint32);
    349 
    350 		case glu::TYPE_FLOAT_VEC3:
    351 		case glu::TYPE_INT_VEC3:
    352 		case glu::TYPE_UINT_VEC3:
    353 		case glu::TYPE_BOOL_VEC3:	// Fall-through to vec4
    354 
    355 		case glu::TYPE_FLOAT_VEC4:
    356 		case glu::TYPE_INT_VEC4:
    357 		case glu::TYPE_UINT_VEC4:
    358 		case glu::TYPE_BOOL_VEC4:	return 4*(int)sizeof(deUint32);
    359 
    360 		case glu::TYPE_UINT8:
    361 		case glu::TYPE_INT8	:			return 1*(int)sizeof(deUint8);
    362 
    363 		case glu::TYPE_UINT8_VEC2:
    364 		case glu::TYPE_INT8_VEC2:		return 2*(int)sizeof(deUint8);
    365 
    366 		case glu::TYPE_UINT8_VEC3:
    367 		case glu::TYPE_INT8_VEC3:		// Fall-through to vec4
    368 
    369 		case glu::TYPE_UINT8_VEC4:
    370 		case glu::TYPE_INT8_VEC4:		return 4*(int)sizeof(deUint8);
    371 
    372 		case glu::TYPE_UINT16:
    373 		case glu::TYPE_INT16:
    374 		case glu::TYPE_FLOAT16:			return 1*(int)sizeof(deUint16);
    375 
    376 		case glu::TYPE_UINT16_VEC2:
    377 		case glu::TYPE_INT16_VEC2:
    378 		case glu::TYPE_FLOAT16_VEC2:	return 2*(int)sizeof(deUint16);
    379 
    380 		case glu::TYPE_UINT16_VEC3:
    381 		case glu::TYPE_INT16_VEC3:
    382 		case glu::TYPE_FLOAT16_VEC3:	// Fall-through to vec4
    383 
    384 		case glu::TYPE_UINT16_VEC4:
    385 		case glu::TYPE_INT16_VEC4:
    386 		case glu::TYPE_FLOAT16_VEC4:	return 4*(int)sizeof(deUint16);
    387 
    388 		default:
    389 			DE_ASSERT(false);
    390 			return 0;
    391 	}
    392 }
    393 
    394 deInt32 getminUniformBufferOffsetAlignment (Context &ctx)
    395 {
    396 	VkPhysicalDeviceProperties properties;
    397 	ctx.getInstanceInterface().getPhysicalDeviceProperties(ctx.getPhysicalDevice(), &properties);
    398 	VkDeviceSize align = properties.limits.minUniformBufferOffsetAlignment;
    399 	DE_ASSERT(align == (VkDeviceSize)(deInt32)align);
    400 	return (deInt32)align;
    401 }
    402 
    403 static inline int deRoundUp32 (int a, int b)
    404 {
    405 	int d = a/b;
    406 	return d*b == a ? a : (d+1)*b;
    407 }
    408 
    409 
    410 int computeStd140BaseAlignment (const VarType& type, deUint32 layoutFlags)
    411 {
    412 	const int vec4Alignment = (int)sizeof(deUint32)*4;
    413 
    414 	if (type.isBasicType())
    415 	{
    416 		glu::DataType basicType = type.getBasicType();
    417 
    418 		if (glu::isDataTypeMatrix(basicType))
    419 		{
    420 			const bool	isRowMajor	= !!(layoutFlags & LAYOUT_ROW_MAJOR);
    421 			const int	vecSize		= isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType)
    422 												 : glu::getDataTypeMatrixNumRows(basicType);
    423 			const int	vecAlign	= deAlign32(getDataTypeByteAlignment(glu::getDataTypeFloatVec(vecSize)), vec4Alignment);
    424 
    425 			return vecAlign;
    426 		}
    427 		else
    428 			return getDataTypeByteAlignment(basicType);
    429 	}
    430 	else if (type.isArrayType())
    431 	{
    432 		int elemAlignment = computeStd140BaseAlignment(type.getElementType(), layoutFlags);
    433 
    434 		// Round up to alignment of vec4
    435 		return deAlign32(elemAlignment, vec4Alignment);
    436 	}
    437 	else
    438 	{
    439 		DE_ASSERT(type.isStructType());
    440 
    441 		int maxBaseAlignment = 0;
    442 
    443 		for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++)
    444 			maxBaseAlignment = de::max(maxBaseAlignment, computeStd140BaseAlignment(memberIter->getType(), layoutFlags));
    445 
    446 		return deAlign32(maxBaseAlignment, vec4Alignment);
    447 	}
    448 }
    449 
    450 int computeStd430BaseAlignment (const VarType& type, deUint32 layoutFlags)
    451 {
    452 	// Otherwise identical to std140 except that alignment of structures and arrays
    453 	// are not rounded up to alignment of vec4.
    454 
    455 	if (type.isBasicType())
    456 	{
    457 		glu::DataType basicType = type.getBasicType();
    458 
    459 		if (glu::isDataTypeMatrix(basicType))
    460 		{
    461 			const bool	isRowMajor	= !!(layoutFlags & LAYOUT_ROW_MAJOR);
    462 			const int	vecSize		= isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType)
    463 												 : glu::getDataTypeMatrixNumRows(basicType);
    464 			const int	vecAlign	= getDataTypeByteAlignment(glu::getDataTypeFloatVec(vecSize));
    465 			return vecAlign;
    466 		}
    467 		else
    468 			return getDataTypeByteAlignment(basicType);
    469 	}
    470 	else if (type.isArrayType())
    471 	{
    472 		return computeStd430BaseAlignment(type.getElementType(), layoutFlags);
    473 	}
    474 	else
    475 	{
    476 		DE_ASSERT(type.isStructType());
    477 
    478 		int maxBaseAlignment = 0;
    479 
    480 		for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++)
    481 			maxBaseAlignment = de::max(maxBaseAlignment, computeStd430BaseAlignment(memberIter->getType(), layoutFlags));
    482 
    483 		return maxBaseAlignment;
    484 	}
    485 }
    486 
    487 int computeRelaxedBlockBaseAlignment (const VarType& type, deUint32 layoutFlags)
    488 {
    489 	if (type.isBasicType())
    490 	{
    491 		glu::DataType basicType = type.getBasicType();
    492 
    493 		if (glu::isDataTypeVector(basicType))
    494 			return getDataTypeByteAlignment(glu::getDataTypeScalarType(basicType));
    495 
    496 		if (glu::isDataTypeMatrix(basicType))
    497 		{
    498 			const bool	isRowMajor	= !!(layoutFlags & LAYOUT_ROW_MAJOR);
    499 			const int	vecSize		= isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType)
    500 												 : glu::getDataTypeMatrixNumRows(basicType);
    501 			const int	vecAlign	= getDataTypeByteAlignment(glu::getDataTypeFloatVec(vecSize));
    502 			return vecAlign;
    503 		}
    504 		else
    505 			return getDataTypeByteAlignment(basicType);
    506 	}
    507 	else if (type.isArrayType())
    508 		return computeStd430BaseAlignment(type.getElementType(), layoutFlags);
    509 	else
    510 	{
    511 		DE_ASSERT(type.isStructType());
    512 
    513 		int maxBaseAlignment = 0;
    514 		for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++)
    515 			maxBaseAlignment = de::max(maxBaseAlignment, computeRelaxedBlockBaseAlignment(memberIter->getType(), layoutFlags));
    516 
    517 		return maxBaseAlignment;
    518 	}
    519 }
    520 
    521 int computeScalarBlockAlignment (const VarType& type, deUint32 layoutFlags)
    522 {
    523 	if (type.isBasicType())
    524 	{
    525 		return getDataTypeByteAlignment(glu::getDataTypeScalarType(type.getBasicType()));
    526 	}
    527 	else if (type.isArrayType())
    528 		return computeScalarBlockAlignment(type.getElementType(), layoutFlags);
    529 	else
    530 	{
    531 		DE_ASSERT(type.isStructType());
    532 
    533 		int maxBaseAlignment = 0;
    534 		for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++)
    535 			maxBaseAlignment = de::max(maxBaseAlignment, computeScalarBlockAlignment(memberIter->getType(), layoutFlags));
    536 
    537 		return maxBaseAlignment;
    538 	}
    539 }
    540 
    541 inline deUint32 mergeLayoutFlags (deUint32 prevFlags, deUint32 newFlags)
    542 {
    543 	const deUint32	packingMask		= LAYOUT_STD140|LAYOUT_STD430|LAYOUT_SCALAR;
    544 	const deUint32	matrixMask		= LAYOUT_ROW_MAJOR|LAYOUT_COLUMN_MAJOR;
    545 
    546 	deUint32 mergedFlags = 0;
    547 
    548 	mergedFlags |= ((newFlags & packingMask)	? newFlags : prevFlags) & packingMask;
    549 	mergedFlags |= ((newFlags & matrixMask)		? newFlags : prevFlags) & matrixMask;
    550 
    551 	return mergedFlags;
    552 }
    553 
    554 //! Appends all child elements to layout, returns value that should be appended to offset.
    555 int computeReferenceLayout (
    556 	UniformLayout&		layout,
    557 	int					curBlockNdx,
    558 	int					baseOffset,
    559 	const std::string&	curPrefix,
    560 	const VarType&		type,
    561 	deUint32			layoutFlags)
    562 {
    563 	// HACK to make code match SSBO tests
    564 	const int LAYOUT_RELAXED = 0;
    565 	// Reference layout uses std140 rules by default. std430 rules are
    566 	// choosen only for blocks that have std140 layout.
    567 	const int	baseAlignment		= (layoutFlags & LAYOUT_SCALAR)  != 0 ? computeScalarBlockAlignment(type, layoutFlags)			:
    568 									  (layoutFlags & LAYOUT_STD430)  != 0 ? computeStd430BaseAlignment(type, layoutFlags)		:
    569 									  (layoutFlags & LAYOUT_RELAXED) != 0 ? computeRelaxedBlockBaseAlignment(type, layoutFlags)	:
    570 									  computeStd140BaseAlignment(type, layoutFlags);
    571 	int			curOffset			= deAlign32(baseOffset, baseAlignment);
    572 	const int	topLevelArraySize	= 1; // Default values
    573 	const int	topLevelArrayStride	= 0;
    574 
    575 	if (type.isBasicType())
    576 	{
    577 		const glu::DataType		basicType	= type.getBasicType();
    578 		UniformLayoutEntry		entry;
    579 
    580 		entry.name					= curPrefix;
    581 		entry.type					= basicType;
    582 		entry.arraySize				= 1;
    583 		entry.arrayStride			= 0;
    584 		entry.matrixStride			= 0;
    585 		entry.topLevelArraySize		= topLevelArraySize;
    586 		entry.topLevelArrayStride	= topLevelArrayStride;
    587 		entry.blockNdx				= curBlockNdx;
    588 
    589 		if (glu::isDataTypeMatrix(basicType))
    590 		{
    591 			// Array of vectors as specified in rules 5 & 7.
    592 			const bool	isRowMajor			= !!(layoutFlags & LAYOUT_ROW_MAJOR);
    593 			const int	vecSize				= isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType)
    594 														 : glu::getDataTypeMatrixNumRows(basicType);
    595 			const glu::DataType	vecType		= glu::getDataTypeFloatVec(vecSize);
    596 			const int	numVecs				= isRowMajor ? glu::getDataTypeMatrixNumRows(basicType)
    597 														 : glu::getDataTypeMatrixNumColumns(basicType);
    598 			const int	vecStride			= (layoutFlags & LAYOUT_SCALAR) ? getDataTypeByteSize(vecType) : baseAlignment;
    599 
    600 			entry.offset		= curOffset;
    601 			entry.matrixStride	= vecStride;
    602 			entry.isRowMajor	= isRowMajor;
    603 
    604 			curOffset += numVecs*entry.matrixStride;
    605 		}
    606 		else
    607 		{
    608 			if (!(layoutFlags & LAYOUT_SCALAR) && (layoutFlags & LAYOUT_RELAXED) &&
    609 				glu::isDataTypeVector(basicType) && (getDataTypeByteSize(basicType) <= 16 ? curOffset / 16 != (curOffset +  getDataTypeByteSize(basicType) - 1) / 16 : curOffset % 16 != 0))
    610 				curOffset = deIntRoundToPow2(curOffset, 16);
    611 
    612 			// Scalar or vector.
    613 			entry.offset = curOffset;
    614 
    615 			curOffset += getDataTypeByteSize(basicType);
    616 		}
    617 
    618 		layout.uniforms.push_back(entry);
    619 	}
    620 	else if (type.isArrayType())
    621 	{
    622 		const VarType&	elemType	= type.getElementType();
    623 
    624 		if (elemType.isBasicType() && !glu::isDataTypeMatrix(elemType.getBasicType()))
    625 		{
    626 			// Array of scalars or vectors.
    627 			const glu::DataType		elemBasicType	= elemType.getBasicType();
    628 			const int				stride			= (layoutFlags & LAYOUT_SCALAR) ? getDataTypeByteSize(elemBasicType) : baseAlignment;
    629 			UniformLayoutEntry		entry;
    630 
    631 			entry.name					= curPrefix + "[0]"; // Array variables are always postfixed with [0]
    632 			entry.type					= elemBasicType;
    633 			entry.blockNdx				= curBlockNdx;
    634 			entry.offset				= curOffset;
    635 			entry.arraySize				= type.getArraySize();
    636 			entry.arrayStride			= stride;
    637 			entry.matrixStride			= 0;
    638 			entry.topLevelArraySize		= topLevelArraySize;
    639 			entry.topLevelArrayStride	= topLevelArrayStride;
    640 
    641 			curOffset += stride*type.getArraySize();
    642 
    643 			layout.uniforms.push_back(entry);
    644 		}
    645 		else if (elemType.isBasicType() && glu::isDataTypeMatrix(elemType.getBasicType()))
    646 		{
    647 			// Array of matrices.
    648 			const glu::DataType			elemBasicType	= elemType.getBasicType();
    649 			const bool					isRowMajor		= !!(layoutFlags & LAYOUT_ROW_MAJOR);
    650 			const int					vecSize			= isRowMajor ? glu::getDataTypeMatrixNumColumns(elemBasicType)
    651 																	 : glu::getDataTypeMatrixNumRows(elemBasicType);
    652 			const glu::DataType			vecType			= glu::getDataTypeFloatVec(vecSize);
    653 			const int					numVecs			= isRowMajor ? glu::getDataTypeMatrixNumRows(elemBasicType)
    654 																	 : glu::getDataTypeMatrixNumColumns(elemBasicType);
    655 			const int					vecStride		= (layoutFlags & LAYOUT_SCALAR) ? getDataTypeByteSize(vecType) : baseAlignment;
    656 			UniformLayoutEntry			entry;
    657 
    658 			entry.name					= curPrefix + "[0]"; // Array variables are always postfixed with [0]
    659 			entry.type					= elemBasicType;
    660 			entry.blockNdx				= curBlockNdx;
    661 			entry.offset				= curOffset;
    662 			entry.arraySize				= type.getArraySize();
    663 			entry.arrayStride			= vecStride*numVecs;
    664 			entry.matrixStride			= vecStride;
    665 			entry.isRowMajor			= isRowMajor;
    666 			entry.topLevelArraySize		= topLevelArraySize;
    667 			entry.topLevelArrayStride	= topLevelArrayStride;
    668 
    669 			curOffset += entry.arrayStride*type.getArraySize();
    670 
    671 			layout.uniforms.push_back(entry);
    672 		}
    673 		else
    674 		{
    675 			DE_ASSERT(elemType.isStructType() || elemType.isArrayType());
    676 
    677 			for (int elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++)
    678 				curOffset += computeReferenceLayout(layout, curBlockNdx, curOffset, curPrefix + "[" + de::toString(elemNdx) + "]", type.getElementType(), layoutFlags);
    679 		}
    680 	}
    681 	else
    682 	{
    683 		DE_ASSERT(type.isStructType());
    684 
    685 		for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++)
    686 			curOffset += computeReferenceLayout(layout, curBlockNdx, curOffset, curPrefix + "." + memberIter->getName(), memberIter->getType(), layoutFlags);
    687 
    688 		if (!(layoutFlags & LAYOUT_SCALAR))
    689 			curOffset = deAlign32(curOffset, baseAlignment);
    690 	}
    691 
    692 	return curOffset-baseOffset;
    693 }
    694 
    695 void computeReferenceLayout (UniformLayout& layout, const ShaderInterface& interface)
    696 {
    697 	int numUniformBlocks = interface.getNumUniformBlocks();
    698 
    699 	for (int blockNdx = 0; blockNdx < numUniformBlocks; blockNdx++)
    700 	{
    701 		const UniformBlock&	block			= interface.getUniformBlock(blockNdx);
    702 		bool				hasInstanceName	= block.hasInstanceName();
    703 		std::string			blockPrefix		= hasInstanceName ? (block.getBlockName() + ".") : "";
    704 		int					curOffset		= 0;
    705 		int					activeBlockNdx	= (int)layout.blocks.size();
    706 		int					firstUniformNdx	= (int)layout.uniforms.size();
    707 
    708 		for (UniformBlock::ConstIterator uniformIter = block.begin(); uniformIter != block.end(); uniformIter++)
    709 		{
    710 			const Uniform& uniform = *uniformIter;
    711 			curOffset += computeReferenceLayout(layout, activeBlockNdx, curOffset, blockPrefix + uniform.getName(), uniform.getType(), mergeLayoutFlags(block.getFlags(), uniform.getFlags()));
    712 		}
    713 
    714 		int	uniformIndicesEnd	= (int)layout.uniforms.size();
    715 		int	blockSize			= curOffset;
    716 		int	numInstances		= block.isArray() ? block.getArraySize() : 1;
    717 
    718 		// Create block layout entries for each instance.
    719 		for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
    720 		{
    721 			// Allocate entry for instance.
    722 			layout.blocks.push_back(BlockLayoutEntry());
    723 			BlockLayoutEntry& blockEntry = layout.blocks.back();
    724 
    725 			blockEntry.name = block.getBlockName();
    726 			blockEntry.size = blockSize;
    727 			blockEntry.bindingNdx = blockNdx;
    728 			blockEntry.blockDeclarationNdx = blockNdx;
    729 			blockEntry.instanceNdx = instanceNdx;
    730 
    731 			// Compute active uniform set for block.
    732 			for (int uniformNdx = firstUniformNdx; uniformNdx < uniformIndicesEnd; uniformNdx++)
    733 				blockEntry.activeUniformIndices.push_back(uniformNdx);
    734 
    735 			if (block.isArray())
    736 				blockEntry.name += "[" + de::toString(instanceNdx) + "]";
    737 		}
    738 	}
    739 }
    740 
    741 // Value generator.
    742 
    743 void generateValue (const UniformLayoutEntry& entry, void* basePtr, de::Random& rnd)
    744 {
    745 	glu::DataType	scalarType		= glu::getDataTypeScalarType(entry.type);
    746 	int				scalarSize		= glu::getDataTypeScalarSize(entry.type);
    747 	bool			isMatrix		= glu::isDataTypeMatrix(entry.type);
    748 	int				numVecs			= isMatrix ? (entry.isRowMajor ? glu::getDataTypeMatrixNumRows(entry.type) : glu::getDataTypeMatrixNumColumns(entry.type)) : 1;
    749 	int				vecSize			= scalarSize / numVecs;
    750 	bool			isArray			= entry.size > 1;
    751 	const size_t	compSize		= getDataTypeByteSize(scalarType);
    752 
    753 	DE_ASSERT(scalarSize%numVecs == 0);
    754 
    755 	for (int elemNdx = 0; elemNdx < entry.size; elemNdx++)
    756 	{
    757 		deUint8* elemPtr = (deUint8*)basePtr + entry.offset + (isArray ? elemNdx*entry.arrayStride : 0);
    758 
    759 		for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
    760 		{
    761 			deUint8* vecPtr = elemPtr + (isMatrix ? vecNdx*entry.matrixStride : 0);
    762 
    763 			for (int compNdx = 0; compNdx < vecSize; compNdx++)
    764 			{
    765 				deUint8* compPtr = vecPtr + compSize*compNdx;
    766 
    767 				switch (scalarType)
    768 				{
    769 					case glu::TYPE_FLOAT:	*((float*)compPtr)		= (float)rnd.getInt(-9, 9);						break;
    770 					case glu::TYPE_INT:		*((int*)compPtr)		= rnd.getInt(-9, 9);							break;
    771 					case glu::TYPE_UINT:	*((deUint32*)compPtr)	= (deUint32)rnd.getInt(0, 9);					break;
    772 					case glu::TYPE_INT8:	*((deInt8*)compPtr)		= (deInt8)rnd.getInt(-9, 9);					break;
    773 					case glu::TYPE_UINT8:	*((deUint8*)compPtr)	= (deUint8)rnd.getInt(0, 9);					break;
    774 					case glu::TYPE_INT16:	*((deInt16*)compPtr)	= (deInt16)rnd.getInt(-9, 9);					break;
    775 					case glu::TYPE_UINT16:	*((deUint16*)compPtr)	= (deUint16)rnd.getInt(0, 9);					break;
    776 					case glu::TYPE_FLOAT16:	*((deFloat16*)compPtr)	= deFloat32To16((float)rnd.getInt(-9, 9));		break;
    777 					// \note Random bit pattern is used for true values. Spec states that all non-zero values are
    778 					//       interpreted as true but some implementations fail this.
    779 					case glu::TYPE_BOOL:	*((deUint32*)compPtr)	= rnd.getBool() ? rnd.getUint32()|1u : 0u;		break;
    780 					default:
    781 						DE_ASSERT(false);
    782 				}
    783 			}
    784 		}
    785 	}
    786 }
    787 
    788 void generateValues (const UniformLayout& layout, const std::map<int, void*>& blockPointers, deUint32 seed)
    789 {
    790 	de::Random	rnd			(seed);
    791 	int			numBlocks	= (int)layout.blocks.size();
    792 
    793 	for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
    794 	{
    795 		void*	basePtr		= blockPointers.find(blockNdx)->second;
    796 		int		numEntries	= (int)layout.blocks[blockNdx].activeUniformIndices.size();
    797 
    798 		for (int entryNdx = 0; entryNdx < numEntries; entryNdx++)
    799 		{
    800 			const UniformLayoutEntry& entry = layout.uniforms[layout.blocks[blockNdx].activeUniformIndices[entryNdx]];
    801 			generateValue(entry, basePtr, rnd);
    802 		}
    803 	}
    804 }
    805 
    806 // Shader generator.
    807 
    808 const char* getCompareFuncForType (glu::DataType type)
    809 {
    810 	switch (type)
    811 	{
    812 		case glu::TYPE_FLOAT:			return "mediump float compare_float    (highp float a, highp float b)  { return abs(a - b) < 0.05 ? 1.0 : 0.0; }\n";
    813 		case glu::TYPE_FLOAT_VEC2:		return "mediump float compare_vec2     (highp vec2 a, highp vec2 b)    { return compare_float(a.x, b.x)*compare_float(a.y, b.y); }\n";
    814 		case glu::TYPE_FLOAT_VEC3:		return "mediump float 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";
    815 		case glu::TYPE_FLOAT_VEC4:		return "mediump float 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";
    816 		case glu::TYPE_FLOAT_MAT2:		return "mediump float compare_mat2     (highp mat2 a, highp mat2 b)    { return compare_vec2(a[0], b[0])*compare_vec2(a[1], b[1]); }\n";
    817 		case glu::TYPE_FLOAT_MAT2X3:	return "mediump float compare_mat2x3   (highp mat2x3 a, highp mat2x3 b){ return compare_vec3(a[0], b[0])*compare_vec3(a[1], b[1]); }\n";
    818 		case glu::TYPE_FLOAT_MAT2X4:	return "mediump float compare_mat2x4   (highp mat2x4 a, highp mat2x4 b){ return compare_vec4(a[0], b[0])*compare_vec4(a[1], b[1]); }\n";
    819 		case glu::TYPE_FLOAT_MAT3X2:	return "mediump float 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";
    820 		case glu::TYPE_FLOAT_MAT3:		return "mediump float 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";
    821 		case glu::TYPE_FLOAT_MAT3X4:	return "mediump float 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";
    822 		case glu::TYPE_FLOAT_MAT4X2:	return "mediump float 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";
    823 		case glu::TYPE_FLOAT_MAT4X3:	return "mediump float 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";
    824 		case glu::TYPE_FLOAT_MAT4:		return "mediump float 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";
    825 		case glu::TYPE_INT:				return "mediump float compare_int      (highp int a, highp int b)      { return a == b ? 1.0 : 0.0; }\n";
    826 		case glu::TYPE_INT_VEC2:		return "mediump float compare_ivec2    (highp ivec2 a, highp ivec2 b)  { return a == b ? 1.0 : 0.0; }\n";
    827 		case glu::TYPE_INT_VEC3:		return "mediump float compare_ivec3    (highp ivec3 a, highp ivec3 b)  { return a == b ? 1.0 : 0.0; }\n";
    828 		case glu::TYPE_INT_VEC4:		return "mediump float compare_ivec4    (highp ivec4 a, highp ivec4 b)  { return a == b ? 1.0 : 0.0; }\n";
    829 		case glu::TYPE_UINT:			return "mediump float compare_uint     (highp uint a, highp uint b)    { return a == b ? 1.0 : 0.0; }\n";
    830 		case glu::TYPE_UINT_VEC2:		return "mediump float compare_uvec2    (highp uvec2 a, highp uvec2 b)  { return a == b ? 1.0 : 0.0; }\n";
    831 		case glu::TYPE_UINT_VEC3:		return "mediump float compare_uvec3    (highp uvec3 a, highp uvec3 b)  { return a == b ? 1.0 : 0.0; }\n";
    832 		case glu::TYPE_UINT_VEC4:		return "mediump float compare_uvec4    (highp uvec4 a, highp uvec4 b)  { return a == b ? 1.0 : 0.0; }\n";
    833 		case glu::TYPE_BOOL:			return "mediump float compare_bool     (bool a, bool b)                { return a == b ? 1.0 : 0.0; }\n";
    834 		case glu::TYPE_BOOL_VEC2:		return "mediump float compare_bvec2    (bvec2 a, bvec2 b)              { return a == b ? 1.0 : 0.0; }\n";
    835 		case glu::TYPE_BOOL_VEC3:		return "mediump float compare_bvec3    (bvec3 a, bvec3 b)              { return a == b ? 1.0 : 0.0; }\n";
    836 		case glu::TYPE_BOOL_VEC4:		return "mediump float compare_bvec4    (bvec4 a, bvec4 b)              { return a == b ? 1.0 : 0.0; }\n";
    837 		case glu::TYPE_FLOAT16:			return "mediump float compare_float16_t(highp float a, highp float b)  { return abs(a - b) < 0.05 ? 1.0 : 0.0; }\n";
    838 		case glu::TYPE_FLOAT16_VEC2:	return "mediump float compare_f16vec2  (highp vec2 a, highp vec2 b)    { return compare_float(a.x, b.x)*compare_float(a.y, b.y); }\n";
    839 		case glu::TYPE_FLOAT16_VEC3:	return "mediump float compare_f16vec3  (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";
    840 		case glu::TYPE_FLOAT16_VEC4:	return "mediump float compare_f16vec4  (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";
    841 		case glu::TYPE_INT8:			return "mediump float compare_int8_t   (highp int a, highp int b)      { return a == b ? 1.0 : 0.0; }\n";
    842 		case glu::TYPE_INT8_VEC2:		return "mediump float compare_i8vec2   (highp ivec2 a, highp ivec2 b)  { return a == b ? 1.0 : 0.0; }\n";
    843 		case glu::TYPE_INT8_VEC3:		return "mediump float compare_i8vec3   (highp ivec3 a, highp ivec3 b)  { return a == b ? 1.0 : 0.0; }\n";
    844 		case glu::TYPE_INT8_VEC4:		return "mediump float compare_i8vec4   (highp ivec4 a, highp ivec4 b)  { return a == b ? 1.0 : 0.0; }\n";
    845 		case glu::TYPE_UINT8:			return "mediump float compare_uint8_t  (highp uint a, highp uint b)    { return a == b ? 1.0 : 0.0; }\n";
    846 		case glu::TYPE_UINT8_VEC2:		return "mediump float compare_u8vec2   (highp uvec2 a, highp uvec2 b)  { return a == b ? 1.0 : 0.0; }\n";
    847 		case glu::TYPE_UINT8_VEC3:		return "mediump float compare_u8vec3   (highp uvec3 a, highp uvec3 b)  { return a == b ? 1.0 : 0.0; }\n";
    848 		case glu::TYPE_UINT8_VEC4:		return "mediump float compare_u8vec4   (highp uvec4 a, highp uvec4 b)  { return a == b ? 1.0 : 0.0; }\n";
    849 		case glu::TYPE_INT16:			return "mediump float compare_int16_t  (highp int a, highp int b)      { return a == b ? 1.0 : 0.0; }\n";
    850 		case glu::TYPE_INT16_VEC2:		return "mediump float compare_i16vec2  (highp ivec2 a, highp ivec2 b)  { return a == b ? 1.0 : 0.0; }\n";
    851 		case glu::TYPE_INT16_VEC3:		return "mediump float compare_i16vec3  (highp ivec3 a, highp ivec3 b)  { return a == b ? 1.0 : 0.0; }\n";
    852 		case glu::TYPE_INT16_VEC4:		return "mediump float compare_i16vec4  (highp ivec4 a, highp ivec4 b)  { return a == b ? 1.0 : 0.0; }\n";
    853 		case glu::TYPE_UINT16:			return "mediump float compare_uint16_t (highp uint a, highp uint b)    { return a == b ? 1.0 : 0.0; }\n";
    854 		case glu::TYPE_UINT16_VEC2:		return "mediump float compare_u16vec2  (highp uvec2 a, highp uvec2 b)  { return a == b ? 1.0 : 0.0; }\n";
    855 		case glu::TYPE_UINT16_VEC3:		return "mediump float compare_u16vec3  (highp uvec3 a, highp uvec3 b)  { return a == b ? 1.0 : 0.0; }\n";
    856 		case glu::TYPE_UINT16_VEC4:		return "mediump float compare_u16vec4  (highp uvec4 a, highp uvec4 b)  { return a == b ? 1.0 : 0.0; }\n";
    857 		default:
    858 			DE_ASSERT(false);
    859 			return DE_NULL;
    860 	}
    861 }
    862 
    863 void getCompareDependencies (std::set<glu::DataType>& compareFuncs, glu::DataType basicType)
    864 {
    865 	switch (basicType)
    866 	{
    867 		case glu::TYPE_FLOAT_VEC2:
    868 		case glu::TYPE_FLOAT_VEC3:
    869 		case glu::TYPE_FLOAT_VEC4:
    870 		case glu::TYPE_FLOAT16_VEC2:
    871 		case glu::TYPE_FLOAT16_VEC3:
    872 		case glu::TYPE_FLOAT16_VEC4:
    873 			compareFuncs.insert(glu::TYPE_FLOAT);
    874 			compareFuncs.insert(basicType);
    875 			break;
    876 
    877 		case glu::TYPE_FLOAT_MAT2:
    878 		case glu::TYPE_FLOAT_MAT2X3:
    879 		case glu::TYPE_FLOAT_MAT2X4:
    880 		case glu::TYPE_FLOAT_MAT3X2:
    881 		case glu::TYPE_FLOAT_MAT3:
    882 		case glu::TYPE_FLOAT_MAT3X4:
    883 		case glu::TYPE_FLOAT_MAT4X2:
    884 		case glu::TYPE_FLOAT_MAT4X3:
    885 		case glu::TYPE_FLOAT_MAT4:
    886 			compareFuncs.insert(glu::TYPE_FLOAT);
    887 			compareFuncs.insert(glu::getDataTypeFloatVec(glu::getDataTypeMatrixNumRows(basicType)));
    888 			compareFuncs.insert(basicType);
    889 			break;
    890 
    891 		default:
    892 			compareFuncs.insert(basicType);
    893 			break;
    894 	}
    895 }
    896 
    897 void collectUniqueBasicTypes (std::set<glu::DataType>& basicTypes, const VarType& type)
    898 {
    899 	if (type.isStructType())
    900 	{
    901 		for (StructType::ConstIterator iter = type.getStruct().begin(); iter != type.getStruct().end(); ++iter)
    902 			collectUniqueBasicTypes(basicTypes, iter->getType());
    903 	}
    904 	else if (type.isArrayType())
    905 		collectUniqueBasicTypes(basicTypes, type.getElementType());
    906 	else
    907 	{
    908 		DE_ASSERT(type.isBasicType());
    909 		basicTypes.insert(type.getBasicType());
    910 	}
    911 }
    912 
    913 void collectUniqueBasicTypes (std::set<glu::DataType>& basicTypes, const UniformBlock& uniformBlock)
    914 {
    915 	for (UniformBlock::ConstIterator iter = uniformBlock.begin(); iter != uniformBlock.end(); ++iter)
    916 		collectUniqueBasicTypes(basicTypes, iter->getType());
    917 }
    918 
    919 void collectUniqueBasicTypes (std::set<glu::DataType>& basicTypes, const ShaderInterface& interface)
    920 {
    921 	for (int ndx = 0; ndx < interface.getNumUniformBlocks(); ++ndx)
    922 		collectUniqueBasicTypes(basicTypes, interface.getUniformBlock(ndx));
    923 }
    924 
    925 void generateCompareFuncs (std::ostream& str, const ShaderInterface& interface)
    926 {
    927 	std::set<glu::DataType> types;
    928 	std::set<glu::DataType> compareFuncs;
    929 
    930 	// Collect unique basic types
    931 	collectUniqueBasicTypes(types, interface);
    932 
    933 	// Set of compare functions required
    934 	for (std::set<glu::DataType>::const_iterator iter = types.begin(); iter != types.end(); ++iter)
    935 	{
    936 		getCompareDependencies(compareFuncs, *iter);
    937 	}
    938 
    939 	for (int type = 0; type < glu::TYPE_LAST; ++type)
    940 	{
    941 		if (compareFuncs.find(glu::DataType(type)) != compareFuncs.end())
    942 			str << getCompareFuncForType(glu::DataType(type));
    943 	}
    944 }
    945 
    946 bool uses16BitStorage (const ShaderInterface& interface)
    947 {
    948 	// If any of blocks has LAYOUT_16BIT_STORAGE flag
    949 	for (int ndx = 0; ndx < interface.getNumUniformBlocks(); ++ndx)
    950 	{
    951 		if (interface.getUniformBlock(ndx).getFlags() & LAYOUT_16BIT_STORAGE)
    952 			return true;
    953 	}
    954 	return false;
    955 }
    956 
    957 bool uses8BitStorage (const ShaderInterface& interface)
    958 {
    959 	// If any of blocks has LAYOUT_8BIT_STORAGE flag
    960 	for (int ndx = 0; ndx < interface.getNumUniformBlocks(); ++ndx)
    961 	{
    962 		if (interface.getUniformBlock(ndx).getFlags() & LAYOUT_8BIT_STORAGE)
    963 			return true;
    964 	}
    965 	return false;
    966 }
    967 
    968 bool usesScalarOrStd430Layout (const ShaderInterface& interface)
    969 {
    970 	// If any of blocks has LAYOUT_SCALAR or LAYOUT_STD430 flags
    971 	for (int ndx = 0; ndx < interface.getNumUniformBlocks(); ++ndx)
    972 	{
    973 		if (interface.getUniformBlock(ndx).getFlags() & (LAYOUT_SCALAR | LAYOUT_STD430))
    974 			return true;
    975 	}
    976 	return false;
    977 }
    978 
    979 struct Indent
    980 {
    981 	int level;
    982 	Indent (int level_) : level(level_) {}
    983 };
    984 
    985 std::ostream& operator<< (std::ostream& str, const Indent& indent)
    986 {
    987 	for (int i = 0; i < indent.level; i++)
    988 		str << "\t";
    989 	return str;
    990 }
    991 
    992 void		generateDeclaration			(std::ostringstream& src, const VarType& type, const std::string& name, int indentLevel, deUint32 unusedHints, deUint32 flagsMask, deUint32 offset);
    993 void		generateDeclaration			(std::ostringstream& src, const Uniform& uniform, int indentLevel, deUint32 offset);
    994 void		generateDeclaration			(std::ostringstream& src, const StructType& structType, int indentLevel);
    995 
    996 void		generateLocalDeclaration	(std::ostringstream& src, const StructType& structType, int indentLevel);
    997 void		generateFullDeclaration		(std::ostringstream& src, const StructType& structType, int indentLevel);
    998 
    999 void generateDeclaration (std::ostringstream& src, const StructType& structType, int indentLevel)
   1000 {
   1001 	DE_ASSERT(structType.hasTypeName());
   1002 	generateFullDeclaration(src, structType, indentLevel);
   1003 	src << ";\n";
   1004 }
   1005 
   1006 void generateFullDeclaration (std::ostringstream& src, const StructType& structType, int indentLevel)
   1007 {
   1008 	src << "struct";
   1009 	if (structType.hasTypeName())
   1010 		src << " " << structType.getTypeName();
   1011 	src << "\n" << Indent(indentLevel) << "{\n";
   1012 
   1013 	for (StructType::ConstIterator memberIter = structType.begin(); memberIter != structType.end(); memberIter++)
   1014 	{
   1015 		src << Indent(indentLevel + 1);
   1016 		generateDeclaration(src, memberIter->getType(), memberIter->getName(), indentLevel + 1, memberIter->getFlags() & UNUSED_BOTH, ~LAYOUT_OFFSET, 0u);
   1017 	}
   1018 
   1019 	src << Indent(indentLevel) << "}";
   1020 }
   1021 
   1022 void generateLocalDeclaration (std::ostringstream& src, const StructType& structType, int /* indentLevel */)
   1023 {
   1024 	src << structType.getTypeName();
   1025 }
   1026 
   1027 void generateLayoutAndPrecisionDeclaration (std::ostringstream& src, deUint32 flags, deUint32 offset)
   1028 {
   1029 	if ((flags & LAYOUT_MASK) != 0)
   1030 		src << "layout(" << LayoutFlagsFmt(flags & LAYOUT_MASK, offset) << ") ";
   1031 
   1032 	if ((flags & PRECISION_MASK) != 0)
   1033 		src << PrecisionFlagsFmt(flags & PRECISION_MASK) << " ";
   1034 }
   1035 
   1036 void generateDeclaration (std::ostringstream& src, const VarType& type, const std::string& name, int indentLevel, deUint32 unusedHints, deUint32 flagsMask, deUint32 offset)
   1037 {
   1038 	generateLayoutAndPrecisionDeclaration(src, type.getFlags() & flagsMask, offset);
   1039 
   1040 	if (type.isBasicType())
   1041 		src << glu::getDataTypeName(type.getBasicType()) << " " << name;
   1042 	else if (type.isArrayType())
   1043 	{
   1044 		std::vector<int>	arraySizes;
   1045 		const VarType*		curType		= &type;
   1046 		while (curType->isArrayType())
   1047 		{
   1048 			arraySizes.push_back(curType->getArraySize());
   1049 			curType = &curType->getElementType();
   1050 		}
   1051 
   1052 		generateLayoutAndPrecisionDeclaration(src, curType->getFlags() & flagsMask, offset);
   1053 
   1054 		if (curType->isBasicType())
   1055 			src << glu::getDataTypeName(curType->getBasicType());
   1056 		else
   1057 		{
   1058 			DE_ASSERT(curType->isStructType());
   1059 			generateLocalDeclaration(src, curType->getStruct(), indentLevel+1);
   1060 		}
   1061 
   1062 		src << " " << name;
   1063 
   1064 		for (std::vector<int>::const_iterator sizeIter = arraySizes.begin(); sizeIter != arraySizes.end(); sizeIter++)
   1065 			src << "[" << *sizeIter << "]";
   1066 	}
   1067 	else
   1068 	{
   1069 		generateLocalDeclaration(src, type.getStruct(), indentLevel+1);
   1070 		src << " " << name;
   1071 	}
   1072 
   1073 	src << ";";
   1074 
   1075 	// Print out unused hints.
   1076 	if (unusedHints != 0)
   1077 		src << " // unused in " << (unusedHints == UNUSED_BOTH		? "both shaders"	:
   1078 									unusedHints == UNUSED_VERTEX	? "vertex shader"	:
   1079 									unusedHints == UNUSED_FRAGMENT	? "fragment shader" : "???");
   1080 
   1081 	src << "\n";
   1082 }
   1083 
   1084 void generateDeclaration (std::ostringstream& src, const Uniform& uniform, int indentLevel, deUint32 offset)
   1085 {
   1086 	if ((uniform.getFlags() & LAYOUT_MASK) != 0)
   1087 		src << "layout(" << LayoutFlagsFmt(uniform.getFlags() & LAYOUT_MASK) << ") ";
   1088 
   1089 	generateDeclaration(src, uniform.getType(), uniform.getName(), indentLevel, uniform.getFlags() & UNUSED_BOTH, ~0u, offset);
   1090 }
   1091 
   1092 deUint32 getBlockMemberOffset (int blockNdx, const UniformBlock& block, const Uniform& uniform, const UniformLayout& layout)
   1093 {
   1094 	std::ostringstream	name;
   1095 	const VarType*		curType = &uniform.getType();
   1096 
   1097 	if (block.getInstanceName().length() != 0)
   1098 		name << block.getBlockName() << ".";	// \note UniformLayoutEntry uses block name rather than instance name
   1099 
   1100 	name << uniform.getName();
   1101 
   1102 	while (!curType->isBasicType())
   1103 	{
   1104 		if (curType->isArrayType())
   1105 		{
   1106 			name << "[0]";
   1107 			curType = &curType->getElementType();
   1108 		}
   1109 
   1110 		if (curType->isStructType())
   1111 		{
   1112 			const StructType::ConstIterator firstMember = curType->getStruct().begin();
   1113 			name << "." << firstMember->getName();
   1114 			curType = &firstMember->getType();
   1115 		}
   1116 	}
   1117 
   1118 	const int uniformNdx = layout.getUniformLayoutIndex(blockNdx, name.str());
   1119 	DE_ASSERT(uniformNdx >= 0);
   1120 
   1121 	return layout.uniforms[uniformNdx].offset;
   1122 }
   1123 
   1124 template<typename T>
   1125 void semiShuffle (std::vector<T>& v)
   1126 {
   1127 	const std::vector<T>	src	= v;
   1128 	int						i	= -1;
   1129 	int						n	= static_cast<int>(src.size());
   1130 
   1131 	v.clear();
   1132 
   1133 	while (n)
   1134 	{
   1135 		i += n;
   1136 		v.push_back(src[i]);
   1137 		n = (n > 0 ? 1 - n : -1 - n);
   1138 	}
   1139 }
   1140 
   1141 template<typename T>
   1142 //! \note Stores pointers to original elements
   1143 class Traverser
   1144 {
   1145 public:
   1146 	template<typename Iter>
   1147 	Traverser (const Iter beg, const Iter end, const bool shuffled)
   1148 	{
   1149 		for (Iter it = beg; it != end; ++it)
   1150 			m_elements.push_back(&(*it));
   1151 
   1152 		if (shuffled)
   1153 			semiShuffle(m_elements);
   1154 
   1155 		m_next = m_elements.begin();
   1156 	}
   1157 
   1158 	T* next (void)
   1159 	{
   1160 		if (m_next != m_elements.end())
   1161 			return *m_next++;
   1162 		else
   1163 			return DE_NULL;
   1164 	}
   1165 
   1166 private:
   1167 	typename std::vector<T*>					m_elements;
   1168 	typename std::vector<T*>::const_iterator	m_next;
   1169 };
   1170 
   1171 glu::DataType getPromoteType(glu::DataType type)
   1172 {
   1173 	switch (type)
   1174 	{
   1175 	case glu::TYPE_UINT8:			return glu::TYPE_UINT;
   1176 	case glu::TYPE_UINT8_VEC2:		return glu::TYPE_UINT_VEC2;
   1177 	case glu::TYPE_UINT8_VEC3:		return glu::TYPE_UINT_VEC3;
   1178 	case glu::TYPE_UINT8_VEC4:		return glu::TYPE_UINT_VEC4;
   1179 	case glu::TYPE_INT8:			return glu::TYPE_INT;
   1180 	case glu::TYPE_INT8_VEC2:		return glu::TYPE_INT_VEC2;
   1181 	case glu::TYPE_INT8_VEC3:		return glu::TYPE_INT_VEC3;
   1182 	case glu::TYPE_INT8_VEC4:		return glu::TYPE_INT_VEC4;
   1183 	case glu::TYPE_UINT16:			return glu::TYPE_UINT;
   1184 	case glu::TYPE_UINT16_VEC2:		return glu::TYPE_UINT_VEC2;
   1185 	case glu::TYPE_UINT16_VEC3:		return glu::TYPE_UINT_VEC3;
   1186 	case glu::TYPE_UINT16_VEC4:		return glu::TYPE_UINT_VEC4;
   1187 	case glu::TYPE_INT16:			return glu::TYPE_INT;
   1188 	case glu::TYPE_INT16_VEC2:		return glu::TYPE_INT_VEC2;
   1189 	case glu::TYPE_INT16_VEC3:		return glu::TYPE_INT_VEC3;
   1190 	case glu::TYPE_INT16_VEC4:		return glu::TYPE_INT_VEC4;
   1191 	case glu::TYPE_FLOAT16:			return glu::TYPE_FLOAT;
   1192 	case glu::TYPE_FLOAT16_VEC2:	return glu::TYPE_FLOAT_VEC2;
   1193 	case glu::TYPE_FLOAT16_VEC3:	return glu::TYPE_FLOAT_VEC3;
   1194 	case glu::TYPE_FLOAT16_VEC4:	return glu::TYPE_FLOAT_VEC4;
   1195 	default: return type;
   1196 	}
   1197 }
   1198 
   1199 void generateDeclaration (std::ostringstream& src, int blockNdx, const UniformBlock& block, const UniformLayout& layout, bool shuffleUniformMembers)
   1200 {
   1201 	src << "layout(set = 0, binding = " << blockNdx;
   1202 	if ((block.getFlags() & LAYOUT_MASK) != 0)
   1203 		src << ", " << LayoutFlagsFmt(block.getFlags() & LAYOUT_MASK);
   1204 	src << ") ";
   1205 
   1206 	src << "uniform " << block.getBlockName();
   1207 	src << "\n{\n";
   1208 
   1209 	Traverser<const Uniform> uniforms(block.begin(), block.end(), shuffleUniformMembers);
   1210 
   1211 	while (const Uniform* pUniform = uniforms.next())
   1212 	{
   1213 		src << Indent(1);
   1214 		generateDeclaration(src, *pUniform, 1 /* indent level */, getBlockMemberOffset(blockNdx, block, *pUniform, layout));
   1215 	}
   1216 
   1217 	src << "}";
   1218 
   1219 	if (block.hasInstanceName())
   1220 	{
   1221 		src << " " << block.getInstanceName();
   1222 		if (block.isArray())
   1223 			src << "[" << block.getArraySize() << "]";
   1224 	}
   1225 	else
   1226 		DE_ASSERT(!block.isArray());
   1227 
   1228 	src << ";\n";
   1229 }
   1230 
   1231 void generateValueSrc (std::ostringstream& src, const UniformLayoutEntry& entry, const void* basePtr, int elementNdx)
   1232 {
   1233 	glu::DataType	scalarType		= glu::getDataTypeScalarType(entry.type);
   1234 	int				scalarSize		= glu::getDataTypeScalarSize(entry.type);
   1235 	bool			isArray			= entry.size > 1;
   1236 	const deUint8*	elemPtr			= (const deUint8*)basePtr + entry.offset + (isArray ? elementNdx * entry.arrayStride : 0);
   1237 	const size_t	compSize		= getDataTypeByteSize(scalarType);
   1238 
   1239 	if (scalarSize > 1)
   1240 		src << glu::getDataTypeName(getPromoteType(entry.type)) << "(";
   1241 
   1242 	if (glu::isDataTypeMatrix(entry.type))
   1243 	{
   1244 		int	numRows	= glu::getDataTypeMatrixNumRows(entry.type);
   1245 		int	numCols	= glu::getDataTypeMatrixNumColumns(entry.type);
   1246 
   1247 		DE_ASSERT(scalarType == glu::TYPE_FLOAT);
   1248 
   1249 		// Constructed in column-wise order.
   1250 		for (int colNdx = 0; colNdx < numCols; colNdx++)
   1251 		{
   1252 			for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
   1253 			{
   1254 				const deUint8*	compPtr	= elemPtr + (entry.isRowMajor ? (rowNdx * entry.matrixStride + colNdx * compSize)
   1255 																	  : (colNdx * entry.matrixStride + rowNdx * compSize));
   1256 
   1257 				if (colNdx > 0 || rowNdx > 0)
   1258 					src << ", ";
   1259 
   1260 				src << de::floatToString(*((const float*)compPtr), 1);
   1261 			}
   1262 		}
   1263 	}
   1264 	else
   1265 	{
   1266 		for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
   1267 		{
   1268 			const deUint8* compPtr = elemPtr + scalarNdx * compSize;
   1269 
   1270 			if (scalarNdx > 0)
   1271 				src << ", ";
   1272 
   1273 			switch (scalarType)
   1274 			{
   1275 				case glu::TYPE_FLOAT16:	src << de::floatToString(deFloat16To32(*((const deFloat16*)compPtr)), 1);	break;
   1276 				case glu::TYPE_FLOAT:	src << de::floatToString(*((const float*)compPtr), 1);			break;
   1277 				case glu::TYPE_INT8:	src << (deUint32)*((const deInt8*)compPtr);						break;
   1278 				case glu::TYPE_INT16:	src << *((const deInt16*)compPtr);								break;
   1279 				case glu::TYPE_INT:		src << *((const int*)compPtr);									break;
   1280 				case glu::TYPE_UINT8:	src << (deUint32)*((const deUint8*)compPtr) << "u";				break;
   1281 				case glu::TYPE_UINT16:	src << *((const deUint16*)compPtr) << "u";						break;
   1282 				case glu::TYPE_UINT:	src << *((const deUint32*)compPtr) << "u";						break;
   1283 				case glu::TYPE_BOOL:	src << (*((const deUint32*)compPtr) != 0u ? "true" : "false");	break;
   1284 				default:
   1285 					DE_ASSERT(false);
   1286 			}
   1287 		}
   1288 	}
   1289 
   1290 	if (scalarSize > 1)
   1291 		src << ")";
   1292 }
   1293 
   1294 bool isMatrix (glu::DataType elementType)
   1295 {
   1296 	return (elementType >= glu::TYPE_FLOAT_MAT2) && (elementType <= glu::TYPE_FLOAT_MAT4);
   1297 }
   1298 
   1299 void writeMatrixTypeSrc (int						columnCount,
   1300 						 int						rowCount,
   1301 						 std::string				compare,
   1302 						 std::string				compareType,
   1303 						 std::ostringstream&		src,
   1304 						 const std::string&			srcName,
   1305 						 const void*				basePtr,
   1306 						 const UniformLayoutEntry&	entry,
   1307 						 bool						vector)
   1308 {
   1309 	if (vector)	// generateTestSrcMatrixPerVec
   1310 	{
   1311 		for (int colNdex = 0; colNdex < columnCount; colNdex++)
   1312 		{
   1313 			src << "\tresult *= " << compare + compareType << "(" << srcName << "[" << colNdex << "], ";
   1314 
   1315 			if (glu::isDataTypeMatrix(entry.type))
   1316 			{
   1317 				int	scalarSize = glu::getDataTypeScalarSize(entry.type);
   1318 				const deUint8*	elemPtr			= (const deUint8*)basePtr + entry.offset;
   1319 				const int		compSize		= sizeof(deUint32);
   1320 
   1321 				if (scalarSize > 1)
   1322 					src << compareType << "(";
   1323 				for (int rowNdex = 0; rowNdex < rowCount; rowNdex++)
   1324 				{
   1325 					const deUint8*	compPtr	= elemPtr + (entry.isRowMajor ? (rowNdex * entry.matrixStride + colNdex * compSize)
   1326 																		  : (colNdex * entry.matrixStride + rowNdex * compSize));
   1327 					src << de::floatToString(*((const float*)compPtr), 1);
   1328 
   1329 					if (rowNdex < rowCount-1)
   1330 						src << ", ";
   1331 				}
   1332 				src << "));\n";
   1333 			}
   1334 			else
   1335 			{
   1336 				generateValueSrc(src, entry, basePtr, 0);
   1337 				src << "[" << colNdex << "]);\n";
   1338 			}
   1339 		}
   1340 	}
   1341 	else		// generateTestSrcMatrixPerElement
   1342 	{
   1343 		for (int colNdex = 0; colNdex < columnCount; colNdex++)
   1344 		{
   1345 			for (int rowNdex = 0; rowNdex < rowCount; rowNdex++)
   1346 			{
   1347 				src << "\tresult *= " << compare + compareType << "(" << srcName << "[" << colNdex << "][" << rowNdex << "], ";
   1348 				if (glu::isDataTypeMatrix(entry.type))
   1349 				{
   1350 					const deUint8*	elemPtr			= (const deUint8*)basePtr + entry.offset;
   1351 					const int		compSize		= sizeof(deUint32);
   1352 					const deUint8*	compPtr	= elemPtr + (entry.isRowMajor ? (rowNdex * entry.matrixStride + colNdex * compSize)
   1353 																		  : (colNdex * entry.matrixStride + rowNdex * compSize));
   1354 
   1355 					src << de::floatToString(*((const float*)compPtr), 1) << ");\n";
   1356 				}
   1357 				else
   1358 				{
   1359 					generateValueSrc(src, entry, basePtr, 0);
   1360 					src << "[" << colNdex << "][" << rowNdex << "]);\n";
   1361 				}
   1362 			}
   1363 		}
   1364 	}
   1365 }
   1366 
   1367 void generateTestSrcMatrixPerVec (glu::DataType				elementType,
   1368 								  std::ostringstream&		src,
   1369 								  const std::string&		srcName,
   1370 								  const void*				basePtr,
   1371 								  const UniformLayoutEntry&	entry,
   1372 								  bool						vector)
   1373 {
   1374 	std::string compare = "compare_";
   1375 	switch (elementType)
   1376 	{
   1377 		case glu::TYPE_FLOAT_MAT2:
   1378 			writeMatrixTypeSrc(2, 2, compare, "vec2", src, srcName, basePtr, entry, vector);
   1379 			break;
   1380 
   1381 		case glu::TYPE_FLOAT_MAT2X3:
   1382 			writeMatrixTypeSrc(2, 3, compare, "vec3", src, srcName, basePtr, entry, vector);
   1383 			break;
   1384 
   1385 		case glu::TYPE_FLOAT_MAT2X4:
   1386 			writeMatrixTypeSrc(2, 4, compare, "vec4", src, srcName, basePtr, entry, vector);
   1387 			break;
   1388 
   1389 		case glu::TYPE_FLOAT_MAT3X4:
   1390 			writeMatrixTypeSrc(3, 4, compare, "vec4", src, srcName, basePtr, entry, vector);
   1391 			break;
   1392 
   1393 		case glu::TYPE_FLOAT_MAT4:
   1394 			writeMatrixTypeSrc(4, 4, compare, "vec4", src, srcName, basePtr, entry, vector);
   1395 			break;
   1396 
   1397 		case glu::TYPE_FLOAT_MAT4X2:
   1398 			writeMatrixTypeSrc(4, 2, compare, "vec2", src, srcName, basePtr, entry, vector);
   1399 			break;
   1400 
   1401 		case glu::TYPE_FLOAT_MAT4X3:
   1402 			writeMatrixTypeSrc(4, 3, compare, "vec3", src, srcName, basePtr, entry, vector);
   1403 			break;
   1404 
   1405 		default:
   1406 			break;
   1407 	}
   1408 }
   1409 
   1410 void generateTestSrcMatrixPerElement (glu::DataType				elementType,
   1411 									  std::ostringstream&		src,
   1412 									  const std::string&		srcName,
   1413 									  const void*				basePtr,
   1414 									  const UniformLayoutEntry&	entry,
   1415 									  bool						vector)
   1416 {
   1417 	std::string compare = "compare_";
   1418 	std::string compareType = "float";
   1419 	switch (elementType)
   1420 	{
   1421 		case glu::TYPE_FLOAT_MAT2:
   1422 			writeMatrixTypeSrc(2, 2, compare, compareType, src, srcName, basePtr, entry, vector);
   1423 			break;
   1424 
   1425 		case glu::TYPE_FLOAT_MAT2X3:
   1426 			writeMatrixTypeSrc(2, 3, compare, compareType, src, srcName, basePtr, entry, vector);
   1427 			break;
   1428 
   1429 		case glu::TYPE_FLOAT_MAT2X4:
   1430 			writeMatrixTypeSrc(2, 4, compare, compareType, src, srcName, basePtr, entry, vector);
   1431 			break;
   1432 
   1433 		case glu::TYPE_FLOAT_MAT3X4:
   1434 			writeMatrixTypeSrc(3, 4, compare, compareType, src, srcName, basePtr, entry, vector);
   1435 			break;
   1436 
   1437 		case glu::TYPE_FLOAT_MAT4:
   1438 			writeMatrixTypeSrc(4, 4, compare, compareType, src, srcName, basePtr, entry, vector);
   1439 			break;
   1440 
   1441 		case glu::TYPE_FLOAT_MAT4X2:
   1442 			writeMatrixTypeSrc(4, 2, compare, compareType, src, srcName, basePtr, entry, vector);
   1443 			break;
   1444 
   1445 		case glu::TYPE_FLOAT_MAT4X3:
   1446 			writeMatrixTypeSrc(4, 3, compare, compareType, src, srcName, basePtr, entry, vector);
   1447 			break;
   1448 
   1449 		default:
   1450 			break;
   1451 	}
   1452 }
   1453 
   1454 void generateSingleCompare (std::ostringstream&			src,
   1455 							glu::DataType				elementType,
   1456 							const std::string&			srcName,
   1457 							const void*					basePtr,
   1458 							const UniformLayoutEntry&	entry,
   1459 							MatrixLoadFlags				matrixLoadFlag)
   1460 {
   1461 	if (matrixLoadFlag == LOAD_FULL_MATRIX)
   1462 	{
   1463 		const char* typeName = glu::getDataTypeName(elementType);
   1464 		const char* castName = "";
   1465 		glu::DataType promoteType = getPromoteType(elementType);
   1466 		if (elementType != promoteType)
   1467 		{
   1468 			castName = glu::getDataTypeName(promoteType);
   1469 		}
   1470 
   1471 		src << "\tresult *= compare_" << typeName << "(" << castName << "(" << srcName << "), ";
   1472 		generateValueSrc(src, entry, basePtr, 0);
   1473 		src << ");\n";
   1474 	}
   1475 	else
   1476 	{
   1477 		if (isMatrix(elementType))
   1478 		{
   1479 			generateTestSrcMatrixPerVec		(elementType, src, srcName, basePtr, entry, true);
   1480 			generateTestSrcMatrixPerElement	(elementType, src, srcName, basePtr, entry, false);
   1481 		}
   1482 	}
   1483 }
   1484 
   1485 void generateCompareSrc (std::ostringstream&	src,
   1486 						 const char*			resultVar,
   1487 						 const VarType&			type,
   1488 						 const std::string&		srcName,
   1489 						 const std::string&		apiName,
   1490 						 const UniformLayout&	layout,
   1491 						 int					blockNdx,
   1492 						 const void*			basePtr,
   1493 						 deUint32				unusedMask,
   1494 						 MatrixLoadFlags		matrixLoadFlag)
   1495 {
   1496 	if (type.isBasicType() || (type.isArrayType() && type.getElementType().isBasicType()))
   1497 	{
   1498 		// Basic type or array of basic types.
   1499 		bool						isArray			= type.isArrayType();
   1500 		glu::DataType				elementType		= isArray ? type.getElementType().getBasicType() : type.getBasicType();
   1501 		const char*					typeName		= glu::getDataTypeName(elementType);
   1502 		std::string					fullApiName		= std::string(apiName) + (isArray ? "[0]" : ""); // Arrays are always postfixed with [0]
   1503 		int							uniformNdx		= layout.getUniformLayoutIndex(blockNdx, fullApiName);
   1504 		const UniformLayoutEntry&	entry			= layout.uniforms[uniformNdx];
   1505 
   1506 		const char* castName = "";
   1507 		glu::DataType promoteType = getPromoteType(elementType);
   1508 		if (elementType != promoteType)
   1509 		{
   1510 			castName = glu::getDataTypeName(promoteType);
   1511 		}
   1512 
   1513 		if (isArray)
   1514 		{
   1515 			for (int elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++)
   1516 			{
   1517 				src << "\tresult *= compare_" << typeName << "(" << castName << "(" << srcName << "[" << elemNdx << "]), ";
   1518 				generateValueSrc(src, entry, basePtr, elemNdx);
   1519 				src << ");\n";
   1520 			}
   1521 		}
   1522 		else
   1523 		{
   1524 			generateSingleCompare(src, elementType, srcName, basePtr, entry, matrixLoadFlag);
   1525 		}
   1526 	}
   1527 	else if (type.isArrayType())
   1528 	{
   1529 		const VarType& elementType = type.getElementType();
   1530 
   1531 		for (int elementNdx = 0; elementNdx < type.getArraySize(); elementNdx++)
   1532 		{
   1533 			std::string op = std::string("[") + de::toString(elementNdx) + "]";
   1534 			std::string elementSrcName = std::string(srcName) + op;
   1535 			std::string elementApiName = std::string(apiName) + op;
   1536 			generateCompareSrc(src, resultVar, elementType, elementSrcName, elementApiName, layout, blockNdx, basePtr, unusedMask, LOAD_FULL_MATRIX);
   1537 		}
   1538 	}
   1539 	else
   1540 	{
   1541 		DE_ASSERT(type.isStructType());
   1542 
   1543 		for (StructType::ConstIterator memberIter = type.getStruct().begin(); memberIter != type.getStruct().end(); memberIter++)
   1544 		{
   1545 			if (memberIter->getFlags() & unusedMask)
   1546 				continue; // Skip member.
   1547 
   1548 			std::string op = std::string(".") + memberIter->getName();
   1549 			std::string memberSrcName = std::string(srcName) + op;
   1550 			std::string memberApiName = std::string(apiName) + op;
   1551 			generateCompareSrc(src, resultVar, memberIter->getType(), memberSrcName, memberApiName, layout, blockNdx, basePtr, unusedMask, LOAD_FULL_MATRIX);
   1552 		}
   1553 	}
   1554 }
   1555 
   1556 void generateCompareSrc (std::ostringstream& src,
   1557 						 const char* resultVar,
   1558 						 const ShaderInterface& interface,
   1559 						 const UniformLayout& layout,
   1560 						 const std::map<int,
   1561 						 void*>& blockPointers,
   1562 						 bool isVertex,
   1563 						 MatrixLoadFlags matrixLoadFlag)
   1564 {
   1565 	deUint32 unusedMask = isVertex ? UNUSED_VERTEX : UNUSED_FRAGMENT;
   1566 
   1567 	for (int blockNdx = 0; blockNdx < interface.getNumUniformBlocks(); blockNdx++)
   1568 	{
   1569 		const UniformBlock& block = interface.getUniformBlock(blockNdx);
   1570 
   1571 		if ((block.getFlags() & (isVertex ? DECLARE_VERTEX : DECLARE_FRAGMENT)) == 0)
   1572 			continue; // Skip.
   1573 
   1574 		bool			hasInstanceName	= block.hasInstanceName();
   1575 		bool			isArray			= block.isArray();
   1576 		int				numInstances	= isArray ? block.getArraySize() : 1;
   1577 		std::string		apiPrefix		= hasInstanceName ? block.getBlockName() + "." : std::string("");
   1578 
   1579 		DE_ASSERT(!isArray || hasInstanceName);
   1580 
   1581 		for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
   1582 		{
   1583 			std::string		instancePostfix		= isArray ? std::string("[") + de::toString(instanceNdx) + "]" : std::string("");
   1584 			std::string		blockInstanceName	= block.getBlockName() + instancePostfix;
   1585 			std::string		srcPrefix			= hasInstanceName ? block.getInstanceName() + instancePostfix + "." : std::string("");
   1586 			int				blockLayoutNdx		= layout.getBlockLayoutIndex(blockNdx, instanceNdx);
   1587 			void*			basePtr				= blockPointers.find(blockLayoutNdx)->second;
   1588 
   1589 			for (UniformBlock::ConstIterator uniformIter = block.begin(); uniformIter != block.end(); uniformIter++)
   1590 			{
   1591 				const Uniform& uniform = *uniformIter;
   1592 
   1593 				if (uniform.getFlags() & unusedMask)
   1594 					continue; // Don't read from that uniform.
   1595 
   1596 				std::string srcName = srcPrefix + uniform.getName();
   1597 				std::string apiName = apiPrefix + uniform.getName();
   1598 				generateCompareSrc(src, resultVar, uniform.getType(), srcName, apiName, layout, blockNdx, basePtr, unusedMask, matrixLoadFlag);
   1599 			}
   1600 		}
   1601 	}
   1602 }
   1603 
   1604 std::string generateVertexShader (const ShaderInterface& interface, const UniformLayout& layout, const std::map<int, void*>& blockPointers, MatrixLoadFlags matrixLoadFlag, bool shuffleUniformMembers)
   1605 {
   1606 	std::ostringstream src;
   1607 	src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n";
   1608 	src << "#extension GL_EXT_shader_16bit_storage : enable\n";
   1609 	src << "#extension GL_EXT_shader_8bit_storage : enable\n";
   1610 	src << "#extension GL_EXT_scalar_block_layout : enable\n";
   1611 
   1612 	src << "layout(location = 0) in highp vec4 a_position;\n";
   1613 	src << "layout(location = 0) out mediump float v_vtxResult;\n";
   1614 	src << "\n";
   1615 
   1616 	std::vector<const StructType*> namedStructs;
   1617 	interface.getNamedStructs(namedStructs);
   1618 	for (std::vector<const StructType*>::const_iterator structIter = namedStructs.begin(); structIter != namedStructs.end(); structIter++)
   1619 		generateDeclaration(src, **structIter, 0);
   1620 
   1621 	for (int blockNdx = 0; blockNdx < interface.getNumUniformBlocks(); blockNdx++)
   1622 	{
   1623 		const UniformBlock& block = interface.getUniformBlock(blockNdx);
   1624 		if (block.getFlags() & DECLARE_VERTEX)
   1625 			generateDeclaration(src, blockNdx, block, layout, shuffleUniformMembers);
   1626 	}
   1627 
   1628 	// Comparison utilities.
   1629 	src << "\n";
   1630 	generateCompareFuncs(src, interface);
   1631 
   1632 	src << "\n"
   1633 		   "void main (void)\n"
   1634 		   "{\n"
   1635 		   "	gl_Position = a_position;\n"
   1636 		   "	mediump float result = 1.0;\n";
   1637 
   1638 	// Value compare.
   1639 	generateCompareSrc(src, "result", interface, layout, blockPointers, true, matrixLoadFlag);
   1640 
   1641 	src << "	v_vtxResult = result;\n"
   1642 		   "}\n";
   1643 
   1644 	return src.str();
   1645 }
   1646 
   1647 std::string generateFragmentShader (const ShaderInterface& interface, const UniformLayout& layout, const std::map<int, void*>& blockPointers, MatrixLoadFlags matrixLoadFlag, bool shuffleUniformMembers)
   1648 {
   1649 	std::ostringstream src;
   1650 	src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n";
   1651 	src << "#extension GL_EXT_shader_16bit_storage : enable\n";
   1652 	src << "#extension GL_EXT_shader_8bit_storage : enable\n";
   1653 	src << "#extension GL_EXT_scalar_block_layout : enable\n";
   1654 
   1655 	src << "layout(location = 0) in mediump float v_vtxResult;\n";
   1656 	src << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
   1657 	src << "\n";
   1658 
   1659 	std::vector<const StructType*> namedStructs;
   1660 	interface.getNamedStructs(namedStructs);
   1661 	for (std::vector<const StructType*>::const_iterator structIter = namedStructs.begin(); structIter != namedStructs.end(); structIter++)
   1662 		generateDeclaration(src, **structIter, 0);
   1663 
   1664 	for (int blockNdx = 0; blockNdx < interface.getNumUniformBlocks(); blockNdx++)
   1665 	{
   1666 		const UniformBlock& block = interface.getUniformBlock(blockNdx);
   1667 		if (block.getFlags() & DECLARE_FRAGMENT)
   1668 			generateDeclaration(src, blockNdx, block, layout, shuffleUniformMembers);
   1669 	}
   1670 
   1671 	// Comparison utilities.
   1672 	src << "\n";
   1673 	generateCompareFuncs(src, interface);
   1674 
   1675 	src << "\n"
   1676 		   "void main (void)\n"
   1677 		   "{\n"
   1678 		   "	mediump float result = 1.0;\n";
   1679 
   1680 	// Value compare.
   1681 	generateCompareSrc(src, "result", interface, layout, blockPointers, false, matrixLoadFlag);
   1682 
   1683 	src << "	dEQP_FragColor = vec4(1.0, v_vtxResult, result, 1.0);\n"
   1684 		   "}\n";
   1685 
   1686 	return src.str();
   1687 }
   1688 
   1689 Move<VkBuffer> createBuffer (Context& context, VkDeviceSize bufferSize, vk::VkBufferUsageFlags usageFlags)
   1690 {
   1691 	const VkDevice				vkDevice			= context.getDevice();
   1692 	const DeviceInterface&		vk					= context.getDeviceInterface();
   1693 	const deUint32				queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
   1694 
   1695 	const VkBufferCreateInfo	bufferInfo			=
   1696 	{
   1697 		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,	// VkStructureType		sType;
   1698 		DE_NULL,								// const void*			pNext;
   1699 		0u,										// VkBufferCreateFlags	flags;
   1700 		bufferSize,								// VkDeviceSize			size;
   1701 		usageFlags,								// VkBufferUsageFlags	usage;
   1702 		VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode		sharingMode;
   1703 		1u,										// deUint32				queueFamilyIndexCount;
   1704 		&queueFamilyIndex						// const deUint32*		pQueueFamilyIndices;
   1705 	};
   1706 
   1707 	return vk::createBuffer(vk, vkDevice, &bufferInfo);
   1708 }
   1709 
   1710 Move<vk::VkImage> createImage2D (Context& context, deUint32 width, deUint32 height, vk::VkFormat format, vk::VkImageTiling tiling, vk::VkImageUsageFlags usageFlags)
   1711 {
   1712 	const deUint32				queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
   1713 	const vk::VkImageCreateInfo	params				=
   1714 	{
   1715 		vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	// VkStructureType			sType
   1716 		DE_NULL,									// const void*				pNext
   1717 		0u,											// VkImageCreateFlags		flags
   1718 		vk::VK_IMAGE_TYPE_2D,						// VkImageType				imageType
   1719 		format,										// VkFormat					format
   1720 		{ width, height, 1u },						// VkExtent3D				extent
   1721 		1u,											// deUint32					mipLevels
   1722 		1u,											// deUint32					arrayLayers
   1723 		VK_SAMPLE_COUNT_1_BIT,						// VkSampleCountFlagBits	samples
   1724 		tiling,										// VkImageTiling			tiling
   1725 		usageFlags,									// VkImageUsageFlags		usage
   1726 		vk::VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode			sharingMode
   1727 		1u,											// deUint32					queueFamilyIndexCount
   1728 		&queueFamilyIndex,							// const deUint32*			pQueueFamilyIndices
   1729 		vk::VK_IMAGE_LAYOUT_UNDEFINED,				// VkImageLayout			initialLayout
   1730 	};
   1731 
   1732 	return vk::createImage(context.getDeviceInterface(), context.getDevice(), &params);
   1733 }
   1734 
   1735 de::MovePtr<vk::Allocation> allocateAndBindMemory (Context& context, vk::VkBuffer buffer, vk::MemoryRequirement memReqs)
   1736 {
   1737 	const vk::DeviceInterface&		vkd		= context.getDeviceInterface();
   1738 	const vk::VkMemoryRequirements	bufReqs	= vk::getBufferMemoryRequirements(vkd, context.getDevice(), buffer);
   1739 	de::MovePtr<vk::Allocation>		memory	= context.getDefaultAllocator().allocate(bufReqs, memReqs);
   1740 
   1741 	vkd.bindBufferMemory(context.getDevice(), buffer, memory->getMemory(), memory->getOffset());
   1742 
   1743 	return memory;
   1744 }
   1745 
   1746 de::MovePtr<vk::Allocation> allocateAndBindMemory (Context& context, vk::VkImage image, vk::MemoryRequirement memReqs)
   1747 {
   1748 	const vk::DeviceInterface&	  vkd	 = context.getDeviceInterface();
   1749 	const vk::VkMemoryRequirements  imgReqs = vk::getImageMemoryRequirements(vkd, context.getDevice(), image);
   1750 	de::MovePtr<vk::Allocation>		 memory  = context.getDefaultAllocator().allocate(imgReqs, memReqs);
   1751 
   1752 	vkd.bindImageMemory(context.getDevice(), image, memory->getMemory(), memory->getOffset());
   1753 
   1754 	return memory;
   1755 }
   1756 
   1757 Move<vk::VkImageView> createAttachmentView (Context& context, vk::VkImage image, vk::VkFormat format)
   1758 {
   1759 	const vk::VkImageViewCreateInfo params =
   1760 	{
   1761 		vk::VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,		// sType
   1762 		DE_NULL,											// pNext
   1763 		0u,													// flags
   1764 		image,												// image
   1765 		vk::VK_IMAGE_VIEW_TYPE_2D,							// viewType
   1766 		format,												// format
   1767 		vk::makeComponentMappingRGBA(),						// components
   1768 		{ vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u,1u },	// subresourceRange
   1769 	};
   1770 
   1771 	return vk::createImageView(context.getDeviceInterface(), context.getDevice(), &params);
   1772 }
   1773 
   1774 Move<vk::VkPipelineLayout> createPipelineLayout (Context& context, vk::VkDescriptorSetLayout descriptorSetLayout)
   1775 {
   1776 	const vk::VkPipelineLayoutCreateInfo params =
   1777 	{
   1778 		vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,	// sType
   1779 		DE_NULL,											// pNext
   1780 		0u,													// flags
   1781 		1u,													// setLayoutCount
   1782 		&descriptorSetLayout,								// pSetLayouts
   1783 		0u,													// pushConstantRangeCount
   1784 		DE_NULL,											// pPushConstantRanges
   1785 	};
   1786 
   1787 	return vk::createPipelineLayout(context.getDeviceInterface(), context.getDevice(), &params);
   1788 }
   1789 
   1790 Move<vk::VkCommandPool> createCmdPool (Context& context)
   1791 {
   1792 	const deUint32	queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
   1793 
   1794 	return vk::createCommandPool(context.getDeviceInterface(), context.getDevice(), vk::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
   1795 }
   1796 
   1797 Move<vk::VkCommandBuffer> createCmdBuffer (Context& context, vk::VkCommandPool cmdPool)
   1798 {
   1799 	return vk::allocateCommandBuffer(context.getDeviceInterface(), context.getDevice(), cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
   1800 }
   1801 
   1802 // UniformBlockCaseInstance
   1803 
   1804 class UniformBlockCaseInstance : public vkt::TestInstance
   1805 {
   1806 public:
   1807 									UniformBlockCaseInstance	(Context&						context,
   1808 																 UniformBlockCase::BufferMode	bufferMode,
   1809 																 const UniformLayout&			layout,
   1810 																 const std::map<int, void*>&	blockPointers);
   1811 	virtual							~UniformBlockCaseInstance	(void);
   1812 	virtual tcu::TestStatus			iterate						(void);
   1813 
   1814 private:
   1815 	enum
   1816 	{
   1817 		RENDER_WIDTH = 100,
   1818 		RENDER_HEIGHT = 100,
   1819 	};
   1820 
   1821 	vk::Move<VkRenderPass>			createRenderPass			(vk::VkFormat format) const;
   1822 	vk::Move<VkFramebuffer>			createFramebuffer			(vk::VkRenderPass renderPass, vk::VkImageView colorImageView) const;
   1823 	vk::Move<VkDescriptorSetLayout>	createDescriptorSetLayout	(void) const;
   1824 	vk::Move<VkDescriptorPool>		createDescriptorPool		(void) const;
   1825 	vk::Move<VkPipeline>			createPipeline				(vk::VkShaderModule vtxShaderModule, vk::VkShaderModule fragShaderModule, vk::VkPipelineLayout pipelineLayout, vk::VkRenderPass renderPass) const;
   1826 
   1827 	vk::VkDescriptorBufferInfo		addUniformData				(deUint32 size, const void* dataPtr);
   1828 
   1829 	UniformBlockCase::BufferMode	m_bufferMode;
   1830 	const UniformLayout&			m_layout;
   1831 	const std::map<int, void*>&		m_blockPointers;
   1832 
   1833 	typedef de::SharedPtr<vk::Unique<vk::VkBuffer> >	VkBufferSp;
   1834 	typedef de::SharedPtr<vk::Allocation>				AllocationSp;
   1835 
   1836 	std::vector<VkBufferSp>			m_uniformBuffers;
   1837 	std::vector<AllocationSp>		m_uniformAllocs;
   1838 };
   1839 
   1840 UniformBlockCaseInstance::UniformBlockCaseInstance (Context&						ctx,
   1841 													UniformBlockCase::BufferMode	bufferMode,
   1842 													const UniformLayout&			layout,
   1843 													const std::map<int, void*>&		blockPointers)
   1844 	: vkt::TestInstance (ctx)
   1845 	, m_bufferMode		(bufferMode)
   1846 	, m_layout			(layout)
   1847 	, m_blockPointers	(blockPointers)
   1848 {
   1849 }
   1850 
   1851 UniformBlockCaseInstance::~UniformBlockCaseInstance (void)
   1852 {
   1853 }
   1854 
   1855 tcu::TestStatus UniformBlockCaseInstance::iterate (void)
   1856 {
   1857 	const vk::DeviceInterface&		vk					= m_context.getDeviceInterface();
   1858 	const vk::VkDevice				device				= m_context.getDevice();
   1859 	const vk::VkQueue				queue				= m_context.getUniversalQueue();
   1860 	const deUint32					queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
   1861 
   1862 	const float positions[] =
   1863 	{
   1864 		-1.0f, -1.0f, 0.0f, 1.0f,
   1865 		-1.0f, +1.0f, 0.0f, 1.0f,
   1866 		+1.0f, -1.0f, 0.0f, 1.0f,
   1867 		+1.0f, +1.0f, 0.0f, 1.0f
   1868 	};
   1869 
   1870 	const deUint32 indices[] = { 0, 1, 2, 2, 1, 3 };
   1871 
   1872 	vk::Unique<VkBuffer>				positionsBuffer		(createBuffer(m_context, sizeof(positions), vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
   1873 	de::UniquePtr<Allocation>			positionsAlloc		(allocateAndBindMemory(m_context, *positionsBuffer, MemoryRequirement::HostVisible));
   1874 	vk::Unique<VkBuffer>				indicesBuffer		(createBuffer(m_context, sizeof(indices), vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT|vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
   1875 	de::UniquePtr<Allocation>			indicesAlloc		(allocateAndBindMemory(m_context, *indicesBuffer, MemoryRequirement::HostVisible));
   1876 
   1877 	int minUniformBufferOffsetAlignment = getminUniformBufferOffsetAlignment(m_context);
   1878 
   1879 	// Upload attrbiutes data
   1880 	{
   1881 		deMemcpy(positionsAlloc->getHostPtr(), positions, sizeof(positions));
   1882 		flushAlloc(vk, device, *positionsAlloc);
   1883 
   1884 		deMemcpy(indicesAlloc->getHostPtr(), indices, sizeof(indices));
   1885 		flushAlloc(vk, device, *indicesAlloc);
   1886 	}
   1887 
   1888 	vk::Unique<VkImage>					colorImage			(createImage2D(m_context,
   1889 																			RENDER_WIDTH,
   1890 																			RENDER_HEIGHT,
   1891 																			vk::VK_FORMAT_R8G8B8A8_UNORM,
   1892 																			vk::VK_IMAGE_TILING_OPTIMAL,
   1893 																			vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT|vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT));
   1894 	de::UniquePtr<Allocation>			colorImageAlloc		(allocateAndBindMemory(m_context, *colorImage, MemoryRequirement::Any));
   1895 	vk::Unique<VkImageView>				colorImageView		(createAttachmentView(m_context, *colorImage, vk::VK_FORMAT_R8G8B8A8_UNORM));
   1896 
   1897 	vk::Unique<VkDescriptorSetLayout>	descriptorSetLayout	(createDescriptorSetLayout());
   1898 	vk::Unique<VkDescriptorPool>		descriptorPool		(createDescriptorPool());
   1899 
   1900 	const VkDescriptorSetAllocateInfo	descriptorSetAllocateInfo =
   1901 	{
   1902 		VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,		// VkStructureType				sType;
   1903 		DE_NULL,											// const void*					pNext;
   1904 		*descriptorPool,									// VkDescriptorPool				descriptorPool;
   1905 		1u,													// deUint32						setLayoutCount;
   1906 		&descriptorSetLayout.get()							// const VkDescriptorSetLayout*	pSetLayouts;
   1907 	};
   1908 
   1909 	vk::Unique<VkDescriptorSet>			descriptorSet(vk::allocateDescriptorSet(vk, device, &descriptorSetAllocateInfo));
   1910 	int									numBlocks = (int)m_layout.blocks.size();
   1911 	std::vector<vk::VkDescriptorBufferInfo>	descriptors(numBlocks);
   1912 
   1913 	// Upload uniform data
   1914 	{
   1915 		vk::DescriptorSetUpdateBuilder	descriptorSetUpdateBuilder;
   1916 
   1917 		if (m_bufferMode == UniformBlockCase::BUFFERMODE_PER_BLOCK)
   1918 		{
   1919 			for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
   1920 			{
   1921 				const BlockLayoutEntry& block = m_layout.blocks[blockNdx];
   1922 				const void*	srcPtr = m_blockPointers.find(blockNdx)->second;
   1923 
   1924 				descriptors[blockNdx] = addUniformData(block.size, srcPtr);
   1925 				descriptorSetUpdateBuilder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::bindingArrayElement(block.bindingNdx, block.instanceNdx),
   1926 														VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descriptors[blockNdx]);
   1927 			}
   1928 		}
   1929 		else
   1930 		{
   1931 			int currentOffset = 0;
   1932 			std::map<int, int> offsets;
   1933 			for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
   1934 			{
   1935 				if (minUniformBufferOffsetAlignment > 0)
   1936 					currentOffset = deAlign32(currentOffset, minUniformBufferOffsetAlignment);
   1937 				offsets[blockNdx] = currentOffset;
   1938 				currentOffset += m_layout.blocks[blockNdx].size;
   1939 			}
   1940 
   1941 			deUint32 totalSize = currentOffset;
   1942 
   1943 			// Make a copy of the data that satisfies the device's min uniform buffer alignment
   1944 			std::vector<deUint8> data;
   1945 			data.resize(totalSize);
   1946 			for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
   1947 			{
   1948 				deMemcpy(&data[offsets[blockNdx]], m_blockPointers.find(blockNdx)->second, m_layout.blocks[blockNdx].size);
   1949 			}
   1950 
   1951 			vk::VkBuffer buffer = addUniformData(totalSize, &data[0]).buffer;
   1952 
   1953 			for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
   1954 			{
   1955 				const BlockLayoutEntry& block = m_layout.blocks[blockNdx];
   1956 				deUint32 size = block.size;
   1957 
   1958 				const VkDescriptorBufferInfo	descriptor =
   1959 				{
   1960 					buffer,							// VkBuffer		buffer;
   1961 					(deUint32)offsets[blockNdx],	// VkDeviceSize	offset;
   1962 					size,							// VkDeviceSize	range;
   1963 				};
   1964 
   1965 				descriptors[blockNdx] = descriptor;
   1966 				descriptorSetUpdateBuilder.writeSingle(*descriptorSet,
   1967 														vk::DescriptorSetUpdateBuilder::Location::bindingArrayElement(block.bindingNdx, block.instanceNdx),
   1968 														VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
   1969 														&descriptors[blockNdx]);
   1970 			}
   1971 		}
   1972 
   1973 		descriptorSetUpdateBuilder.update(vk, device);
   1974 	}
   1975 
   1976 	vk::Unique<VkRenderPass>			renderPass			(createRenderPass(vk::VK_FORMAT_R8G8B8A8_UNORM));
   1977 	vk::Unique<VkFramebuffer>			framebuffer			(createFramebuffer(*renderPass, *colorImageView));
   1978 	vk::Unique<VkPipelineLayout>		pipelineLayout		(createPipelineLayout(m_context, *descriptorSetLayout));
   1979 
   1980 	vk::Unique<VkShaderModule>			vtxShaderModule		(vk::createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0));
   1981 	vk::Unique<VkShaderModule>			fragShaderModule	(vk::createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0));
   1982 	vk::Unique<VkPipeline>				pipeline			(createPipeline(*vtxShaderModule, *fragShaderModule, *pipelineLayout, *renderPass));
   1983 	vk::Unique<VkCommandPool>			cmdPool				(createCmdPool(m_context));
   1984 	vk::Unique<VkCommandBuffer>			cmdBuffer			(createCmdBuffer(m_context, *cmdPool));
   1985 	vk::Unique<VkBuffer>				readImageBuffer		(createBuffer(m_context, (vk::VkDeviceSize)(RENDER_WIDTH * RENDER_HEIGHT * 4), vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT));
   1986 	de::UniquePtr<Allocation>			readImageAlloc		(allocateAndBindMemory(m_context, *readImageBuffer, vk::MemoryRequirement::HostVisible));
   1987 
   1988 	// Record command buffer
   1989 	const vk::VkCommandBufferBeginInfo beginInfo	=
   1990 	{
   1991 		vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,	// VkStructureType					sType;
   1992 		DE_NULL,											// const void*						pNext;
   1993 		0u,													// VkCommandBufferUsageFlags		flags;
   1994 		(const vk::VkCommandBufferInheritanceInfo*)DE_NULL,
   1995 	};
   1996 	VK_CHECK(vk.beginCommandBuffer(*cmdBuffer, &beginInfo));
   1997 
   1998 	// Add barrier for initializing image state
   1999 	{
   2000 		const vk::VkImageMemoryBarrier  initializeBarrier =
   2001 		{
   2002 			vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,		// VkStructureType			sType;
   2003 			DE_NULL,										// const void*				pNext
   2004 			0,												// VVkAccessFlags			srcAccessMask;
   2005 			vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,		// VkAccessFlags			dstAccessMask;
   2006 			vk::VK_IMAGE_LAYOUT_UNDEFINED,					// VkImageLayout			oldLayout;
   2007 			vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	// VkImageLayout			newLayout;
   2008 			queueFamilyIndex,								// deUint32					srcQueueFamilyIndex;
   2009 			queueFamilyIndex,								// deUint32					dstQueueFamilyIndex;
   2010 			*colorImage,									// VkImage					image;
   2011 			{
   2012 				vk::VK_IMAGE_ASPECT_COLOR_BIT,			// VkImageAspectFlags	aspectMask;
   2013 				0u,										// deUint32				baseMipLevel;
   2014 				1u,										// deUint32				mipLevels;
   2015 				0u,										// deUint32				baseArraySlice;
   2016 				1u,										// deUint32				arraySize;
   2017 			}												// VkImageSubresourceRange	subresourceRange
   2018 		};
   2019 
   2020 		vk.cmdPipelineBarrier(*cmdBuffer, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, vk::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, (vk::VkDependencyFlags)0,
   2021 			0, (const vk::VkMemoryBarrier*)DE_NULL,
   2022 			0, (const vk::VkBufferMemoryBarrier*)DE_NULL,
   2023 			1, &initializeBarrier);
   2024 	}
   2025 
   2026 	beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(0, 0, RENDER_WIDTH, RENDER_HEIGHT), tcu::Vec4(0.125f, 0.25f, 0.75f, 1.0f));
   2027 
   2028 	vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
   2029 	vk.cmdBindDescriptorSets(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u, DE_NULL);
   2030 
   2031 	const vk::VkDeviceSize offsets[] = { 0u };
   2032 	vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &*positionsBuffer, offsets);
   2033 	vk.cmdBindIndexBuffer(*cmdBuffer, *indicesBuffer, (vk::VkDeviceSize)0, vk::VK_INDEX_TYPE_UINT32);
   2034 
   2035 	vk.cmdDrawIndexed(*cmdBuffer, DE_LENGTH_OF_ARRAY(indices), 1u, 0u, 0u, 0u);
   2036 	endRenderPass(vk, *cmdBuffer);
   2037 
   2038 	copyImageToBuffer(vk, *cmdBuffer, *colorImage, *readImageBuffer, tcu::IVec2(RENDER_WIDTH, RENDER_HEIGHT));
   2039 
   2040 	endCommandBuffer(vk, *cmdBuffer);
   2041 
   2042 	// Submit the command buffer
   2043 	submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
   2044 
   2045 	// Read back the results
   2046 	tcu::Surface surface(RENDER_WIDTH, RENDER_HEIGHT);
   2047 	{
   2048 		const tcu::TextureFormat textureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
   2049 		const tcu::ConstPixelBufferAccess imgAccess(textureFormat, RENDER_WIDTH, RENDER_HEIGHT, 1, readImageAlloc->getHostPtr());
   2050 		invalidateAlloc(vk, device, *readImageAlloc);
   2051 
   2052 		tcu::copy(surface.getAccess(), imgAccess);
   2053 	}
   2054 
   2055 	// Check if the result image is all white
   2056 	tcu::RGBA white(tcu::RGBA::white());
   2057 	int numFailedPixels = 0;
   2058 
   2059 	for (int y = 0; y < surface.getHeight(); y++)
   2060 	{
   2061 		for (int x = 0; x < surface.getWidth(); x++)
   2062 		{
   2063 			if (surface.getPixel(x, y) != white)
   2064 				numFailedPixels += 1;
   2065 		}
   2066 	}
   2067 
   2068 	if (numFailedPixels > 0)
   2069 	{
   2070 		tcu::TestLog& log = m_context.getTestContext().getLog();
   2071 		log << tcu::TestLog::Image("Image", "Rendered image", surface);
   2072 		log << tcu::TestLog::Message << "Image comparison failed, got " << numFailedPixels << " non-white pixels" << tcu::TestLog::EndMessage;
   2073 
   2074 		for (size_t blockNdx = 0; blockNdx < m_layout.blocks.size(); blockNdx++)
   2075 		{
   2076 			const BlockLayoutEntry& block = m_layout.blocks[blockNdx];
   2077 			log << tcu::TestLog::Message << "Block index: " << blockNdx << " infos: " << block << tcu::TestLog::EndMessage;
   2078 		}
   2079 
   2080 		for (size_t uniformNdx = 0; uniformNdx < m_layout.uniforms.size(); uniformNdx++)
   2081 		{
   2082 			log << tcu::TestLog::Message << "Uniform index: " << uniformNdx << " infos: " << m_layout.uniforms[uniformNdx] << tcu::TestLog::EndMessage;
   2083 		}
   2084 
   2085 		return tcu::TestStatus::fail("Detected non-white pixels");
   2086 	}
   2087 	else
   2088 		return tcu::TestStatus::pass("Full white image ok");
   2089 }
   2090 
   2091 vk::VkDescriptorBufferInfo UniformBlockCaseInstance::addUniformData (deUint32 size, const void* dataPtr)
   2092 {
   2093 	const VkDevice					vkDevice			= m_context.getDevice();
   2094 	const DeviceInterface&			vk					= m_context.getDeviceInterface();
   2095 
   2096 	Move<VkBuffer>					buffer	= createBuffer(m_context, size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
   2097 	de::MovePtr<Allocation>			alloc	= allocateAndBindMemory(m_context, *buffer, vk::MemoryRequirement::HostVisible);
   2098 
   2099 	deMemcpy(alloc->getHostPtr(), dataPtr, size);
   2100 	flushAlloc(vk, vkDevice, *alloc);
   2101 
   2102 	const VkDescriptorBufferInfo			descriptor			=
   2103 	{
   2104 		*buffer,				// VkBuffer		buffer;
   2105 		0u,						// VkDeviceSize	offset;
   2106 		size,					// VkDeviceSize	range;
   2107 
   2108 	};
   2109 
   2110 	m_uniformBuffers.push_back(VkBufferSp(new vk::Unique<vk::VkBuffer>(buffer)));
   2111 	m_uniformAllocs.push_back(AllocationSp(alloc.release()));
   2112 
   2113 	return descriptor;
   2114 }
   2115 
   2116 vk::Move<VkRenderPass> UniformBlockCaseInstance::createRenderPass (vk::VkFormat format) const
   2117 {
   2118 	const VkDevice					vkDevice				= m_context.getDevice();
   2119 	const DeviceInterface&			vk						= m_context.getDeviceInterface();
   2120 
   2121 	return vk::makeRenderPass(vk, vkDevice, format);
   2122 }
   2123 
   2124 vk::Move<VkFramebuffer> UniformBlockCaseInstance::createFramebuffer (vk::VkRenderPass renderPass, vk::VkImageView colorImageView) const
   2125 {
   2126 	const VkDevice					vkDevice			= m_context.getDevice();
   2127 	const DeviceInterface&			vk					= m_context.getDeviceInterface();
   2128 
   2129 	const VkFramebufferCreateInfo	framebufferParams	=
   2130 	{
   2131 		VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,		// VkStructureType			sType;
   2132 		DE_NULL,										// const void*				pNext;
   2133 		0u,												// VkFramebufferCreateFlags	flags;
   2134 		renderPass,										// VkRenderPass				renderPass;
   2135 		1u,												// deUint32					attachmentCount;
   2136 		&colorImageView,								// const VkImageView*		pAttachments;
   2137 		RENDER_WIDTH,									// deUint32					width;
   2138 		RENDER_HEIGHT,									// deUint32					height;
   2139 		1u												// deUint32					layers;
   2140 	};
   2141 
   2142 	return vk::createFramebuffer(vk, vkDevice, &framebufferParams);
   2143 }
   2144 
   2145 vk::Move<VkDescriptorSetLayout> UniformBlockCaseInstance::createDescriptorSetLayout (void) const
   2146 {
   2147 	int numBlocks = (int)m_layout.blocks.size();
   2148 	int lastBindingNdx = -1;
   2149 	std::vector<int> lengths;
   2150 
   2151 	for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
   2152 	{
   2153 		const BlockLayoutEntry& block = m_layout.blocks[blockNdx];
   2154 
   2155 		if (block.bindingNdx == lastBindingNdx)
   2156 		{
   2157 			lengths.back()++;
   2158 		}
   2159 		else
   2160 		{
   2161 			lengths.push_back(1);
   2162 			lastBindingNdx = block.bindingNdx;
   2163 		}
   2164 	}
   2165 
   2166 	vk::DescriptorSetLayoutBuilder layoutBuilder;
   2167 	for (size_t i = 0; i < lengths.size(); i++)
   2168 	{
   2169 		if (lengths[i] > 0)
   2170 		{
   2171 			layoutBuilder.addArrayBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, lengths[i], vk::VK_SHADER_STAGE_ALL);
   2172 		}
   2173 		else
   2174 		{
   2175 			layoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_SHADER_STAGE_ALL);
   2176 		}
   2177 	}
   2178 
   2179 	return layoutBuilder.build(m_context.getDeviceInterface(), m_context.getDevice());
   2180 }
   2181 
   2182 vk::Move<VkDescriptorPool> UniformBlockCaseInstance::createDescriptorPool (void) const
   2183 {
   2184 	vk::DescriptorPoolBuilder poolBuilder;
   2185 
   2186 	return poolBuilder
   2187 		.addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, (int)m_layout.blocks.size())
   2188 		.build(m_context.getDeviceInterface(), m_context.getDevice(), VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
   2189 }
   2190 
   2191 vk::Move<VkPipeline> UniformBlockCaseInstance::createPipeline (vk::VkShaderModule vtxShaderModule, vk::VkShaderModule fragShaderModule, vk::VkPipelineLayout pipelineLayout, vk::VkRenderPass renderPass) const
   2192 {
   2193 	const VkDevice									vkDevice				= m_context.getDevice();
   2194 	const DeviceInterface&							vk						= m_context.getDeviceInterface();
   2195 
   2196 	const std::vector<VkViewport>					viewports				(1, makeViewport(tcu::UVec2(RENDER_WIDTH, RENDER_HEIGHT)));
   2197 	const std::vector<VkRect2D>						scissors				(1, makeRect2D(tcu::UVec2(RENDER_WIDTH, RENDER_HEIGHT)));
   2198 
   2199 	return vk::makeGraphicsPipeline(vk,					// const DeviceInterface&            vk
   2200 									vkDevice,			// const VkDevice                    device
   2201 									pipelineLayout,		// const VkPipelineLayout            pipelineLayout
   2202 									vtxShaderModule,	// const VkShaderModule              vertexShaderModule
   2203 									DE_NULL,			// const VkShaderModule              tessellationControlShaderModule
   2204 									DE_NULL,			// const VkShaderModule              tessellationEvalShaderModule
   2205 									DE_NULL,			// const VkShaderModule              geometryShaderModule
   2206 									fragShaderModule,	// const VkShaderModule              fragmentShaderModule
   2207 									renderPass,			// const VkRenderPass                renderPass
   2208 									viewports,			// const std::vector<VkViewport>&    viewports
   2209 									scissors);			// const std::vector<VkRect2D>&      scissors
   2210 }
   2211 
   2212 } // anonymous (utilities)
   2213 
   2214 // UniformBlockCase.
   2215 
   2216 UniformBlockCase::UniformBlockCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, BufferMode bufferMode, MatrixLoadFlags matrixLoadFlag, bool shuffleUniformMembers)
   2217 	: TestCase					(testCtx, name, description)
   2218 	, m_bufferMode				(bufferMode)
   2219 	, m_matrixLoadFlag			(matrixLoadFlag)
   2220 	, m_shuffleUniformMembers	(shuffleUniformMembers)
   2221 {
   2222 }
   2223 
   2224 UniformBlockCase::~UniformBlockCase (void)
   2225 {
   2226 }
   2227 
   2228 void UniformBlockCase::initPrograms (vk::SourceCollections& programCollection) const
   2229 {
   2230 	DE_ASSERT(!m_vertShaderSource.empty());
   2231 	DE_ASSERT(!m_fragShaderSource.empty());
   2232 
   2233 	vk::ShaderBuildOptions::Flags flags = vk::ShaderBuildOptions::Flags(0);
   2234 	// TODO(dneto): If these tests ever use LAYOUT_RELAXED, then add support
   2235 	// here as well.
   2236 	if (usesBlockLayout(UniformFlags(LAYOUT_SCALAR | LAYOUT_STD430)))
   2237 	{
   2238 		flags = vk::ShaderBuildOptions::FLAG_ALLOW_SCALAR_OFFSETS;
   2239 	}
   2240 
   2241 	programCollection.glslSources.add("vert") << glu::VertexSource(m_vertShaderSource)
   2242 	<< vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::getBaselineSpirvVersion(programCollection.usedVulkanVersion), flags);
   2243 
   2244 	programCollection.glslSources.add("frag") << glu::FragmentSource(m_fragShaderSource)
   2245 	<< vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::getBaselineSpirvVersion(programCollection.usedVulkanVersion), flags);
   2246 }
   2247 
   2248 TestInstance* UniformBlockCase::createInstance (Context& context) const
   2249 {
   2250 	if (!context.get16BitStorageFeatures().uniformAndStorageBuffer16BitAccess && uses16BitStorage(m_interface))
   2251 		TCU_THROW(NotSupportedError, "uniformAndStorageBuffer16BitAccess not supported");
   2252 	if (!context.get8BitStorageFeatures().uniformAndStorageBuffer8BitAccess && uses8BitStorage(m_interface))
   2253 		TCU_THROW(NotSupportedError, "uniformAndStorageBuffer8BitAccess not supported");
   2254 	if (!context.getScalarBlockLayoutFeatures().scalarBlockLayout && usesScalarOrStd430Layout(m_interface))
   2255 		TCU_THROW(NotSupportedError, "scalarBlockLayout not supported");
   2256 
   2257 	return new UniformBlockCaseInstance(context, m_bufferMode, m_uniformLayout, m_blockPointers);
   2258 }
   2259 
   2260 void UniformBlockCase::init (void)
   2261 {
   2262 	const int vec4Alignment = (int)sizeof(deUint32)*4;
   2263 
   2264 	// Compute reference layout.
   2265 	computeReferenceLayout(m_uniformLayout, m_interface);
   2266 
   2267 	// Assign storage for reference values.
   2268 	{
   2269 		int totalSize = 0;
   2270 		for (std::vector<BlockLayoutEntry>::const_iterator blockIter = m_uniformLayout.blocks.begin(); blockIter != m_uniformLayout.blocks.end(); blockIter++)
   2271 		{
   2272 			// Include enough space for alignment of individual blocks
   2273 			totalSize += deRoundUp32(blockIter->size, vec4Alignment);
   2274 		}
   2275 		m_data.resize(totalSize);
   2276 
   2277 		// Pointers for each block.
   2278 		int curOffset = 0;
   2279 		for (int blockNdx = 0; blockNdx < (int)m_uniformLayout.blocks.size(); blockNdx++)
   2280 		{
   2281 			m_blockPointers[blockNdx] = &m_data[0] + curOffset;
   2282 
   2283 			// Ensure each new block starts fully aligned to avoid unaligned host accesses
   2284 			curOffset += deRoundUp32(m_uniformLayout.blocks[blockNdx].size, vec4Alignment);
   2285 		}
   2286 	}
   2287 
   2288 	// Generate values.
   2289 	generateValues(m_uniformLayout, m_blockPointers, 1 /* seed */);
   2290 
   2291 	// Generate shaders.
   2292 	m_vertShaderSource = generateVertexShader(m_interface, m_uniformLayout, m_blockPointers, m_matrixLoadFlag, m_shuffleUniformMembers);
   2293 	m_fragShaderSource = generateFragmentShader(m_interface, m_uniformLayout, m_blockPointers, m_matrixLoadFlag, m_shuffleUniformMembers);
   2294 }
   2295 
   2296 } // ubo
   2297 } // vkt
   2298