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