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