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(), ¶ms);
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(), ¶ms);
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(), ¶ms);
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