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