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