1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2015 The Khronos Group Inc.
6  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
7  * Copyright (c) 2016 The Android Open Source Project
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*!
22  * \file
23  * \brief Uniform block case.
24  *//*--------------------------------------------------------------------*/
25 
26 #include "vktUniformBlockCase.hpp"
27 
28 #include "vkPrograms.hpp"
29 
30 #include "gluVarType.hpp"
31 #include "tcuTestLog.hpp"
32 #include "tcuSurface.hpp"
33 #include "deRandom.hpp"
34 #include "deStringUtil.hpp"
35 
36 #include "tcuTextureUtil.hpp"
37 #include "deSharedPtr.hpp"
38 #include "deFloat16.h"
39 
40 #include "vkMemUtil.hpp"
41 #include "vkQueryUtil.hpp"
42 #include "vkTypeUtil.hpp"
43 #include "vkRef.hpp"
44 #include "vkRefUtil.hpp"
45 #include "vkBuilderUtil.hpp"
46 #include "vkCmdUtil.hpp"
47 #include "vkObjUtil.hpp"
48 #include "vkImageUtil.hpp"
49 
50 #include <map>
51 #include <set>
52 
53 namespace vkt
54 {
55 namespace ubo
56 {
57 
58 using namespace vk;
59 
60 // VarType implementation.
61 
VarType(void)62 VarType::VarType (void)
63 	: m_type	(TYPE_LAST)
64 	, m_flags	(0)
65 {
66 }
67 
VarType(const VarType & other)68 VarType::VarType (const VarType& other)
69 	: m_type	(TYPE_LAST)
70 	, m_flags	(0)
71 {
72 	*this = other;
73 }
74 
VarType(glu::DataType basicType,deUint32 flags)75 VarType::VarType (glu::DataType basicType, deUint32 flags)
76 	: m_type	(TYPE_BASIC)
77 	, m_flags	(flags)
78 {
79 	m_data.basicType = basicType;
80 }
81 
VarType(const VarType & elementType,int arraySize)82 VarType::VarType (const VarType& elementType, int arraySize)
83 	: m_type	(TYPE_ARRAY)
84 	, m_flags	(0)
85 {
86 	m_data.array.size			= arraySize;
87 	m_data.array.elementType	= new VarType(elementType);
88 }
89 
VarType(const StructType * structPtr,deUint32 flags)90 VarType::VarType (const StructType* structPtr, deUint32 flags)
91 	: m_type	(TYPE_STRUCT)
92 	, m_flags	(flags)
93 {
94 	m_data.structPtr = structPtr;
95 }
96 
~VarType(void)97 VarType::~VarType (void)
98 {
99 	if (m_type == TYPE_ARRAY)
100 		delete m_data.array.elementType;
101 }
102 
operator =(const VarType & other)103 VarType& VarType::operator= (const VarType& other)
104 {
105 	if (this == &other)
106 		return *this; // Self-assignment.
107 
108 	VarType *oldElementType = m_type == TYPE_ARRAY ? m_data.array.elementType : DE_NULL;
109 
110 	m_type	= other.m_type;
111 	m_flags	= other.m_flags;
112 	m_data	= Data();
113 
114 	if (m_type == TYPE_ARRAY)
115 	{
116 		m_data.array.elementType	= new VarType(*other.m_data.array.elementType);
117 		m_data.array.size			= other.m_data.array.size;
118 	}
119 	else
120 		m_data = other.m_data;
121 
122 	delete oldElementType;
123 
124 	return *this;
125 }
126 
127 // StructType implementation.
128 
addMember(const std::string & name,const VarType & type,deUint32 flags)129 void StructType::addMember (const std::string& name, const VarType& type, deUint32 flags)
130 {
131 	m_members.push_back(StructMember(name, type, flags));
132 }
133 
134 // Uniform implementation.
135 
Uniform(const std::string & name,const VarType & type,deUint32 flags)136 Uniform::Uniform (const std::string& name, const VarType& type, deUint32 flags)
137 	: m_name	(name)
138 	, m_type	(type)
139 	, m_flags	(flags)
140 {
141 }
142 
143 // UniformBlock implementation.
144 
UniformBlock(const std::string & blockName)145 UniformBlock::UniformBlock (const std::string& blockName)
146 	: m_blockName	(blockName)
147 	, m_arraySize	(0)
148 	, m_flags		(0)
149 {
150 }
151 
operator <<(std::ostream & stream,const BlockLayoutEntry & entry)152 std::ostream& operator<< (std::ostream& stream, const BlockLayoutEntry& entry)
153 {
154 	stream << entry.name << " { name = " << entry.name
155 		   << ", size = " << entry.size
156 		   << ", activeUniformIndices = [";
157 
158 	for (std::vector<int>::const_iterator i = entry.activeUniformIndices.begin(); i != entry.activeUniformIndices.end(); i++)
159 	{
160 		if (i != entry.activeUniformIndices.begin())
161 			stream << ", ";
162 		stream << *i;
163 	}
164 
165 	stream << "] }";
166 	return stream;
167 }
168 
operator <<(std::ostream & stream,const UniformLayoutEntry & entry)169 std::ostream& operator<< (std::ostream& stream, const UniformLayoutEntry& entry)
170 {
171 	stream << entry.name << " { type = " << glu::getDataTypeName(entry.type)
172 		   << ", size = " << entry.size
173 		   << ", blockNdx = " << entry.blockNdx
174 		   << ", offset = " << entry.offset
175 		   << ", arrayStride = " << entry.arrayStride
176 		   << ", matrixStride = " << entry.matrixStride
177 		   << ", isRowMajor = " << (entry.isRowMajor ? "true" : "false")
178 		   << " }";
179 	return stream;
180 }
181 
getUniformLayoutIndex(int blockNdx,const std::string & name) const182 int UniformLayout::getUniformLayoutIndex (int blockNdx, const std::string& name) const
183 {
184 	for (int ndx = 0; ndx < (int)uniforms.size(); ndx++)
185 	{
186 		if (blocks[uniforms[ndx].blockNdx].blockDeclarationNdx == blockNdx &&
187 			uniforms[ndx].name == name)
188 			return ndx;
189 	}
190 
191 	return -1;
192 }
193 
getBlockLayoutIndex(int blockNdx,int instanceNdx) const194 int UniformLayout::getBlockLayoutIndex (int blockNdx, int instanceNdx) const
195 {
196 	for (int ndx = 0; ndx < (int)blocks.size(); ndx++)
197 	{
198 		if (blocks[ndx].blockDeclarationNdx == blockNdx &&
199 			blocks[ndx].instanceNdx == instanceNdx)
200 			return ndx;
201 	}
202 
203 	return -1;
204 }
205 
206 // ShaderInterface implementation.
207 
ShaderInterface(void)208 ShaderInterface::ShaderInterface (void)
209 {
210 }
211 
~ShaderInterface(void)212 ShaderInterface::~ShaderInterface (void)
213 {
214 }
215 
allocStruct(const std::string & name)216 StructType& ShaderInterface::allocStruct (const std::string& name)
217 {
218 	m_structs.push_back(StructTypeSP(new StructType(name)));
219 	return *m_structs.back();
220 }
221 
222 struct StructNameEquals
223 {
224 	std::string name;
225 
StructNameEqualsvkt::ubo::StructNameEquals226 	StructNameEquals (const std::string& name_) : name(name_) {}
227 
operator ()vkt::ubo::StructNameEquals228 	bool operator() (const StructTypeSP type) const
229 	{
230 		return type->hasTypeName() && name == type->getTypeName();
231 	}
232 };
233 
getNamedStructs(std::vector<const StructType * > & structs) const234 void ShaderInterface::getNamedStructs (std::vector<const StructType*>& structs) const
235 {
236 	for (std::vector<StructTypeSP>::const_iterator i = m_structs.begin(); i != m_structs.end(); i++)
237 	{
238 		if ((*i)->hasTypeName())
239 			structs.push_back((*i).get());
240 	}
241 }
242 
allocBlock(const std::string & name)243 UniformBlock& ShaderInterface::allocBlock (const std::string& name)
244 {
245 	m_uniformBlocks.push_back(UniformBlockSP(new UniformBlock(name)));
246 	return *m_uniformBlocks.back();
247 }
248 
usesBlockLayout(UniformFlags layoutFlag) const249 bool ShaderInterface::usesBlockLayout (UniformFlags layoutFlag) const
250 {
251 	for (int i = 0, num_blocks = getNumUniformBlocks() ; i < num_blocks ; i++)
252 	{
253 		if (m_uniformBlocks[i]->getFlags() & layoutFlag)
254 			return true;
255 	}
256 	return false;
257 }
258 
259 namespace // Utilities
260 {
261 
262 struct PrecisionFlagsFmt
263 {
264 	deUint32 flags;
PrecisionFlagsFmtvkt::ubo::__anon0393f7100111::PrecisionFlagsFmt265 	PrecisionFlagsFmt (deUint32 flags_) : flags(flags_) {}
266 };
267 
operator <<(std::ostream & str,const PrecisionFlagsFmt & fmt)268 std::ostream& operator<< (std::ostream& str, const PrecisionFlagsFmt& fmt)
269 {
270 	// Precision.
271 	DE_ASSERT(dePop32(fmt.flags & (PRECISION_LOW|PRECISION_MEDIUM|PRECISION_HIGH)) <= 1);
272 	str << (fmt.flags & PRECISION_LOW		? "lowp"	:
273 			fmt.flags & PRECISION_MEDIUM	? "mediump"	:
274 			fmt.flags & PRECISION_HIGH		? "highp"	: "");
275 	return str;
276 }
277 
278 struct LayoutFlagsFmt
279 {
280 	deUint32 flags;
281 	deUint32 offset;
LayoutFlagsFmtvkt::ubo::__anon0393f7100111::LayoutFlagsFmt282 	LayoutFlagsFmt (deUint32 flags_, deUint32 offset_ = 0u) : flags(flags_), offset(offset_) {}
283 };
284 
operator <<(std::ostream & str,const LayoutFlagsFmt & fmt)285 std::ostream& operator<< (std::ostream& str, const LayoutFlagsFmt& fmt)
286 {
287 	static const struct
288 	{
289 		deUint32	bit;
290 		const char*	token;
291 	} bitDesc[] =
292 	{
293 		{ LAYOUT_STD140,		"std140"		},
294 		{ LAYOUT_STD430,		"std430"		},
295 		{ LAYOUT_SCALAR,		"scalar"		},
296 		{ LAYOUT_ROW_MAJOR,		"row_major"		},
297 		{ LAYOUT_COLUMN_MAJOR,	"column_major"	},
298 		{ LAYOUT_OFFSET,		"offset"		},
299 	};
300 
301 	deUint32 remBits = fmt.flags;
302 	for (int descNdx = 0; descNdx < DE_LENGTH_OF_ARRAY(bitDesc); descNdx++)
303 	{
304 		if (remBits & bitDesc[descNdx].bit)
305 		{
306 			if (remBits != fmt.flags)
307 				str << ", ";
308 			str << bitDesc[descNdx].token;
309 			if (bitDesc[descNdx].bit == LAYOUT_OFFSET)
310 				str << " = " << fmt.offset;
311 			remBits &= ~bitDesc[descNdx].bit;
312 		}
313 	}
314 	DE_ASSERT(remBits == 0);
315 	return str;
316 }
317 
318 // Layout computation.
319 
getDataTypeByteSize(glu::DataType type)320 int getDataTypeByteSize (glu::DataType type)
321 {
322 	if (deInRange32(type, glu::TYPE_UINT8, glu::TYPE_UINT8_VEC4) || deInRange32(type, glu::TYPE_INT8, glu::TYPE_INT8_VEC4))
323 	{
324 		return glu::getDataTypeScalarSize(type)*(int)sizeof(deUint8);
325 	}
326 	if (deInRange32(type, glu::TYPE_UINT16, glu::TYPE_UINT16_VEC4) || deInRange32(type, glu::TYPE_INT16, glu::TYPE_INT16_VEC4) || deInRange32(type, glu::TYPE_FLOAT16, glu::TYPE_FLOAT16_VEC4))
327 	{
328 		return glu::getDataTypeScalarSize(type)*(int)sizeof(deUint16);
329 	}
330 	else
331 	{
332 		return glu::getDataTypeScalarSize(type)*(int)sizeof(deUint32);
333 	}
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:		return 1*(int)sizeof(deUint32);
344 
345 		case glu::TYPE_FLOAT_VEC2:
346 		case glu::TYPE_INT_VEC2:
347 		case glu::TYPE_UINT_VEC2:
348 		case glu::TYPE_BOOL_VEC2:	return 2*(int)sizeof(deUint32);
349 
350 		case glu::TYPE_FLOAT_VEC3:
351 		case glu::TYPE_INT_VEC3:
352 		case glu::TYPE_UINT_VEC3:
353 		case glu::TYPE_BOOL_VEC3:	// Fall-through to vec4
354 
355 		case glu::TYPE_FLOAT_VEC4:
356 		case glu::TYPE_INT_VEC4:
357 		case glu::TYPE_UINT_VEC4:
358 		case glu::TYPE_BOOL_VEC4:	return 4*(int)sizeof(deUint32);
359 
360 		case glu::TYPE_UINT8:
361 		case glu::TYPE_INT8	:			return 1*(int)sizeof(deUint8);
362 
363 		case glu::TYPE_UINT8_VEC2:
364 		case glu::TYPE_INT8_VEC2:		return 2*(int)sizeof(deUint8);
365 
366 		case glu::TYPE_UINT8_VEC3:
367 		case glu::TYPE_INT8_VEC3:		// Fall-through to vec4
368 
369 		case glu::TYPE_UINT8_VEC4:
370 		case glu::TYPE_INT8_VEC4:		return 4*(int)sizeof(deUint8);
371 
372 		case glu::TYPE_UINT16:
373 		case glu::TYPE_INT16:
374 		case glu::TYPE_FLOAT16:			return 1*(int)sizeof(deUint16);
375 
376 		case glu::TYPE_UINT16_VEC2:
377 		case glu::TYPE_INT16_VEC2:
378 		case glu::TYPE_FLOAT16_VEC2:	return 2*(int)sizeof(deUint16);
379 
380 		case glu::TYPE_UINT16_VEC3:
381 		case glu::TYPE_INT16_VEC3:
382 		case glu::TYPE_FLOAT16_VEC3:	// Fall-through to vec4
383 
384 		case glu::TYPE_UINT16_VEC4:
385 		case glu::TYPE_INT16_VEC4:
386 		case glu::TYPE_FLOAT16_VEC4:	return 4*(int)sizeof(deUint16);
387 
388 		default:
389 			DE_ASSERT(false);
390 			return 0;
391 	}
392 }
393 
getminUniformBufferOffsetAlignment(Context & ctx)394 deInt32 getminUniformBufferOffsetAlignment (Context &ctx)
395 {
396 	VkPhysicalDeviceProperties properties;
397 	ctx.getInstanceInterface().getPhysicalDeviceProperties(ctx.getPhysicalDevice(), &properties);
398 	VkDeviceSize align = properties.limits.minUniformBufferOffsetAlignment;
399 	DE_ASSERT(align == (VkDeviceSize)(deInt32)align);
400 	return (deInt32)align;
401 }
402 
deRoundUp32(int a,int b)403 static inline int deRoundUp32 (int a, int b)
404 {
405 	int d = a/b;
406 	return d*b == a ? a : (d+1)*b;
407 }
408 
409 
computeStd140BaseAlignment(const VarType & type,deUint32 layoutFlags)410 int computeStd140BaseAlignment (const VarType& type, deUint32 layoutFlags)
411 {
412 	const int vec4Alignment = (int)sizeof(deUint32)*4;
413 
414 	if (type.isBasicType())
415 	{
416 		glu::DataType basicType = type.getBasicType();
417 
418 		if (glu::isDataTypeMatrix(basicType))
419 		{
420 			const bool	isRowMajor	= !!(layoutFlags & LAYOUT_ROW_MAJOR);
421 			const int	vecSize		= isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType)
422 												 : glu::getDataTypeMatrixNumRows(basicType);
423 			const int	vecAlign	= deAlign32(getDataTypeByteAlignment(glu::getDataTypeFloatVec(vecSize)), vec4Alignment);
424 
425 			return vecAlign;
426 		}
427 		else
428 			return getDataTypeByteAlignment(basicType);
429 	}
430 	else if (type.isArrayType())
431 	{
432 		int elemAlignment = computeStd140BaseAlignment(type.getElementType(), layoutFlags);
433 
434 		// Round up to alignment of vec4
435 		return deAlign32(elemAlignment, vec4Alignment);
436 	}
437 	else
438 	{
439 		DE_ASSERT(type.isStructType());
440 
441 		int maxBaseAlignment = 0;
442 
443 		for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++)
444 			maxBaseAlignment = de::max(maxBaseAlignment, computeStd140BaseAlignment(memberIter->getType(), layoutFlags));
445 
446 		return deAlign32(maxBaseAlignment, vec4Alignment);
447 	}
448 }
449 
computeStd430BaseAlignment(const VarType & type,deUint32 layoutFlags)450 int computeStd430BaseAlignment (const VarType& type, deUint32 layoutFlags)
451 {
452 	// Otherwise identical to std140 except that alignment of structures and arrays
453 	// are not rounded up to alignment of vec4.
454 
455 	if (type.isBasicType())
456 	{
457 		glu::DataType basicType = type.getBasicType();
458 
459 		if (glu::isDataTypeMatrix(basicType))
460 		{
461 			const bool	isRowMajor	= !!(layoutFlags & LAYOUT_ROW_MAJOR);
462 			const int	vecSize		= isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType)
463 												 : glu::getDataTypeMatrixNumRows(basicType);
464 			const int	vecAlign	= getDataTypeByteAlignment(glu::getDataTypeFloatVec(vecSize));
465 			return vecAlign;
466 		}
467 		else
468 			return getDataTypeByteAlignment(basicType);
469 	}
470 	else if (type.isArrayType())
471 	{
472 		return computeStd430BaseAlignment(type.getElementType(), layoutFlags);
473 	}
474 	else
475 	{
476 		DE_ASSERT(type.isStructType());
477 
478 		int maxBaseAlignment = 0;
479 
480 		for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++)
481 			maxBaseAlignment = de::max(maxBaseAlignment, computeStd430BaseAlignment(memberIter->getType(), layoutFlags));
482 
483 		return maxBaseAlignment;
484 	}
485 }
486 
computeRelaxedBlockBaseAlignment(const VarType & type,deUint32 layoutFlags)487 int computeRelaxedBlockBaseAlignment (const VarType& type, deUint32 layoutFlags)
488 {
489 	if (type.isBasicType())
490 	{
491 		glu::DataType basicType = type.getBasicType();
492 
493 		if (glu::isDataTypeVector(basicType))
494 			return getDataTypeByteAlignment(glu::getDataTypeScalarType(basicType));
495 
496 		if (glu::isDataTypeMatrix(basicType))
497 		{
498 			const bool	isRowMajor	= !!(layoutFlags & LAYOUT_ROW_MAJOR);
499 			const int	vecSize		= isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType)
500 												 : glu::getDataTypeMatrixNumRows(basicType);
501 			const int	vecAlign	= getDataTypeByteAlignment(glu::getDataTypeFloatVec(vecSize));
502 			return vecAlign;
503 		}
504 		else
505 			return getDataTypeByteAlignment(basicType);
506 	}
507 	else if (type.isArrayType())
508 		return computeStd430BaseAlignment(type.getElementType(), layoutFlags);
509 	else
510 	{
511 		DE_ASSERT(type.isStructType());
512 
513 		int maxBaseAlignment = 0;
514 		for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++)
515 			maxBaseAlignment = de::max(maxBaseAlignment, computeRelaxedBlockBaseAlignment(memberIter->getType(), layoutFlags));
516 
517 		return maxBaseAlignment;
518 	}
519 }
520 
computeScalarBlockAlignment(const VarType & type,deUint32 layoutFlags)521 int computeScalarBlockAlignment (const VarType& type, deUint32 layoutFlags)
522 {
523 	if (type.isBasicType())
524 	{
525 		return getDataTypeByteAlignment(glu::getDataTypeScalarType(type.getBasicType()));
526 	}
527 	else if (type.isArrayType())
528 		return computeScalarBlockAlignment(type.getElementType(), layoutFlags);
529 	else
530 	{
531 		DE_ASSERT(type.isStructType());
532 
533 		int maxBaseAlignment = 0;
534 		for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++)
535 			maxBaseAlignment = de::max(maxBaseAlignment, computeScalarBlockAlignment(memberIter->getType(), layoutFlags));
536 
537 		return maxBaseAlignment;
538 	}
539 }
540 
mergeLayoutFlags(deUint32 prevFlags,deUint32 newFlags)541 inline deUint32 mergeLayoutFlags (deUint32 prevFlags, deUint32 newFlags)
542 {
543 	const deUint32	packingMask		= LAYOUT_STD140|LAYOUT_STD430|LAYOUT_SCALAR;
544 	const deUint32	matrixMask		= LAYOUT_ROW_MAJOR|LAYOUT_COLUMN_MAJOR;
545 
546 	deUint32 mergedFlags = 0;
547 
548 	mergedFlags |= ((newFlags & packingMask)	? newFlags : prevFlags) & packingMask;
549 	mergedFlags |= ((newFlags & matrixMask)		? newFlags : prevFlags) & matrixMask;
550 
551 	return mergedFlags;
552 }
553 
554 //! Appends all child elements to layout, returns value that should be appended to offset.
computeReferenceLayout(UniformLayout & layout,int curBlockNdx,int baseOffset,const std::string & curPrefix,const VarType & type,deUint32 layoutFlags)555 int computeReferenceLayout (
556 	UniformLayout&		layout,
557 	int					curBlockNdx,
558 	int					baseOffset,
559 	const std::string&	curPrefix,
560 	const VarType&		type,
561 	deUint32			layoutFlags)
562 {
563 	// HACK to make code match SSBO tests
564 	const int LAYOUT_RELAXED = 0;
565 	// Reference layout uses std140 rules by default. std430 rules are
566 	// choosen only for blocks that have std140 layout.
567 	const int	baseAlignment		= (layoutFlags & LAYOUT_SCALAR)  != 0 ? computeScalarBlockAlignment(type, layoutFlags)			:
568 									  (layoutFlags & LAYOUT_STD430)  != 0 ? computeStd430BaseAlignment(type, layoutFlags)		:
569 									  (layoutFlags & LAYOUT_RELAXED) != 0 ? computeRelaxedBlockBaseAlignment(type, layoutFlags)	:
570 									  computeStd140BaseAlignment(type, layoutFlags);
571 	int			curOffset			= deAlign32(baseOffset, baseAlignment);
572 	const int	topLevelArraySize	= 1; // Default values
573 	const int	topLevelArrayStride	= 0;
574 
575 	if (type.isBasicType())
576 	{
577 		const glu::DataType		basicType	= type.getBasicType();
578 		UniformLayoutEntry		entry;
579 
580 		entry.name					= curPrefix;
581 		entry.type					= basicType;
582 		entry.arraySize				= 1;
583 		entry.arrayStride			= 0;
584 		entry.matrixStride			= 0;
585 		entry.topLevelArraySize		= topLevelArraySize;
586 		entry.topLevelArrayStride	= topLevelArrayStride;
587 		entry.blockNdx				= curBlockNdx;
588 
589 		if (glu::isDataTypeMatrix(basicType))
590 		{
591 			// Array of vectors as specified in rules 5 & 7.
592 			const bool	isRowMajor			= !!(layoutFlags & LAYOUT_ROW_MAJOR);
593 			const int	vecSize				= isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType)
594 														 : glu::getDataTypeMatrixNumRows(basicType);
595 			const glu::DataType	vecType		= glu::getDataTypeFloatVec(vecSize);
596 			const int	numVecs				= isRowMajor ? glu::getDataTypeMatrixNumRows(basicType)
597 														 : glu::getDataTypeMatrixNumColumns(basicType);
598 			const int	vecStride			= (layoutFlags & LAYOUT_SCALAR) ? getDataTypeByteSize(vecType) : baseAlignment;
599 
600 			entry.offset		= curOffset;
601 			entry.matrixStride	= vecStride;
602 			entry.isRowMajor	= isRowMajor;
603 
604 			curOffset += numVecs*entry.matrixStride;
605 		}
606 		else
607 		{
608 			if (!(layoutFlags & LAYOUT_SCALAR) && (layoutFlags & LAYOUT_RELAXED) &&
609 				glu::isDataTypeVector(basicType) && (getDataTypeByteSize(basicType) <= 16 ? curOffset / 16 != (curOffset +  getDataTypeByteSize(basicType) - 1) / 16 : curOffset % 16 != 0))
610 				curOffset = deIntRoundToPow2(curOffset, 16);
611 
612 			// Scalar or vector.
613 			entry.offset = curOffset;
614 
615 			curOffset += getDataTypeByteSize(basicType);
616 		}
617 
618 		layout.uniforms.push_back(entry);
619 	}
620 	else if (type.isArrayType())
621 	{
622 		const VarType&	elemType	= type.getElementType();
623 
624 		if (elemType.isBasicType() && !glu::isDataTypeMatrix(elemType.getBasicType()))
625 		{
626 			// Array of scalars or vectors.
627 			const glu::DataType		elemBasicType	= elemType.getBasicType();
628 			const int				stride			= (layoutFlags & LAYOUT_SCALAR) ? getDataTypeByteSize(elemBasicType) : baseAlignment;
629 			UniformLayoutEntry		entry;
630 
631 			entry.name					= curPrefix + "[0]"; // Array variables are always postfixed with [0]
632 			entry.type					= elemBasicType;
633 			entry.blockNdx				= curBlockNdx;
634 			entry.offset				= curOffset;
635 			entry.arraySize				= type.getArraySize();
636 			entry.arrayStride			= stride;
637 			entry.matrixStride			= 0;
638 			entry.topLevelArraySize		= topLevelArraySize;
639 			entry.topLevelArrayStride	= topLevelArrayStride;
640 
641 			curOffset += stride*type.getArraySize();
642 
643 			layout.uniforms.push_back(entry);
644 		}
645 		else if (elemType.isBasicType() && glu::isDataTypeMatrix(elemType.getBasicType()))
646 		{
647 			// Array of matrices.
648 			const glu::DataType			elemBasicType	= elemType.getBasicType();
649 			const bool					isRowMajor		= !!(layoutFlags & LAYOUT_ROW_MAJOR);
650 			const int					vecSize			= isRowMajor ? glu::getDataTypeMatrixNumColumns(elemBasicType)
651 																	 : glu::getDataTypeMatrixNumRows(elemBasicType);
652 			const glu::DataType			vecType			= glu::getDataTypeFloatVec(vecSize);
653 			const int					numVecs			= isRowMajor ? glu::getDataTypeMatrixNumRows(elemBasicType)
654 																	 : glu::getDataTypeMatrixNumColumns(elemBasicType);
655 			const int					vecStride		= (layoutFlags & LAYOUT_SCALAR) ? getDataTypeByteSize(vecType) : baseAlignment;
656 			UniformLayoutEntry			entry;
657 
658 			entry.name					= curPrefix + "[0]"; // Array variables are always postfixed with [0]
659 			entry.type					= elemBasicType;
660 			entry.blockNdx				= curBlockNdx;
661 			entry.offset				= curOffset;
662 			entry.arraySize				= type.getArraySize();
663 			entry.arrayStride			= vecStride*numVecs;
664 			entry.matrixStride			= vecStride;
665 			entry.isRowMajor			= isRowMajor;
666 			entry.topLevelArraySize		= topLevelArraySize;
667 			entry.topLevelArrayStride	= topLevelArrayStride;
668 
669 			curOffset += entry.arrayStride*type.getArraySize();
670 
671 			layout.uniforms.push_back(entry);
672 		}
673 		else
674 		{
675 			DE_ASSERT(elemType.isStructType() || elemType.isArrayType());
676 
677 			for (int elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++)
678 				curOffset += computeReferenceLayout(layout, curBlockNdx, curOffset, curPrefix + "[" + de::toString(elemNdx) + "]", type.getElementType(), layoutFlags);
679 		}
680 	}
681 	else
682 	{
683 		DE_ASSERT(type.isStructType());
684 
685 		for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++)
686 			curOffset += computeReferenceLayout(layout, curBlockNdx, curOffset, curPrefix + "." + memberIter->getName(), memberIter->getType(), layoutFlags);
687 
688 		if (!(layoutFlags & LAYOUT_SCALAR))
689 			curOffset = deAlign32(curOffset, baseAlignment);
690 	}
691 
692 	return curOffset-baseOffset;
693 }
694 
computeReferenceLayout(UniformLayout & layout,const ShaderInterface & interface)695 void computeReferenceLayout (UniformLayout& layout, const ShaderInterface& interface)
696 {
697 	int numUniformBlocks = interface.getNumUniformBlocks();
698 
699 	for (int blockNdx = 0; blockNdx < numUniformBlocks; blockNdx++)
700 	{
701 		const UniformBlock&	block			= interface.getUniformBlock(blockNdx);
702 		bool				hasInstanceName	= block.hasInstanceName();
703 		std::string			blockPrefix		= hasInstanceName ? (block.getBlockName() + ".") : "";
704 		int					curOffset		= 0;
705 		int					activeBlockNdx	= (int)layout.blocks.size();
706 		int					firstUniformNdx	= (int)layout.uniforms.size();
707 
708 		for (UniformBlock::ConstIterator uniformIter = block.begin(); uniformIter != block.end(); uniformIter++)
709 		{
710 			const Uniform& uniform = *uniformIter;
711 			curOffset += computeReferenceLayout(layout, activeBlockNdx, curOffset, blockPrefix + uniform.getName(), uniform.getType(), mergeLayoutFlags(block.getFlags(), uniform.getFlags()));
712 		}
713 
714 		int	uniformIndicesEnd	= (int)layout.uniforms.size();
715 		int	blockSize			= curOffset;
716 		int	numInstances		= block.isArray() ? block.getArraySize() : 1;
717 
718 		// Create block layout entries for each instance.
719 		for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
720 		{
721 			// Allocate entry for instance.
722 			layout.blocks.push_back(BlockLayoutEntry());
723 			BlockLayoutEntry& blockEntry = layout.blocks.back();
724 
725 			blockEntry.name = block.getBlockName();
726 			blockEntry.size = blockSize;
727 			blockEntry.bindingNdx = blockNdx;
728 			blockEntry.blockDeclarationNdx = blockNdx;
729 			blockEntry.instanceNdx = instanceNdx;
730 
731 			// Compute active uniform set for block.
732 			for (int uniformNdx = firstUniformNdx; uniformNdx < uniformIndicesEnd; uniformNdx++)
733 				blockEntry.activeUniformIndices.push_back(uniformNdx);
734 
735 			if (block.isArray())
736 				blockEntry.name += "[" + de::toString(instanceNdx) + "]";
737 		}
738 	}
739 }
740 
741 // Value generator.
742 
generateValue(const UniformLayoutEntry & entry,void * basePtr,de::Random & rnd)743 void generateValue (const UniformLayoutEntry& entry, void* basePtr, de::Random& rnd)
744 {
745 	glu::DataType	scalarType		= glu::getDataTypeScalarType(entry.type);
746 	int				scalarSize		= glu::getDataTypeScalarSize(entry.type);
747 	bool			isMatrix		= glu::isDataTypeMatrix(entry.type);
748 	int				numVecs			= isMatrix ? (entry.isRowMajor ? glu::getDataTypeMatrixNumRows(entry.type) : glu::getDataTypeMatrixNumColumns(entry.type)) : 1;
749 	int				vecSize			= scalarSize / numVecs;
750 	bool			isArray			= entry.size > 1;
751 	const size_t	compSize		= getDataTypeByteSize(scalarType);
752 
753 	DE_ASSERT(scalarSize%numVecs == 0);
754 
755 	for (int elemNdx = 0; elemNdx < entry.size; elemNdx++)
756 	{
757 		deUint8* elemPtr = (deUint8*)basePtr + entry.offset + (isArray ? elemNdx*entry.arrayStride : 0);
758 
759 		for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
760 		{
761 			deUint8* vecPtr = elemPtr + (isMatrix ? vecNdx*entry.matrixStride : 0);
762 
763 			for (int compNdx = 0; compNdx < vecSize; compNdx++)
764 			{
765 				deUint8* compPtr = vecPtr + compSize*compNdx;
766 
767 				switch (scalarType)
768 				{
769 					case glu::TYPE_FLOAT:	*((float*)compPtr)		= (float)rnd.getInt(-9, 9);						break;
770 					case glu::TYPE_INT:		*((int*)compPtr)		= rnd.getInt(-9, 9);							break;
771 					case glu::TYPE_UINT:	*((deUint32*)compPtr)	= (deUint32)rnd.getInt(0, 9);					break;
772 					case glu::TYPE_INT8:	*((deInt8*)compPtr)		= (deInt8)rnd.getInt(-9, 9);					break;
773 					case glu::TYPE_UINT8:	*((deUint8*)compPtr)	= (deUint8)rnd.getInt(0, 9);					break;
774 					case glu::TYPE_INT16:	*((deInt16*)compPtr)	= (deInt16)rnd.getInt(-9, 9);					break;
775 					case glu::TYPE_UINT16:	*((deUint16*)compPtr)	= (deUint16)rnd.getInt(0, 9);					break;
776 					case glu::TYPE_FLOAT16:	*((deFloat16*)compPtr)	= deFloat32To16((float)rnd.getInt(-9, 9));		break;
777 					// \note Random bit pattern is used for true values. Spec states that all non-zero values are
778 					//       interpreted as true but some implementations fail this.
779 					case glu::TYPE_BOOL:	*((deUint32*)compPtr)	= rnd.getBool() ? rnd.getUint32()|1u : 0u;		break;
780 					default:
781 						DE_ASSERT(false);
782 				}
783 			}
784 		}
785 	}
786 }
787 
generateValues(const UniformLayout & layout,const std::map<int,void * > & blockPointers,deUint32 seed)788 void generateValues (const UniformLayout& layout, const std::map<int, void*>& blockPointers, deUint32 seed)
789 {
790 	de::Random	rnd			(seed);
791 	int			numBlocks	= (int)layout.blocks.size();
792 
793 	for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
794 	{
795 		void*	basePtr		= blockPointers.find(blockNdx)->second;
796 		int		numEntries	= (int)layout.blocks[blockNdx].activeUniformIndices.size();
797 
798 		for (int entryNdx = 0; entryNdx < numEntries; entryNdx++)
799 		{
800 			const UniformLayoutEntry& entry = layout.uniforms[layout.blocks[blockNdx].activeUniformIndices[entryNdx]];
801 			generateValue(entry, basePtr, rnd);
802 		}
803 	}
804 }
805 
806 // Shader generator.
807 
getCompareFuncForType(glu::DataType type)808 const char* getCompareFuncForType (glu::DataType type)
809 {
810 	switch (type)
811 	{
812 		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";
813 		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";
814 		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";
815 		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";
816 		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";
817 		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";
818 		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";
819 		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";
820 		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";
821 		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";
822 		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";
823 		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";
824 		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";
825 		case glu::TYPE_INT:				return "mediump float compare_int      (highp int a, highp int b)      { return a == b ? 1.0 : 0.0; }\n";
826 		case glu::TYPE_INT_VEC2:		return "mediump float compare_ivec2    (highp ivec2 a, highp ivec2 b)  { return a == b ? 1.0 : 0.0; }\n";
827 		case glu::TYPE_INT_VEC3:		return "mediump float compare_ivec3    (highp ivec3 a, highp ivec3 b)  { return a == b ? 1.0 : 0.0; }\n";
828 		case glu::TYPE_INT_VEC4:		return "mediump float compare_ivec4    (highp ivec4 a, highp ivec4 b)  { return a == b ? 1.0 : 0.0; }\n";
829 		case glu::TYPE_UINT:			return "mediump float compare_uint     (highp uint a, highp uint b)    { return a == b ? 1.0 : 0.0; }\n";
830 		case glu::TYPE_UINT_VEC2:		return "mediump float compare_uvec2    (highp uvec2 a, highp uvec2 b)  { return a == b ? 1.0 : 0.0; }\n";
831 		case glu::TYPE_UINT_VEC3:		return "mediump float compare_uvec3    (highp uvec3 a, highp uvec3 b)  { return a == b ? 1.0 : 0.0; }\n";
832 		case glu::TYPE_UINT_VEC4:		return "mediump float compare_uvec4    (highp uvec4 a, highp uvec4 b)  { return a == b ? 1.0 : 0.0; }\n";
833 		case glu::TYPE_BOOL:			return "mediump float compare_bool     (bool a, bool b)                { return a == b ? 1.0 : 0.0; }\n";
834 		case glu::TYPE_BOOL_VEC2:		return "mediump float compare_bvec2    (bvec2 a, bvec2 b)              { return a == b ? 1.0 : 0.0; }\n";
835 		case glu::TYPE_BOOL_VEC3:		return "mediump float compare_bvec3    (bvec3 a, bvec3 b)              { return a == b ? 1.0 : 0.0; }\n";
836 		case glu::TYPE_BOOL_VEC4:		return "mediump float compare_bvec4    (bvec4 a, bvec4 b)              { return a == b ? 1.0 : 0.0; }\n";
837 		case glu::TYPE_FLOAT16:			return "mediump float compare_float16_t(highp float a, highp float b)  { return abs(a - b) < 0.05 ? 1.0 : 0.0; }\n";
838 		case glu::TYPE_FLOAT16_VEC2:	return "mediump float compare_f16vec2  (highp vec2 a, highp vec2 b)    { return compare_float(a.x, b.x)*compare_float(a.y, b.y); }\n";
839 		case glu::TYPE_FLOAT16_VEC3:	return "mediump float compare_f16vec3  (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";
840 		case glu::TYPE_FLOAT16_VEC4:	return "mediump float compare_f16vec4  (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";
841 		case glu::TYPE_INT8:			return "mediump float compare_int8_t   (highp int a, highp int b)      { return a == b ? 1.0 : 0.0; }\n";
842 		case glu::TYPE_INT8_VEC2:		return "mediump float compare_i8vec2   (highp ivec2 a, highp ivec2 b)  { return a == b ? 1.0 : 0.0; }\n";
843 		case glu::TYPE_INT8_VEC3:		return "mediump float compare_i8vec3   (highp ivec3 a, highp ivec3 b)  { return a == b ? 1.0 : 0.0; }\n";
844 		case glu::TYPE_INT8_VEC4:		return "mediump float compare_i8vec4   (highp ivec4 a, highp ivec4 b)  { return a == b ? 1.0 : 0.0; }\n";
845 		case glu::TYPE_UINT8:			return "mediump float compare_uint8_t  (highp uint a, highp uint b)    { return a == b ? 1.0 : 0.0; }\n";
846 		case glu::TYPE_UINT8_VEC2:		return "mediump float compare_u8vec2   (highp uvec2 a, highp uvec2 b)  { return a == b ? 1.0 : 0.0; }\n";
847 		case glu::TYPE_UINT8_VEC3:		return "mediump float compare_u8vec3   (highp uvec3 a, highp uvec3 b)  { return a == b ? 1.0 : 0.0; }\n";
848 		case glu::TYPE_UINT8_VEC4:		return "mediump float compare_u8vec4   (highp uvec4 a, highp uvec4 b)  { return a == b ? 1.0 : 0.0; }\n";
849 		case glu::TYPE_INT16:			return "mediump float compare_int16_t  (highp int a, highp int b)      { return a == b ? 1.0 : 0.0; }\n";
850 		case glu::TYPE_INT16_VEC2:		return "mediump float compare_i16vec2  (highp ivec2 a, highp ivec2 b)  { return a == b ? 1.0 : 0.0; }\n";
851 		case glu::TYPE_INT16_VEC3:		return "mediump float compare_i16vec3  (highp ivec3 a, highp ivec3 b)  { return a == b ? 1.0 : 0.0; }\n";
852 		case glu::TYPE_INT16_VEC4:		return "mediump float compare_i16vec4  (highp ivec4 a, highp ivec4 b)  { return a == b ? 1.0 : 0.0; }\n";
853 		case glu::TYPE_UINT16:			return "mediump float compare_uint16_t (highp uint a, highp uint b)    { return a == b ? 1.0 : 0.0; }\n";
854 		case glu::TYPE_UINT16_VEC2:		return "mediump float compare_u16vec2  (highp uvec2 a, highp uvec2 b)  { return a == b ? 1.0 : 0.0; }\n";
855 		case glu::TYPE_UINT16_VEC3:		return "mediump float compare_u16vec3  (highp uvec3 a, highp uvec3 b)  { return a == b ? 1.0 : 0.0; }\n";
856 		case glu::TYPE_UINT16_VEC4:		return "mediump float compare_u16vec4  (highp uvec4 a, highp uvec4 b)  { return a == b ? 1.0 : 0.0; }\n";
857 		default:
858 			DE_ASSERT(false);
859 			return DE_NULL;
860 	}
861 }
862 
getCompareDependencies(std::set<glu::DataType> & compareFuncs,glu::DataType basicType)863 void getCompareDependencies (std::set<glu::DataType>& compareFuncs, glu::DataType basicType)
864 {
865 	switch (basicType)
866 	{
867 		case glu::TYPE_FLOAT_VEC2:
868 		case glu::TYPE_FLOAT_VEC3:
869 		case glu::TYPE_FLOAT_VEC4:
870 		case glu::TYPE_FLOAT16_VEC2:
871 		case glu::TYPE_FLOAT16_VEC3:
872 		case glu::TYPE_FLOAT16_VEC4:
873 			compareFuncs.insert(glu::TYPE_FLOAT);
874 			compareFuncs.insert(basicType);
875 			break;
876 
877 		case glu::TYPE_FLOAT_MAT2:
878 		case glu::TYPE_FLOAT_MAT2X3:
879 		case glu::TYPE_FLOAT_MAT2X4:
880 		case glu::TYPE_FLOAT_MAT3X2:
881 		case glu::TYPE_FLOAT_MAT3:
882 		case glu::TYPE_FLOAT_MAT3X4:
883 		case glu::TYPE_FLOAT_MAT4X2:
884 		case glu::TYPE_FLOAT_MAT4X3:
885 		case glu::TYPE_FLOAT_MAT4:
886 			compareFuncs.insert(glu::TYPE_FLOAT);
887 			compareFuncs.insert(glu::getDataTypeFloatVec(glu::getDataTypeMatrixNumRows(basicType)));
888 			compareFuncs.insert(basicType);
889 			break;
890 
891 		default:
892 			compareFuncs.insert(basicType);
893 			break;
894 	}
895 }
896 
collectUniqueBasicTypes(std::set<glu::DataType> & basicTypes,const VarType & type)897 void collectUniqueBasicTypes (std::set<glu::DataType>& basicTypes, const VarType& type)
898 {
899 	if (type.isStructType())
900 	{
901 		for (StructType::ConstIterator iter = type.getStruct().begin(); iter != type.getStruct().end(); ++iter)
902 			collectUniqueBasicTypes(basicTypes, iter->getType());
903 	}
904 	else if (type.isArrayType())
905 		collectUniqueBasicTypes(basicTypes, type.getElementType());
906 	else
907 	{
908 		DE_ASSERT(type.isBasicType());
909 		basicTypes.insert(type.getBasicType());
910 	}
911 }
912 
collectUniqueBasicTypes(std::set<glu::DataType> & basicTypes,const UniformBlock & uniformBlock)913 void collectUniqueBasicTypes (std::set<glu::DataType>& basicTypes, const UniformBlock& uniformBlock)
914 {
915 	for (UniformBlock::ConstIterator iter = uniformBlock.begin(); iter != uniformBlock.end(); ++iter)
916 		collectUniqueBasicTypes(basicTypes, iter->getType());
917 }
918 
collectUniqueBasicTypes(std::set<glu::DataType> & basicTypes,const ShaderInterface & interface)919 void collectUniqueBasicTypes (std::set<glu::DataType>& basicTypes, const ShaderInterface& interface)
920 {
921 	for (int ndx = 0; ndx < interface.getNumUniformBlocks(); ++ndx)
922 		collectUniqueBasicTypes(basicTypes, interface.getUniformBlock(ndx));
923 }
924 
generateCompareFuncs(std::ostream & str,const ShaderInterface & interface)925 void generateCompareFuncs (std::ostream& str, const ShaderInterface& interface)
926 {
927 	std::set<glu::DataType> types;
928 	std::set<glu::DataType> compareFuncs;
929 
930 	// Collect unique basic types
931 	collectUniqueBasicTypes(types, interface);
932 
933 	// Set of compare functions required
934 	for (std::set<glu::DataType>::const_iterator iter = types.begin(); iter != types.end(); ++iter)
935 	{
936 		getCompareDependencies(compareFuncs, *iter);
937 	}
938 
939 	for (int type = 0; type < glu::TYPE_LAST; ++type)
940 	{
941 		if (compareFuncs.find(glu::DataType(type)) != compareFuncs.end())
942 			str << getCompareFuncForType(glu::DataType(type));
943 	}
944 }
945 
uses16BitStorage(const ShaderInterface & interface)946 bool uses16BitStorage (const ShaderInterface& interface)
947 {
948 	// If any of blocks has LAYOUT_16BIT_STORAGE flag
949 	for (int ndx = 0; ndx < interface.getNumUniformBlocks(); ++ndx)
950 	{
951 		if (interface.getUniformBlock(ndx).getFlags() & LAYOUT_16BIT_STORAGE)
952 			return true;
953 	}
954 	return false;
955 }
956 
uses8BitStorage(const ShaderInterface & interface)957 bool uses8BitStorage (const ShaderInterface& interface)
958 {
959 	// If any of blocks has LAYOUT_8BIT_STORAGE flag
960 	for (int ndx = 0; ndx < interface.getNumUniformBlocks(); ++ndx)
961 	{
962 		if (interface.getUniformBlock(ndx).getFlags() & LAYOUT_8BIT_STORAGE)
963 			return true;
964 	}
965 	return false;
966 }
967 
usesScalarOrStd430Layout(const ShaderInterface & interface)968 bool usesScalarOrStd430Layout (const ShaderInterface& interface)
969 {
970 	// If any of blocks has LAYOUT_SCALAR or LAYOUT_STD430 flags
971 	for (int ndx = 0; ndx < interface.getNumUniformBlocks(); ++ndx)
972 	{
973 		if (interface.getUniformBlock(ndx).getFlags() & (LAYOUT_SCALAR | LAYOUT_STD430))
974 			return true;
975 	}
976 	return false;
977 }
978 
979 struct Indent
980 {
981 	int level;
Indentvkt::ubo::__anon0393f7100111::Indent982 	Indent (int level_) : level(level_) {}
983 };
984 
operator <<(std::ostream & str,const Indent & indent)985 std::ostream& operator<< (std::ostream& str, const Indent& indent)
986 {
987 	for (int i = 0; i < indent.level; i++)
988 		str << "\t";
989 	return str;
990 }
991 
992 void		generateDeclaration			(std::ostringstream& src, const VarType& type, const std::string& name, int indentLevel, deUint32 unusedHints, deUint32 flagsMask, deUint32 offset);
993 void		generateDeclaration			(std::ostringstream& src, const Uniform& uniform, int indentLevel, deUint32 offset);
994 void		generateDeclaration			(std::ostringstream& src, const StructType& structType, int indentLevel);
995 
996 void		generateLocalDeclaration	(std::ostringstream& src, const StructType& structType, int indentLevel);
997 void		generateFullDeclaration		(std::ostringstream& src, const StructType& structType, int indentLevel);
998 
generateDeclaration(std::ostringstream & src,const StructType & structType,int indentLevel)999 void generateDeclaration (std::ostringstream& src, const StructType& structType, int indentLevel)
1000 {
1001 	DE_ASSERT(structType.hasTypeName());
1002 	generateFullDeclaration(src, structType, indentLevel);
1003 	src << ";\n";
1004 }
1005 
generateFullDeclaration(std::ostringstream & src,const StructType & structType,int indentLevel)1006 void generateFullDeclaration (std::ostringstream& src, const StructType& structType, int indentLevel)
1007 {
1008 	src << "struct";
1009 	if (structType.hasTypeName())
1010 		src << " " << structType.getTypeName();
1011 	src << "\n" << Indent(indentLevel) << "{\n";
1012 
1013 	for (StructType::ConstIterator memberIter = structType.begin(); memberIter != structType.end(); memberIter++)
1014 	{
1015 		src << Indent(indentLevel + 1);
1016 		generateDeclaration(src, memberIter->getType(), memberIter->getName(), indentLevel + 1, memberIter->getFlags() & UNUSED_BOTH, ~LAYOUT_OFFSET, 0u);
1017 	}
1018 
1019 	src << Indent(indentLevel) << "}";
1020 }
1021 
generateLocalDeclaration(std::ostringstream & src,const StructType & structType,int)1022 void generateLocalDeclaration (std::ostringstream& src, const StructType& structType, int /* indentLevel */)
1023 {
1024 	src << structType.getTypeName();
1025 }
1026 
generateLayoutAndPrecisionDeclaration(std::ostringstream & src,deUint32 flags,deUint32 offset)1027 void generateLayoutAndPrecisionDeclaration (std::ostringstream& src, deUint32 flags, deUint32 offset)
1028 {
1029 	if ((flags & LAYOUT_MASK) != 0)
1030 		src << "layout(" << LayoutFlagsFmt(flags & LAYOUT_MASK, offset) << ") ";
1031 
1032 	if ((flags & PRECISION_MASK) != 0)
1033 		src << PrecisionFlagsFmt(flags & PRECISION_MASK) << " ";
1034 }
1035 
generateDeclaration(std::ostringstream & src,const VarType & type,const std::string & name,int indentLevel,deUint32 unusedHints,deUint32 flagsMask,deUint32 offset)1036 void generateDeclaration (std::ostringstream& src, const VarType& type, const std::string& name, int indentLevel, deUint32 unusedHints, deUint32 flagsMask, deUint32 offset)
1037 {
1038 	generateLayoutAndPrecisionDeclaration(src, type.getFlags() & flagsMask, offset);
1039 
1040 	if (type.isBasicType())
1041 		src << glu::getDataTypeName(type.getBasicType()) << " " << name;
1042 	else if (type.isArrayType())
1043 	{
1044 		std::vector<int>	arraySizes;
1045 		const VarType*		curType		= &type;
1046 		while (curType->isArrayType())
1047 		{
1048 			arraySizes.push_back(curType->getArraySize());
1049 			curType = &curType->getElementType();
1050 		}
1051 
1052 		generateLayoutAndPrecisionDeclaration(src, curType->getFlags() & flagsMask, offset);
1053 
1054 		if (curType->isBasicType())
1055 			src << glu::getDataTypeName(curType->getBasicType());
1056 		else
1057 		{
1058 			DE_ASSERT(curType->isStructType());
1059 			generateLocalDeclaration(src, curType->getStruct(), indentLevel+1);
1060 		}
1061 
1062 		src << " " << name;
1063 
1064 		for (std::vector<int>::const_iterator sizeIter = arraySizes.begin(); sizeIter != arraySizes.end(); sizeIter++)
1065 			src << "[" << *sizeIter << "]";
1066 	}
1067 	else
1068 	{
1069 		generateLocalDeclaration(src, type.getStruct(), indentLevel+1);
1070 		src << " " << name;
1071 	}
1072 
1073 	src << ";";
1074 
1075 	// Print out unused hints.
1076 	if (unusedHints != 0)
1077 		src << " // unused in " << (unusedHints == UNUSED_BOTH		? "both shaders"	:
1078 									unusedHints == UNUSED_VERTEX	? "vertex shader"	:
1079 									unusedHints == UNUSED_FRAGMENT	? "fragment shader" : "???");
1080 
1081 	src << "\n";
1082 }
1083 
generateDeclaration(std::ostringstream & src,const Uniform & uniform,int indentLevel,deUint32 offset)1084 void generateDeclaration (std::ostringstream& src, const Uniform& uniform, int indentLevel, deUint32 offset)
1085 {
1086 	if ((uniform.getFlags() & LAYOUT_MASK) != 0)
1087 		src << "layout(" << LayoutFlagsFmt(uniform.getFlags() & LAYOUT_MASK) << ") ";
1088 
1089 	generateDeclaration(src, uniform.getType(), uniform.getName(), indentLevel, uniform.getFlags() & UNUSED_BOTH, ~0u, offset);
1090 }
1091 
getBlockMemberOffset(int blockNdx,const UniformBlock & block,const Uniform & uniform,const UniformLayout & layout)1092 deUint32 getBlockMemberOffset (int blockNdx, const UniformBlock& block, const Uniform& uniform, const UniformLayout& layout)
1093 {
1094 	std::ostringstream	name;
1095 	const VarType*		curType = &uniform.getType();
1096 
1097 	if (block.getInstanceName().length() != 0)
1098 		name << block.getBlockName() << ".";	// \note UniformLayoutEntry uses block name rather than instance name
1099 
1100 	name << uniform.getName();
1101 
1102 	while (!curType->isBasicType())
1103 	{
1104 		if (curType->isArrayType())
1105 		{
1106 			name << "[0]";
1107 			curType = &curType->getElementType();
1108 		}
1109 
1110 		if (curType->isStructType())
1111 		{
1112 			const StructType::ConstIterator firstMember = curType->getStruct().begin();
1113 			name << "." << firstMember->getName();
1114 			curType = &firstMember->getType();
1115 		}
1116 	}
1117 
1118 	const int uniformNdx = layout.getUniformLayoutIndex(blockNdx, name.str());
1119 	DE_ASSERT(uniformNdx >= 0);
1120 
1121 	return layout.uniforms[uniformNdx].offset;
1122 }
1123 
1124 template<typename T>
semiShuffle(std::vector<T> & v)1125 void semiShuffle (std::vector<T>& v)
1126 {
1127 	const std::vector<T>	src	= v;
1128 	int						i	= -1;
1129 	int						n	= static_cast<int>(src.size());
1130 
1131 	v.clear();
1132 
1133 	while (n)
1134 	{
1135 		i += n;
1136 		v.push_back(src[i]);
1137 		n = (n > 0 ? 1 - n : -1 - n);
1138 	}
1139 }
1140 
1141 template<typename T>
1142 //! \note Stores pointers to original elements
1143 class Traverser
1144 {
1145 public:
1146 	template<typename Iter>
Traverser(const Iter beg,const Iter end,const bool shuffled)1147 	Traverser (const Iter beg, const Iter end, const bool shuffled)
1148 	{
1149 		for (Iter it = beg; it != end; ++it)
1150 			m_elements.push_back(&(*it));
1151 
1152 		if (shuffled)
1153 			semiShuffle(m_elements);
1154 
1155 		m_next = m_elements.begin();
1156 	}
1157 
next(void)1158 	T* next (void)
1159 	{
1160 		if (m_next != m_elements.end())
1161 			return *m_next++;
1162 		else
1163 			return DE_NULL;
1164 	}
1165 
1166 private:
1167 	typename std::vector<T*>					m_elements;
1168 	typename std::vector<T*>::const_iterator	m_next;
1169 };
1170 
getPromoteType(glu::DataType type)1171 glu::DataType getPromoteType(glu::DataType type)
1172 {
1173 	switch (type)
1174 	{
1175 	case glu::TYPE_UINT8:			return glu::TYPE_UINT;
1176 	case glu::TYPE_UINT8_VEC2:		return glu::TYPE_UINT_VEC2;
1177 	case glu::TYPE_UINT8_VEC3:		return glu::TYPE_UINT_VEC3;
1178 	case glu::TYPE_UINT8_VEC4:		return glu::TYPE_UINT_VEC4;
1179 	case glu::TYPE_INT8:			return glu::TYPE_INT;
1180 	case glu::TYPE_INT8_VEC2:		return glu::TYPE_INT_VEC2;
1181 	case glu::TYPE_INT8_VEC3:		return glu::TYPE_INT_VEC3;
1182 	case glu::TYPE_INT8_VEC4:		return glu::TYPE_INT_VEC4;
1183 	case glu::TYPE_UINT16:			return glu::TYPE_UINT;
1184 	case glu::TYPE_UINT16_VEC2:		return glu::TYPE_UINT_VEC2;
1185 	case glu::TYPE_UINT16_VEC3:		return glu::TYPE_UINT_VEC3;
1186 	case glu::TYPE_UINT16_VEC4:		return glu::TYPE_UINT_VEC4;
1187 	case glu::TYPE_INT16:			return glu::TYPE_INT;
1188 	case glu::TYPE_INT16_VEC2:		return glu::TYPE_INT_VEC2;
1189 	case glu::TYPE_INT16_VEC3:		return glu::TYPE_INT_VEC3;
1190 	case glu::TYPE_INT16_VEC4:		return glu::TYPE_INT_VEC4;
1191 	case glu::TYPE_FLOAT16:			return glu::TYPE_FLOAT;
1192 	case glu::TYPE_FLOAT16_VEC2:	return glu::TYPE_FLOAT_VEC2;
1193 	case glu::TYPE_FLOAT16_VEC3:	return glu::TYPE_FLOAT_VEC3;
1194 	case glu::TYPE_FLOAT16_VEC4:	return glu::TYPE_FLOAT_VEC4;
1195 	default: return type;
1196 	}
1197 }
1198 
generateDeclaration(std::ostringstream & src,int blockNdx,const UniformBlock & block,const UniformLayout & layout,bool shuffleUniformMembers)1199 void generateDeclaration (std::ostringstream& src, int blockNdx, const UniformBlock& block, const UniformLayout& layout, bool shuffleUniformMembers)
1200 {
1201 	src << "layout(set = 0, binding = " << blockNdx;
1202 	if ((block.getFlags() & LAYOUT_MASK) != 0)
1203 		src << ", " << LayoutFlagsFmt(block.getFlags() & LAYOUT_MASK);
1204 	src << ") ";
1205 
1206 	src << "uniform " << block.getBlockName();
1207 	src << "\n{\n";
1208 
1209 	Traverser<const Uniform> uniforms(block.begin(), block.end(), shuffleUniformMembers);
1210 
1211 	while (const Uniform* pUniform = uniforms.next())
1212 	{
1213 		src << Indent(1);
1214 		generateDeclaration(src, *pUniform, 1 /* indent level */, getBlockMemberOffset(blockNdx, block, *pUniform, layout));
1215 	}
1216 
1217 	src << "}";
1218 
1219 	if (block.hasInstanceName())
1220 	{
1221 		src << " " << block.getInstanceName();
1222 		if (block.isArray())
1223 			src << "[" << block.getArraySize() << "]";
1224 	}
1225 	else
1226 		DE_ASSERT(!block.isArray());
1227 
1228 	src << ";\n";
1229 }
1230 
generateValueSrc(std::ostringstream & src,const UniformLayoutEntry & entry,const void * basePtr,int elementNdx)1231 void generateValueSrc (std::ostringstream& src, const UniformLayoutEntry& entry, const void* basePtr, int elementNdx)
1232 {
1233 	glu::DataType	scalarType		= glu::getDataTypeScalarType(entry.type);
1234 	int				scalarSize		= glu::getDataTypeScalarSize(entry.type);
1235 	bool			isArray			= entry.size > 1;
1236 	const deUint8*	elemPtr			= (const deUint8*)basePtr + entry.offset + (isArray ? elementNdx * entry.arrayStride : 0);
1237 	const size_t	compSize		= getDataTypeByteSize(scalarType);
1238 
1239 	if (scalarSize > 1)
1240 		src << glu::getDataTypeName(getPromoteType(entry.type)) << "(";
1241 
1242 	if (glu::isDataTypeMatrix(entry.type))
1243 	{
1244 		int	numRows	= glu::getDataTypeMatrixNumRows(entry.type);
1245 		int	numCols	= glu::getDataTypeMatrixNumColumns(entry.type);
1246 
1247 		DE_ASSERT(scalarType == glu::TYPE_FLOAT);
1248 
1249 		// Constructed in column-wise order.
1250 		for (int colNdx = 0; colNdx < numCols; colNdx++)
1251 		{
1252 			for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
1253 			{
1254 				const deUint8*	compPtr	= elemPtr + (entry.isRowMajor ? (rowNdx * entry.matrixStride + colNdx * compSize)
1255 																	  : (colNdx * entry.matrixStride + rowNdx * compSize));
1256 
1257 				if (colNdx > 0 || rowNdx > 0)
1258 					src << ", ";
1259 
1260 				src << de::floatToString(*((const float*)compPtr), 1);
1261 			}
1262 		}
1263 	}
1264 	else
1265 	{
1266 		for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
1267 		{
1268 			const deUint8* compPtr = elemPtr + scalarNdx * compSize;
1269 
1270 			if (scalarNdx > 0)
1271 				src << ", ";
1272 
1273 			switch (scalarType)
1274 			{
1275 				case glu::TYPE_FLOAT16:	src << de::floatToString(deFloat16To32(*((const deFloat16*)compPtr)), 1);	break;
1276 				case glu::TYPE_FLOAT:	src << de::floatToString(*((const float*)compPtr), 1);			break;
1277 				case glu::TYPE_INT8:	src << (deUint32)*((const deInt8*)compPtr);						break;
1278 				case glu::TYPE_INT16:	src << *((const deInt16*)compPtr);								break;
1279 				case glu::TYPE_INT:		src << *((const int*)compPtr);									break;
1280 				case glu::TYPE_UINT8:	src << (deUint32)*((const deUint8*)compPtr) << "u";				break;
1281 				case glu::TYPE_UINT16:	src << *((const deUint16*)compPtr) << "u";						break;
1282 				case glu::TYPE_UINT:	src << *((const deUint32*)compPtr) << "u";						break;
1283 				case glu::TYPE_BOOL:	src << (*((const deUint32*)compPtr) != 0u ? "true" : "false");	break;
1284 				default:
1285 					DE_ASSERT(false);
1286 			}
1287 		}
1288 	}
1289 
1290 	if (scalarSize > 1)
1291 		src << ")";
1292 }
1293 
isMatrix(glu::DataType elementType)1294 bool isMatrix (glu::DataType elementType)
1295 {
1296 	return (elementType >= glu::TYPE_FLOAT_MAT2) && (elementType <= glu::TYPE_FLOAT_MAT4);
1297 }
1298 
writeMatrixTypeSrc(int columnCount,int rowCount,std::string compare,std::string compareType,std::ostringstream & src,const std::string & srcName,const void * basePtr,const UniformLayoutEntry & entry,bool vector)1299 void writeMatrixTypeSrc (int						columnCount,
1300 						 int						rowCount,
1301 						 std::string				compare,
1302 						 std::string				compareType,
1303 						 std::ostringstream&		src,
1304 						 const std::string&			srcName,
1305 						 const void*				basePtr,
1306 						 const UniformLayoutEntry&	entry,
1307 						 bool						vector)
1308 {
1309 	if (vector)	// generateTestSrcMatrixPerVec
1310 	{
1311 		for (int colNdex = 0; colNdex < columnCount; colNdex++)
1312 		{
1313 			src << "\tresult *= " << compare + compareType << "(" << srcName << "[" << colNdex << "], ";
1314 
1315 			if (glu::isDataTypeMatrix(entry.type))
1316 			{
1317 				int	scalarSize = glu::getDataTypeScalarSize(entry.type);
1318 				const deUint8*	elemPtr			= (const deUint8*)basePtr + entry.offset;
1319 				const int		compSize		= sizeof(deUint32);
1320 
1321 				if (scalarSize > 1)
1322 					src << compareType << "(";
1323 				for (int rowNdex = 0; rowNdex < rowCount; rowNdex++)
1324 				{
1325 					const deUint8*	compPtr	= elemPtr + (entry.isRowMajor ? (rowNdex * entry.matrixStride + colNdex * compSize)
1326 																		  : (colNdex * entry.matrixStride + rowNdex * compSize));
1327 					src << de::floatToString(*((const float*)compPtr), 1);
1328 
1329 					if (rowNdex < rowCount-1)
1330 						src << ", ";
1331 				}
1332 				src << "));\n";
1333 			}
1334 			else
1335 			{
1336 				generateValueSrc(src, entry, basePtr, 0);
1337 				src << "[" << colNdex << "]);\n";
1338 			}
1339 		}
1340 	}
1341 	else		// generateTestSrcMatrixPerElement
1342 	{
1343 		for (int colNdex = 0; colNdex < columnCount; colNdex++)
1344 		{
1345 			for (int rowNdex = 0; rowNdex < rowCount; rowNdex++)
1346 			{
1347 				src << "\tresult *= " << compare + compareType << "(" << srcName << "[" << colNdex << "][" << rowNdex << "], ";
1348 				if (glu::isDataTypeMatrix(entry.type))
1349 				{
1350 					const deUint8*	elemPtr			= (const deUint8*)basePtr + entry.offset;
1351 					const int		compSize		= sizeof(deUint32);
1352 					const deUint8*	compPtr	= elemPtr + (entry.isRowMajor ? (rowNdex * entry.matrixStride + colNdex * compSize)
1353 																		  : (colNdex * entry.matrixStride + rowNdex * compSize));
1354 
1355 					src << de::floatToString(*((const float*)compPtr), 1) << ");\n";
1356 				}
1357 				else
1358 				{
1359 					generateValueSrc(src, entry, basePtr, 0);
1360 					src << "[" << colNdex << "][" << rowNdex << "]);\n";
1361 				}
1362 			}
1363 		}
1364 	}
1365 }
1366 
generateTestSrcMatrixPerVec(glu::DataType elementType,std::ostringstream & src,const std::string & srcName,const void * basePtr,const UniformLayoutEntry & entry,bool vector)1367 void generateTestSrcMatrixPerVec (glu::DataType				elementType,
1368 								  std::ostringstream&		src,
1369 								  const std::string&		srcName,
1370 								  const void*				basePtr,
1371 								  const UniformLayoutEntry&	entry,
1372 								  bool						vector)
1373 {
1374 	std::string compare = "compare_";
1375 	switch (elementType)
1376 	{
1377 		case glu::TYPE_FLOAT_MAT2:
1378 			writeMatrixTypeSrc(2, 2, compare, "vec2", src, srcName, basePtr, entry, vector);
1379 			break;
1380 
1381 		case glu::TYPE_FLOAT_MAT2X3:
1382 			writeMatrixTypeSrc(2, 3, compare, "vec3", src, srcName, basePtr, entry, vector);
1383 			break;
1384 
1385 		case glu::TYPE_FLOAT_MAT2X4:
1386 			writeMatrixTypeSrc(2, 4, compare, "vec4", src, srcName, basePtr, entry, vector);
1387 			break;
1388 
1389 		case glu::TYPE_FLOAT_MAT3X4:
1390 			writeMatrixTypeSrc(3, 4, compare, "vec4", src, srcName, basePtr, entry, vector);
1391 			break;
1392 
1393 		case glu::TYPE_FLOAT_MAT4:
1394 			writeMatrixTypeSrc(4, 4, compare, "vec4", src, srcName, basePtr, entry, vector);
1395 			break;
1396 
1397 		case glu::TYPE_FLOAT_MAT4X2:
1398 			writeMatrixTypeSrc(4, 2, compare, "vec2", src, srcName, basePtr, entry, vector);
1399 			break;
1400 
1401 		case glu::TYPE_FLOAT_MAT4X3:
1402 			writeMatrixTypeSrc(4, 3, compare, "vec3", src, srcName, basePtr, entry, vector);
1403 			break;
1404 
1405 		default:
1406 			break;
1407 	}
1408 }
1409 
generateTestSrcMatrixPerElement(glu::DataType elementType,std::ostringstream & src,const std::string & srcName,const void * basePtr,const UniformLayoutEntry & entry,bool vector)1410 void generateTestSrcMatrixPerElement (glu::DataType				elementType,
1411 									  std::ostringstream&		src,
1412 									  const std::string&		srcName,
1413 									  const void*				basePtr,
1414 									  const UniformLayoutEntry&	entry,
1415 									  bool						vector)
1416 {
1417 	std::string compare = "compare_";
1418 	std::string compareType = "float";
1419 	switch (elementType)
1420 	{
1421 		case glu::TYPE_FLOAT_MAT2:
1422 			writeMatrixTypeSrc(2, 2, compare, compareType, src, srcName, basePtr, entry, vector);
1423 			break;
1424 
1425 		case glu::TYPE_FLOAT_MAT2X3:
1426 			writeMatrixTypeSrc(2, 3, compare, compareType, src, srcName, basePtr, entry, vector);
1427 			break;
1428 
1429 		case glu::TYPE_FLOAT_MAT2X4:
1430 			writeMatrixTypeSrc(2, 4, compare, compareType, src, srcName, basePtr, entry, vector);
1431 			break;
1432 
1433 		case glu::TYPE_FLOAT_MAT3X4:
1434 			writeMatrixTypeSrc(3, 4, compare, compareType, src, srcName, basePtr, entry, vector);
1435 			break;
1436 
1437 		case glu::TYPE_FLOAT_MAT4:
1438 			writeMatrixTypeSrc(4, 4, compare, compareType, src, srcName, basePtr, entry, vector);
1439 			break;
1440 
1441 		case glu::TYPE_FLOAT_MAT4X2:
1442 			writeMatrixTypeSrc(4, 2, compare, compareType, src, srcName, basePtr, entry, vector);
1443 			break;
1444 
1445 		case glu::TYPE_FLOAT_MAT4X3:
1446 			writeMatrixTypeSrc(4, 3, compare, compareType, src, srcName, basePtr, entry, vector);
1447 			break;
1448 
1449 		default:
1450 			break;
1451 	}
1452 }
1453 
generateSingleCompare(std::ostringstream & src,glu::DataType elementType,const std::string & srcName,const void * basePtr,const UniformLayoutEntry & entry,MatrixLoadFlags matrixLoadFlag)1454 void generateSingleCompare (std::ostringstream&			src,
1455 							glu::DataType				elementType,
1456 							const std::string&			srcName,
1457 							const void*					basePtr,
1458 							const UniformLayoutEntry&	entry,
1459 							MatrixLoadFlags				matrixLoadFlag)
1460 {
1461 	if (matrixLoadFlag == LOAD_FULL_MATRIX)
1462 	{
1463 		const char* typeName = glu::getDataTypeName(elementType);
1464 		const char* castName = "";
1465 		glu::DataType promoteType = getPromoteType(elementType);
1466 		if (elementType != promoteType)
1467 		{
1468 			castName = glu::getDataTypeName(promoteType);
1469 		}
1470 
1471 		src << "\tresult *= compare_" << typeName << "(" << castName << "(" << srcName << "), ";
1472 		generateValueSrc(src, entry, basePtr, 0);
1473 		src << ");\n";
1474 	}
1475 	else
1476 	{
1477 		if (isMatrix(elementType))
1478 		{
1479 			generateTestSrcMatrixPerVec		(elementType, src, srcName, basePtr, entry, true);
1480 			generateTestSrcMatrixPerElement	(elementType, src, srcName, basePtr, entry, false);
1481 		}
1482 	}
1483 }
1484 
generateCompareSrc(std::ostringstream & src,const char * resultVar,const VarType & type,const std::string & srcName,const std::string & apiName,const UniformLayout & layout,int blockNdx,const void * basePtr,deUint32 unusedMask,MatrixLoadFlags matrixLoadFlag)1485 void generateCompareSrc (std::ostringstream&	src,
1486 						 const char*			resultVar,
1487 						 const VarType&			type,
1488 						 const std::string&		srcName,
1489 						 const std::string&		apiName,
1490 						 const UniformLayout&	layout,
1491 						 int					blockNdx,
1492 						 const void*			basePtr,
1493 						 deUint32				unusedMask,
1494 						 MatrixLoadFlags		matrixLoadFlag)
1495 {
1496 	if (type.isBasicType() || (type.isArrayType() && type.getElementType().isBasicType()))
1497 	{
1498 		// Basic type or array of basic types.
1499 		bool						isArray			= type.isArrayType();
1500 		glu::DataType				elementType		= isArray ? type.getElementType().getBasicType() : type.getBasicType();
1501 		const char*					typeName		= glu::getDataTypeName(elementType);
1502 		std::string					fullApiName		= std::string(apiName) + (isArray ? "[0]" : ""); // Arrays are always postfixed with [0]
1503 		int							uniformNdx		= layout.getUniformLayoutIndex(blockNdx, fullApiName);
1504 		const UniformLayoutEntry&	entry			= layout.uniforms[uniformNdx];
1505 
1506 		const char* castName = "";
1507 		glu::DataType promoteType = getPromoteType(elementType);
1508 		if (elementType != promoteType)
1509 		{
1510 			castName = glu::getDataTypeName(promoteType);
1511 		}
1512 
1513 		if (isArray)
1514 		{
1515 			for (int elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++)
1516 			{
1517 				src << "\tresult *= compare_" << typeName << "(" << castName << "(" << srcName << "[" << elemNdx << "]), ";
1518 				generateValueSrc(src, entry, basePtr, elemNdx);
1519 				src << ");\n";
1520 			}
1521 		}
1522 		else
1523 		{
1524 			generateSingleCompare(src, elementType, srcName, basePtr, entry, matrixLoadFlag);
1525 		}
1526 	}
1527 	else if (type.isArrayType())
1528 	{
1529 		const VarType& elementType = type.getElementType();
1530 
1531 		for (int elementNdx = 0; elementNdx < type.getArraySize(); elementNdx++)
1532 		{
1533 			std::string op = std::string("[") + de::toString(elementNdx) + "]";
1534 			std::string elementSrcName = std::string(srcName) + op;
1535 			std::string elementApiName = std::string(apiName) + op;
1536 			generateCompareSrc(src, resultVar, elementType, elementSrcName, elementApiName, layout, blockNdx, basePtr, unusedMask, LOAD_FULL_MATRIX);
1537 		}
1538 	}
1539 	else
1540 	{
1541 		DE_ASSERT(type.isStructType());
1542 
1543 		for (StructType::ConstIterator memberIter = type.getStruct().begin(); memberIter != type.getStruct().end(); memberIter++)
1544 		{
1545 			if (memberIter->getFlags() & unusedMask)
1546 				continue; // Skip member.
1547 
1548 			std::string op = std::string(".") + memberIter->getName();
1549 			std::string memberSrcName = std::string(srcName) + op;
1550 			std::string memberApiName = std::string(apiName) + op;
1551 			generateCompareSrc(src, resultVar, memberIter->getType(), memberSrcName, memberApiName, layout, blockNdx, basePtr, unusedMask, LOAD_FULL_MATRIX);
1552 		}
1553 	}
1554 }
1555 
generateCompareSrc(std::ostringstream & src,const char * resultVar,const ShaderInterface & interface,const UniformLayout & layout,const std::map<int,void * > & blockPointers,bool isVertex,MatrixLoadFlags matrixLoadFlag)1556 void generateCompareSrc (std::ostringstream& src,
1557 						 const char* resultVar,
1558 						 const ShaderInterface& interface,
1559 						 const UniformLayout& layout,
1560 						 const std::map<int,
1561 						 void*>& blockPointers,
1562 						 bool isVertex,
1563 						 MatrixLoadFlags matrixLoadFlag)
1564 {
1565 	deUint32 unusedMask = isVertex ? UNUSED_VERTEX : UNUSED_FRAGMENT;
1566 
1567 	for (int blockNdx = 0; blockNdx < interface.getNumUniformBlocks(); blockNdx++)
1568 	{
1569 		const UniformBlock& block = interface.getUniformBlock(blockNdx);
1570 
1571 		if ((block.getFlags() & (isVertex ? DECLARE_VERTEX : DECLARE_FRAGMENT)) == 0)
1572 			continue; // Skip.
1573 
1574 		bool			hasInstanceName	= block.hasInstanceName();
1575 		bool			isArray			= block.isArray();
1576 		int				numInstances	= isArray ? block.getArraySize() : 1;
1577 		std::string		apiPrefix		= hasInstanceName ? block.getBlockName() + "." : std::string("");
1578 
1579 		DE_ASSERT(!isArray || hasInstanceName);
1580 
1581 		for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1582 		{
1583 			std::string		instancePostfix		= isArray ? std::string("[") + de::toString(instanceNdx) + "]" : std::string("");
1584 			std::string		blockInstanceName	= block.getBlockName() + instancePostfix;
1585 			std::string		srcPrefix			= hasInstanceName ? block.getInstanceName() + instancePostfix + "." : std::string("");
1586 			int				blockLayoutNdx		= layout.getBlockLayoutIndex(blockNdx, instanceNdx);
1587 			void*			basePtr				= blockPointers.find(blockLayoutNdx)->second;
1588 
1589 			for (UniformBlock::ConstIterator uniformIter = block.begin(); uniformIter != block.end(); uniformIter++)
1590 			{
1591 				const Uniform& uniform = *uniformIter;
1592 
1593 				if (uniform.getFlags() & unusedMask)
1594 					continue; // Don't read from that uniform.
1595 
1596 				std::string srcName = srcPrefix + uniform.getName();
1597 				std::string apiName = apiPrefix + uniform.getName();
1598 				generateCompareSrc(src, resultVar, uniform.getType(), srcName, apiName, layout, blockNdx, basePtr, unusedMask, matrixLoadFlag);
1599 			}
1600 		}
1601 	}
1602 }
1603 
generateVertexShader(const ShaderInterface & interface,const UniformLayout & layout,const std::map<int,void * > & blockPointers,MatrixLoadFlags matrixLoadFlag,bool shuffleUniformMembers)1604 std::string generateVertexShader (const ShaderInterface& interface, const UniformLayout& layout, const std::map<int, void*>& blockPointers, MatrixLoadFlags matrixLoadFlag, bool shuffleUniformMembers)
1605 {
1606 	std::ostringstream src;
1607 	src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n";
1608 	src << "#extension GL_EXT_shader_16bit_storage : enable\n";
1609 	src << "#extension GL_EXT_shader_8bit_storage : enable\n";
1610 	src << "#extension GL_EXT_scalar_block_layout : enable\n";
1611 
1612 	src << "layout(location = 0) in highp vec4 a_position;\n";
1613 	src << "layout(location = 0) out mediump float v_vtxResult;\n";
1614 	src << "\n";
1615 
1616 	std::vector<const StructType*> namedStructs;
1617 	interface.getNamedStructs(namedStructs);
1618 	for (std::vector<const StructType*>::const_iterator structIter = namedStructs.begin(); structIter != namedStructs.end(); structIter++)
1619 		generateDeclaration(src, **structIter, 0);
1620 
1621 	for (int blockNdx = 0; blockNdx < interface.getNumUniformBlocks(); blockNdx++)
1622 	{
1623 		const UniformBlock& block = interface.getUniformBlock(blockNdx);
1624 		if (block.getFlags() & DECLARE_VERTEX)
1625 			generateDeclaration(src, blockNdx, block, layout, shuffleUniformMembers);
1626 	}
1627 
1628 	// Comparison utilities.
1629 	src << "\n";
1630 	generateCompareFuncs(src, interface);
1631 
1632 	src << "\n"
1633 		   "void main (void)\n"
1634 		   "{\n"
1635 		   "	gl_Position = a_position;\n"
1636 		   "	mediump float result = 1.0;\n";
1637 
1638 	// Value compare.
1639 	generateCompareSrc(src, "result", interface, layout, blockPointers, true, matrixLoadFlag);
1640 
1641 	src << "	v_vtxResult = result;\n"
1642 		   "}\n";
1643 
1644 	return src.str();
1645 }
1646 
generateFragmentShader(const ShaderInterface & interface,const UniformLayout & layout,const std::map<int,void * > & blockPointers,MatrixLoadFlags matrixLoadFlag,bool shuffleUniformMembers)1647 std::string generateFragmentShader (const ShaderInterface& interface, const UniformLayout& layout, const std::map<int, void*>& blockPointers, MatrixLoadFlags matrixLoadFlag, bool shuffleUniformMembers)
1648 {
1649 	std::ostringstream src;
1650 	src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n";
1651 	src << "#extension GL_EXT_shader_16bit_storage : enable\n";
1652 	src << "#extension GL_EXT_shader_8bit_storage : enable\n";
1653 	src << "#extension GL_EXT_scalar_block_layout : enable\n";
1654 
1655 	src << "layout(location = 0) in mediump float v_vtxResult;\n";
1656 	src << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
1657 	src << "\n";
1658 
1659 	std::vector<const StructType*> namedStructs;
1660 	interface.getNamedStructs(namedStructs);
1661 	for (std::vector<const StructType*>::const_iterator structIter = namedStructs.begin(); structIter != namedStructs.end(); structIter++)
1662 		generateDeclaration(src, **structIter, 0);
1663 
1664 	for (int blockNdx = 0; blockNdx < interface.getNumUniformBlocks(); blockNdx++)
1665 	{
1666 		const UniformBlock& block = interface.getUniformBlock(blockNdx);
1667 		if (block.getFlags() & DECLARE_FRAGMENT)
1668 			generateDeclaration(src, blockNdx, block, layout, shuffleUniformMembers);
1669 	}
1670 
1671 	// Comparison utilities.
1672 	src << "\n";
1673 	generateCompareFuncs(src, interface);
1674 
1675 	src << "\n"
1676 		   "void main (void)\n"
1677 		   "{\n"
1678 		   "	mediump float result = 1.0;\n";
1679 
1680 	// Value compare.
1681 	generateCompareSrc(src, "result", interface, layout, blockPointers, false, matrixLoadFlag);
1682 
1683 	src << "	dEQP_FragColor = vec4(1.0, v_vtxResult, result, 1.0);\n"
1684 		   "}\n";
1685 
1686 	return src.str();
1687 }
1688 
createBuffer(Context & context,VkDeviceSize bufferSize,vk::VkBufferUsageFlags usageFlags)1689 Move<VkBuffer> createBuffer (Context& context, VkDeviceSize bufferSize, vk::VkBufferUsageFlags usageFlags)
1690 {
1691 	const VkDevice				vkDevice			= context.getDevice();
1692 	const DeviceInterface&		vk					= context.getDeviceInterface();
1693 	const deUint32				queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
1694 
1695 	const VkBufferCreateInfo	bufferInfo			=
1696 	{
1697 		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,	// VkStructureType		sType;
1698 		DE_NULL,								// const void*			pNext;
1699 		0u,										// VkBufferCreateFlags	flags;
1700 		bufferSize,								// VkDeviceSize			size;
1701 		usageFlags,								// VkBufferUsageFlags	usage;
1702 		VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode		sharingMode;
1703 		1u,										// deUint32				queueFamilyIndexCount;
1704 		&queueFamilyIndex						// const deUint32*		pQueueFamilyIndices;
1705 	};
1706 
1707 	return vk::createBuffer(vk, vkDevice, &bufferInfo);
1708 }
1709 
createImage2D(Context & context,deUint32 width,deUint32 height,vk::VkFormat format,vk::VkImageTiling tiling,vk::VkImageUsageFlags usageFlags)1710 Move<vk::VkImage> createImage2D (Context& context, deUint32 width, deUint32 height, vk::VkFormat format, vk::VkImageTiling tiling, vk::VkImageUsageFlags usageFlags)
1711 {
1712 	const deUint32				queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
1713 	const vk::VkImageCreateInfo	params				=
1714 	{
1715 		vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	// VkStructureType			sType
1716 		DE_NULL,									// const void*				pNext
1717 		0u,											// VkImageCreateFlags		flags
1718 		vk::VK_IMAGE_TYPE_2D,						// VkImageType				imageType
1719 		format,										// VkFormat					format
1720 		{ width, height, 1u },						// VkExtent3D				extent
1721 		1u,											// deUint32					mipLevels
1722 		1u,											// deUint32					arrayLayers
1723 		VK_SAMPLE_COUNT_1_BIT,						// VkSampleCountFlagBits	samples
1724 		tiling,										// VkImageTiling			tiling
1725 		usageFlags,									// VkImageUsageFlags		usage
1726 		vk::VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode			sharingMode
1727 		1u,											// deUint32					queueFamilyIndexCount
1728 		&queueFamilyIndex,							// const deUint32*			pQueueFamilyIndices
1729 		vk::VK_IMAGE_LAYOUT_UNDEFINED,				// VkImageLayout			initialLayout
1730 	};
1731 
1732 	return vk::createImage(context.getDeviceInterface(), context.getDevice(), &params);
1733 }
1734 
allocateAndBindMemory(Context & context,vk::VkBuffer buffer,vk::MemoryRequirement memReqs)1735 de::MovePtr<vk::Allocation> allocateAndBindMemory (Context& context, vk::VkBuffer buffer, vk::MemoryRequirement memReqs)
1736 {
1737 	const vk::DeviceInterface&		vkd		= context.getDeviceInterface();
1738 	const vk::VkMemoryRequirements	bufReqs	= vk::getBufferMemoryRequirements(vkd, context.getDevice(), buffer);
1739 	de::MovePtr<vk::Allocation>		memory	= context.getDefaultAllocator().allocate(bufReqs, memReqs);
1740 
1741 	vkd.bindBufferMemory(context.getDevice(), buffer, memory->getMemory(), memory->getOffset());
1742 
1743 	return memory;
1744 }
1745 
allocateAndBindMemory(Context & context,vk::VkImage image,vk::MemoryRequirement memReqs)1746 de::MovePtr<vk::Allocation> allocateAndBindMemory (Context& context, vk::VkImage image, vk::MemoryRequirement memReqs)
1747 {
1748 	const vk::DeviceInterface&	  vkd	 = context.getDeviceInterface();
1749 	const vk::VkMemoryRequirements  imgReqs = vk::getImageMemoryRequirements(vkd, context.getDevice(), image);
1750 	de::MovePtr<vk::Allocation>		 memory  = context.getDefaultAllocator().allocate(imgReqs, memReqs);
1751 
1752 	vkd.bindImageMemory(context.getDevice(), image, memory->getMemory(), memory->getOffset());
1753 
1754 	return memory;
1755 }
1756 
createAttachmentView(Context & context,vk::VkImage image,vk::VkFormat format)1757 Move<vk::VkImageView> createAttachmentView (Context& context, vk::VkImage image, vk::VkFormat format)
1758 {
1759 	const vk::VkImageViewCreateInfo params =
1760 	{
1761 		vk::VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,		// sType
1762 		DE_NULL,											// pNext
1763 		0u,													// flags
1764 		image,												// image
1765 		vk::VK_IMAGE_VIEW_TYPE_2D,							// viewType
1766 		format,												// format
1767 		vk::makeComponentMappingRGBA(),						// components
1768 		{ vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u,1u },	// subresourceRange
1769 	};
1770 
1771 	return vk::createImageView(context.getDeviceInterface(), context.getDevice(), &params);
1772 }
1773 
createPipelineLayout(Context & context,vk::VkDescriptorSetLayout descriptorSetLayout)1774 Move<vk::VkPipelineLayout> createPipelineLayout (Context& context, vk::VkDescriptorSetLayout descriptorSetLayout)
1775 {
1776 	const vk::VkPipelineLayoutCreateInfo params =
1777 	{
1778 		vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,	// sType
1779 		DE_NULL,											// pNext
1780 		0u,													// flags
1781 		1u,													// setLayoutCount
1782 		&descriptorSetLayout,								// pSetLayouts
1783 		0u,													// pushConstantRangeCount
1784 		DE_NULL,											// pPushConstantRanges
1785 	};
1786 
1787 	return vk::createPipelineLayout(context.getDeviceInterface(), context.getDevice(), &params);
1788 }
1789 
createCmdPool(Context & context)1790 Move<vk::VkCommandPool> createCmdPool (Context& context)
1791 {
1792 	const deUint32	queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
1793 
1794 	return vk::createCommandPool(context.getDeviceInterface(), context.getDevice(), vk::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
1795 }
1796 
createCmdBuffer(Context & context,vk::VkCommandPool cmdPool)1797 Move<vk::VkCommandBuffer> createCmdBuffer (Context& context, vk::VkCommandPool cmdPool)
1798 {
1799 	return vk::allocateCommandBuffer(context.getDeviceInterface(), context.getDevice(), cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1800 }
1801 
1802 // UniformBlockCaseInstance
1803 
1804 class UniformBlockCaseInstance : public vkt::TestInstance
1805 {
1806 public:
1807 									UniformBlockCaseInstance	(Context&						context,
1808 																 UniformBlockCase::BufferMode	bufferMode,
1809 																 const UniformLayout&			layout,
1810 																 const std::map<int, void*>&	blockPointers);
1811 	virtual							~UniformBlockCaseInstance	(void);
1812 	virtual tcu::TestStatus			iterate						(void);
1813 
1814 private:
1815 	enum
1816 	{
1817 		RENDER_WIDTH = 100,
1818 		RENDER_HEIGHT = 100,
1819 	};
1820 
1821 	vk::Move<VkRenderPass>			createRenderPass			(vk::VkFormat format) const;
1822 	vk::Move<VkFramebuffer>			createFramebuffer			(vk::VkRenderPass renderPass, vk::VkImageView colorImageView) const;
1823 	vk::Move<VkDescriptorSetLayout>	createDescriptorSetLayout	(void) const;
1824 	vk::Move<VkDescriptorPool>		createDescriptorPool		(void) const;
1825 	vk::Move<VkPipeline>			createPipeline				(vk::VkShaderModule vtxShaderModule, vk::VkShaderModule fragShaderModule, vk::VkPipelineLayout pipelineLayout, vk::VkRenderPass renderPass) const;
1826 
1827 	vk::VkDescriptorBufferInfo		addUniformData				(deUint32 size, const void* dataPtr);
1828 
1829 	UniformBlockCase::BufferMode	m_bufferMode;
1830 	const UniformLayout&			m_layout;
1831 	const std::map<int, void*>&		m_blockPointers;
1832 
1833 	typedef de::SharedPtr<vk::Unique<vk::VkBuffer> >	VkBufferSp;
1834 	typedef de::SharedPtr<vk::Allocation>				AllocationSp;
1835 
1836 	std::vector<VkBufferSp>			m_uniformBuffers;
1837 	std::vector<AllocationSp>		m_uniformAllocs;
1838 };
1839 
UniformBlockCaseInstance(Context & ctx,UniformBlockCase::BufferMode bufferMode,const UniformLayout & layout,const std::map<int,void * > & blockPointers)1840 UniformBlockCaseInstance::UniformBlockCaseInstance (Context&						ctx,
1841 													UniformBlockCase::BufferMode	bufferMode,
1842 													const UniformLayout&			layout,
1843 													const std::map<int, void*>&		blockPointers)
1844 	: vkt::TestInstance (ctx)
1845 	, m_bufferMode		(bufferMode)
1846 	, m_layout			(layout)
1847 	, m_blockPointers	(blockPointers)
1848 {
1849 }
1850 
~UniformBlockCaseInstance(void)1851 UniformBlockCaseInstance::~UniformBlockCaseInstance (void)
1852 {
1853 }
1854 
iterate(void)1855 tcu::TestStatus UniformBlockCaseInstance::iterate (void)
1856 {
1857 	const vk::DeviceInterface&		vk					= m_context.getDeviceInterface();
1858 	const vk::VkDevice				device				= m_context.getDevice();
1859 	const vk::VkQueue				queue				= m_context.getUniversalQueue();
1860 	const deUint32					queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
1861 
1862 	const float positions[] =
1863 	{
1864 		-1.0f, -1.0f, 0.0f, 1.0f,
1865 		-1.0f, +1.0f, 0.0f, 1.0f,
1866 		+1.0f, -1.0f, 0.0f, 1.0f,
1867 		+1.0f, +1.0f, 0.0f, 1.0f
1868 	};
1869 
1870 	const deUint32 indices[] = { 0, 1, 2, 2, 1, 3 };
1871 
1872 	vk::Unique<VkBuffer>				positionsBuffer		(createBuffer(m_context, sizeof(positions), vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
1873 	de::UniquePtr<Allocation>			positionsAlloc		(allocateAndBindMemory(m_context, *positionsBuffer, MemoryRequirement::HostVisible));
1874 	vk::Unique<VkBuffer>				indicesBuffer		(createBuffer(m_context, sizeof(indices), vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT|vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
1875 	de::UniquePtr<Allocation>			indicesAlloc		(allocateAndBindMemory(m_context, *indicesBuffer, MemoryRequirement::HostVisible));
1876 
1877 	int minUniformBufferOffsetAlignment = getminUniformBufferOffsetAlignment(m_context);
1878 
1879 	// Upload attrbiutes data
1880 	{
1881 		deMemcpy(positionsAlloc->getHostPtr(), positions, sizeof(positions));
1882 		flushAlloc(vk, device, *positionsAlloc);
1883 
1884 		deMemcpy(indicesAlloc->getHostPtr(), indices, sizeof(indices));
1885 		flushAlloc(vk, device, *indicesAlloc);
1886 	}
1887 
1888 	vk::Unique<VkImage>					colorImage			(createImage2D(m_context,
1889 																			RENDER_WIDTH,
1890 																			RENDER_HEIGHT,
1891 																			vk::VK_FORMAT_R8G8B8A8_UNORM,
1892 																			vk::VK_IMAGE_TILING_OPTIMAL,
1893 																			vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT|vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT));
1894 	de::UniquePtr<Allocation>			colorImageAlloc		(allocateAndBindMemory(m_context, *colorImage, MemoryRequirement::Any));
1895 	vk::Unique<VkImageView>				colorImageView		(createAttachmentView(m_context, *colorImage, vk::VK_FORMAT_R8G8B8A8_UNORM));
1896 
1897 	vk::Unique<VkDescriptorSetLayout>	descriptorSetLayout	(createDescriptorSetLayout());
1898 	vk::Unique<VkDescriptorPool>		descriptorPool		(createDescriptorPool());
1899 
1900 	const VkDescriptorSetAllocateInfo	descriptorSetAllocateInfo =
1901 	{
1902 		VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,		// VkStructureType				sType;
1903 		DE_NULL,											// const void*					pNext;
1904 		*descriptorPool,									// VkDescriptorPool				descriptorPool;
1905 		1u,													// deUint32						setLayoutCount;
1906 		&descriptorSetLayout.get()							// const VkDescriptorSetLayout*	pSetLayouts;
1907 	};
1908 
1909 	vk::Unique<VkDescriptorSet>			descriptorSet(vk::allocateDescriptorSet(vk, device, &descriptorSetAllocateInfo));
1910 	int									numBlocks = (int)m_layout.blocks.size();
1911 	std::vector<vk::VkDescriptorBufferInfo>	descriptors(numBlocks);
1912 
1913 	// Upload uniform data
1914 	{
1915 		vk::DescriptorSetUpdateBuilder	descriptorSetUpdateBuilder;
1916 
1917 		if (m_bufferMode == UniformBlockCase::BUFFERMODE_PER_BLOCK)
1918 		{
1919 			for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1920 			{
1921 				const BlockLayoutEntry& block = m_layout.blocks[blockNdx];
1922 				const void*	srcPtr = m_blockPointers.find(blockNdx)->second;
1923 
1924 				descriptors[blockNdx] = addUniformData(block.size, srcPtr);
1925 				descriptorSetUpdateBuilder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::bindingArrayElement(block.bindingNdx, block.instanceNdx),
1926 														VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descriptors[blockNdx]);
1927 			}
1928 		}
1929 		else
1930 		{
1931 			int currentOffset = 0;
1932 			std::map<int, int> offsets;
1933 			for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1934 			{
1935 				if (minUniformBufferOffsetAlignment > 0)
1936 					currentOffset = deAlign32(currentOffset, minUniformBufferOffsetAlignment);
1937 				offsets[blockNdx] = currentOffset;
1938 				currentOffset += m_layout.blocks[blockNdx].size;
1939 			}
1940 
1941 			deUint32 totalSize = currentOffset;
1942 
1943 			// Make a copy of the data that satisfies the device's min uniform buffer alignment
1944 			std::vector<deUint8> data;
1945 			data.resize(totalSize);
1946 			for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1947 			{
1948 				deMemcpy(&data[offsets[blockNdx]], m_blockPointers.find(blockNdx)->second, m_layout.blocks[blockNdx].size);
1949 			}
1950 
1951 			vk::VkBuffer buffer = addUniformData(totalSize, &data[0]).buffer;
1952 
1953 			for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1954 			{
1955 				const BlockLayoutEntry& block = m_layout.blocks[blockNdx];
1956 				deUint32 size = block.size;
1957 
1958 				const VkDescriptorBufferInfo	descriptor =
1959 				{
1960 					buffer,							// VkBuffer		buffer;
1961 					(deUint32)offsets[blockNdx],	// VkDeviceSize	offset;
1962 					size,							// VkDeviceSize	range;
1963 				};
1964 
1965 				descriptors[blockNdx] = descriptor;
1966 				descriptorSetUpdateBuilder.writeSingle(*descriptorSet,
1967 														vk::DescriptorSetUpdateBuilder::Location::bindingArrayElement(block.bindingNdx, block.instanceNdx),
1968 														VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
1969 														&descriptors[blockNdx]);
1970 			}
1971 		}
1972 
1973 		descriptorSetUpdateBuilder.update(vk, device);
1974 	}
1975 
1976 	vk::Unique<VkRenderPass>			renderPass			(createRenderPass(vk::VK_FORMAT_R8G8B8A8_UNORM));
1977 	vk::Unique<VkFramebuffer>			framebuffer			(createFramebuffer(*renderPass, *colorImageView));
1978 	vk::Unique<VkPipelineLayout>		pipelineLayout		(createPipelineLayout(m_context, *descriptorSetLayout));
1979 
1980 	vk::Unique<VkShaderModule>			vtxShaderModule		(vk::createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0));
1981 	vk::Unique<VkShaderModule>			fragShaderModule	(vk::createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0));
1982 	vk::Unique<VkPipeline>				pipeline			(createPipeline(*vtxShaderModule, *fragShaderModule, *pipelineLayout, *renderPass));
1983 	vk::Unique<VkCommandPool>			cmdPool				(createCmdPool(m_context));
1984 	vk::Unique<VkCommandBuffer>			cmdBuffer			(createCmdBuffer(m_context, *cmdPool));
1985 	vk::Unique<VkBuffer>				readImageBuffer		(createBuffer(m_context, (vk::VkDeviceSize)(RENDER_WIDTH * RENDER_HEIGHT * 4), vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT));
1986 	de::UniquePtr<Allocation>			readImageAlloc		(allocateAndBindMemory(m_context, *readImageBuffer, vk::MemoryRequirement::HostVisible));
1987 
1988 	// Record command buffer
1989 	const vk::VkCommandBufferBeginInfo beginInfo	=
1990 	{
1991 		vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,	// VkStructureType					sType;
1992 		DE_NULL,											// const void*						pNext;
1993 		0u,													// VkCommandBufferUsageFlags		flags;
1994 		(const vk::VkCommandBufferInheritanceInfo*)DE_NULL,
1995 	};
1996 	VK_CHECK(vk.beginCommandBuffer(*cmdBuffer, &beginInfo));
1997 
1998 	// Add barrier for initializing image state
1999 	{
2000 		const vk::VkImageMemoryBarrier  initializeBarrier =
2001 		{
2002 			vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,		// VkStructureType			sType;
2003 			DE_NULL,										// const void*				pNext
2004 			0,												// VVkAccessFlags			srcAccessMask;
2005 			vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,		// VkAccessFlags			dstAccessMask;
2006 			vk::VK_IMAGE_LAYOUT_UNDEFINED,					// VkImageLayout			oldLayout;
2007 			vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	// VkImageLayout			newLayout;
2008 			queueFamilyIndex,								// deUint32					srcQueueFamilyIndex;
2009 			queueFamilyIndex,								// deUint32					dstQueueFamilyIndex;
2010 			*colorImage,									// VkImage					image;
2011 			{
2012 				vk::VK_IMAGE_ASPECT_COLOR_BIT,			// VkImageAspectFlags	aspectMask;
2013 				0u,										// deUint32				baseMipLevel;
2014 				1u,										// deUint32				mipLevels;
2015 				0u,										// deUint32				baseArraySlice;
2016 				1u,										// deUint32				arraySize;
2017 			}												// VkImageSubresourceRange	subresourceRange
2018 		};
2019 
2020 		vk.cmdPipelineBarrier(*cmdBuffer, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, vk::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, (vk::VkDependencyFlags)0,
2021 			0, (const vk::VkMemoryBarrier*)DE_NULL,
2022 			0, (const vk::VkBufferMemoryBarrier*)DE_NULL,
2023 			1, &initializeBarrier);
2024 	}
2025 
2026 	beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(0, 0, RENDER_WIDTH, RENDER_HEIGHT), tcu::Vec4(0.125f, 0.25f, 0.75f, 1.0f));
2027 
2028 	vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
2029 	vk.cmdBindDescriptorSets(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u, DE_NULL);
2030 
2031 	const vk::VkDeviceSize offsets[] = { 0u };
2032 	vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &*positionsBuffer, offsets);
2033 	vk.cmdBindIndexBuffer(*cmdBuffer, *indicesBuffer, (vk::VkDeviceSize)0, vk::VK_INDEX_TYPE_UINT32);
2034 
2035 	vk.cmdDrawIndexed(*cmdBuffer, DE_LENGTH_OF_ARRAY(indices), 1u, 0u, 0u, 0u);
2036 	endRenderPass(vk, *cmdBuffer);
2037 
2038 	copyImageToBuffer(vk, *cmdBuffer, *colorImage, *readImageBuffer, tcu::IVec2(RENDER_WIDTH, RENDER_HEIGHT));
2039 
2040 	endCommandBuffer(vk, *cmdBuffer);
2041 
2042 	// Submit the command buffer
2043 	submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
2044 
2045 	// Read back the results
2046 	tcu::Surface surface(RENDER_WIDTH, RENDER_HEIGHT);
2047 	{
2048 		const tcu::TextureFormat textureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
2049 		const tcu::ConstPixelBufferAccess imgAccess(textureFormat, RENDER_WIDTH, RENDER_HEIGHT, 1, readImageAlloc->getHostPtr());
2050 		invalidateAlloc(vk, device, *readImageAlloc);
2051 
2052 		tcu::copy(surface.getAccess(), imgAccess);
2053 	}
2054 
2055 	// Check if the result image is all white
2056 	tcu::RGBA white(tcu::RGBA::white());
2057 	int numFailedPixels = 0;
2058 
2059 	for (int y = 0; y < surface.getHeight(); y++)
2060 	{
2061 		for (int x = 0; x < surface.getWidth(); x++)
2062 		{
2063 			if (surface.getPixel(x, y) != white)
2064 				numFailedPixels += 1;
2065 		}
2066 	}
2067 
2068 	if (numFailedPixels > 0)
2069 	{
2070 		tcu::TestLog& log = m_context.getTestContext().getLog();
2071 		log << tcu::TestLog::Image("Image", "Rendered image", surface);
2072 		log << tcu::TestLog::Message << "Image comparison failed, got " << numFailedPixels << " non-white pixels" << tcu::TestLog::EndMessage;
2073 
2074 		for (size_t blockNdx = 0; blockNdx < m_layout.blocks.size(); blockNdx++)
2075 		{
2076 			const BlockLayoutEntry& block = m_layout.blocks[blockNdx];
2077 			log << tcu::TestLog::Message << "Block index: " << blockNdx << " infos: " << block << tcu::TestLog::EndMessage;
2078 		}
2079 
2080 		for (size_t uniformNdx = 0; uniformNdx < m_layout.uniforms.size(); uniformNdx++)
2081 		{
2082 			log << tcu::TestLog::Message << "Uniform index: " << uniformNdx << " infos: " << m_layout.uniforms[uniformNdx] << tcu::TestLog::EndMessage;
2083 		}
2084 
2085 		return tcu::TestStatus::fail("Detected non-white pixels");
2086 	}
2087 	else
2088 		return tcu::TestStatus::pass("Full white image ok");
2089 }
2090 
addUniformData(deUint32 size,const void * dataPtr)2091 vk::VkDescriptorBufferInfo UniformBlockCaseInstance::addUniformData (deUint32 size, const void* dataPtr)
2092 {
2093 	const VkDevice					vkDevice			= m_context.getDevice();
2094 	const DeviceInterface&			vk					= m_context.getDeviceInterface();
2095 
2096 	Move<VkBuffer>					buffer	= createBuffer(m_context, size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
2097 	de::MovePtr<Allocation>			alloc	= allocateAndBindMemory(m_context, *buffer, vk::MemoryRequirement::HostVisible);
2098 
2099 	deMemcpy(alloc->getHostPtr(), dataPtr, size);
2100 	flushAlloc(vk, vkDevice, *alloc);
2101 
2102 	const VkDescriptorBufferInfo			descriptor			=
2103 	{
2104 		*buffer,				// VkBuffer		buffer;
2105 		0u,						// VkDeviceSize	offset;
2106 		size,					// VkDeviceSize	range;
2107 
2108 	};
2109 
2110 	m_uniformBuffers.push_back(VkBufferSp(new vk::Unique<vk::VkBuffer>(buffer)));
2111 	m_uniformAllocs.push_back(AllocationSp(alloc.release()));
2112 
2113 	return descriptor;
2114 }
2115 
createRenderPass(vk::VkFormat format) const2116 vk::Move<VkRenderPass> UniformBlockCaseInstance::createRenderPass (vk::VkFormat format) const
2117 {
2118 	const VkDevice					vkDevice				= m_context.getDevice();
2119 	const DeviceInterface&			vk						= m_context.getDeviceInterface();
2120 
2121 	return vk::makeRenderPass(vk, vkDevice, format);
2122 }
2123 
createFramebuffer(vk::VkRenderPass renderPass,vk::VkImageView colorImageView) const2124 vk::Move<VkFramebuffer> UniformBlockCaseInstance::createFramebuffer (vk::VkRenderPass renderPass, vk::VkImageView colorImageView) const
2125 {
2126 	const VkDevice					vkDevice			= m_context.getDevice();
2127 	const DeviceInterface&			vk					= m_context.getDeviceInterface();
2128 
2129 	const VkFramebufferCreateInfo	framebufferParams	=
2130 	{
2131 		VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,		// VkStructureType			sType;
2132 		DE_NULL,										// const void*				pNext;
2133 		0u,												// VkFramebufferCreateFlags	flags;
2134 		renderPass,										// VkRenderPass				renderPass;
2135 		1u,												// deUint32					attachmentCount;
2136 		&colorImageView,								// const VkImageView*		pAttachments;
2137 		RENDER_WIDTH,									// deUint32					width;
2138 		RENDER_HEIGHT,									// deUint32					height;
2139 		1u												// deUint32					layers;
2140 	};
2141 
2142 	return vk::createFramebuffer(vk, vkDevice, &framebufferParams);
2143 }
2144 
createDescriptorSetLayout(void) const2145 vk::Move<VkDescriptorSetLayout> UniformBlockCaseInstance::createDescriptorSetLayout (void) const
2146 {
2147 	int numBlocks = (int)m_layout.blocks.size();
2148 	int lastBindingNdx = -1;
2149 	std::vector<int> lengths;
2150 
2151 	for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
2152 	{
2153 		const BlockLayoutEntry& block = m_layout.blocks[blockNdx];
2154 
2155 		if (block.bindingNdx == lastBindingNdx)
2156 		{
2157 			lengths.back()++;
2158 		}
2159 		else
2160 		{
2161 			lengths.push_back(1);
2162 			lastBindingNdx = block.bindingNdx;
2163 		}
2164 	}
2165 
2166 	vk::DescriptorSetLayoutBuilder layoutBuilder;
2167 	for (size_t i = 0; i < lengths.size(); i++)
2168 	{
2169 		if (lengths[i] > 0)
2170 		{
2171 			layoutBuilder.addArrayBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, lengths[i], vk::VK_SHADER_STAGE_ALL);
2172 		}
2173 		else
2174 		{
2175 			layoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_SHADER_STAGE_ALL);
2176 		}
2177 	}
2178 
2179 	return layoutBuilder.build(m_context.getDeviceInterface(), m_context.getDevice());
2180 }
2181 
createDescriptorPool(void) const2182 vk::Move<VkDescriptorPool> UniformBlockCaseInstance::createDescriptorPool (void) const
2183 {
2184 	vk::DescriptorPoolBuilder poolBuilder;
2185 
2186 	return poolBuilder
2187 		.addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, (int)m_layout.blocks.size())
2188 		.build(m_context.getDeviceInterface(), m_context.getDevice(), VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
2189 }
2190 
createPipeline(vk::VkShaderModule vtxShaderModule,vk::VkShaderModule fragShaderModule,vk::VkPipelineLayout pipelineLayout,vk::VkRenderPass renderPass) const2191 vk::Move<VkPipeline> UniformBlockCaseInstance::createPipeline (vk::VkShaderModule vtxShaderModule, vk::VkShaderModule fragShaderModule, vk::VkPipelineLayout pipelineLayout, vk::VkRenderPass renderPass) const
2192 {
2193 	const VkDevice									vkDevice				= m_context.getDevice();
2194 	const DeviceInterface&							vk						= m_context.getDeviceInterface();
2195 
2196 	const std::vector<VkViewport>					viewports				(1, makeViewport(tcu::UVec2(RENDER_WIDTH, RENDER_HEIGHT)));
2197 	const std::vector<VkRect2D>						scissors				(1, makeRect2D(tcu::UVec2(RENDER_WIDTH, RENDER_HEIGHT)));
2198 
2199 	return vk::makeGraphicsPipeline(vk,					// const DeviceInterface&            vk
2200 									vkDevice,			// const VkDevice                    device
2201 									pipelineLayout,		// const VkPipelineLayout            pipelineLayout
2202 									vtxShaderModule,	// const VkShaderModule              vertexShaderModule
2203 									DE_NULL,			// const VkShaderModule              tessellationControlShaderModule
2204 									DE_NULL,			// const VkShaderModule              tessellationEvalShaderModule
2205 									DE_NULL,			// const VkShaderModule              geometryShaderModule
2206 									fragShaderModule,	// const VkShaderModule              fragmentShaderModule
2207 									renderPass,			// const VkRenderPass                renderPass
2208 									viewports,			// const std::vector<VkViewport>&    viewports
2209 									scissors);			// const std::vector<VkRect2D>&      scissors
2210 }
2211 
2212 } // anonymous (utilities)
2213 
2214 // UniformBlockCase.
2215 
UniformBlockCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,BufferMode bufferMode,MatrixLoadFlags matrixLoadFlag,bool shuffleUniformMembers)2216 UniformBlockCase::UniformBlockCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, BufferMode bufferMode, MatrixLoadFlags matrixLoadFlag, bool shuffleUniformMembers)
2217 	: TestCase					(testCtx, name, description)
2218 	, m_bufferMode				(bufferMode)
2219 	, m_matrixLoadFlag			(matrixLoadFlag)
2220 	, m_shuffleUniformMembers	(shuffleUniformMembers)
2221 {
2222 }
2223 
~UniformBlockCase(void)2224 UniformBlockCase::~UniformBlockCase (void)
2225 {
2226 }
2227 
initPrograms(vk::SourceCollections & programCollection) const2228 void UniformBlockCase::initPrograms (vk::SourceCollections& programCollection) const
2229 {
2230 	DE_ASSERT(!m_vertShaderSource.empty());
2231 	DE_ASSERT(!m_fragShaderSource.empty());
2232 
2233 	vk::ShaderBuildOptions::Flags flags = vk::ShaderBuildOptions::Flags(0);
2234 	// TODO(dneto): If these tests ever use LAYOUT_RELAXED, then add support
2235 	// here as well.
2236 	if (usesBlockLayout(UniformFlags(LAYOUT_SCALAR | LAYOUT_STD430)))
2237 	{
2238 		flags = vk::ShaderBuildOptions::FLAG_ALLOW_SCALAR_OFFSETS;
2239 	}
2240 
2241 	programCollection.glslSources.add("vert") << glu::VertexSource(m_vertShaderSource)
2242 	<< vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::getBaselineSpirvVersion(programCollection.usedVulkanVersion), flags);
2243 
2244 	programCollection.glslSources.add("frag") << glu::FragmentSource(m_fragShaderSource)
2245 	<< vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::getBaselineSpirvVersion(programCollection.usedVulkanVersion), flags);
2246 }
2247 
createInstance(Context & context) const2248 TestInstance* UniformBlockCase::createInstance (Context& context) const
2249 {
2250 	if (!context.get16BitStorageFeatures().uniformAndStorageBuffer16BitAccess && uses16BitStorage(m_interface))
2251 		TCU_THROW(NotSupportedError, "uniformAndStorageBuffer16BitAccess not supported");
2252 	if (!context.get8BitStorageFeatures().uniformAndStorageBuffer8BitAccess && uses8BitStorage(m_interface))
2253 		TCU_THROW(NotSupportedError, "uniformAndStorageBuffer8BitAccess not supported");
2254 	if (!context.getScalarBlockLayoutFeatures().scalarBlockLayout && usesScalarOrStd430Layout(m_interface))
2255 		TCU_THROW(NotSupportedError, "scalarBlockLayout not supported");
2256 
2257 	return new UniformBlockCaseInstance(context, m_bufferMode, m_uniformLayout, m_blockPointers);
2258 }
2259 
init(void)2260 void UniformBlockCase::init (void)
2261 {
2262 	const int vec4Alignment = (int)sizeof(deUint32)*4;
2263 
2264 	// Compute reference layout.
2265 	computeReferenceLayout(m_uniformLayout, m_interface);
2266 
2267 	// Assign storage for reference values.
2268 	{
2269 		int totalSize = 0;
2270 		for (std::vector<BlockLayoutEntry>::const_iterator blockIter = m_uniformLayout.blocks.begin(); blockIter != m_uniformLayout.blocks.end(); blockIter++)
2271 		{
2272 			// Include enough space for alignment of individual blocks
2273 			totalSize += deRoundUp32(blockIter->size, vec4Alignment);
2274 		}
2275 		m_data.resize(totalSize);
2276 
2277 		// Pointers for each block.
2278 		int curOffset = 0;
2279 		for (int blockNdx = 0; blockNdx < (int)m_uniformLayout.blocks.size(); blockNdx++)
2280 		{
2281 			m_blockPointers[blockNdx] = &m_data[0] + curOffset;
2282 
2283 			// Ensure each new block starts fully aligned to avoid unaligned host accesses
2284 			curOffset += deRoundUp32(m_uniformLayout.blocks[blockNdx].size, vec4Alignment);
2285 		}
2286 	}
2287 
2288 	// Generate values.
2289 	generateValues(m_uniformLayout, m_blockPointers, 1 /* seed */);
2290 
2291 	// Generate shaders.
2292 	m_vertShaderSource = generateVertexShader(m_interface, m_uniformLayout, m_blockPointers, m_matrixLoadFlag, m_shuffleUniformMembers);
2293 	m_fragShaderSource = generateFragmentShader(m_interface, m_uniformLayout, m_blockPointers, m_matrixLoadFlag, m_shuffleUniformMembers);
2294 }
2295 
2296 } // ubo
2297 } // vkt
2298