Home | History | Annotate | Download | only in common
      1 /*-------------------------------------------------------------------------
      2  * OpenGL Conformance Test Suite
      3  * -----------------------------
      4  *
      5  * Copyright (c) 2016 Google Inc.
      6  * Copyright (c) 2016 The Khronos Group Inc.
      7  *
      8  * Licensed under the Apache License, Version 2.0 (the "License");
      9  * you may not use this file except in compliance with the License.
     10  * You may obtain a copy of the License at
     11  *
     12  *      http://www.apache.org/licenses/LICENSE-2.0
     13  *
     14  * Unless required by applicable law or agreed to in writing, software
     15  * distributed under the License is distributed on an "AS IS" BASIS,
     16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     17  * See the License for the specific language governing permissions and
     18  * limitations under the License.
     19  *
     20  */ /*!
     21  * \file
     22  * \brief Uniform block case.
     23  */ /*-------------------------------------------------------------------*/
     24 
     25 #include "glcUniformBlockCase.hpp"
     26 #include "deMemory.h"
     27 #include "deRandom.hpp"
     28 #include "deString.h"
     29 #include "deStringUtil.hpp"
     30 #include "gluContextInfo.hpp"
     31 #include "gluDrawUtil.hpp"
     32 #include "gluPixelTransfer.hpp"
     33 #include "gluRenderContext.hpp"
     34 #include "glwEnums.hpp"
     35 #include "glwFunctions.hpp"
     36 #include "tcuRenderTarget.hpp"
     37 #include "tcuSurface.hpp"
     38 #include "tcuTestLog.hpp"
     39 
     40 #include <algorithm>
     41 #include <map>
     42 
     43 using tcu::TestLog;
     44 using std::string;
     45 using std::vector;
     46 using std::map;
     47 
     48 namespace deqp
     49 {
     50 namespace ub
     51 {
     52 
     53 struct PrecisionFlagsFmt
     54 {
     55 	deUint32 flags;
     56 
     57 	PrecisionFlagsFmt(deUint32 flags_) : flags(flags_)
     58 	{
     59 	}
     60 };
     61 
     62 std::ostream& operator<<(std::ostream& str, const PrecisionFlagsFmt& fmt)
     63 {
     64 	// Precision.
     65 	DE_ASSERT(dePop32(fmt.flags & (PRECISION_LOW | PRECISION_MEDIUM | PRECISION_HIGH)) <= 1);
     66 	str << (fmt.flags & PRECISION_LOW ?
     67 				"lowp" :
     68 				fmt.flags & PRECISION_MEDIUM ? "mediump" : fmt.flags & PRECISION_HIGH ? "highp" : "");
     69 	return str;
     70 }
     71 
     72 struct LayoutFlagsFmt
     73 {
     74 	deUint32 flags;
     75 	LayoutFlagsFmt(deUint32 flags_) : flags(flags_)
     76 	{
     77 	}
     78 };
     79 
     80 std::ostream& operator<<(std::ostream& str, const LayoutFlagsFmt& fmt)
     81 {
     82 	static const struct
     83 	{
     84 		deUint32	bit;
     85 		const char* token;
     86 	} bitDesc[] = { { LAYOUT_SHARED, "shared" },
     87 					{ LAYOUT_PACKED, "packed" },
     88 					{ LAYOUT_STD140, "std140" },
     89 					{ LAYOUT_ROW_MAJOR, "row_major" },
     90 					{ LAYOUT_COLUMN_MAJOR, "column_major" } };
     91 
     92 	deUint32 remBits = fmt.flags;
     93 	for (int descNdx = 0; descNdx < DE_LENGTH_OF_ARRAY(bitDesc); descNdx++)
     94 	{
     95 		if (remBits & bitDesc[descNdx].bit)
     96 		{
     97 			if (remBits != fmt.flags)
     98 				str << ", ";
     99 			str << bitDesc[descNdx].token;
    100 			remBits &= ~bitDesc[descNdx].bit;
    101 		}
    102 	}
    103 	DE_ASSERT(remBits == 0);
    104 	return str;
    105 }
    106 
    107 // VarType implementation.
    108 
    109 VarType::VarType(void) : m_type(TYPE_LAST), m_flags(0)
    110 {
    111 }
    112 
    113 VarType::VarType(const VarType& other) : m_type(TYPE_LAST), m_flags(0)
    114 {
    115 	*this = other;
    116 }
    117 
    118 VarType::VarType(glu::DataType basicType, deUint32 flags) : m_type(TYPE_BASIC), m_flags(flags)
    119 {
    120 	m_data.basicType = basicType;
    121 }
    122 
    123 VarType::VarType(const VarType& elementType, int arraySize) : m_type(TYPE_ARRAY), m_flags(0)
    124 {
    125 	m_data.array.size		 = arraySize;
    126 	m_data.array.elementType = new VarType(elementType);
    127 }
    128 
    129 VarType::VarType(const StructType* structPtr) : m_type(TYPE_STRUCT), m_flags(0)
    130 {
    131 	m_data.structPtr = structPtr;
    132 }
    133 
    134 VarType::~VarType(void)
    135 {
    136 	if (m_type == TYPE_ARRAY)
    137 		delete m_data.array.elementType;
    138 }
    139 
    140 VarType& VarType::operator=(const VarType& other)
    141 {
    142 	if (this == &other)
    143 		return *this; // Self-assignment.
    144 
    145 	if (m_type == TYPE_ARRAY)
    146 		delete m_data.array.elementType;
    147 
    148 	m_type  = other.m_type;
    149 	m_flags = other.m_flags;
    150 	m_data  = Data();
    151 
    152 	if (m_type == TYPE_ARRAY)
    153 	{
    154 		m_data.array.elementType = new VarType(*other.m_data.array.elementType);
    155 		m_data.array.size		 = other.m_data.array.size;
    156 	}
    157 	else
    158 		m_data = other.m_data;
    159 
    160 	return *this;
    161 }
    162 
    163 // StructType implementation.
    164 
    165 void StructType::addMember(const char* name, const VarType& type, deUint32 flags)
    166 {
    167 	m_members.push_back(StructMember(name, type, flags));
    168 }
    169 
    170 // Uniform implementation.
    171 
    172 Uniform::Uniform(const char* name, const VarType& type, deUint32 flags) : m_name(name), m_type(type), m_flags(flags)
    173 {
    174 }
    175 
    176 // UniformBlock implementation.
    177 
    178 UniformBlock::UniformBlock(const char* blockName) : m_blockName(blockName), m_arraySize(0), m_flags(0)
    179 {
    180 }
    181 
    182 struct BlockLayoutEntry
    183 {
    184 	BlockLayoutEntry(void) : size(0)
    185 	{
    186 	}
    187 
    188 	std::string		 name;
    189 	int				 size;
    190 	std::vector<int> activeUniformIndices;
    191 };
    192 
    193 std::ostream& operator<<(std::ostream& stream, const BlockLayoutEntry& entry)
    194 {
    195 	stream << entry.name << " { name = " << entry.name << ", size = " << entry.size << ", activeUniformIndices = [";
    196 
    197 	for (vector<int>::const_iterator i = entry.activeUniformIndices.begin(); i != entry.activeUniformIndices.end(); i++)
    198 	{
    199 		if (i != entry.activeUniformIndices.begin())
    200 			stream << ", ";
    201 		stream << *i;
    202 	}
    203 
    204 	stream << "] }";
    205 	return stream;
    206 }
    207 
    208 struct UniformLayoutEntry
    209 {
    210 	UniformLayoutEntry(void)
    211 		: type(glu::TYPE_LAST), size(0), blockNdx(-1), offset(-1), arrayStride(-1), matrixStride(-1), isRowMajor(false)
    212 	{
    213 	}
    214 
    215 	std::string   name;
    216 	glu::DataType type;
    217 	int			  size;
    218 	int			  blockNdx;
    219 	int			  offset;
    220 	int			  arrayStride;
    221 	int			  matrixStride;
    222 	bool		  isRowMajor;
    223 };
    224 
    225 std::ostream& operator<<(std::ostream& stream, const UniformLayoutEntry& entry)
    226 {
    227 	stream << entry.name << " { type = " << glu::getDataTypeName(entry.type) << ", size = " << entry.size
    228 		   << ", blockNdx = " << entry.blockNdx << ", offset = " << entry.offset
    229 		   << ", arrayStride = " << entry.arrayStride << ", matrixStride = " << entry.matrixStride
    230 		   << ", isRowMajor = " << (entry.isRowMajor ? "true" : "false") << " }";
    231 	return stream;
    232 }
    233 
    234 class UniformLayout
    235 {
    236 public:
    237 	std::vector<BlockLayoutEntry>   blocks;
    238 	std::vector<UniformLayoutEntry> uniforms;
    239 
    240 	int getUniformIndex(const char* name) const;
    241 	int getBlockIndex(const char* name) const;
    242 };
    243 
    244 // \todo [2012-01-24 pyry] Speed up lookups using hash.
    245 
    246 int UniformLayout::getUniformIndex(const char* name) const
    247 {
    248 	for (int ndx = 0; ndx < (int)uniforms.size(); ndx++)
    249 	{
    250 		if (uniforms[ndx].name == name)
    251 			return ndx;
    252 	}
    253 	return -1;
    254 }
    255 
    256 int UniformLayout::getBlockIndex(const char* name) const
    257 {
    258 	for (int ndx = 0; ndx < (int)blocks.size(); ndx++)
    259 	{
    260 		if (blocks[ndx].name == name)
    261 			return ndx;
    262 	}
    263 	return -1;
    264 }
    265 
    266 // ShaderInterface implementation.
    267 
    268 ShaderInterface::ShaderInterface(void)
    269 {
    270 }
    271 
    272 ShaderInterface::~ShaderInterface(void)
    273 {
    274 	for (std::vector<StructType*>::iterator i = m_structs.begin(); i != m_structs.end(); i++)
    275 		delete *i;
    276 
    277 	for (std::vector<UniformBlock*>::iterator i = m_uniformBlocks.begin(); i != m_uniformBlocks.end(); i++)
    278 		delete *i;
    279 }
    280 
    281 StructType& ShaderInterface::allocStruct(const char* name)
    282 {
    283 	m_structs.reserve(m_structs.size() + 1);
    284 	m_structs.push_back(new StructType(name));
    285 	return *m_structs.back();
    286 }
    287 
    288 struct StructNameEquals
    289 {
    290 	std::string name;
    291 
    292 	StructNameEquals(const char* name_) : name(name_)
    293 	{
    294 	}
    295 
    296 	bool operator()(const StructType* type) const
    297 	{
    298 		return type->getTypeName() && name == type->getTypeName();
    299 	}
    300 };
    301 
    302 const StructType* ShaderInterface::findStruct(const char* name) const
    303 {
    304 	std::vector<StructType*>::const_iterator pos =
    305 		std::find_if(m_structs.begin(), m_structs.end(), StructNameEquals(name));
    306 	return pos != m_structs.end() ? *pos : DE_NULL;
    307 }
    308 
    309 void ShaderInterface::getNamedStructs(std::vector<const StructType*>& structs) const
    310 {
    311 	for (std::vector<StructType*>::const_iterator i = m_structs.begin(); i != m_structs.end(); i++)
    312 	{
    313 		if ((*i)->getTypeName() != DE_NULL)
    314 			structs.push_back(*i);
    315 	}
    316 }
    317 
    318 UniformBlock& ShaderInterface::allocBlock(const char* name)
    319 {
    320 	m_uniformBlocks.reserve(m_uniformBlocks.size() + 1);
    321 	m_uniformBlocks.push_back(new UniformBlock(name));
    322 	return *m_uniformBlocks.back();
    323 }
    324 
    325 namespace // Utilities
    326 {
    327 
    328 // Layout computation.
    329 
    330 int getDataTypeByteSize(glu::DataType type)
    331 {
    332 	return static_cast<int>(glu::getDataTypeScalarSize(type) * sizeof(deUint32));
    333 }
    334 
    335 int getDataTypeByteAlignment(glu::DataType type)
    336 {
    337 	switch (type)
    338 	{
    339 	case glu::TYPE_FLOAT:
    340 	case glu::TYPE_INT:
    341 	case glu::TYPE_UINT:
    342 	case glu::TYPE_BOOL:
    343 		return static_cast<int>(1 * 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:
    349 		return static_cast<int>(2 * sizeof(deUint32));
    350 
    351 	case glu::TYPE_FLOAT_VEC3:
    352 	case glu::TYPE_INT_VEC3:
    353 	case glu::TYPE_UINT_VEC3:
    354 	case glu::TYPE_BOOL_VEC3: // Fall-through to vec4
    355 
    356 	case glu::TYPE_FLOAT_VEC4:
    357 	case glu::TYPE_INT_VEC4:
    358 	case glu::TYPE_UINT_VEC4:
    359 	case glu::TYPE_BOOL_VEC4:
    360 		return static_cast<int>(4 * sizeof(deUint32));
    361 
    362 	default:
    363 		DE_ASSERT(false);
    364 		return 0;
    365 	}
    366 }
    367 
    368 int getDataTypeArrayStride(glu::DataType type)
    369 {
    370 	DE_ASSERT(!glu::isDataTypeMatrix(type));
    371 
    372 	int baseStride	= getDataTypeByteSize(type);
    373 	int vec4Alignment = static_cast<int>(sizeof(deUint32) * 4);
    374 
    375 	DE_ASSERT(baseStride <= vec4Alignment);
    376 	return de::max(baseStride, vec4Alignment); // Really? See rule 4.
    377 }
    378 
    379 static inline int deRoundUp32(int a, int b)
    380 {
    381 	int d = a / b;
    382 	return d * b == a ? a : (d + 1) * b;
    383 }
    384 
    385 int computeStd140BaseAlignment(const VarType& type)
    386 {
    387 	const int vec4Alignment = static_cast<int>(sizeof(deUint32) * 4);
    388 
    389 	if (type.isBasicType())
    390 	{
    391 		glu::DataType basicType = type.getBasicType();
    392 
    393 		if (glu::isDataTypeMatrix(basicType))
    394 		{
    395 			bool isRowMajor = !!(type.getFlags() & LAYOUT_ROW_MAJOR);
    396 			int  vecSize =
    397 				isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType) : glu::getDataTypeMatrixNumRows(basicType);
    398 
    399 			return getDataTypeArrayStride(glu::getDataTypeFloatVec(vecSize));
    400 		}
    401 		else
    402 			return getDataTypeByteAlignment(basicType);
    403 	}
    404 	else if (type.isArrayType())
    405 	{
    406 		int elemAlignment = computeStd140BaseAlignment(type.getElementType());
    407 
    408 		// Round up to alignment of vec4
    409 		return deRoundUp32(elemAlignment, vec4Alignment);
    410 	}
    411 	else
    412 	{
    413 		DE_ASSERT(type.isStructType());
    414 
    415 		int maxBaseAlignment = 0;
    416 
    417 		for (StructType::ConstIterator memberIter = type.getStruct().begin(); memberIter != type.getStruct().end();
    418 			 memberIter++)
    419 			maxBaseAlignment = de::max(maxBaseAlignment, computeStd140BaseAlignment(memberIter->getType()));
    420 
    421 		return deRoundUp32(maxBaseAlignment, vec4Alignment);
    422 	}
    423 }
    424 
    425 inline deUint32 mergeLayoutFlags(deUint32 prevFlags, deUint32 newFlags)
    426 {
    427 	const deUint32 packingMask = LAYOUT_PACKED | LAYOUT_SHARED | LAYOUT_STD140;
    428 	const deUint32 matrixMask  = LAYOUT_ROW_MAJOR | LAYOUT_COLUMN_MAJOR;
    429 
    430 	deUint32 mergedFlags = 0;
    431 
    432 	mergedFlags |= ((newFlags & packingMask) ? newFlags : prevFlags) & packingMask;
    433 	mergedFlags |= ((newFlags & matrixMask) ? newFlags : prevFlags) & matrixMask;
    434 
    435 	return mergedFlags;
    436 }
    437 
    438 void computeStd140Layout(UniformLayout& layout, int& curOffset, int curBlockNdx, const std::string& curPrefix,
    439 						 const VarType& type, deUint32 layoutFlags)
    440 {
    441 	int baseAlignment = computeStd140BaseAlignment(type);
    442 
    443 	curOffset = deAlign32(curOffset, baseAlignment);
    444 
    445 	if (type.isBasicType())
    446 	{
    447 		glu::DataType	  basicType = type.getBasicType();
    448 		UniformLayoutEntry entry;
    449 
    450 		entry.name		   = curPrefix;
    451 		entry.type		   = basicType;
    452 		entry.size		   = 1;
    453 		entry.arrayStride  = 0;
    454 		entry.matrixStride = 0;
    455 		entry.blockNdx	 = curBlockNdx;
    456 
    457 		if (glu::isDataTypeMatrix(basicType))
    458 		{
    459 			// Array of vectors as specified in rules 5 & 7.
    460 			bool isRowMajor = !!(layoutFlags & LAYOUT_ROW_MAJOR);
    461 			int  vecSize =
    462 				isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType) : glu::getDataTypeMatrixNumRows(basicType);
    463 			int numVecs =
    464 				isRowMajor ? glu::getDataTypeMatrixNumRows(basicType) : glu::getDataTypeMatrixNumColumns(basicType);
    465 			int stride = getDataTypeArrayStride(glu::getDataTypeFloatVec(vecSize));
    466 
    467 			entry.offset	   = curOffset;
    468 			entry.matrixStride = stride;
    469 			entry.isRowMajor   = isRowMajor;
    470 
    471 			curOffset += numVecs * stride;
    472 		}
    473 		else
    474 		{
    475 			// Scalar or vector.
    476 			entry.offset = curOffset;
    477 
    478 			curOffset += getDataTypeByteSize(basicType);
    479 		}
    480 
    481 		layout.uniforms.push_back(entry);
    482 	}
    483 	else if (type.isArrayType())
    484 	{
    485 		const VarType& elemType = type.getElementType();
    486 
    487 		if (elemType.isBasicType() && !glu::isDataTypeMatrix(elemType.getBasicType()))
    488 		{
    489 			// Array of scalars or vectors.
    490 			glu::DataType	  elemBasicType = elemType.getBasicType();
    491 			UniformLayoutEntry entry;
    492 			int				   stride = getDataTypeArrayStride(elemBasicType);
    493 
    494 			entry.name		   = curPrefix + "[0]"; // Array uniforms are always postfixed with [0]
    495 			entry.type		   = elemBasicType;
    496 			entry.blockNdx	 = curBlockNdx;
    497 			entry.offset	   = curOffset;
    498 			entry.size		   = type.getArraySize();
    499 			entry.arrayStride  = stride;
    500 			entry.matrixStride = 0;
    501 
    502 			curOffset += stride * type.getArraySize();
    503 
    504 			layout.uniforms.push_back(entry);
    505 		}
    506 		else if (elemType.isBasicType() && glu::isDataTypeMatrix(elemType.getBasicType()))
    507 		{
    508 			// Array of matrices.
    509 			glu::DataType elemBasicType = elemType.getBasicType();
    510 			bool		  isRowMajor	= !!(layoutFlags & LAYOUT_ROW_MAJOR);
    511 			int			  vecSize		= isRowMajor ? glu::getDataTypeMatrixNumColumns(elemBasicType) :
    512 									   glu::getDataTypeMatrixNumRows(elemBasicType);
    513 			int numVecs = isRowMajor ? glu::getDataTypeMatrixNumRows(elemBasicType) :
    514 									   glu::getDataTypeMatrixNumColumns(elemBasicType);
    515 			int				   stride = getDataTypeArrayStride(glu::getDataTypeFloatVec(vecSize));
    516 			UniformLayoutEntry entry;
    517 
    518 			entry.name		   = curPrefix + "[0]"; // Array uniforms are always postfixed with [0]
    519 			entry.type		   = elemBasicType;
    520 			entry.blockNdx	 = curBlockNdx;
    521 			entry.offset	   = curOffset;
    522 			entry.size		   = type.getArraySize();
    523 			entry.arrayStride  = stride * numVecs;
    524 			entry.matrixStride = stride;
    525 			entry.isRowMajor   = isRowMajor;
    526 
    527 			curOffset += numVecs * type.getArraySize() * stride;
    528 
    529 			layout.uniforms.push_back(entry);
    530 		}
    531 		else
    532 		{
    533 			DE_ASSERT(elemType.isStructType() || elemType.isArrayType());
    534 
    535 			for (int elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++)
    536 				computeStd140Layout(layout, curOffset, curBlockNdx, curPrefix + "[" + de::toString(elemNdx) + "]",
    537 									type.getElementType(), layoutFlags);
    538 		}
    539 	}
    540 	else
    541 	{
    542 		DE_ASSERT(type.isStructType());
    543 
    544 		for (StructType::ConstIterator memberIter = type.getStruct().begin(); memberIter != type.getStruct().end();
    545 			 memberIter++)
    546 			computeStd140Layout(layout, curOffset, curBlockNdx, curPrefix + "." + memberIter->getName(),
    547 								memberIter->getType(), layoutFlags);
    548 
    549 		curOffset = deAlign32(curOffset, baseAlignment);
    550 	}
    551 }
    552 
    553 void computeStd140Layout(UniformLayout& layout, const ShaderInterface& interface)
    554 {
    555 	// \todo [2012-01-23 pyry] Uniforms in default block.
    556 
    557 	int numUniformBlocks = interface.getNumUniformBlocks();
    558 
    559 	for (int blockNdx = 0; blockNdx < numUniformBlocks; blockNdx++)
    560 	{
    561 		const UniformBlock& block			= interface.getUniformBlock(blockNdx);
    562 		bool				hasInstanceName = block.getInstanceName() != DE_NULL;
    563 		std::string			blockPrefix = hasInstanceName ? (std::string(block.getBlockName()) + ".") : std::string("");
    564 		int					curOffset   = 0;
    565 		int					activeBlockNdx  = (int)layout.blocks.size();
    566 		int					firstUniformNdx = (int)layout.uniforms.size();
    567 
    568 		for (UniformBlock::ConstIterator uniformIter = block.begin(); uniformIter != block.end(); uniformIter++)
    569 		{
    570 			const Uniform& uniform = *uniformIter;
    571 			computeStd140Layout(layout, curOffset, activeBlockNdx, blockPrefix + uniform.getName(), uniform.getType(),
    572 								mergeLayoutFlags(block.getFlags(), uniform.getFlags()));
    573 		}
    574 
    575 		int uniformIndicesEnd = (int)layout.uniforms.size();
    576 		int blockSize		  = curOffset;
    577 		int numInstances	  = block.isArray() ? block.getArraySize() : 1;
    578 
    579 		// Create block layout entries for each instance.
    580 		for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
    581 		{
    582 			// Allocate entry for instance.
    583 			layout.blocks.push_back(BlockLayoutEntry());
    584 			BlockLayoutEntry& blockEntry = layout.blocks.back();
    585 
    586 			blockEntry.name = block.getBlockName();
    587 			blockEntry.size = blockSize;
    588 
    589 			// Compute active uniform set for block.
    590 			for (int uniformNdx = firstUniformNdx; uniformNdx < uniformIndicesEnd; uniformNdx++)
    591 				blockEntry.activeUniformIndices.push_back(uniformNdx);
    592 
    593 			if (block.isArray())
    594 				blockEntry.name += "[" + de::toString(instanceNdx) + "]";
    595 		}
    596 	}
    597 }
    598 
    599 // Value generator.
    600 
    601 void generateValue(const UniformLayoutEntry& entry, void* basePtr, de::Random& rnd)
    602 {
    603 	glu::DataType scalarType = glu::getDataTypeScalarType(entry.type);
    604 	int			  scalarSize = glu::getDataTypeScalarSize(entry.type);
    605 	bool		  isMatrix   = glu::isDataTypeMatrix(entry.type);
    606 	int			  numVecs	= isMatrix ? (entry.isRowMajor ? glu::getDataTypeMatrixNumRows(entry.type) :
    607 												 glu::getDataTypeMatrixNumColumns(entry.type)) :
    608 							 1;
    609 	int		  vecSize  = scalarSize / numVecs;
    610 	bool	  isArray  = entry.size > 1;
    611 	const int compSize = sizeof(deUint32);
    612 
    613 	DE_ASSERT(scalarSize % numVecs == 0);
    614 
    615 	for (int elemNdx = 0; elemNdx < entry.size; elemNdx++)
    616 	{
    617 		deUint8* elemPtr = (deUint8*)basePtr + entry.offset + (isArray ? elemNdx * entry.arrayStride : 0);
    618 
    619 		for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
    620 		{
    621 			deUint8* vecPtr = elemPtr + (isMatrix ? vecNdx * entry.matrixStride : 0);
    622 
    623 			for (int compNdx = 0; compNdx < vecSize; compNdx++)
    624 			{
    625 				deUint8* compPtr = vecPtr + compSize * compNdx;
    626 
    627 				switch (scalarType)
    628 				{
    629 				case glu::TYPE_FLOAT:
    630 					*((float*)compPtr) = (float)rnd.getInt(-9, 9);
    631 					break;
    632 				case glu::TYPE_INT:
    633 					*((int*)compPtr) = rnd.getInt(-9, 9);
    634 					break;
    635 				case glu::TYPE_UINT:
    636 					*((deUint32*)compPtr) = (deUint32)rnd.getInt(0, 9);
    637 					break;
    638 				// \note Random bit pattern is used for true values. Spec states that all non-zero values are
    639 				//       interpreted as true but some implementations fail this.
    640 				case glu::TYPE_BOOL:
    641 					*((deUint32*)compPtr) = rnd.getBool() ? rnd.getUint32() | 1u : 0u;
    642 					break;
    643 				default:
    644 					DE_ASSERT(false);
    645 				}
    646 			}
    647 		}
    648 	}
    649 }
    650 
    651 void generateValues(const UniformLayout& layout, const std::map<int, void*>& blockPointers, deUint32 seed)
    652 {
    653 	de::Random rnd(seed);
    654 	int		   numBlocks = (int)layout.blocks.size();
    655 
    656 	for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
    657 	{
    658 		void* basePtr	= blockPointers.find(blockNdx)->second;
    659 		int   numEntries = (int)layout.blocks[blockNdx].activeUniformIndices.size();
    660 
    661 		for (int entryNdx = 0; entryNdx < numEntries; entryNdx++)
    662 		{
    663 			const UniformLayoutEntry& entry = layout.uniforms[layout.blocks[blockNdx].activeUniformIndices[entryNdx]];
    664 			generateValue(entry, basePtr, rnd);
    665 		}
    666 	}
    667 }
    668 
    669 // Shader generator.
    670 
    671 static const char* s_compareFuncs =
    672 	"mediump float compare_float    (highp float a, highp float b)  { return abs(a - b) < 0.05 ? 1.0 : 0.0; }\n"
    673 	"mediump float compare_vec2     (highp vec2 a, highp vec2 b)    { return compare_float(a.x, "
    674 	"b.x)*compare_float(a.y, b.y); }\n"
    675 	"mediump float compare_vec3     (highp vec3 a, highp vec3 b)    { return compare_float(a.x, "
    676 	"b.x)*compare_float(a.y, b.y)*compare_float(a.z, b.z); }\n"
    677 	"mediump float compare_vec4     (highp vec4 a, highp vec4 b)    { return compare_float(a.x, "
    678 	"b.x)*compare_float(a.y, b.y)*compare_float(a.z, b.z)*compare_float(a.w, b.w); }\n"
    679 	"mediump float compare_mat2     (highp mat2 a, highp mat2 b)    { return compare_vec2(a[0], "
    680 	"b[0])*compare_vec2(a[1], b[1]); }\n"
    681 	"mediump float compare_mat2x3   (highp mat2x3 a, highp mat2x3 b){ return compare_vec3(a[0], "
    682 	"b[0])*compare_vec3(a[1], b[1]); }\n"
    683 	"mediump float compare_mat2x4   (highp mat2x4 a, highp mat2x4 b){ return compare_vec4(a[0], "
    684 	"b[0])*compare_vec4(a[1], b[1]); }\n"
    685 	"mediump float compare_mat3x2   (highp mat3x2 a, highp mat3x2 b){ return compare_vec2(a[0], "
    686 	"b[0])*compare_vec2(a[1], b[1])*compare_vec2(a[2], b[2]); }\n"
    687 	"mediump float compare_mat3     (highp mat3 a, highp mat3 b)    { return compare_vec3(a[0], "
    688 	"b[0])*compare_vec3(a[1], b[1])*compare_vec3(a[2], b[2]); }\n"
    689 	"mediump float compare_mat3x4   (highp mat3x4 a, highp mat3x4 b){ return compare_vec4(a[0], "
    690 	"b[0])*compare_vec4(a[1], b[1])*compare_vec4(a[2], b[2]); }\n"
    691 	"mediump float compare_mat4x2   (highp mat4x2 a, highp mat4x2 b){ return compare_vec2(a[0], "
    692 	"b[0])*compare_vec2(a[1], b[1])*compare_vec2(a[2], b[2])*compare_vec2(a[3], b[3]); }\n"
    693 	"mediump float compare_mat4x3   (highp mat4x3 a, highp mat4x3 b){ return compare_vec3(a[0], "
    694 	"b[0])*compare_vec3(a[1], b[1])*compare_vec3(a[2], b[2])*compare_vec3(a[3], b[3]); }\n"
    695 	"mediump float compare_mat4     (highp mat4 a, highp mat4 b)    { return compare_vec4(a[0], "
    696 	"b[0])*compare_vec4(a[1], b[1])*compare_vec4(a[2], b[2])*compare_vec4(a[3], b[3]); }\n"
    697 	"mediump float compare_int      (highp int a, highp int b)      { return a == b ? 1.0 : 0.0; }\n"
    698 	"mediump float compare_ivec2    (highp ivec2 a, highp ivec2 b)  { return a == b ? 1.0 : 0.0; }\n"
    699 	"mediump float compare_ivec3    (highp ivec3 a, highp ivec3 b)  { return a == b ? 1.0 : 0.0; }\n"
    700 	"mediump float compare_ivec4    (highp ivec4 a, highp ivec4 b)  { return a == b ? 1.0 : 0.0; }\n"
    701 	"mediump float compare_uint     (highp uint a, highp uint b)    { return a == b ? 1.0 : 0.0; }\n"
    702 	"mediump float compare_uvec2    (highp uvec2 a, highp uvec2 b)  { return a == b ? 1.0 : 0.0; }\n"
    703 	"mediump float compare_uvec3    (highp uvec3 a, highp uvec3 b)  { return a == b ? 1.0 : 0.0; }\n"
    704 	"mediump float compare_uvec4    (highp uvec4 a, highp uvec4 b)  { return a == b ? 1.0 : 0.0; }\n"
    705 	"mediump float compare_bool     (bool a, bool b)                { return a == b ? 1.0 : 0.0; }\n"
    706 	"mediump float compare_bvec2    (bvec2 a, bvec2 b)              { return a == b ? 1.0 : 0.0; }\n"
    707 	"mediump float compare_bvec3    (bvec3 a, bvec3 b)              { return a == b ? 1.0 : 0.0; }\n"
    708 	"mediump float compare_bvec4    (bvec4 a, bvec4 b)              { return a == b ? 1.0 : 0.0; }\n";
    709 
    710 struct Indent
    711 {
    712 	int level;
    713 
    714 	Indent(int level_) : level(level_)
    715 	{
    716 	}
    717 };
    718 
    719 std::ostream& operator<<(std::ostream& str, const Indent& indent)
    720 {
    721 	for (int i = 0; i < indent.level; i++)
    722 		str << "\t";
    723 	return str;
    724 }
    725 
    726 void generateDeclaration(std::ostringstream& src, const VarType& type, const char* name, int indentLevel,
    727 						 deUint32 unusedHints);
    728 void generateDeclaration(std::ostringstream& src, const Uniform& uniform, int indentLevel);
    729 void generateDeclaration(std::ostringstream& src, const StructType& structType, int indentLevel);
    730 
    731 void generateLocalDeclaration(std::ostringstream& src, const StructType& structType, int indentLevel);
    732 void generateFullDeclaration(std::ostringstream& src, const StructType& structType, int indentLevel);
    733 
    734 void generateDeclaration(std::ostringstream& src, const StructType& structType, int indentLevel)
    735 {
    736 	DE_ASSERT(structType.getTypeName() != DE_NULL);
    737 	generateFullDeclaration(src, structType, indentLevel);
    738 	src << ";\n";
    739 }
    740 
    741 void generateFullDeclaration(std::ostringstream& src, const StructType& structType, int indentLevel)
    742 {
    743 	src << "struct";
    744 	if (structType.getTypeName())
    745 		src << " " << structType.getTypeName();
    746 	src << "\n" << Indent(indentLevel) << "{\n";
    747 
    748 	for (StructType::ConstIterator memberIter = structType.begin(); memberIter != structType.end(); memberIter++)
    749 	{
    750 		src << Indent(indentLevel + 1);
    751 		generateDeclaration(src, memberIter->getType(), memberIter->getName(), indentLevel + 1,
    752 							memberIter->getFlags() & UNUSED_BOTH);
    753 	}
    754 
    755 	src << Indent(indentLevel) << "}";
    756 }
    757 
    758 void generateLocalDeclaration(std::ostringstream& src, const StructType& structType, int indentLevel)
    759 {
    760 	if (structType.getTypeName() == DE_NULL)
    761 		generateFullDeclaration(src, structType, indentLevel);
    762 	else
    763 		src << structType.getTypeName();
    764 }
    765 
    766 void generateDeclaration(std::ostringstream& src, const VarType& type, const char* name, int indentLevel,
    767 						 deUint32 unusedHints)
    768 {
    769 	deUint32 flags = type.getFlags();
    770 
    771 	if ((flags & LAYOUT_MASK) != 0)
    772 		src << "layout(" << LayoutFlagsFmt(flags & LAYOUT_MASK) << ") ";
    773 
    774 	if ((flags & PRECISION_MASK) != 0)
    775 		src << PrecisionFlagsFmt(flags & PRECISION_MASK) << " ";
    776 
    777 	if (type.isBasicType())
    778 		src << glu::getDataTypeName(type.getBasicType()) << " " << name;
    779 	else if (type.isArrayType())
    780 	{
    781 		std::vector<int> arraySizes;
    782 		const VarType*   curType = &type;
    783 		while (curType->isArrayType())
    784 		{
    785 			arraySizes.push_back(curType->getArraySize());
    786 			curType = &curType->getElementType();
    787 		}
    788 
    789 		if (curType->isBasicType())
    790 		{
    791 			if ((curType->getFlags() & PRECISION_MASK) != 0)
    792 				src << PrecisionFlagsFmt(curType->getFlags() & PRECISION_MASK) << " ";
    793 			src << glu::getDataTypeName(curType->getBasicType());
    794 		}
    795 		else
    796 		{
    797 			DE_ASSERT(curType->isStructType());
    798 			generateLocalDeclaration(src, curType->getStruct(), indentLevel + 1);
    799 		}
    800 
    801 		src << " " << name;
    802 
    803 		for (std::vector<int>::const_reverse_iterator sizeIter = arraySizes.rbegin(); sizeIter != arraySizes.rend();
    804 			 sizeIter++)
    805 			src << "[" << *sizeIter << "]";
    806 	}
    807 	else
    808 	{
    809 		generateLocalDeclaration(src, type.getStruct(), indentLevel + 1);
    810 		src << " " << name;
    811 	}
    812 
    813 	src << ";";
    814 
    815 	// Print out unused hints.
    816 	if (unusedHints != 0)
    817 		src << " // unused in "
    818 			<< (unusedHints == UNUSED_BOTH ?
    819 					"both shaders" :
    820 					unusedHints == UNUSED_VERTEX ? "vertex shader" :
    821 												   unusedHints == UNUSED_FRAGMENT ? "fragment shader" : "???");
    822 
    823 	src << "\n";
    824 }
    825 
    826 void generateDeclaration(std::ostringstream& src, const Uniform& uniform, int indentLevel)
    827 {
    828 	if ((uniform.getFlags() & LAYOUT_MASK) != 0)
    829 		src << "layout(" << LayoutFlagsFmt(uniform.getFlags() & LAYOUT_MASK) << ") ";
    830 
    831 	generateDeclaration(src, uniform.getType(), uniform.getName(), indentLevel, uniform.getFlags() & UNUSED_BOTH);
    832 }
    833 
    834 void generateDeclaration(std::ostringstream& src, const UniformBlock& block)
    835 {
    836 	if ((block.getFlags() & LAYOUT_MASK) != 0)
    837 		src << "layout(" << LayoutFlagsFmt(block.getFlags() & LAYOUT_MASK) << ") ";
    838 
    839 	src << "uniform " << block.getBlockName();
    840 	src << "\n{\n";
    841 
    842 	for (UniformBlock::ConstIterator uniformIter = block.begin(); uniformIter != block.end(); uniformIter++)
    843 	{
    844 		src << Indent(1);
    845 		generateDeclaration(src, *uniformIter, 1 /* indent level */);
    846 	}
    847 
    848 	src << "}";
    849 
    850 	if (block.getInstanceName() != DE_NULL)
    851 	{
    852 		src << " " << block.getInstanceName();
    853 		if (block.isArray())
    854 			src << "[" << block.getArraySize() << "]";
    855 	}
    856 	else
    857 		DE_ASSERT(!block.isArray());
    858 
    859 	src << ";\n";
    860 }
    861 
    862 void generateValueSrc(std::ostringstream& src, const UniformLayoutEntry& entry, const void* basePtr, int elementNdx)
    863 {
    864 	glu::DataType  scalarType = glu::getDataTypeScalarType(entry.type);
    865 	int			   scalarSize = glu::getDataTypeScalarSize(entry.type);
    866 	bool		   isArray	= entry.size > 1;
    867 	const deUint8* elemPtr	= (const deUint8*)basePtr + entry.offset + (isArray ? elementNdx * entry.arrayStride : 0);
    868 	const int	  compSize   = sizeof(deUint32);
    869 
    870 	if (scalarSize > 1)
    871 		src << glu::getDataTypeName(entry.type) << "(";
    872 
    873 	if (glu::isDataTypeMatrix(entry.type))
    874 	{
    875 		int numRows = glu::getDataTypeMatrixNumRows(entry.type);
    876 		int numCols = glu::getDataTypeMatrixNumColumns(entry.type);
    877 
    878 		DE_ASSERT(scalarType == glu::TYPE_FLOAT);
    879 
    880 		// Constructed in column-wise order.
    881 		for (int colNdx = 0; colNdx < numCols; colNdx++)
    882 		{
    883 			for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
    884 			{
    885 				const deUint8* compPtr = elemPtr + (entry.isRowMajor ? rowNdx * entry.matrixStride + colNdx * compSize :
    886 																	   colNdx * entry.matrixStride + rowNdx * compSize);
    887 
    888 				if (colNdx > 0 || rowNdx > 0)
    889 					src << ", ";
    890 
    891 				src << de::floatToString(*((const float*)compPtr), 1);
    892 			}
    893 		}
    894 	}
    895 	else
    896 	{
    897 		for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
    898 		{
    899 			const deUint8* compPtr = elemPtr + scalarNdx * compSize;
    900 
    901 			if (scalarNdx > 0)
    902 				src << ", ";
    903 
    904 			switch (scalarType)
    905 			{
    906 			case glu::TYPE_FLOAT:
    907 				src << de::floatToString(*((const float*)compPtr), 1);
    908 				break;
    909 			case glu::TYPE_INT:
    910 				src << *((const int*)compPtr);
    911 				break;
    912 			case glu::TYPE_UINT:
    913 				src << *((const deUint32*)compPtr) << "u";
    914 				break;
    915 			case glu::TYPE_BOOL:
    916 				src << (*((const deUint32*)compPtr) != 0u ? "true" : "false");
    917 				break;
    918 			default:
    919 				DE_ASSERT(false);
    920 			}
    921 		}
    922 	}
    923 
    924 	if (scalarSize > 1)
    925 		src << ")";
    926 }
    927 
    928 void generateCompareSrc(std::ostringstream& src, const char* resultVar, const VarType& type, const char* srcName,
    929 						const char* apiName, const UniformLayout& layout, const void* basePtr, deUint32 unusedMask)
    930 {
    931 	if (type.isBasicType() || (type.isArrayType() && type.getElementType().isBasicType()))
    932 	{
    933 		// Basic type or array of basic types.
    934 		bool		  isArray	 = type.isArrayType();
    935 		glu::DataType elementType = isArray ? type.getElementType().getBasicType() : type.getBasicType();
    936 		const char*   typeName	= glu::getDataTypeName(elementType);
    937 		std::string   fullApiName = string(apiName) + (isArray ? "[0]" : ""); // Arrays are always postfixed with [0]
    938 		int			  uniformNdx  = layout.getUniformIndex(fullApiName.c_str());
    939 		const UniformLayoutEntry& entry = layout.uniforms[uniformNdx];
    940 
    941 		if (isArray)
    942 		{
    943 			for (int elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++)
    944 			{
    945 				src << "\tresult *= compare_" << typeName << "(" << srcName << "[" << elemNdx << "], ";
    946 				generateValueSrc(src, entry, basePtr, elemNdx);
    947 				src << ");\n";
    948 			}
    949 		}
    950 		else
    951 		{
    952 			src << "\tresult *= compare_" << typeName << "(" << srcName << ", ";
    953 			generateValueSrc(src, entry, basePtr, 0);
    954 			src << ");\n";
    955 		}
    956 	}
    957 	else if (type.isArrayType())
    958 	{
    959 		const VarType& elementType = type.getElementType();
    960 		DE_ASSERT(!elementType.isArrayType());
    961 
    962 		for (int elementNdx = 0; elementNdx < type.getArraySize(); elementNdx++)
    963 		{
    964 			std::string op = string("[") + de::toString(elementNdx) + "]";
    965 			generateCompareSrc(src, resultVar, elementType, (string(srcName) + op).c_str(),
    966 							   (string(apiName) + op).c_str(), layout, basePtr, unusedMask);
    967 		}
    968 	}
    969 	else
    970 	{
    971 		DE_ASSERT(type.isStructType());
    972 
    973 		for (StructType::ConstIterator memberIter = type.getStruct().begin(); memberIter != type.getStruct().end();
    974 			 memberIter++)
    975 		{
    976 			if (memberIter->getFlags() & unusedMask)
    977 				continue; // Skip member.
    978 
    979 			string op = string(".") + memberIter->getName();
    980 			generateCompareSrc(src, resultVar, memberIter->getType(), (string(srcName) + op).c_str(),
    981 							   (string(apiName) + op).c_str(), layout, basePtr, unusedMask);
    982 		}
    983 	}
    984 }
    985 
    986 void generateCompareSrc(std::ostringstream& src, const char* resultVar, const ShaderInterface& interface,
    987 						const UniformLayout& layout, const std::map<int, void*>& blockPointers, bool isVertex)
    988 {
    989 	deUint32 unusedMask = isVertex ? UNUSED_VERTEX : UNUSED_FRAGMENT;
    990 
    991 	for (int blockNdx = 0; blockNdx < interface.getNumUniformBlocks(); blockNdx++)
    992 	{
    993 		const UniformBlock& block = interface.getUniformBlock(blockNdx);
    994 
    995 		if ((block.getFlags() & (isVertex ? DECLARE_VERTEX : DECLARE_FRAGMENT)) == 0)
    996 			continue; // Skip.
    997 
    998 		bool		hasInstanceName = block.getInstanceName() != DE_NULL;
    999 		bool		isArray			= block.isArray();
   1000 		int			numInstances	= isArray ? block.getArraySize() : 1;
   1001 		std::string apiPrefix		= hasInstanceName ? string(block.getBlockName()) + "." : string("");
   1002 
   1003 		DE_ASSERT(!isArray || hasInstanceName);
   1004 
   1005 		for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
   1006 		{
   1007 			std::string instancePostfix   = isArray ? string("[") + de::toString(instanceNdx) + "]" : string("");
   1008 			std::string blockInstanceName = block.getBlockName() + instancePostfix;
   1009 			std::string srcPrefix =
   1010 				hasInstanceName ? string(block.getInstanceName()) + instancePostfix + "." : string("");
   1011 			int   activeBlockNdx = layout.getBlockIndex(blockInstanceName.c_str());
   1012 			void* basePtr		 = blockPointers.find(activeBlockNdx)->second;
   1013 
   1014 			for (UniformBlock::ConstIterator uniformIter = block.begin(); uniformIter != block.end(); uniformIter++)
   1015 			{
   1016 				const Uniform& uniform = *uniformIter;
   1017 
   1018 				if (uniform.getFlags() & unusedMask)
   1019 					continue; // Don't read from that uniform.
   1020 
   1021 				generateCompareSrc(src, resultVar, uniform.getType(), (srcPrefix + uniform.getName()).c_str(),
   1022 								   (apiPrefix + uniform.getName()).c_str(), layout, basePtr, unusedMask);
   1023 			}
   1024 		}
   1025 	}
   1026 }
   1027 
   1028 void generateVertexShader(std::ostringstream& src, glu::GLSLVersion glslVersion, const ShaderInterface& interface,
   1029 						  const UniformLayout& layout, const std::map<int, void*>& blockPointers)
   1030 {
   1031 	DE_ASSERT(glslVersion == glu::GLSL_VERSION_300_ES || glslVersion == glu::GLSL_VERSION_310_ES ||
   1032 			  de::inRange<int>(glslVersion, glu::GLSL_VERSION_330, glu::GLSL_VERSION_430));
   1033 
   1034 	src << glu::getGLSLVersionDeclaration(glslVersion) << "\n";
   1035 	src << "in highp vec4 a_position;\n";
   1036 	src << "out mediump float v_vtxResult;\n";
   1037 	src << "\n";
   1038 
   1039 	std::vector<const StructType*> namedStructs;
   1040 	interface.getNamedStructs(namedStructs);
   1041 	for (std::vector<const StructType*>::const_iterator structIter = namedStructs.begin();
   1042 		 structIter != namedStructs.end(); structIter++)
   1043 		generateDeclaration(src, **structIter, 0);
   1044 
   1045 	for (int blockNdx = 0; blockNdx < interface.getNumUniformBlocks(); blockNdx++)
   1046 	{
   1047 		const UniformBlock& block = interface.getUniformBlock(blockNdx);
   1048 		if (block.getFlags() & DECLARE_VERTEX)
   1049 			generateDeclaration(src, block);
   1050 	}
   1051 
   1052 	// Comparison utilities.
   1053 	src << "\n" << s_compareFuncs;
   1054 
   1055 	src << "\n"
   1056 		   "void main (void)\n"
   1057 		   "{\n"
   1058 		   "    gl_Position = a_position;\n"
   1059 		   "    mediump float result = 1.0;\n";
   1060 
   1061 	// Value compare.
   1062 	generateCompareSrc(src, "result", interface, layout, blockPointers, true);
   1063 
   1064 	src << "    v_vtxResult = result;\n"
   1065 		   "}\n";
   1066 }
   1067 
   1068 void generateFragmentShader(std::ostringstream& src, glu::GLSLVersion glslVersion, const ShaderInterface& interface,
   1069 							const UniformLayout& layout, const std::map<int, void*>& blockPointers)
   1070 {
   1071 	DE_ASSERT(glslVersion == glu::GLSL_VERSION_300_ES || glslVersion == glu::GLSL_VERSION_310_ES ||
   1072 			  de::inRange<int>(glslVersion, glu::GLSL_VERSION_330, glu::GLSL_VERSION_430));
   1073 
   1074 	src << glu::getGLSLVersionDeclaration(glslVersion) << "\n";
   1075 	src << "in mediump float v_vtxResult;\n";
   1076 	src << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
   1077 	src << "\n";
   1078 
   1079 	std::vector<const StructType*> namedStructs;
   1080 	interface.getNamedStructs(namedStructs);
   1081 	for (std::vector<const StructType*>::const_iterator structIter = namedStructs.begin();
   1082 		 structIter != namedStructs.end(); structIter++)
   1083 		generateDeclaration(src, **structIter, 0);
   1084 
   1085 	for (int blockNdx = 0; blockNdx < interface.getNumUniformBlocks(); blockNdx++)
   1086 	{
   1087 		const UniformBlock& block = interface.getUniformBlock(blockNdx);
   1088 		if (block.getFlags() & DECLARE_FRAGMENT)
   1089 			generateDeclaration(src, block);
   1090 	}
   1091 
   1092 	// Comparison utilities.
   1093 	src << "\n" << s_compareFuncs;
   1094 
   1095 	src << "\n"
   1096 		   "void main (void)\n"
   1097 		   "{\n"
   1098 		   "    mediump float result = 1.0;\n";
   1099 
   1100 	// Value compare.
   1101 	generateCompareSrc(src, "result", interface, layout, blockPointers, false);
   1102 
   1103 	src << "    dEQP_FragColor = vec4(1.0, v_vtxResult, result, 1.0);\n"
   1104 		   "}\n";
   1105 }
   1106 
   1107 void getGLUniformLayout(const glw::Functions& gl, UniformLayout& layout, deUint32 program)
   1108 {
   1109 	int numActiveUniforms = 0;
   1110 	int numActiveBlocks   = 0;
   1111 
   1112 	gl.getProgramiv(program, GL_ACTIVE_UNIFORMS, &numActiveUniforms);
   1113 	gl.getProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &numActiveBlocks);
   1114 
   1115 	GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to get number of uniforms and uniform blocks");
   1116 
   1117 	// Block entries.
   1118 	layout.blocks.resize(numActiveBlocks);
   1119 	for (int blockNdx = 0; blockNdx < numActiveBlocks; blockNdx++)
   1120 	{
   1121 		BlockLayoutEntry& entry = layout.blocks[blockNdx];
   1122 		int				  size;
   1123 		int				  nameLen;
   1124 		int				  numBlockUniforms;
   1125 
   1126 		gl.getActiveUniformBlockiv(program, (deUint32)blockNdx, GL_UNIFORM_BLOCK_DATA_SIZE, &size);
   1127 		gl.getActiveUniformBlockiv(program, (deUint32)blockNdx, GL_UNIFORM_BLOCK_NAME_LENGTH, &nameLen);
   1128 		gl.getActiveUniformBlockiv(program, (deUint32)blockNdx, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &numBlockUniforms);
   1129 
   1130 		GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform block query failed");
   1131 
   1132 		// \note Some implementations incorrectly return 0 as name length even though the length should include null terminator.
   1133 		std::vector<char> nameBuf(nameLen > 0 ? nameLen : 1);
   1134 		gl.getActiveUniformBlockName(program, (deUint32)blockNdx, (glw::GLsizei)nameBuf.size(), DE_NULL, &nameBuf[0]);
   1135 
   1136 		entry.name = std::string(&nameBuf[0]);
   1137 		entry.size = size;
   1138 		entry.activeUniformIndices.resize(numBlockUniforms);
   1139 
   1140 		if (numBlockUniforms > 0)
   1141 			gl.getActiveUniformBlockiv(program, (deUint32)blockNdx, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES,
   1142 									   &entry.activeUniformIndices[0]);
   1143 
   1144 		GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform block query failed");
   1145 	}
   1146 
   1147 	if (numActiveUniforms > 0)
   1148 	{
   1149 		// Uniform entries.
   1150 		std::vector<deUint32> uniformIndices(numActiveUniforms);
   1151 		for (int i			  = 0; i < numActiveUniforms; i++)
   1152 			uniformIndices[i] = (deUint32)i;
   1153 
   1154 		std::vector<int> types(numActiveUniforms);
   1155 		std::vector<int> sizes(numActiveUniforms);
   1156 		std::vector<int> nameLengths(numActiveUniforms);
   1157 		std::vector<int> blockIndices(numActiveUniforms);
   1158 		std::vector<int> offsets(numActiveUniforms);
   1159 		std::vector<int> arrayStrides(numActiveUniforms);
   1160 		std::vector<int> matrixStrides(numActiveUniforms);
   1161 		std::vector<int> rowMajorFlags(numActiveUniforms);
   1162 
   1163 		// Execute queries.
   1164 		gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0], GL_UNIFORM_TYPE,
   1165 							   &types[0]);
   1166 		gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0], GL_UNIFORM_SIZE,
   1167 							   &sizes[0]);
   1168 		gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0], GL_UNIFORM_NAME_LENGTH,
   1169 							   &nameLengths[0]);
   1170 		gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0], GL_UNIFORM_BLOCK_INDEX,
   1171 							   &blockIndices[0]);
   1172 		gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0], GL_UNIFORM_OFFSET,
   1173 							   &offsets[0]);
   1174 		gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0],
   1175 							   GL_UNIFORM_ARRAY_STRIDE, &arrayStrides[0]);
   1176 		gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0],
   1177 							   GL_UNIFORM_MATRIX_STRIDE, &matrixStrides[0]);
   1178 		gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0],
   1179 							   GL_UNIFORM_IS_ROW_MAJOR, &rowMajorFlags[0]);
   1180 
   1181 		GLU_EXPECT_NO_ERROR(gl.getError(), "Active uniform query failed");
   1182 
   1183 		// Translate to LayoutEntries
   1184 		layout.uniforms.resize(numActiveUniforms);
   1185 		for (int uniformNdx = 0; uniformNdx < numActiveUniforms; uniformNdx++)
   1186 		{
   1187 			UniformLayoutEntry& entry = layout.uniforms[uniformNdx];
   1188 			std::vector<char>   nameBuf(nameLengths[uniformNdx]);
   1189 			glw::GLsizei		nameLen = 0;
   1190 			int					size	= 0;
   1191 			deUint32			type	= GL_NONE;
   1192 
   1193 			gl.getActiveUniform(program, (deUint32)uniformNdx, (glw::GLsizei)nameBuf.size(), &nameLen, &size, &type,
   1194 								&nameBuf[0]);
   1195 
   1196 			GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform name query failed");
   1197 
   1198 			// \note glGetActiveUniform() returns length without \0 and glGetActiveUniformsiv() with \0
   1199 			if (nameLen + 1 != nameLengths[uniformNdx] || size != sizes[uniformNdx] ||
   1200 				type != (deUint32)types[uniformNdx])
   1201 				TCU_FAIL("Values returned by glGetActiveUniform() don't match with values queried with "
   1202 						 "glGetActiveUniformsiv().");
   1203 
   1204 			entry.name		   = std::string(&nameBuf[0]);
   1205 			entry.type		   = glu::getDataTypeFromGLType(types[uniformNdx]);
   1206 			entry.size		   = sizes[uniformNdx];
   1207 			entry.blockNdx	 = blockIndices[uniformNdx];
   1208 			entry.offset	   = offsets[uniformNdx];
   1209 			entry.arrayStride  = arrayStrides[uniformNdx];
   1210 			entry.matrixStride = matrixStrides[uniformNdx];
   1211 			entry.isRowMajor   = rowMajorFlags[uniformNdx] != GL_FALSE;
   1212 		}
   1213 	}
   1214 }
   1215 
   1216 void copyUniformData(const UniformLayoutEntry& dstEntry, void* dstBlockPtr, const UniformLayoutEntry& srcEntry,
   1217 					 const void* srcBlockPtr)
   1218 {
   1219 	deUint8*	   dstBasePtr = (deUint8*)dstBlockPtr + dstEntry.offset;
   1220 	const deUint8* srcBasePtr = (const deUint8*)srcBlockPtr + srcEntry.offset;
   1221 
   1222 	DE_ASSERT(dstEntry.size <= srcEntry.size);
   1223 	DE_ASSERT(dstEntry.type == srcEntry.type);
   1224 
   1225 	int		  scalarSize = glu::getDataTypeScalarSize(dstEntry.type);
   1226 	bool	  isMatrix   = glu::isDataTypeMatrix(dstEntry.type);
   1227 	const int compSize   = sizeof(deUint32);
   1228 
   1229 	for (int elementNdx = 0; elementNdx < dstEntry.size; elementNdx++)
   1230 	{
   1231 		deUint8*	   dstElemPtr = dstBasePtr + elementNdx * dstEntry.arrayStride;
   1232 		const deUint8* srcElemPtr = srcBasePtr + elementNdx * srcEntry.arrayStride;
   1233 
   1234 		if (isMatrix)
   1235 		{
   1236 			int numRows = glu::getDataTypeMatrixNumRows(dstEntry.type);
   1237 			int numCols = glu::getDataTypeMatrixNumColumns(dstEntry.type);
   1238 
   1239 			for (int colNdx = 0; colNdx < numCols; colNdx++)
   1240 			{
   1241 				for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
   1242 				{
   1243 					deUint8* dstCompPtr =
   1244 						dstElemPtr + (dstEntry.isRowMajor ? rowNdx * dstEntry.matrixStride + colNdx * compSize :
   1245 															colNdx * dstEntry.matrixStride + rowNdx * compSize);
   1246 					const deUint8* srcCompPtr =
   1247 						srcElemPtr + (srcEntry.isRowMajor ? rowNdx * srcEntry.matrixStride + colNdx * compSize :
   1248 															colNdx * srcEntry.matrixStride + rowNdx * compSize);
   1249 					deMemcpy(dstCompPtr, srcCompPtr, compSize);
   1250 				}
   1251 			}
   1252 		}
   1253 		else
   1254 			deMemcpy(dstElemPtr, srcElemPtr, scalarSize * compSize);
   1255 	}
   1256 }
   1257 
   1258 void copyUniformData(const UniformLayout& dstLayout, const std::map<int, void*>& dstBlockPointers,
   1259 					 const UniformLayout& srcLayout, const std::map<int, void*>& srcBlockPointers)
   1260 {
   1261 	// \note Src layout is used as reference in case of activeUniforms happens to be incorrect in dstLayout blocks.
   1262 	int numBlocks = (int)srcLayout.blocks.size();
   1263 
   1264 	for (int srcBlockNdx = 0; srcBlockNdx < numBlocks; srcBlockNdx++)
   1265 	{
   1266 		const BlockLayoutEntry& srcBlock	= srcLayout.blocks[srcBlockNdx];
   1267 		const void*				srcBlockPtr = srcBlockPointers.find(srcBlockNdx)->second;
   1268 		int						dstBlockNdx = dstLayout.getBlockIndex(srcBlock.name.c_str());
   1269 		void*					dstBlockPtr = dstBlockNdx >= 0 ? dstBlockPointers.find(dstBlockNdx)->second : DE_NULL;
   1270 
   1271 		if (dstBlockNdx < 0)
   1272 			continue;
   1273 
   1274 		for (vector<int>::const_iterator srcUniformNdxIter = srcBlock.activeUniformIndices.begin();
   1275 			 srcUniformNdxIter != srcBlock.activeUniformIndices.end(); srcUniformNdxIter++)
   1276 		{
   1277 			const UniformLayoutEntry& srcEntry		= srcLayout.uniforms[*srcUniformNdxIter];
   1278 			int						  dstUniformNdx = dstLayout.getUniformIndex(srcEntry.name.c_str());
   1279 
   1280 			if (dstUniformNdx < 0)
   1281 				continue;
   1282 
   1283 			copyUniformData(dstLayout.uniforms[dstUniformNdx], dstBlockPtr, srcEntry, srcBlockPtr);
   1284 		}
   1285 	}
   1286 }
   1287 
   1288 } // anonymous (utilities)
   1289 
   1290 class UniformBufferManager
   1291 {
   1292 public:
   1293 	UniformBufferManager(const glu::RenderContext& renderCtx);
   1294 	~UniformBufferManager(void);
   1295 
   1296 	deUint32 allocBuffer(void);
   1297 
   1298 private:
   1299 	UniformBufferManager(const UniformBufferManager& other);
   1300 	UniformBufferManager& operator=(const UniformBufferManager& other);
   1301 
   1302 	const glu::RenderContext& m_renderCtx;
   1303 	std::vector<deUint32>	 m_buffers;
   1304 };
   1305 
   1306 UniformBufferManager::UniformBufferManager(const glu::RenderContext& renderCtx) : m_renderCtx(renderCtx)
   1307 {
   1308 }
   1309 
   1310 UniformBufferManager::~UniformBufferManager(void)
   1311 {
   1312 	if (!m_buffers.empty())
   1313 		m_renderCtx.getFunctions().deleteBuffers((glw::GLsizei)m_buffers.size(), &m_buffers[0]);
   1314 }
   1315 
   1316 deUint32 UniformBufferManager::allocBuffer(void)
   1317 {
   1318 	deUint32 buf = 0;
   1319 
   1320 	m_buffers.reserve(m_buffers.size() + 1);
   1321 	m_renderCtx.getFunctions().genBuffers(1, &buf);
   1322 	GLU_EXPECT_NO_ERROR(m_renderCtx.getFunctions().getError(), "Failed to allocate uniform buffer");
   1323 	m_buffers.push_back(buf);
   1324 
   1325 	return buf;
   1326 }
   1327 
   1328 } // ub
   1329 
   1330 using namespace ub;
   1331 
   1332 // UniformBlockCase.
   1333 
   1334 UniformBlockCase::UniformBlockCase(Context& context, const char* name, const char* description,
   1335 								   glu::GLSLVersion glslVersion, BufferMode bufferMode)
   1336 	: TestCase(context, name, description), m_glslVersion(glslVersion), m_bufferMode(bufferMode)
   1337 {
   1338 	// \todo [2013-05-25 pyry] Support other versions as well.
   1339 	DE_ASSERT(glslVersion == glu::GLSL_VERSION_300_ES || glslVersion == glu::GLSL_VERSION_330);
   1340 }
   1341 
   1342 UniformBlockCase::~UniformBlockCase(void)
   1343 {
   1344 }
   1345 
   1346 UniformBlockCase::IterateResult UniformBlockCase::iterate(void)
   1347 {
   1348 	TestLog&			  log = m_testCtx.getLog();
   1349 	const glw::Functions& gl  = m_context.getRenderContext().getFunctions();
   1350 	UniformLayout		  refLayout; //!< std140 layout.
   1351 	vector<deUint8>		  data;		 //!< Data.
   1352 	map<int, void*> blockPointers;   //!< Reference block pointers.
   1353 
   1354 	// Initialize result to pass.
   1355 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
   1356 
   1357 	// Compute reference layout.
   1358 	computeStd140Layout(refLayout, m_interface);
   1359 
   1360 	// Assign storage for reference values.
   1361 	{
   1362 		int totalSize = 0;
   1363 		for (vector<BlockLayoutEntry>::const_iterator blockIter = refLayout.blocks.begin();
   1364 			 blockIter != refLayout.blocks.end(); blockIter++)
   1365 			totalSize += blockIter->size;
   1366 		data.resize(totalSize);
   1367 
   1368 		// Pointers for each block.
   1369 		int curOffset = 0;
   1370 		for (int blockNdx = 0; blockNdx < (int)refLayout.blocks.size(); blockNdx++)
   1371 		{
   1372 			blockPointers[blockNdx] = &data[0] + curOffset;
   1373 			curOffset += refLayout.blocks[blockNdx].size;
   1374 		}
   1375 	}
   1376 
   1377 	// Generate values.
   1378 	generateValues(refLayout, blockPointers, 1 /* seed */);
   1379 
   1380 	// Generate shaders and build program.
   1381 	std::ostringstream vtxSrc;
   1382 	std::ostringstream fragSrc;
   1383 
   1384 	generateVertexShader(vtxSrc, m_glslVersion, m_interface, refLayout, blockPointers);
   1385 	generateFragmentShader(fragSrc, m_glslVersion, m_interface, refLayout, blockPointers);
   1386 
   1387 	glu::ShaderProgram program(m_context.getRenderContext(),
   1388 							   glu::makeVtxFragSources(vtxSrc.str().c_str(), fragSrc.str().c_str()));
   1389 	log << program;
   1390 
   1391 	if (!program.isOk())
   1392 	{
   1393 		// Compile failed.
   1394 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compile failed");
   1395 		return STOP;
   1396 	}
   1397 
   1398 	// Query layout from GL.
   1399 	UniformLayout glLayout;
   1400 	getGLUniformLayout(gl, glLayout, program.getProgram());
   1401 
   1402 	// Print layout to log.
   1403 	log << TestLog::Section("ActiveUniformBlocks", "Active Uniform Blocks");
   1404 	for (int blockNdx = 0; blockNdx < (int)glLayout.blocks.size(); blockNdx++)
   1405 		log << TestLog::Message << blockNdx << ": " << glLayout.blocks[blockNdx] << TestLog::EndMessage;
   1406 	log << TestLog::EndSection;
   1407 
   1408 	log << TestLog::Section("ActiveUniforms", "Active Uniforms");
   1409 	for (int uniformNdx = 0; uniformNdx < (int)glLayout.uniforms.size(); uniformNdx++)
   1410 		log << TestLog::Message << uniformNdx << ": " << glLayout.uniforms[uniformNdx] << TestLog::EndMessage;
   1411 	log << TestLog::EndSection;
   1412 
   1413 	// Check that we can even try rendering with given layout.
   1414 	if (!checkLayoutIndices(glLayout) || !checkLayoutBounds(glLayout) || !compareTypes(refLayout, glLayout))
   1415 	{
   1416 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid layout");
   1417 		return STOP; // It is not safe to use the given layout.
   1418 	}
   1419 
   1420 	// Verify all std140 blocks.
   1421 	if (!compareStd140Blocks(refLayout, glLayout))
   1422 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid std140 layout");
   1423 
   1424 	// Verify all shared blocks - all uniforms should be active, and certain properties match.
   1425 	if (!compareSharedBlocks(refLayout, glLayout))
   1426 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid shared layout");
   1427 
   1428 	// Check consistency with index queries
   1429 	if (!checkIndexQueries(program.getProgram(), glLayout))
   1430 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Inconsintent block index query results");
   1431 
   1432 	// Use program.
   1433 	gl.useProgram(program.getProgram());
   1434 
   1435 	// Assign binding points to all active uniform blocks.
   1436 	for (int blockNdx = 0; blockNdx < (int)glLayout.blocks.size(); blockNdx++)
   1437 	{
   1438 		deUint32 binding = (deUint32)blockNdx; // \todo [2012-01-25 pyry] Randomize order?
   1439 		gl.uniformBlockBinding(program.getProgram(), (deUint32)blockNdx, binding);
   1440 	}
   1441 
   1442 	GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set uniform block bindings");
   1443 
   1444 	// Allocate buffers, write data and bind to targets.
   1445 	UniformBufferManager bufferManager(m_context.getRenderContext());
   1446 	if (m_bufferMode == BUFFERMODE_PER_BLOCK)
   1447 	{
   1448 		int						 numBlocks = (int)glLayout.blocks.size();
   1449 		vector<vector<deUint8> > glData(numBlocks);
   1450 		map<int, void*> glBlockPointers;
   1451 
   1452 		for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
   1453 		{
   1454 			glData[blockNdx].resize(glLayout.blocks[blockNdx].size);
   1455 			glBlockPointers[blockNdx] = &glData[blockNdx][0];
   1456 		}
   1457 
   1458 		copyUniformData(glLayout, glBlockPointers, refLayout, blockPointers);
   1459 
   1460 		for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
   1461 		{
   1462 			deUint32 buffer  = bufferManager.allocBuffer();
   1463 			deUint32 binding = (deUint32)blockNdx;
   1464 
   1465 			gl.bindBuffer(GL_UNIFORM_BUFFER, buffer);
   1466 			gl.bufferData(GL_UNIFORM_BUFFER, (glw::GLsizeiptr)glData[blockNdx].size(), &glData[blockNdx][0],
   1467 						  GL_STATIC_DRAW);
   1468 			GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to upload uniform buffer data");
   1469 
   1470 			gl.bindBufferBase(GL_UNIFORM_BUFFER, binding, buffer);
   1471 			GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase(GL_UNIFORM_BUFFER) failed");
   1472 		}
   1473 	}
   1474 	else
   1475 	{
   1476 		DE_ASSERT(m_bufferMode == BUFFERMODE_SINGLE);
   1477 
   1478 		int totalSize		 = 0;
   1479 		int curOffset		 = 0;
   1480 		int numBlocks		 = (int)glLayout.blocks.size();
   1481 		int bindingAlignment = m_context.getContextInfo().getInt(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT);
   1482 		map<int, int> glBlockOffsets;
   1483 
   1484 		// Compute total size and offsets.
   1485 		curOffset = 0;
   1486 		for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
   1487 		{
   1488 			if (bindingAlignment > 0)
   1489 				curOffset			 = deRoundUp32(curOffset, bindingAlignment);
   1490 			glBlockOffsets[blockNdx] = curOffset;
   1491 			curOffset += glLayout.blocks[blockNdx].size;
   1492 		}
   1493 		totalSize = curOffset;
   1494 
   1495 		// Assign block pointers.
   1496 		vector<deUint8> glData(totalSize);
   1497 		map<int, void*> glBlockPointers;
   1498 
   1499 		for (int blockNdx			  = 0; blockNdx < numBlocks; blockNdx++)
   1500 			glBlockPointers[blockNdx] = &glData[glBlockOffsets[blockNdx]];
   1501 
   1502 		// Copy to gl format.
   1503 		copyUniformData(glLayout, glBlockPointers, refLayout, blockPointers);
   1504 
   1505 		// Allocate buffer and upload data.
   1506 		deUint32 buffer = bufferManager.allocBuffer();
   1507 		gl.bindBuffer(GL_UNIFORM_BUFFER, buffer);
   1508 		if (!glData.empty())
   1509 			gl.bufferData(GL_UNIFORM_BUFFER, (glw::GLsizeiptr)glData.size(), &glData[0], GL_STATIC_DRAW);
   1510 
   1511 		GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to upload uniform buffer data");
   1512 
   1513 		// Bind ranges to binding points.
   1514 		curOffset = 0;
   1515 		for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
   1516 		{
   1517 			deUint32 binding = (deUint32)blockNdx;
   1518 			gl.bindBufferRange(GL_UNIFORM_BUFFER, binding, buffer, (glw::GLintptr)glBlockOffsets[blockNdx],
   1519 							   (glw::GLsizeiptr)glLayout.blocks[blockNdx].size);
   1520 			GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferRange(GL_UNIFORM_BUFFER) failed");
   1521 			curOffset += glLayout.blocks[blockNdx].size;
   1522 		}
   1523 	}
   1524 
   1525 	bool renderOk = render(program);
   1526 	if (!renderOk)
   1527 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image compare failed");
   1528 
   1529 	return STOP;
   1530 }
   1531 
   1532 bool UniformBlockCase::compareStd140Blocks(const UniformLayout& refLayout, const UniformLayout& cmpLayout) const
   1533 {
   1534 	TestLog& log	   = m_testCtx.getLog();
   1535 	bool	 isOk	  = true;
   1536 	int		 numBlocks = m_interface.getNumUniformBlocks();
   1537 
   1538 	for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
   1539 	{
   1540 		const UniformBlock& block		 = m_interface.getUniformBlock(blockNdx);
   1541 		bool				isArray		 = block.isArray();
   1542 		std::string			instanceName = string(block.getBlockName()) + (isArray ? "[0]" : "");
   1543 		int					refBlockNdx  = refLayout.getBlockIndex(instanceName.c_str());
   1544 		int					cmpBlockNdx  = cmpLayout.getBlockIndex(instanceName.c_str());
   1545 		bool				isUsed		 = (block.getFlags() & (DECLARE_VERTEX | DECLARE_FRAGMENT)) != 0;
   1546 
   1547 		if ((block.getFlags() & LAYOUT_STD140) == 0)
   1548 			continue; // Not std140 layout.
   1549 
   1550 		DE_ASSERT(refBlockNdx >= 0);
   1551 
   1552 		if (cmpBlockNdx < 0)
   1553 		{
   1554 			// Not found, should it?
   1555 			if (isUsed)
   1556 			{
   1557 				log << TestLog::Message << "Error: Uniform block '" << instanceName << "' not found"
   1558 					<< TestLog::EndMessage;
   1559 				isOk = false;
   1560 			}
   1561 
   1562 			continue; // Skip block.
   1563 		}
   1564 
   1565 		const BlockLayoutEntry& refBlockLayout = refLayout.blocks[refBlockNdx];
   1566 		const BlockLayoutEntry& cmpBlockLayout = cmpLayout.blocks[cmpBlockNdx];
   1567 
   1568 		// \todo [2012-01-24 pyry] Verify that activeUniformIndices is correct.
   1569 		// \todo [2012-01-24 pyry] Verify all instances.
   1570 		if (refBlockLayout.activeUniformIndices.size() != cmpBlockLayout.activeUniformIndices.size())
   1571 		{
   1572 			log << TestLog::Message << "Error: Number of active uniforms differ in block '" << instanceName
   1573 				<< "' (expected " << refBlockLayout.activeUniformIndices.size() << ", got "
   1574 				<< cmpBlockLayout.activeUniformIndices.size() << ")" << TestLog::EndMessage;
   1575 			isOk = false;
   1576 		}
   1577 
   1578 		for (vector<int>::const_iterator ndxIter = refBlockLayout.activeUniformIndices.begin();
   1579 			 ndxIter != refBlockLayout.activeUniformIndices.end(); ndxIter++)
   1580 		{
   1581 			const UniformLayoutEntry& refEntry	= refLayout.uniforms[*ndxIter];
   1582 			int						  cmpEntryNdx = cmpLayout.getUniformIndex(refEntry.name.c_str());
   1583 
   1584 			if (cmpEntryNdx < 0)
   1585 			{
   1586 				log << TestLog::Message << "Error: Uniform '" << refEntry.name << "' not found" << TestLog::EndMessage;
   1587 				isOk = false;
   1588 				continue;
   1589 			}
   1590 
   1591 			const UniformLayoutEntry& cmpEntry = cmpLayout.uniforms[cmpEntryNdx];
   1592 
   1593 			if (refEntry.type != cmpEntry.type || refEntry.size != cmpEntry.size ||
   1594 				refEntry.offset != cmpEntry.offset || refEntry.arrayStride != cmpEntry.arrayStride ||
   1595 				refEntry.matrixStride != cmpEntry.matrixStride || refEntry.isRowMajor != cmpEntry.isRowMajor)
   1596 			{
   1597 				log << TestLog::Message << "Error: Layout mismatch in '" << refEntry.name << "':\n"
   1598 					<< "  expected: type = " << glu::getDataTypeName(refEntry.type) << ", size = " << refEntry.size
   1599 					<< ", offset = " << refEntry.offset << ", array stride = " << refEntry.arrayStride
   1600 					<< ", matrix stride = " << refEntry.matrixStride
   1601 					<< ", row major = " << (refEntry.isRowMajor ? "true" : "false") << "\n"
   1602 					<< "  got: type = " << glu::getDataTypeName(cmpEntry.type) << ", size = " << cmpEntry.size
   1603 					<< ", offset = " << cmpEntry.offset << ", array stride = " << cmpEntry.arrayStride
   1604 					<< ", matrix stride = " << cmpEntry.matrixStride
   1605 					<< ", row major = " << (cmpEntry.isRowMajor ? "true" : "false") << TestLog::EndMessage;
   1606 				isOk = false;
   1607 			}
   1608 		}
   1609 	}
   1610 
   1611 	return isOk;
   1612 }
   1613 
   1614 bool UniformBlockCase::compareSharedBlocks(const UniformLayout& refLayout, const UniformLayout& cmpLayout) const
   1615 {
   1616 	TestLog& log	   = m_testCtx.getLog();
   1617 	bool	 isOk	  = true;
   1618 	int		 numBlocks = m_interface.getNumUniformBlocks();
   1619 
   1620 	for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
   1621 	{
   1622 		const UniformBlock& block		 = m_interface.getUniformBlock(blockNdx);
   1623 		bool				isArray		 = block.isArray();
   1624 		std::string			instanceName = string(block.getBlockName()) + (isArray ? "[0]" : "");
   1625 		int					refBlockNdx  = refLayout.getBlockIndex(instanceName.c_str());
   1626 		int					cmpBlockNdx  = cmpLayout.getBlockIndex(instanceName.c_str());
   1627 		bool				isUsed		 = (block.getFlags() & (DECLARE_VERTEX | DECLARE_FRAGMENT)) != 0;
   1628 
   1629 		if ((block.getFlags() & LAYOUT_SHARED) == 0)
   1630 			continue; // Not shared layout.
   1631 
   1632 		DE_ASSERT(refBlockNdx >= 0);
   1633 
   1634 		if (cmpBlockNdx < 0)
   1635 		{
   1636 			// Not found, should it?
   1637 			if (isUsed)
   1638 			{
   1639 				log << TestLog::Message << "Error: Uniform block '" << instanceName << "' not found"
   1640 					<< TestLog::EndMessage;
   1641 				isOk = false;
   1642 			}
   1643 
   1644 			continue; // Skip block.
   1645 		}
   1646 
   1647 		const BlockLayoutEntry& refBlockLayout = refLayout.blocks[refBlockNdx];
   1648 		const BlockLayoutEntry& cmpBlockLayout = cmpLayout.blocks[cmpBlockNdx];
   1649 
   1650 		if (refBlockLayout.activeUniformIndices.size() != cmpBlockLayout.activeUniformIndices.size())
   1651 		{
   1652 			log << TestLog::Message << "Error: Number of active uniforms differ in block '" << instanceName
   1653 				<< "' (expected " << refBlockLayout.activeUniformIndices.size() << ", got "
   1654 				<< cmpBlockLayout.activeUniformIndices.size() << ")" << TestLog::EndMessage;
   1655 			isOk = false;
   1656 		}
   1657 
   1658 		for (vector<int>::const_iterator ndxIter = refBlockLayout.activeUniformIndices.begin();
   1659 			 ndxIter != refBlockLayout.activeUniformIndices.end(); ndxIter++)
   1660 		{
   1661 			const UniformLayoutEntry& refEntry	= refLayout.uniforms[*ndxIter];
   1662 			int						  cmpEntryNdx = cmpLayout.getUniformIndex(refEntry.name.c_str());
   1663 
   1664 			if (cmpEntryNdx < 0)
   1665 			{
   1666 				log << TestLog::Message << "Error: Uniform '" << refEntry.name << "' not found" << TestLog::EndMessage;
   1667 				isOk = false;
   1668 				continue;
   1669 			}
   1670 
   1671 			const UniformLayoutEntry& cmpEntry = cmpLayout.uniforms[cmpEntryNdx];
   1672 
   1673 			if (refEntry.type != cmpEntry.type || refEntry.size != cmpEntry.size ||
   1674 				refEntry.isRowMajor != cmpEntry.isRowMajor)
   1675 			{
   1676 				log << TestLog::Message << "Error: Layout mismatch in '" << refEntry.name << "':\n"
   1677 					<< "  expected: type = " << glu::getDataTypeName(refEntry.type) << ", size = " << refEntry.size
   1678 					<< ", row major = " << (refEntry.isRowMajor ? "true" : "false") << "\n"
   1679 					<< "  got: type = " << glu::getDataTypeName(cmpEntry.type) << ", size = " << cmpEntry.size
   1680 					<< ", row major = " << (cmpEntry.isRowMajor ? "true" : "false") << TestLog::EndMessage;
   1681 				isOk = false;
   1682 			}
   1683 		}
   1684 	}
   1685 
   1686 	return isOk;
   1687 }
   1688 
   1689 bool UniformBlockCase::compareTypes(const UniformLayout& refLayout, const UniformLayout& cmpLayout) const
   1690 {
   1691 	TestLog& log	   = m_testCtx.getLog();
   1692 	bool	 isOk	  = true;
   1693 	int		 numBlocks = m_interface.getNumUniformBlocks();
   1694 
   1695 	for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
   1696 	{
   1697 		const UniformBlock& block		 = m_interface.getUniformBlock(blockNdx);
   1698 		bool				isArray		 = block.isArray();
   1699 		int					numInstances = isArray ? block.getArraySize() : 1;
   1700 
   1701 		for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
   1702 		{
   1703 			std::ostringstream instanceName;
   1704 
   1705 			instanceName << block.getBlockName();
   1706 			if (isArray)
   1707 				instanceName << "[" << instanceNdx << "]";
   1708 
   1709 			int cmpBlockNdx = cmpLayout.getBlockIndex(instanceName.str().c_str());
   1710 
   1711 			if (cmpBlockNdx < 0)
   1712 				continue;
   1713 
   1714 			const BlockLayoutEntry& cmpBlockLayout = cmpLayout.blocks[cmpBlockNdx];
   1715 
   1716 			for (vector<int>::const_iterator ndxIter = cmpBlockLayout.activeUniformIndices.begin();
   1717 				 ndxIter != cmpBlockLayout.activeUniformIndices.end(); ndxIter++)
   1718 			{
   1719 				const UniformLayoutEntry& cmpEntry	= cmpLayout.uniforms[*ndxIter];
   1720 				int						  refEntryNdx = refLayout.getUniformIndex(cmpEntry.name.c_str());
   1721 
   1722 				if (refEntryNdx < 0)
   1723 				{
   1724 					log << TestLog::Message << "Error: Uniform '" << cmpEntry.name << "' not found in reference layout"
   1725 						<< TestLog::EndMessage;
   1726 					isOk = false;
   1727 					continue;
   1728 				}
   1729 
   1730 				const UniformLayoutEntry& refEntry = refLayout.uniforms[refEntryNdx];
   1731 
   1732 				// \todo [2012-11-26 pyry] Should we check other properties as well?
   1733 				if (refEntry.type != cmpEntry.type)
   1734 				{
   1735 					log << TestLog::Message << "Error: Uniform type mismatch in '" << refEntry.name << "':\n"
   1736 						<< "  expected: " << glu::getDataTypeName(refEntry.type) << "\n"
   1737 						<< "  got: " << glu::getDataTypeName(cmpEntry.type) << TestLog::EndMessage;
   1738 					isOk = false;
   1739 				}
   1740 			}
   1741 		}
   1742 	}
   1743 
   1744 	return isOk;
   1745 }
   1746 
   1747 bool UniformBlockCase::checkLayoutIndices(const UniformLayout& layout) const
   1748 {
   1749 	TestLog& log		 = m_testCtx.getLog();
   1750 	int		 numUniforms = (int)layout.uniforms.size();
   1751 	int		 numBlocks   = (int)layout.blocks.size();
   1752 	bool	 isOk		 = true;
   1753 
   1754 	// Check uniform block indices.
   1755 	for (int uniformNdx = 0; uniformNdx < numUniforms; uniformNdx++)
   1756 	{
   1757 		const UniformLayoutEntry& uniform = layout.uniforms[uniformNdx];
   1758 
   1759 		if (uniform.blockNdx < 0 || !deInBounds32(uniform.blockNdx, 0, numBlocks))
   1760 		{
   1761 			log << TestLog::Message << "Error: Invalid block index in uniform '" << uniform.name << "'"
   1762 				<< TestLog::EndMessage;
   1763 			isOk = false;
   1764 		}
   1765 	}
   1766 
   1767 	// Check active uniforms.
   1768 	for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
   1769 	{
   1770 		const BlockLayoutEntry& block = layout.blocks[blockNdx];
   1771 
   1772 		for (vector<int>::const_iterator uniformIter = block.activeUniformIndices.begin();
   1773 			 uniformIter != block.activeUniformIndices.end(); uniformIter++)
   1774 		{
   1775 			if (!deInBounds32(*uniformIter, 0, numUniforms))
   1776 			{
   1777 				log << TestLog::Message << "Error: Invalid active uniform index " << *uniformIter << " in block '"
   1778 					<< block.name << "'" << TestLog::EndMessage;
   1779 				isOk = false;
   1780 			}
   1781 		}
   1782 	}
   1783 
   1784 	return isOk;
   1785 }
   1786 
   1787 bool UniformBlockCase::checkLayoutBounds(const UniformLayout& layout) const
   1788 {
   1789 	TestLog& log		 = m_testCtx.getLog();
   1790 	int		 numUniforms = (int)layout.uniforms.size();
   1791 	bool	 isOk		 = true;
   1792 
   1793 	for (int uniformNdx = 0; uniformNdx < numUniforms; uniformNdx++)
   1794 	{
   1795 		const UniformLayoutEntry& uniform = layout.uniforms[uniformNdx];
   1796 
   1797 		if (uniform.blockNdx < 0)
   1798 			continue;
   1799 
   1800 		const BlockLayoutEntry& block	= layout.blocks[uniform.blockNdx];
   1801 		bool					isMatrix = glu::isDataTypeMatrix(uniform.type);
   1802 		int						numVecs = isMatrix ? (uniform.isRowMajor ? glu::getDataTypeMatrixNumRows(uniform.type) :
   1803 													   glu::getDataTypeMatrixNumColumns(uniform.type)) :
   1804 								 1;
   1805 		int numComps = isMatrix ? (uniform.isRowMajor ? glu::getDataTypeMatrixNumColumns(uniform.type) :
   1806 														glu::getDataTypeMatrixNumRows(uniform.type)) :
   1807 								  glu::getDataTypeScalarSize(uniform.type);
   1808 		int		  numElements = uniform.size;
   1809 		const int compSize	= sizeof(deUint32);
   1810 		int		  vecSize	 = numComps * compSize;
   1811 
   1812 		int minOffset = 0;
   1813 		int maxOffset = 0;
   1814 
   1815 		// For negative strides.
   1816 		minOffset = de::min(minOffset, (numVecs - 1) * uniform.matrixStride);
   1817 		minOffset = de::min(minOffset, (numElements - 1) * uniform.arrayStride);
   1818 		minOffset = de::min(minOffset, (numElements - 1) * uniform.arrayStride + (numVecs - 1) * uniform.matrixStride);
   1819 
   1820 		maxOffset = de::max(maxOffset, vecSize);
   1821 		maxOffset = de::max(maxOffset, (numVecs - 1) * uniform.matrixStride + vecSize);
   1822 		maxOffset = de::max(maxOffset, (numElements - 1) * uniform.arrayStride + vecSize);
   1823 		maxOffset = de::max(maxOffset,
   1824 							(numElements - 1) * uniform.arrayStride + (numVecs - 1) * uniform.matrixStride + vecSize);
   1825 
   1826 		if (uniform.offset + minOffset < 0 || uniform.offset + maxOffset > block.size)
   1827 		{
   1828 			log << TestLog::Message << "Error: Uniform '" << uniform.name << "' out of block bounds"
   1829 				<< TestLog::EndMessage;
   1830 			isOk = false;
   1831 		}
   1832 	}
   1833 
   1834 	return isOk;
   1835 }
   1836 
   1837 bool UniformBlockCase::checkIndexQueries(deUint32 program, const UniformLayout& layout) const
   1838 {
   1839 	tcu::TestLog&		  log   = m_testCtx.getLog();
   1840 	const glw::Functions& gl	= m_context.getRenderContext().getFunctions();
   1841 	bool				  allOk = true;
   1842 
   1843 	// \note Spec mandates that uniform blocks are assigned consecutive locations from 0
   1844 	//       to ACTIVE_UNIFORM_BLOCKS. BlockLayoutEntries are stored in that order in UniformLayout.
   1845 	for (int blockNdx = 0; blockNdx < (int)layout.blocks.size(); blockNdx++)
   1846 	{
   1847 		const BlockLayoutEntry& block	  = layout.blocks[blockNdx];
   1848 		const int				queriedNdx = gl.getUniformBlockIndex(program, block.name.c_str());
   1849 
   1850 		if (queriedNdx != blockNdx)
   1851 		{
   1852 			log << TestLog::Message << "ERROR: glGetUniformBlockIndex(" << block.name << ") returned " << queriedNdx
   1853 				<< ", expected " << blockNdx << "!" << TestLog::EndMessage;
   1854 			allOk = false;
   1855 		}
   1856 
   1857 		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformBlockIndex()");
   1858 	}
   1859 
   1860 	return allOk;
   1861 }
   1862 
   1863 bool UniformBlockCase::render(glu::ShaderProgram& program) const
   1864 {
   1865 	tcu::TestLog&			 log = m_testCtx.getLog();
   1866 	const glw::Functions&	gl  = m_context.getRenderContext().getFunctions();
   1867 	de::Random				 rnd(deStringHash(getName()));
   1868 	const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget();
   1869 	const int				 viewportW	= de::min(renderTarget.getWidth(), 128);
   1870 	const int				 viewportH	= de::min(renderTarget.getHeight(), 128);
   1871 	const int				 viewportX	= rnd.getInt(0, renderTarget.getWidth() - viewportW);
   1872 	const int				 viewportY	= rnd.getInt(0, renderTarget.getHeight() - viewportH);
   1873 
   1874 	// Draw
   1875 	{
   1876 		const float position[] = { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, +1.0f, 0.0f, 1.0f,
   1877 								   +1.0f, -1.0f, 0.0f, 1.0f, +1.0f, +1.0f, 0.0f, 1.0f };
   1878 		const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 };
   1879 
   1880 		gl.viewport(viewportX, viewportY, viewportW, viewportH);
   1881 
   1882 		glu::VertexArrayBinding posArray = glu::va::Float("a_position", 4, 4, 0, &position[0]);
   1883 		glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posArray,
   1884 				  glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
   1885 		GLU_EXPECT_NO_ERROR(gl.getError(), "Draw failed");
   1886 	}
   1887 
   1888 	// Verify that all pixels are white.
   1889 	{
   1890 		tcu::Surface pixels(viewportW, viewportH);
   1891 		int			 numFailedPixels = 0;
   1892 
   1893 		glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, pixels.getAccess());
   1894 		GLU_EXPECT_NO_ERROR(gl.getError(), "Reading pixels failed");
   1895 
   1896 		for (int y = 0; y < pixels.getHeight(); y++)
   1897 		{
   1898 			for (int x = 0; x < pixels.getWidth(); x++)
   1899 			{
   1900 				if (pixels.getPixel(x, y) != tcu::RGBA::white())
   1901 					numFailedPixels += 1;
   1902 			}
   1903 		}
   1904 
   1905 		if (numFailedPixels > 0)
   1906 		{
   1907 			log << TestLog::Image("Image", "Rendered image", pixels);
   1908 			log << TestLog::Message << "Image comparison failed, got " << numFailedPixels << " non-white pixels"
   1909 				<< TestLog::EndMessage;
   1910 		}
   1911 
   1912 		return numFailedPixels == 0;
   1913 	}
   1914 }
   1915 
   1916 } // deqp
   1917