• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
44 using tcu::TestLog;
45 using std::string;
46 using std::vector;
47 using std::map;
48 
49 namespace deqp
50 {
51 namespace ub
52 {
53 
54 struct PrecisionFlagsFmt
55 {
56 	deUint32 flags;
57 
PrecisionFlagsFmtdeqp::ub::PrecisionFlagsFmt58 	PrecisionFlagsFmt(deUint32 flags_) : flags(flags_)
59 	{
60 	}
61 };
62 
operator <<(std::ostream & str,const PrecisionFlagsFmt & fmt)63 std::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 
73 struct LayoutFlagsFmt
74 {
75 	deUint32 flags;
LayoutFlagsFmtdeqp::ub::LayoutFlagsFmt76 	LayoutFlagsFmt(deUint32 flags_) : flags(flags_)
77 	{
78 	}
79 };
80 
operator <<(std::ostream & str,const LayoutFlagsFmt & fmt)81 std::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 
VarType(void)110 VarType::VarType(void) : m_type(TYPE_LAST), m_flags(0)
111 {
112 }
113 
VarType(const VarType & other)114 VarType::VarType(const VarType& other) : m_type(TYPE_LAST), m_flags(0)
115 {
116 	*this = other;
117 }
118 
VarType(glu::DataType basicType,deUint32 flags)119 VarType::VarType(glu::DataType basicType, deUint32 flags) : m_type(TYPE_BASIC), m_flags(flags)
120 {
121 	m_data.basicType = basicType;
122 }
123 
VarType(const VarType & elementType,int arraySize)124 VarType::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 
VarType(const StructType * structPtr)130 VarType::VarType(const StructType* structPtr) : m_type(TYPE_STRUCT), m_flags(0)
131 {
132 	m_data.structPtr = structPtr;
133 }
134 
~VarType(void)135 VarType::~VarType(void)
136 {
137 	if (m_type == TYPE_ARRAY)
138 		delete m_data.array.elementType;
139 }
140 
operator =(const VarType & other)141 VarType& 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 
addMember(const char * name,const VarType & type,deUint32 flags)166 void 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 
Uniform(const char * name,const VarType & type,deUint32 flags)173 Uniform::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 
UniformBlock(const char * blockName)179 UniformBlock::UniformBlock(const char* blockName) : m_blockName(blockName), m_arraySize(0), m_flags(0)
180 {
181 }
182 
183 struct BlockLayoutEntry
184 {
BlockLayoutEntrydeqp::ub::BlockLayoutEntry185 	BlockLayoutEntry(void) : size(0)
186 	{
187 	}
188 
189 	std::string		 name;
190 	int				 size;
191 	std::vector<int> activeUniformIndices;
192 };
193 
operator <<(std::ostream & stream,const BlockLayoutEntry & entry)194 std::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 
209 struct UniformLayoutEntry
210 {
UniformLayoutEntrydeqp::ub::UniformLayoutEntry211 	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 
operator <<(std::ostream & stream,const UniformLayoutEntry & entry)226 std::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 
235 class UniformLayout
236 {
237 public:
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 
getUniformIndex(const char * name) const247 int 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 
getBlockIndex(const char * name) const257 int 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 
ShaderInterface(void)269 ShaderInterface::ShaderInterface(void)
270 {
271 }
272 
~ShaderInterface(void)273 ShaderInterface::~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 
allocStruct(const char * name)282 StructType& 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 
289 struct StructNameEquals
290 {
291 	std::string name;
292 
StructNameEqualsdeqp::ub::StructNameEquals293 	StructNameEquals(const char* name_) : name(name_)
294 	{
295 	}
296 
operator ()deqp::ub::StructNameEquals297 	bool operator()(const StructType* type) const
298 	{
299 		return type->getTypeName() && name == type->getTypeName();
300 	}
301 };
302 
findStruct(const char * name) const303 const 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 
getNamedStructs(std::vector<const StructType * > & structs) const310 void 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 
allocBlock(const char * name)319 UniformBlock& 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 
326 namespace // Utilities
327 {
328 
329 // Layout computation.
330 
getDataTypeByteSize(glu::DataType type)331 int getDataTypeByteSize(glu::DataType type)
332 {
333 	return static_cast<int>(glu::getDataTypeScalarSize(type) * sizeof(deUint32));
334 }
335 
getDataTypeByteAlignment(glu::DataType type)336 int 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 
getDataTypeArrayStride(glu::DataType type)369 int 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 
computeStd140BaseAlignment(const VarType & type)380 int 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 
mergeLayoutFlags(deUint32 prevFlags,deUint32 newFlags)420 inline 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 
computeStd140Layout(UniformLayout & layout,int & curOffset,int curBlockNdx,const std::string & curPrefix,const VarType & type,deUint32 layoutFlags)433 void 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 
computeStd140Layout(UniformLayout & layout,const ShaderInterface & interface)548 void 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 
generateValue(const UniformLayoutEntry & entry,void * basePtr,de::Random & rnd)596 void 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 
generateValues(const UniformLayout & layout,const std::map<int,void * > & blockPointers,deUint32 seed)646 void 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 
666 static 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 
705 struct Indent
706 {
707 	int level;
708 
Indentdeqp::ub::__anon85e218f40211::Indent709 	Indent(int level_) : level(level_)
710 	{
711 	}
712 };
713 
operator <<(std::ostream & str,const Indent & indent)714 std::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 
721 void generateDeclaration(std::ostringstream& src, const VarType& type, const char* name, int indentLevel,
722 						 deUint32 unusedHints);
723 void generateDeclaration(std::ostringstream& src, const Uniform& uniform, int indentLevel);
724 void generateDeclaration(std::ostringstream& src, const StructType& structType, int indentLevel);
725 
726 void generateLocalDeclaration(std::ostringstream& src, const StructType& structType, int indentLevel);
727 void generateFullDeclaration(std::ostringstream& src, const StructType& structType, int indentLevel);
728 
generateDeclaration(std::ostringstream & src,const StructType & structType,int indentLevel)729 void 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 
generateFullDeclaration(std::ostringstream & src,const StructType & structType,int indentLevel)736 void 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 
generateLocalDeclaration(std::ostringstream & src,const StructType & structType,int indentLevel)753 void 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 
generateDeclaration(std::ostringstream & src,const VarType & type,const char * name,int indentLevel,deUint32 unusedHints)761 void 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 
generateDeclaration(std::ostringstream & src,const Uniform & uniform,int indentLevel)821 void 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 
generateDeclaration(std::ostringstream & src,const UniformBlock & block)829 void 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 
generateValueSrc(std::ostringstream & src,const UniformLayoutEntry & entry,const void * basePtr,int elementNdx)857 void 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 
generateCompareSrc(std::ostringstream & src,const char * resultVar,const VarType & type,const char * srcName,const char * apiName,const UniformLayout & layout,const void * basePtr,deUint32 unusedMask)923 void 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 
generateCompareSrc(std::ostringstream & src,const char * resultVar,const ShaderInterface & interface,const UniformLayout & layout,const std::map<int,void * > & blockPointers,bool isVertex)981 void 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 
generateVertexShader(std::ostringstream & src,glu::GLSLVersion glslVersion,const ShaderInterface & interface,const UniformLayout & layout,const std::map<int,void * > & blockPointers)1023 void 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 
generateFragmentShader(std::ostringstream & src,glu::GLSLVersion glslVersion,const ShaderInterface & interface,const UniformLayout & layout,const std::map<int,void * > & blockPointers)1063 void 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 
getGLUniformLayout(const glw::Functions & gl,UniformLayout & layout,deUint32 program)1102 void 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 
copyUniformData(const UniformLayoutEntry & dstEntry,void * dstBlockPtr,const UniformLayoutEntry & srcEntry,const void * srcBlockPtr)1211 void 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 
copyUniformData(const UniformLayout & dstLayout,const std::map<int,void * > & dstBlockPointers,const UniformLayout & srcLayout,const std::map<int,void * > & srcBlockPointers)1253 void 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 
1285 class UniformBufferManager
1286 {
1287 public:
1288 	UniformBufferManager(const glu::RenderContext& renderCtx);
1289 	~UniformBufferManager(void);
1290 
1291 	deUint32 allocBuffer(void);
1292 
1293 private:
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 
UniformBufferManager(const glu::RenderContext & renderCtx)1301 UniformBufferManager::UniformBufferManager(const glu::RenderContext& renderCtx) : m_renderCtx(renderCtx)
1302 {
1303 }
1304 
~UniformBufferManager(void)1305 UniformBufferManager::~UniformBufferManager(void)
1306 {
1307 	if (!m_buffers.empty())
1308 		m_renderCtx.getFunctions().deleteBuffers((glw::GLsizei)m_buffers.size(), &m_buffers[0]);
1309 }
1310 
allocBuffer(void)1311 deUint32 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 
1325 using namespace ub;
1326 
1327 // UniformBlockCase.
1328 
UniformBlockCase(Context & context,const char * name,const char * description,glu::GLSLVersion glslVersion,BufferMode bufferMode)1329 UniformBlockCase::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 
~UniformBlockCase(void)1337 UniformBlockCase::~UniformBlockCase(void)
1338 {
1339 }
1340 
iterate(void)1341 UniformBlockCase::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 
compareStd140Blocks(const UniformLayout & refLayout,const UniformLayout & cmpLayout) const1527 bool 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 
compareSharedBlocks(const UniformLayout & refLayout,const UniformLayout & cmpLayout) const1609 bool 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 
compareTypes(const UniformLayout & refLayout,const UniformLayout & cmpLayout) const1684 bool 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 
checkLayoutIndices(const UniformLayout & layout) const1742 bool 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 
checkLayoutBounds(const UniformLayout & layout) const1782 bool 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 
checkIndexQueries(deUint32 program,const UniformLayout & layout) const1832 bool 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 
render(glu::ShaderProgram & program) const1858 bool 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