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
44using tcu::TestLog;
45using std::string;
46using std::vector;
47using std::map;
48
49namespace deqp
50{
51namespace gls
52{
53namespace ub
54{
55
56static bool isSupportedGLSLVersion (glu::GLSLVersion version)
57{
58	return version >= (glslVersionIsES(version) ? glu::GLSL_VERSION_300_ES : glu::GLSL_VERSION_330);
59}
60
61struct PrecisionFlagsFmt
62{
63	deUint32 flags;
64	PrecisionFlagsFmt (deUint32 flags_) : flags(flags_) {}
65};
66
67std::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
77struct LayoutFlagsFmt
78{
79	deUint32 flags;
80	LayoutFlagsFmt (deUint32 flags_) : flags(flags_) {}
81};
82
83std::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
115VarType::VarType (void)
116	: m_type	(TYPE_LAST)
117	, m_flags	(0)
118{
119}
120
121VarType::VarType (const VarType& other)
122	: m_type	(TYPE_LAST)
123	, m_flags	(0)
124{
125	*this = other;
126}
127
128VarType::VarType (glu::DataType basicType, deUint32 flags)
129	: m_type	(TYPE_BASIC)
130	, m_flags	(flags)
131{
132	m_data.basicType = basicType;
133}
134
135VarType::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
143VarType::VarType (const StructType* structPtr)
144	: m_type	(TYPE_STRUCT)
145	, m_flags	(0)
146{
147	m_data.structPtr = structPtr;
148}
149
150VarType::~VarType (void)
151{
152	if (m_type == TYPE_ARRAY)
153		delete m_data.array.elementType;
154}
155
156VarType& 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
181void 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
188Uniform::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
197UniformBlock::UniformBlock (const char* blockName)
198	: m_blockName	(blockName)
199	, m_arraySize	(0)
200	, m_flags		(0)
201{
202}
203
204struct 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
216std::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
233struct 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
256std::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
269class UniformLayout
270{
271public:
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
281int 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
291int 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
303ShaderInterface::ShaderInterface (void)
304{
305}
306
307ShaderInterface::~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
316StructType& 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
323struct 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
335const 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
341void 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
350UniformBlock& 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
357namespace // Utilities
358{
359
360// Layout computation.
361
362int getDataTypeByteSize (glu::DataType type)
363{
364	return glu::getDataTypeScalarSize(type)*sizeof(deUint32);
365}
366
367int 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*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*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*sizeof(deUint32);
390
391		default:
392			DE_ASSERT(false);
393			return 0;
394	}
395}
396
397int getDataTypeArrayStride (glu::DataType type)
398{
399	DE_ASSERT(!glu::isDataTypeMatrix(type));
400
401	int baseStride		= getDataTypeByteSize(type);
402	int vec4Alignment	= sizeof(deUint32)*4;
403
404	DE_ASSERT(baseStride <= vec4Alignment);
405	return de::max(baseStride, vec4Alignment); // Really? See rule 4.
406}
407
408static inline int deRoundUp32 (int a, int b)
409{
410	int d = a/b;
411	return d*b == a ? a : (d+1)*b;
412}
413
414int computeStd140BaseAlignment (const VarType& type)
415{
416	const int vec4Alignment = 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
453inline 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
466void 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
577void 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
624void 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
664void 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
684const 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
719void 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
750void 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
766void 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
772void 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
778void 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
799struct Indent
800{
801	int level;
802	Indent (int level_) : level(level_) {}
803};
804
805std::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
812void		generateDeclaration			(std::ostringstream& src, const VarType& type, const char* name, int indentLevel, deUint32 unusedHints);
813void		generateDeclaration			(std::ostringstream& src, const Uniform& uniform, int indentLevel);
814void		generateDeclaration			(std::ostringstream& src, const StructType& structType, int indentLevel);
815
816void		generateLocalDeclaration	(std::ostringstream& src, const StructType& structType, int indentLevel);
817void		generateFullDeclaration		(std::ostringstream& src, const StructType& structType, int indentLevel);
818
819void 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
826void 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
842void 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
850void 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
906void 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
914void 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
942void 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
1000void 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
1053void 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
1092void 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
1130void 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
1167void 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
1266void 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
1305void 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
1335class UniformBufferManager
1336{
1337public:
1338								UniformBufferManager	(const glu::RenderContext& renderCtx);
1339								~UniformBufferManager	(void);
1340
1341	deUint32					allocBuffer				(void);
1342
1343private:
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
1351UniformBufferManager::UniformBufferManager (const glu::RenderContext& renderCtx)
1352	: m_renderCtx(renderCtx)
1353{
1354}
1355
1356UniformBufferManager::~UniformBufferManager (void)
1357{
1358	if (!m_buffers.empty())
1359		m_renderCtx.getFunctions().deleteBuffers((glw::GLsizei)m_buffers.size(), &m_buffers[0]);
1360}
1361
1362deUint32 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
1376using namespace ub;
1377
1378// UniformBlockCase.
1379
1380UniformBlockCase::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
1389UniformBlockCase::~UniformBlockCase (void)
1390{
1391}
1392
1393UniformBlockCase::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
1575bool 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
1654bool 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
1728bool 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
1785bool 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
1822bool 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
1866bool 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
1891bool 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