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