xref: /aosp_15_r20/external/deqp/external/openglcts/modules/common/glcUniformBlockCase.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * OpenGL Conformance Test Suite
3  * -----------------------------
4  *
5  * Copyright (c) 2016 Google Inc.
6  * Copyright (c) 2016 The Khronos Group Inc.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */ /*!
21  * \file
22  * \brief Uniform block case.
23  */ /*-------------------------------------------------------------------*/
24 
25 #include "glcUniformBlockCase.hpp"
26 #include "deInt32.h"
27 #include "deMemory.h"
28 #include "deRandom.hpp"
29 #include "deString.h"
30 #include "deStringUtil.hpp"
31 #include "gluContextInfo.hpp"
32 #include "gluDrawUtil.hpp"
33 #include "gluPixelTransfer.hpp"
34 #include "gluRenderContext.hpp"
35 #include "glwEnums.hpp"
36 #include "glwFunctions.hpp"
37 #include "tcuRenderTarget.hpp"
38 #include "tcuSurface.hpp"
39 #include "tcuTestLog.hpp"
40 
41 #include <algorithm>
42 #include <map>
43 
44 using std::map;
45 using std::string;
46 using std::vector;
47 using tcu::TestLog;
48 
49 namespace deqp
50 {
51 namespace ub
52 {
53 
54 struct PrecisionFlagsFmt
55 {
56     uint32_t flags;
57 
PrecisionFlagsFmtdeqp::ub::PrecisionFlagsFmt58     PrecisionFlagsFmt(uint32_t flags_) : flags(flags_)
59     {
60     }
61 };
62 
operator <<(std::ostream & str,const PrecisionFlagsFmt & fmt)63 std::ostream &operator<<(std::ostream &str, const PrecisionFlagsFmt &fmt)
64 {
65     // Precision.
66     DE_ASSERT(dePop32(fmt.flags & (PRECISION_LOW | PRECISION_MEDIUM | PRECISION_HIGH)) <= 1);
67     str << (fmt.flags & PRECISION_LOW    ? "lowp" :
68             fmt.flags & PRECISION_MEDIUM ? "mediump" :
69             fmt.flags & PRECISION_HIGH   ? "highp" :
70                                            "");
71     return str;
72 }
73 
74 struct LayoutFlagsFmt
75 {
76     uint32_t flags;
LayoutFlagsFmtdeqp::ub::LayoutFlagsFmt77     LayoutFlagsFmt(uint32_t flags_) : flags(flags_)
78     {
79     }
80 };
81 
operator <<(std::ostream & str,const LayoutFlagsFmt & fmt)82 std::ostream &operator<<(std::ostream &str, const LayoutFlagsFmt &fmt)
83 {
84     static const struct
85     {
86         uint32_t bit;
87         const char *token;
88     } bitDesc[] = {{LAYOUT_SHARED, "shared"},
89                    {LAYOUT_PACKED, "packed"},
90                    {LAYOUT_STD140, "std140"},
91                    {LAYOUT_ROW_MAJOR, "row_major"},
92                    {LAYOUT_COLUMN_MAJOR, "column_major"}};
93 
94     uint32_t remBits = fmt.flags;
95     for (int descNdx = 0; descNdx < DE_LENGTH_OF_ARRAY(bitDesc); descNdx++)
96     {
97         if (remBits & bitDesc[descNdx].bit)
98         {
99             if (remBits != fmt.flags)
100                 str << ", ";
101             str << bitDesc[descNdx].token;
102             remBits &= ~bitDesc[descNdx].bit;
103         }
104     }
105     DE_ASSERT(remBits == 0);
106     return str;
107 }
108 
109 // VarType implementation.
110 
VarType(void)111 VarType::VarType(void) : m_type(TYPE_LAST), m_flags(0)
112 {
113 }
114 
VarType(const VarType & other)115 VarType::VarType(const VarType &other) : m_type(TYPE_LAST), m_flags(0)
116 {
117     *this = other;
118 }
119 
VarType(glu::DataType basicType,uint32_t flags)120 VarType::VarType(glu::DataType basicType, uint32_t flags) : m_type(TYPE_BASIC), m_flags(flags)
121 {
122     m_data.basicType = basicType;
123 }
124 
VarType(const VarType & elementType,int arraySize)125 VarType::VarType(const VarType &elementType, int arraySize) : m_type(TYPE_ARRAY), m_flags(0)
126 {
127     m_data.array.size        = arraySize;
128     m_data.array.elementType = new VarType(elementType);
129 }
130 
VarType(const StructType * structPtr)131 VarType::VarType(const StructType *structPtr) : m_type(TYPE_STRUCT), m_flags(0)
132 {
133     m_data.structPtr = structPtr;
134 }
135 
~VarType(void)136 VarType::~VarType(void)
137 {
138     if (m_type == TYPE_ARRAY)
139         delete m_data.array.elementType;
140 }
141 
operator =(const VarType & other)142 VarType &VarType::operator=(const VarType &other)
143 {
144     if (this == &other)
145         return *this; // Self-assignment.
146 
147     if (m_type == TYPE_ARRAY)
148         delete m_data.array.elementType;
149 
150     m_type  = other.m_type;
151     m_flags = other.m_flags;
152     m_data  = Data();
153 
154     if (m_type == TYPE_ARRAY)
155     {
156         m_data.array.elementType = new VarType(*other.m_data.array.elementType);
157         m_data.array.size        = other.m_data.array.size;
158     }
159     else
160         m_data = other.m_data;
161 
162     return *this;
163 }
164 
165 // StructType implementation.
166 
addMember(const char * name,const VarType & type,uint32_t flags)167 void StructType::addMember(const char *name, const VarType &type, uint32_t flags)
168 {
169     m_members.push_back(StructMember(name, type, flags));
170 }
171 
172 // Uniform implementation.
173 
Uniform(const char * name,const VarType & type,uint32_t flags)174 Uniform::Uniform(const char *name, const VarType &type, uint32_t flags) : m_name(name), m_type(type), m_flags(flags)
175 {
176 }
177 
178 // UniformBlock implementation.
179 
UniformBlock(const char * blockName)180 UniformBlock::UniformBlock(const char *blockName) : m_blockName(blockName), m_arraySize(0), m_flags(0)
181 {
182 }
183 
184 struct BlockLayoutEntry
185 {
BlockLayoutEntrydeqp::ub::BlockLayoutEntry186     BlockLayoutEntry(void) : size(0)
187     {
188     }
189 
190     std::string name;
191     int size;
192     std::vector<int> activeUniformIndices;
193 };
194 
operator <<(std::ostream & stream,const BlockLayoutEntry & entry)195 std::ostream &operator<<(std::ostream &stream, const BlockLayoutEntry &entry)
196 {
197     stream << entry.name << " { name = " << entry.name << ", size = " << entry.size << ", activeUniformIndices = [";
198 
199     for (vector<int>::const_iterator i = entry.activeUniformIndices.begin(); i != entry.activeUniformIndices.end(); i++)
200     {
201         if (i != entry.activeUniformIndices.begin())
202             stream << ", ";
203         stream << *i;
204     }
205 
206     stream << "] }";
207     return stream;
208 }
209 
210 struct UniformLayoutEntry
211 {
UniformLayoutEntrydeqp::ub::UniformLayoutEntry212     UniformLayoutEntry(void)
213         : type(glu::TYPE_LAST)
214         , size(0)
215         , blockNdx(-1)
216         , offset(-1)
217         , arrayStride(-1)
218         , matrixStride(-1)
219         , isRowMajor(false)
220     {
221     }
222 
223     std::string name;
224     glu::DataType type;
225     int size;
226     int blockNdx;
227     int offset;
228     int arrayStride;
229     int matrixStride;
230     bool isRowMajor;
231 };
232 
operator <<(std::ostream & stream,const UniformLayoutEntry & entry)233 std::ostream &operator<<(std::ostream &stream, const UniformLayoutEntry &entry)
234 {
235     stream << entry.name << " { type = " << glu::getDataTypeName(entry.type) << ", size = " << entry.size
236            << ", blockNdx = " << entry.blockNdx << ", offset = " << entry.offset
237            << ", arrayStride = " << entry.arrayStride << ", matrixStride = " << entry.matrixStride
238            << ", isRowMajor = " << (entry.isRowMajor ? "true" : "false") << " }";
239     return stream;
240 }
241 
242 class UniformLayout
243 {
244 public:
245     std::vector<BlockLayoutEntry> blocks;
246     std::vector<UniformLayoutEntry> uniforms;
247 
248     int getUniformIndex(const char *name) const;
249     int getBlockIndex(const char *name) const;
250 };
251 
252 // \todo [2012-01-24 pyry] Speed up lookups using hash.
253 
getUniformIndex(const char * name) const254 int UniformLayout::getUniformIndex(const char *name) const
255 {
256     for (int ndx = 0; ndx < (int)uniforms.size(); ndx++)
257     {
258         if (uniforms[ndx].name == name)
259             return ndx;
260     }
261     return -1;
262 }
263 
getBlockIndex(const char * name) const264 int UniformLayout::getBlockIndex(const char *name) const
265 {
266     for (int ndx = 0; ndx < (int)blocks.size(); ndx++)
267     {
268         if (blocks[ndx].name == name)
269             return ndx;
270     }
271     return -1;
272 }
273 
274 // ShaderInterface implementation.
275 
ShaderInterface(void)276 ShaderInterface::ShaderInterface(void)
277 {
278 }
279 
~ShaderInterface(void)280 ShaderInterface::~ShaderInterface(void)
281 {
282     for (std::vector<StructType *>::iterator i = m_structs.begin(); i != m_structs.end(); i++)
283         delete *i;
284 
285     for (std::vector<UniformBlock *>::iterator i = m_uniformBlocks.begin(); i != m_uniformBlocks.end(); i++)
286         delete *i;
287 }
288 
allocStruct(const char * name)289 StructType &ShaderInterface::allocStruct(const char *name)
290 {
291     m_structs.reserve(m_structs.size() + 1);
292     m_structs.push_back(new StructType(name));
293     return *m_structs.back();
294 }
295 
296 struct StructNameEquals
297 {
298     std::string name;
299 
StructNameEqualsdeqp::ub::StructNameEquals300     StructNameEquals(const char *name_) : name(name_)
301     {
302     }
303 
operator ()deqp::ub::StructNameEquals304     bool operator()(const StructType *type) const
305     {
306         return type->getTypeName() && name == type->getTypeName();
307     }
308 };
309 
findStruct(const char * name) const310 const StructType *ShaderInterface::findStruct(const char *name) const
311 {
312     std::vector<StructType *>::const_iterator pos =
313         std::find_if(m_structs.begin(), m_structs.end(), StructNameEquals(name));
314     return pos != m_structs.end() ? *pos : DE_NULL;
315 }
316 
getNamedStructs(std::vector<const StructType * > & structs) const317 void ShaderInterface::getNamedStructs(std::vector<const StructType *> &structs) const
318 {
319     for (std::vector<StructType *>::const_iterator i = m_structs.begin(); i != m_structs.end(); i++)
320     {
321         if ((*i)->getTypeName() != DE_NULL)
322             structs.push_back(*i);
323     }
324 }
325 
allocBlock(const char * name)326 UniformBlock &ShaderInterface::allocBlock(const char *name)
327 {
328     m_uniformBlocks.reserve(m_uniformBlocks.size() + 1);
329     m_uniformBlocks.push_back(new UniformBlock(name));
330     return *m_uniformBlocks.back();
331 }
332 
333 namespace // Utilities
334 {
335 
336 // Layout computation.
337 
getDataTypeByteSize(glu::DataType type)338 int getDataTypeByteSize(glu::DataType type)
339 {
340     return static_cast<int>(glu::getDataTypeScalarSize(type) * sizeof(uint32_t));
341 }
342 
getDataTypeByteAlignment(glu::DataType type)343 int getDataTypeByteAlignment(glu::DataType type)
344 {
345     switch (type)
346     {
347     case glu::TYPE_FLOAT:
348     case glu::TYPE_INT:
349     case glu::TYPE_UINT:
350     case glu::TYPE_BOOL:
351         return static_cast<int>(1 * sizeof(uint32_t));
352 
353     case glu::TYPE_FLOAT_VEC2:
354     case glu::TYPE_INT_VEC2:
355     case glu::TYPE_UINT_VEC2:
356     case glu::TYPE_BOOL_VEC2:
357         return static_cast<int>(2 * sizeof(uint32_t));
358 
359     case glu::TYPE_FLOAT_VEC3:
360     case glu::TYPE_INT_VEC3:
361     case glu::TYPE_UINT_VEC3:
362     case glu::TYPE_BOOL_VEC3: // Fall-through to vec4
363 
364     case glu::TYPE_FLOAT_VEC4:
365     case glu::TYPE_INT_VEC4:
366     case glu::TYPE_UINT_VEC4:
367     case glu::TYPE_BOOL_VEC4:
368         return static_cast<int>(4 * sizeof(uint32_t));
369 
370     default:
371         DE_ASSERT(false);
372         return 0;
373     }
374 }
375 
getDataTypeArrayStride(glu::DataType type)376 int getDataTypeArrayStride(glu::DataType type)
377 {
378     DE_ASSERT(!glu::isDataTypeMatrix(type));
379 
380     int baseStride    = getDataTypeByteSize(type);
381     int vec4Alignment = static_cast<int>(sizeof(uint32_t) * 4);
382 
383     DE_ASSERT(baseStride <= vec4Alignment);
384     return de::max(baseStride, vec4Alignment); // Really? See rule 4.
385 }
386 
computeStd140BaseAlignment(const VarType & type)387 int computeStd140BaseAlignment(const VarType &type)
388 {
389     const int vec4Alignment = static_cast<int>(sizeof(uint32_t) * 4);
390 
391     if (type.isBasicType())
392     {
393         glu::DataType basicType = type.getBasicType();
394 
395         if (glu::isDataTypeMatrix(basicType))
396         {
397             bool isRowMajor = !!(type.getFlags() & LAYOUT_ROW_MAJOR);
398             int vecSize =
399                 isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType) : glu::getDataTypeMatrixNumRows(basicType);
400 
401             return getDataTypeArrayStride(glu::getDataTypeFloatVec(vecSize));
402         }
403         else
404             return getDataTypeByteAlignment(basicType);
405     }
406     else if (type.isArrayType())
407     {
408         int elemAlignment = computeStd140BaseAlignment(type.getElementType());
409 
410         // Round up to alignment of vec4
411         return deRoundUp32(elemAlignment, vec4Alignment);
412     }
413     else
414     {
415         DE_ASSERT(type.isStructType());
416 
417         int maxBaseAlignment = 0;
418 
419         for (StructType::ConstIterator memberIter = type.getStruct().begin(); memberIter != type.getStruct().end();
420              memberIter++)
421             maxBaseAlignment = de::max(maxBaseAlignment, computeStd140BaseAlignment(memberIter->getType()));
422 
423         return deRoundUp32(maxBaseAlignment, vec4Alignment);
424     }
425 }
426 
mergeLayoutFlags(uint32_t prevFlags,uint32_t newFlags)427 inline uint32_t mergeLayoutFlags(uint32_t prevFlags, uint32_t newFlags)
428 {
429     const uint32_t packingMask = LAYOUT_PACKED | LAYOUT_SHARED | LAYOUT_STD140;
430     const uint32_t matrixMask  = LAYOUT_ROW_MAJOR | LAYOUT_COLUMN_MAJOR;
431 
432     uint32_t mergedFlags = 0;
433 
434     mergedFlags |= ((newFlags & packingMask) ? newFlags : prevFlags) & packingMask;
435     mergedFlags |= ((newFlags & matrixMask) ? newFlags : prevFlags) & matrixMask;
436 
437     return mergedFlags;
438 }
439 
computeStd140Layout(UniformLayout & layout,int & curOffset,int curBlockNdx,const std::string & curPrefix,const VarType & type,uint32_t layoutFlags)440 void computeStd140Layout(UniformLayout &layout, int &curOffset, int curBlockNdx, const std::string &curPrefix,
441                          const VarType &type, uint32_t layoutFlags)
442 {
443     int baseAlignment = computeStd140BaseAlignment(type);
444 
445     curOffset = deAlign32(curOffset, baseAlignment);
446 
447     if (type.isBasicType())
448     {
449         glu::DataType basicType = type.getBasicType();
450         UniformLayoutEntry entry;
451 
452         entry.name         = curPrefix;
453         entry.type         = basicType;
454         entry.size         = 1;
455         entry.arrayStride  = 0;
456         entry.matrixStride = 0;
457         entry.blockNdx     = curBlockNdx;
458 
459         if (glu::isDataTypeMatrix(basicType))
460         {
461             // Array of vectors as specified in rules 5 & 7.
462             bool isRowMajor = !!(layoutFlags & LAYOUT_ROW_MAJOR);
463             int vecSize =
464                 isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType) : glu::getDataTypeMatrixNumRows(basicType);
465             int numVecs =
466                 isRowMajor ? glu::getDataTypeMatrixNumRows(basicType) : glu::getDataTypeMatrixNumColumns(basicType);
467             int stride = getDataTypeArrayStride(glu::getDataTypeFloatVec(vecSize));
468 
469             entry.offset       = curOffset;
470             entry.matrixStride = stride;
471             entry.isRowMajor   = isRowMajor;
472 
473             curOffset += numVecs * stride;
474         }
475         else
476         {
477             // Scalar or vector.
478             entry.offset = curOffset;
479 
480             curOffset += getDataTypeByteSize(basicType);
481         }
482 
483         layout.uniforms.push_back(entry);
484     }
485     else if (type.isArrayType())
486     {
487         const VarType &elemType = type.getElementType();
488 
489         if (elemType.isBasicType() && !glu::isDataTypeMatrix(elemType.getBasicType()))
490         {
491             // Array of scalars or vectors.
492             glu::DataType elemBasicType = elemType.getBasicType();
493             UniformLayoutEntry entry;
494             int stride = getDataTypeArrayStride(elemBasicType);
495 
496             entry.name         = curPrefix + "[0]"; // Array uniforms are always postfixed with [0]
497             entry.type         = elemBasicType;
498             entry.blockNdx     = curBlockNdx;
499             entry.offset       = curOffset;
500             entry.size         = type.getArraySize();
501             entry.arrayStride  = stride;
502             entry.matrixStride = 0;
503 
504             curOffset += stride * type.getArraySize();
505 
506             layout.uniforms.push_back(entry);
507         }
508         else if (elemType.isBasicType() && glu::isDataTypeMatrix(elemType.getBasicType()))
509         {
510             // Array of matrices.
511             glu::DataType elemBasicType = elemType.getBasicType();
512             bool isRowMajor             = !!(layoutFlags & LAYOUT_ROW_MAJOR);
513             int vecSize                 = isRowMajor ? glu::getDataTypeMatrixNumColumns(elemBasicType) :
514                                                        glu::getDataTypeMatrixNumRows(elemBasicType);
515             int numVecs                 = isRowMajor ? glu::getDataTypeMatrixNumRows(elemBasicType) :
516                                                        glu::getDataTypeMatrixNumColumns(elemBasicType);
517             int stride                  = getDataTypeArrayStride(glu::getDataTypeFloatVec(vecSize));
518             UniformLayoutEntry entry;
519 
520             entry.name         = curPrefix + "[0]"; // Array uniforms are always postfixed with [0]
521             entry.type         = elemBasicType;
522             entry.blockNdx     = curBlockNdx;
523             entry.offset       = curOffset;
524             entry.size         = type.getArraySize();
525             entry.arrayStride  = stride * numVecs;
526             entry.matrixStride = stride;
527             entry.isRowMajor   = isRowMajor;
528 
529             curOffset += numVecs * type.getArraySize() * stride;
530 
531             layout.uniforms.push_back(entry);
532         }
533         else
534         {
535             DE_ASSERT(elemType.isStructType() || elemType.isArrayType());
536 
537             for (int elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++)
538                 computeStd140Layout(layout, curOffset, curBlockNdx, curPrefix + "[" + de::toString(elemNdx) + "]",
539                                     type.getElementType(), layoutFlags);
540         }
541     }
542     else
543     {
544         DE_ASSERT(type.isStructType());
545 
546         for (StructType::ConstIterator memberIter = type.getStruct().begin(); memberIter != type.getStruct().end();
547              memberIter++)
548             computeStd140Layout(layout, curOffset, curBlockNdx, curPrefix + "." + memberIter->getName(),
549                                 memberIter->getType(), layoutFlags);
550 
551         curOffset = deAlign32(curOffset, baseAlignment);
552     }
553 }
554 
computeStd140Layout(UniformLayout & layout,const ShaderInterface & interface)555 void computeStd140Layout(UniformLayout &layout, const ShaderInterface &interface)
556 {
557     // \todo [2012-01-23 pyry] Uniforms in default block.
558 
559     int numUniformBlocks = interface.getNumUniformBlocks();
560 
561     for (int blockNdx = 0; blockNdx < numUniformBlocks; blockNdx++)
562     {
563         const UniformBlock &block = interface.getUniformBlock(blockNdx);
564         bool hasInstanceName      = block.getInstanceName() != DE_NULL;
565         std::string blockPrefix   = hasInstanceName ? (std::string(block.getBlockName()) + ".") : std::string("");
566         int curOffset             = 0;
567         int activeBlockNdx        = (int)layout.blocks.size();
568         int firstUniformNdx       = (int)layout.uniforms.size();
569 
570         for (UniformBlock::ConstIterator uniformIter = block.begin(); uniformIter != block.end(); uniformIter++)
571         {
572             const Uniform &uniform = *uniformIter;
573             computeStd140Layout(layout, curOffset, activeBlockNdx, blockPrefix + uniform.getName(), uniform.getType(),
574                                 mergeLayoutFlags(block.getFlags(), uniform.getFlags()));
575         }
576 
577         int uniformIndicesEnd = (int)layout.uniforms.size();
578         int blockSize         = curOffset;
579         int numInstances      = block.isArray() ? block.getArraySize() : 1;
580 
581         // Create block layout entries for each instance.
582         for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
583         {
584             // Allocate entry for instance.
585             layout.blocks.push_back(BlockLayoutEntry());
586             BlockLayoutEntry &blockEntry = layout.blocks.back();
587 
588             blockEntry.name = block.getBlockName();
589             blockEntry.size = blockSize;
590 
591             // Compute active uniform set for block.
592             for (int uniformNdx = firstUniformNdx; uniformNdx < uniformIndicesEnd; uniformNdx++)
593                 blockEntry.activeUniformIndices.push_back(uniformNdx);
594 
595             if (block.isArray())
596                 blockEntry.name += "[" + de::toString(instanceNdx) + "]";
597         }
598     }
599 }
600 
601 // Value generator.
602 
generateValue(const UniformLayoutEntry & entry,void * basePtr,de::Random & rnd)603 void generateValue(const UniformLayoutEntry &entry, void *basePtr, de::Random &rnd)
604 {
605     glu::DataType scalarType = glu::getDataTypeScalarType(entry.type);
606     int scalarSize           = glu::getDataTypeScalarSize(entry.type);
607     bool isMatrix            = glu::isDataTypeMatrix(entry.type);
608     int numVecs              = isMatrix ? (entry.isRowMajor ? glu::getDataTypeMatrixNumRows(entry.type) :
609                                                               glu::getDataTypeMatrixNumColumns(entry.type)) :
610                                           1;
611     int vecSize              = scalarSize / numVecs;
612     bool isArray             = entry.size > 1;
613     const int compSize       = sizeof(uint32_t);
614 
615     DE_ASSERT(scalarSize % numVecs == 0);
616 
617     for (int elemNdx = 0; elemNdx < entry.size; elemNdx++)
618     {
619         uint8_t *elemPtr = (uint8_t *)basePtr + entry.offset + (isArray ? elemNdx * entry.arrayStride : 0);
620 
621         for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
622         {
623             uint8_t *vecPtr = elemPtr + (isMatrix ? vecNdx * entry.matrixStride : 0);
624 
625             for (int compNdx = 0; compNdx < vecSize; compNdx++)
626             {
627                 uint8_t *compPtr = vecPtr + compSize * compNdx;
628 
629                 switch (scalarType)
630                 {
631                 case glu::TYPE_FLOAT:
632                     *((float *)compPtr) = (float)rnd.getInt(-9, 9);
633                     break;
634                 case glu::TYPE_INT:
635                     *((int *)compPtr) = rnd.getInt(-9, 9);
636                     break;
637                 case glu::TYPE_UINT:
638                     *((uint32_t *)compPtr) = (uint32_t)rnd.getInt(0, 9);
639                     break;
640                 // \note Random bit pattern is used for true values. Spec states that all non-zero values are
641                 //       interpreted as true but some implementations fail this.
642                 case glu::TYPE_BOOL:
643                     *((uint32_t *)compPtr) = rnd.getBool() ? rnd.getUint32() | 1u : 0u;
644                     break;
645                 default:
646                     DE_ASSERT(false);
647                 }
648             }
649         }
650     }
651 }
652 
generateValues(const UniformLayout & layout,const std::map<int,void * > & blockPointers,uint32_t seed)653 void generateValues(const UniformLayout &layout, const std::map<int, void *> &blockPointers, uint32_t seed)
654 {
655     de::Random rnd(seed);
656     int numBlocks = (int)layout.blocks.size();
657 
658     for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
659     {
660         void *basePtr  = blockPointers.find(blockNdx)->second;
661         int numEntries = (int)layout.blocks[blockNdx].activeUniformIndices.size();
662 
663         for (int entryNdx = 0; entryNdx < numEntries; entryNdx++)
664         {
665             const UniformLayoutEntry &entry = layout.uniforms[layout.blocks[blockNdx].activeUniformIndices[entryNdx]];
666             generateValue(entry, basePtr, rnd);
667         }
668     }
669 }
670 
671 // Shader generator.
672 
673 static const char *s_compareFuncs =
674     "mediump float compare_float    (highp float a, highp float b)  { return abs(a - b) < 0.05 ? 1.0 : 0.0; }\n"
675     "mediump float compare_vec2     (highp vec2 a, highp vec2 b)    { return compare_float(a.x, "
676     "b.x)*compare_float(a.y, b.y); }\n"
677     "mediump float compare_vec3     (highp vec3 a, highp vec3 b)    { return compare_float(a.x, "
678     "b.x)*compare_float(a.y, b.y)*compare_float(a.z, b.z); }\n"
679     "mediump float compare_vec4     (highp vec4 a, highp vec4 b)    { return compare_float(a.x, "
680     "b.x)*compare_float(a.y, b.y)*compare_float(a.z, b.z)*compare_float(a.w, b.w); }\n"
681     "mediump float compare_mat2     (highp mat2 a, highp mat2 b)    { return compare_vec2(a[0], "
682     "b[0])*compare_vec2(a[1], b[1]); }\n"
683     "mediump float compare_mat2x3   (highp mat2x3 a, highp mat2x3 b){ return compare_vec3(a[0], "
684     "b[0])*compare_vec3(a[1], b[1]); }\n"
685     "mediump float compare_mat2x4   (highp mat2x4 a, highp mat2x4 b){ return compare_vec4(a[0], "
686     "b[0])*compare_vec4(a[1], b[1]); }\n"
687     "mediump float compare_mat3x2   (highp mat3x2 a, highp mat3x2 b){ return compare_vec2(a[0], "
688     "b[0])*compare_vec2(a[1], b[1])*compare_vec2(a[2], b[2]); }\n"
689     "mediump float compare_mat3     (highp mat3 a, highp mat3 b)    { return compare_vec3(a[0], "
690     "b[0])*compare_vec3(a[1], b[1])*compare_vec3(a[2], b[2]); }\n"
691     "mediump float compare_mat3x4   (highp mat3x4 a, highp mat3x4 b){ return compare_vec4(a[0], "
692     "b[0])*compare_vec4(a[1], b[1])*compare_vec4(a[2], b[2]); }\n"
693     "mediump float compare_mat4x2   (highp mat4x2 a, highp mat4x2 b){ return compare_vec2(a[0], "
694     "b[0])*compare_vec2(a[1], b[1])*compare_vec2(a[2], b[2])*compare_vec2(a[3], b[3]); }\n"
695     "mediump float compare_mat4x3   (highp mat4x3 a, highp mat4x3 b){ return compare_vec3(a[0], "
696     "b[0])*compare_vec3(a[1], b[1])*compare_vec3(a[2], b[2])*compare_vec3(a[3], b[3]); }\n"
697     "mediump float compare_mat4     (highp mat4 a, highp mat4 b)    { return compare_vec4(a[0], "
698     "b[0])*compare_vec4(a[1], b[1])*compare_vec4(a[2], b[2])*compare_vec4(a[3], b[3]); }\n"
699     "mediump float compare_int      (highp int a, highp int b)      { return a == b ? 1.0 : 0.0; }\n"
700     "mediump float compare_ivec2    (highp ivec2 a, highp ivec2 b)  { return a == b ? 1.0 : 0.0; }\n"
701     "mediump float compare_ivec3    (highp ivec3 a, highp ivec3 b)  { return a == b ? 1.0 : 0.0; }\n"
702     "mediump float compare_ivec4    (highp ivec4 a, highp ivec4 b)  { return a == b ? 1.0 : 0.0; }\n"
703     "mediump float compare_uint     (highp uint a, highp uint b)    { return a == b ? 1.0 : 0.0; }\n"
704     "mediump float compare_uvec2    (highp uvec2 a, highp uvec2 b)  { return a == b ? 1.0 : 0.0; }\n"
705     "mediump float compare_uvec3    (highp uvec3 a, highp uvec3 b)  { return a == b ? 1.0 : 0.0; }\n"
706     "mediump float compare_uvec4    (highp uvec4 a, highp uvec4 b)  { return a == b ? 1.0 : 0.0; }\n"
707     "mediump float compare_bool     (bool a, bool b)                { return a == b ? 1.0 : 0.0; }\n"
708     "mediump float compare_bvec2    (bvec2 a, bvec2 b)              { return a == b ? 1.0 : 0.0; }\n"
709     "mediump float compare_bvec3    (bvec3 a, bvec3 b)              { return a == b ? 1.0 : 0.0; }\n"
710     "mediump float compare_bvec4    (bvec4 a, bvec4 b)              { return a == b ? 1.0 : 0.0; }\n";
711 
712 struct Indent
713 {
714     int level;
715 
Indentdeqp::ub::__anon657cb1de0211::Indent716     Indent(int level_) : level(level_)
717     {
718     }
719 };
720 
operator <<(std::ostream & str,const Indent & indent)721 std::ostream &operator<<(std::ostream &str, const Indent &indent)
722 {
723     for (int i = 0; i < indent.level; i++)
724         str << "\t";
725     return str;
726 }
727 
728 void generateDeclaration(std::ostringstream &src, const VarType &type, const char *name, int indentLevel,
729                          uint32_t unusedHints);
730 void generateDeclaration(std::ostringstream &src, const Uniform &uniform, int indentLevel);
731 void generateDeclaration(std::ostringstream &src, const StructType &structType, int indentLevel);
732 
733 void generateLocalDeclaration(std::ostringstream &src, const StructType &structType, int indentLevel);
734 void generateFullDeclaration(std::ostringstream &src, const StructType &structType, int indentLevel);
735 
generateDeclaration(std::ostringstream & src,const StructType & structType,int indentLevel)736 void generateDeclaration(std::ostringstream &src, const StructType &structType, int indentLevel)
737 {
738     DE_ASSERT(structType.getTypeName() != DE_NULL);
739     generateFullDeclaration(src, structType, indentLevel);
740     src << ";\n";
741 }
742 
generateFullDeclaration(std::ostringstream & src,const StructType & structType,int indentLevel)743 void generateFullDeclaration(std::ostringstream &src, const StructType &structType, int indentLevel)
744 {
745     src << "struct";
746     if (structType.getTypeName())
747         src << " " << structType.getTypeName();
748     src << "\n" << Indent(indentLevel) << "{\n";
749 
750     for (StructType::ConstIterator memberIter = structType.begin(); memberIter != structType.end(); memberIter++)
751     {
752         src << Indent(indentLevel + 1);
753         generateDeclaration(src, memberIter->getType(), memberIter->getName(), indentLevel + 1,
754                             memberIter->getFlags() & UNUSED_BOTH);
755     }
756 
757     src << Indent(indentLevel) << "}";
758 }
759 
generateLocalDeclaration(std::ostringstream & src,const StructType & structType,int indentLevel)760 void generateLocalDeclaration(std::ostringstream &src, const StructType &structType, int indentLevel)
761 {
762     if (structType.getTypeName() == DE_NULL)
763         generateFullDeclaration(src, structType, indentLevel);
764     else
765         src << structType.getTypeName();
766 }
767 
generateDeclaration(std::ostringstream & src,const VarType & type,const char * name,int indentLevel,uint32_t unusedHints)768 void generateDeclaration(std::ostringstream &src, const VarType &type, const char *name, int indentLevel,
769                          uint32_t unusedHints)
770 {
771     uint32_t flags = type.getFlags();
772 
773     if ((flags & LAYOUT_MASK) != 0)
774         src << "layout(" << LayoutFlagsFmt(flags & LAYOUT_MASK) << ") ";
775 
776     if ((flags & PRECISION_MASK) != 0)
777         src << PrecisionFlagsFmt(flags & PRECISION_MASK) << " ";
778 
779     if (type.isBasicType())
780         src << glu::getDataTypeName(type.getBasicType()) << " " << name;
781     else if (type.isArrayType())
782     {
783         std::vector<int> arraySizes;
784         const VarType *curType = &type;
785         while (curType->isArrayType())
786         {
787             arraySizes.push_back(curType->getArraySize());
788             curType = &curType->getElementType();
789         }
790 
791         if (curType->isBasicType())
792         {
793             if ((curType->getFlags() & PRECISION_MASK) != 0)
794                 src << PrecisionFlagsFmt(curType->getFlags() & PRECISION_MASK) << " ";
795             src << glu::getDataTypeName(curType->getBasicType());
796         }
797         else
798         {
799             DE_ASSERT(curType->isStructType());
800             generateLocalDeclaration(src, curType->getStruct(), indentLevel + 1);
801         }
802 
803         src << " " << name;
804 
805         for (std::vector<int>::const_reverse_iterator sizeIter = arraySizes.rbegin(); sizeIter != arraySizes.rend();
806              sizeIter++)
807             src << "[" << *sizeIter << "]";
808     }
809     else
810     {
811         generateLocalDeclaration(src, type.getStruct(), indentLevel + 1);
812         src << " " << name;
813     }
814 
815     src << ";";
816 
817     // Print out unused hints.
818     if (unusedHints != 0)
819         src << " // unused in "
820             << (unusedHints == UNUSED_BOTH     ? "both shaders" :
821                 unusedHints == UNUSED_VERTEX   ? "vertex shader" :
822                 unusedHints == UNUSED_FRAGMENT ? "fragment shader" :
823                                                  "???");
824 
825     src << "\n";
826 }
827 
generateDeclaration(std::ostringstream & src,const Uniform & uniform,int indentLevel)828 void generateDeclaration(std::ostringstream &src, const Uniform &uniform, int indentLevel)
829 {
830     if ((uniform.getFlags() & LAYOUT_MASK) != 0)
831         src << "layout(" << LayoutFlagsFmt(uniform.getFlags() & LAYOUT_MASK) << ") ";
832 
833     generateDeclaration(src, uniform.getType(), uniform.getName(), indentLevel, uniform.getFlags() & UNUSED_BOTH);
834 }
835 
generateDeclaration(std::ostringstream & src,const UniformBlock & block)836 void generateDeclaration(std::ostringstream &src, const UniformBlock &block)
837 {
838     if ((block.getFlags() & LAYOUT_MASK) != 0)
839         src << "layout(" << LayoutFlagsFmt(block.getFlags() & LAYOUT_MASK) << ") ";
840 
841     src << "uniform " << block.getBlockName();
842     src << "\n{\n";
843 
844     for (UniformBlock::ConstIterator uniformIter = block.begin(); uniformIter != block.end(); uniformIter++)
845     {
846         src << Indent(1);
847         generateDeclaration(src, *uniformIter, 1 /* indent level */);
848     }
849 
850     src << "}";
851 
852     if (block.getInstanceName() != DE_NULL)
853     {
854         src << " " << block.getInstanceName();
855         if (block.isArray())
856             src << "[" << block.getArraySize() << "]";
857     }
858     else
859         DE_ASSERT(!block.isArray());
860 
861     src << ";\n";
862 }
863 
generateValueSrc(std::ostringstream & src,const UniformLayoutEntry & entry,const void * basePtr,int elementNdx)864 void generateValueSrc(std::ostringstream &src, const UniformLayoutEntry &entry, const void *basePtr, int elementNdx)
865 {
866     glu::DataType scalarType = glu::getDataTypeScalarType(entry.type);
867     int scalarSize           = glu::getDataTypeScalarSize(entry.type);
868     bool isArray             = entry.size > 1;
869     const uint8_t *elemPtr   = (const uint8_t *)basePtr + entry.offset + (isArray ? elementNdx * entry.arrayStride : 0);
870     const int compSize       = sizeof(uint32_t);
871 
872     if (scalarSize > 1)
873         src << glu::getDataTypeName(entry.type) << "(";
874 
875     if (glu::isDataTypeMatrix(entry.type))
876     {
877         int numRows = glu::getDataTypeMatrixNumRows(entry.type);
878         int numCols = glu::getDataTypeMatrixNumColumns(entry.type);
879 
880         DE_ASSERT(scalarType == glu::TYPE_FLOAT);
881 
882         // Constructed in column-wise order.
883         for (int colNdx = 0; colNdx < numCols; colNdx++)
884         {
885             for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
886             {
887                 const uint8_t *compPtr = elemPtr + (entry.isRowMajor ? rowNdx * entry.matrixStride + colNdx * compSize :
888                                                                        colNdx * entry.matrixStride + rowNdx * compSize);
889 
890                 if (colNdx > 0 || rowNdx > 0)
891                     src << ", ";
892 
893                 src << de::floatToString(*((const float *)compPtr), 1);
894             }
895         }
896     }
897     else
898     {
899         for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
900         {
901             const uint8_t *compPtr = elemPtr + scalarNdx * compSize;
902 
903             if (scalarNdx > 0)
904                 src << ", ";
905 
906             switch (scalarType)
907             {
908             case glu::TYPE_FLOAT:
909                 src << de::floatToString(*((const float *)compPtr), 1);
910                 break;
911             case glu::TYPE_INT:
912                 src << *((const int *)compPtr);
913                 break;
914             case glu::TYPE_UINT:
915                 src << *((const uint32_t *)compPtr) << "u";
916                 break;
917             case glu::TYPE_BOOL:
918                 src << (*((const uint32_t *)compPtr) != 0u ? "true" : "false");
919                 break;
920             default:
921                 DE_ASSERT(false);
922             }
923         }
924     }
925 
926     if (scalarSize > 1)
927         src << ")";
928 }
929 
generateCompareSrc(std::ostringstream & src,const char * resultVar,const VarType & type,const char * srcName,const char * apiName,const UniformLayout & layout,const void * basePtr,uint32_t unusedMask)930 void generateCompareSrc(std::ostringstream &src, const char *resultVar, const VarType &type, const char *srcName,
931                         const char *apiName, const UniformLayout &layout, const void *basePtr, uint32_t unusedMask)
932 {
933     if (type.isBasicType() || (type.isArrayType() && type.getElementType().isBasicType()))
934     {
935         // Basic type or array of basic types.
936         bool isArray              = type.isArrayType();
937         glu::DataType elementType = isArray ? type.getElementType().getBasicType() : type.getBasicType();
938         const char *typeName      = glu::getDataTypeName(elementType);
939         std::string fullApiName   = string(apiName) + (isArray ? "[0]" : ""); // Arrays are always postfixed with [0]
940         int uniformNdx            = layout.getUniformIndex(fullApiName.c_str());
941         const UniformLayoutEntry &entry = layout.uniforms[uniformNdx];
942 
943         if (isArray)
944         {
945             for (int elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++)
946             {
947                 src << "\tresult *= compare_" << typeName << "(" << srcName << "[" << elemNdx << "], ";
948                 generateValueSrc(src, entry, basePtr, elemNdx);
949                 src << ");\n";
950             }
951         }
952         else
953         {
954             src << "\tresult *= compare_" << typeName << "(" << srcName << ", ";
955             generateValueSrc(src, entry, basePtr, 0);
956             src << ");\n";
957         }
958     }
959     else if (type.isArrayType())
960     {
961         const VarType &elementType = type.getElementType();
962         DE_ASSERT(!elementType.isArrayType());
963 
964         for (int elementNdx = 0; elementNdx < type.getArraySize(); elementNdx++)
965         {
966             std::string op = string("[") + de::toString(elementNdx) + "]";
967             generateCompareSrc(src, resultVar, elementType, (string(srcName) + op).c_str(),
968                                (string(apiName) + op).c_str(), layout, basePtr, unusedMask);
969         }
970     }
971     else
972     {
973         DE_ASSERT(type.isStructType());
974 
975         for (StructType::ConstIterator memberIter = type.getStruct().begin(); memberIter != type.getStruct().end();
976              memberIter++)
977         {
978             if (memberIter->getFlags() & unusedMask)
979                 continue; // Skip member.
980 
981             string op = string(".") + memberIter->getName();
982             generateCompareSrc(src, resultVar, memberIter->getType(), (string(srcName) + op).c_str(),
983                                (string(apiName) + op).c_str(), layout, basePtr, unusedMask);
984         }
985     }
986 }
987 
generateCompareSrc(std::ostringstream & src,const char * resultVar,const ShaderInterface & interface,const UniformLayout & layout,const std::map<int,void * > & blockPointers,bool isVertex)988 void generateCompareSrc(std::ostringstream &src, const char *resultVar, const ShaderInterface &interface,
989                         const UniformLayout &layout, const std::map<int, void *> &blockPointers, bool isVertex)
990 {
991     uint32_t unusedMask = isVertex ? UNUSED_VERTEX : UNUSED_FRAGMENT;
992 
993     for (int blockNdx = 0; blockNdx < interface.getNumUniformBlocks(); blockNdx++)
994     {
995         const UniformBlock &block = interface.getUniformBlock(blockNdx);
996 
997         if ((block.getFlags() & (isVertex ? DECLARE_VERTEX : DECLARE_FRAGMENT)) == 0)
998             continue; // Skip.
999 
1000         bool hasInstanceName  = block.getInstanceName() != DE_NULL;
1001         bool isArray          = block.isArray();
1002         int numInstances      = isArray ? block.getArraySize() : 1;
1003         std::string apiPrefix = hasInstanceName ? string(block.getBlockName()) + "." : string("");
1004 
1005         DE_ASSERT(!isArray || hasInstanceName);
1006 
1007         for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1008         {
1009             std::string instancePostfix   = isArray ? string("[") + de::toString(instanceNdx) + "]" : string("");
1010             std::string blockInstanceName = block.getBlockName() + instancePostfix;
1011             std::string srcPrefix =
1012                 hasInstanceName ? string(block.getInstanceName()) + instancePostfix + "." : string("");
1013             int activeBlockNdx = layout.getBlockIndex(blockInstanceName.c_str());
1014             void *basePtr      = blockPointers.find(activeBlockNdx)->second;
1015 
1016             for (UniformBlock::ConstIterator uniformIter = block.begin(); uniformIter != block.end(); uniformIter++)
1017             {
1018                 const Uniform &uniform = *uniformIter;
1019 
1020                 if (uniform.getFlags() & unusedMask)
1021                     continue; // Don't read from that uniform.
1022 
1023                 generateCompareSrc(src, resultVar, uniform.getType(), (srcPrefix + uniform.getName()).c_str(),
1024                                    (apiPrefix + uniform.getName()).c_str(), layout, basePtr, unusedMask);
1025             }
1026         }
1027     }
1028 }
1029 
generateVertexShader(std::ostringstream & src,glu::GLSLVersion glslVersion,const ShaderInterface & interface,const UniformLayout & layout,const std::map<int,void * > & blockPointers)1030 void generateVertexShader(std::ostringstream &src, glu::GLSLVersion glslVersion, const ShaderInterface &interface,
1031                           const UniformLayout &layout, const std::map<int, void *> &blockPointers)
1032 {
1033     DE_ASSERT(glslVersion == glu::GLSL_VERSION_300_ES || glslVersion == glu::GLSL_VERSION_310_ES ||
1034               de::inRange<int>(glslVersion, glu::GLSL_VERSION_330, glu::GLSL_VERSION_430));
1035 
1036     src << glu::getGLSLVersionDeclaration(glslVersion) << "\n";
1037     src << "in highp vec4 a_position;\n";
1038     src << "out mediump float v_vtxResult;\n";
1039     src << "\n";
1040 
1041     std::vector<const StructType *> namedStructs;
1042     interface.getNamedStructs(namedStructs);
1043     for (std::vector<const StructType *>::const_iterator structIter = namedStructs.begin();
1044          structIter != namedStructs.end(); structIter++)
1045         generateDeclaration(src, **structIter, 0);
1046 
1047     for (int blockNdx = 0; blockNdx < interface.getNumUniformBlocks(); blockNdx++)
1048     {
1049         const UniformBlock &block = interface.getUniformBlock(blockNdx);
1050         if (block.getFlags() & DECLARE_VERTEX)
1051             generateDeclaration(src, block);
1052     }
1053 
1054     // Comparison utilities.
1055     src << "\n" << s_compareFuncs;
1056 
1057     src << "\n"
1058            "void main (void)\n"
1059            "{\n"
1060            "    gl_Position = a_position;\n"
1061            "    mediump float result = 1.0;\n";
1062 
1063     // Value compare.
1064     generateCompareSrc(src, "result", interface, layout, blockPointers, true);
1065 
1066     src << "    v_vtxResult = result;\n"
1067            "}\n";
1068 }
1069 
generateFragmentShader(std::ostringstream & src,glu::GLSLVersion glslVersion,const ShaderInterface & interface,const UniformLayout & layout,const std::map<int,void * > & blockPointers)1070 void generateFragmentShader(std::ostringstream &src, glu::GLSLVersion glslVersion, const ShaderInterface &interface,
1071                             const UniformLayout &layout, const std::map<int, void *> &blockPointers)
1072 {
1073     DE_ASSERT(glslVersion == glu::GLSL_VERSION_300_ES || glslVersion == glu::GLSL_VERSION_310_ES ||
1074               de::inRange<int>(glslVersion, glu::GLSL_VERSION_330, glu::GLSL_VERSION_430));
1075 
1076     src << glu::getGLSLVersionDeclaration(glslVersion) << "\n";
1077     src << "in mediump float v_vtxResult;\n";
1078     src << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
1079     src << "\n";
1080 
1081     std::vector<const StructType *> namedStructs;
1082     interface.getNamedStructs(namedStructs);
1083     for (std::vector<const StructType *>::const_iterator structIter = namedStructs.begin();
1084          structIter != namedStructs.end(); structIter++)
1085         generateDeclaration(src, **structIter, 0);
1086 
1087     for (int blockNdx = 0; blockNdx < interface.getNumUniformBlocks(); blockNdx++)
1088     {
1089         const UniformBlock &block = interface.getUniformBlock(blockNdx);
1090         if (block.getFlags() & DECLARE_FRAGMENT)
1091             generateDeclaration(src, block);
1092     }
1093 
1094     // Comparison utilities.
1095     src << "\n" << s_compareFuncs;
1096 
1097     src << "\n"
1098            "void main (void)\n"
1099            "{\n"
1100            "    mediump float result = 1.0;\n";
1101 
1102     // Value compare.
1103     generateCompareSrc(src, "result", interface, layout, blockPointers, false);
1104 
1105     src << "    dEQP_FragColor = vec4(1.0, v_vtxResult, result, 1.0);\n"
1106            "}\n";
1107 }
1108 
getGLUniformLayout(const glw::Functions & gl,UniformLayout & layout,uint32_t program)1109 void getGLUniformLayout(const glw::Functions &gl, UniformLayout &layout, uint32_t program)
1110 {
1111     int numActiveUniforms = 0;
1112     int numActiveBlocks   = 0;
1113 
1114     gl.getProgramiv(program, GL_ACTIVE_UNIFORMS, &numActiveUniforms);
1115     gl.getProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &numActiveBlocks);
1116 
1117     GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to get number of uniforms and uniform blocks");
1118 
1119     // Block entries.
1120     layout.blocks.resize(numActiveBlocks);
1121     for (int blockNdx = 0; blockNdx < numActiveBlocks; blockNdx++)
1122     {
1123         BlockLayoutEntry &entry = layout.blocks[blockNdx];
1124         int size;
1125         int nameLen;
1126         int numBlockUniforms;
1127 
1128         gl.getActiveUniformBlockiv(program, (uint32_t)blockNdx, GL_UNIFORM_BLOCK_DATA_SIZE, &size);
1129         gl.getActiveUniformBlockiv(program, (uint32_t)blockNdx, GL_UNIFORM_BLOCK_NAME_LENGTH, &nameLen);
1130         gl.getActiveUniformBlockiv(program, (uint32_t)blockNdx, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &numBlockUniforms);
1131 
1132         GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform block query failed");
1133 
1134         // \note Some implementations incorrectly return 0 as name length even though the length should include null terminator.
1135         std::vector<char> nameBuf(nameLen > 0 ? nameLen : 1);
1136         gl.getActiveUniformBlockName(program, (uint32_t)blockNdx, (glw::GLsizei)nameBuf.size(), DE_NULL, &nameBuf[0]);
1137 
1138         entry.name = std::string(&nameBuf[0]);
1139         entry.size = size;
1140         entry.activeUniformIndices.resize(numBlockUniforms);
1141 
1142         if (numBlockUniforms > 0)
1143             gl.getActiveUniformBlockiv(program, (uint32_t)blockNdx, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES,
1144                                        &entry.activeUniformIndices[0]);
1145 
1146         GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform block query failed");
1147     }
1148 
1149     if (numActiveUniforms > 0)
1150     {
1151         // Uniform entries.
1152         std::vector<uint32_t> uniformIndices(numActiveUniforms);
1153         for (int i = 0; i < numActiveUniforms; i++)
1154             uniformIndices[i] = (uint32_t)i;
1155 
1156         std::vector<int> types(numActiveUniforms);
1157         std::vector<int> sizes(numActiveUniforms);
1158         std::vector<int> nameLengths(numActiveUniforms);
1159         std::vector<int> blockIndices(numActiveUniforms);
1160         std::vector<int> offsets(numActiveUniforms);
1161         std::vector<int> arrayStrides(numActiveUniforms);
1162         std::vector<int> matrixStrides(numActiveUniforms);
1163         std::vector<int> rowMajorFlags(numActiveUniforms);
1164 
1165         // Execute queries.
1166         gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0], GL_UNIFORM_TYPE,
1167                                &types[0]);
1168         gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0], GL_UNIFORM_SIZE,
1169                                &sizes[0]);
1170         gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0], GL_UNIFORM_NAME_LENGTH,
1171                                &nameLengths[0]);
1172         gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0], GL_UNIFORM_BLOCK_INDEX,
1173                                &blockIndices[0]);
1174         gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0], GL_UNIFORM_OFFSET,
1175                                &offsets[0]);
1176         gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0],
1177                                GL_UNIFORM_ARRAY_STRIDE, &arrayStrides[0]);
1178         gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0],
1179                                GL_UNIFORM_MATRIX_STRIDE, &matrixStrides[0]);
1180         gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0],
1181                                GL_UNIFORM_IS_ROW_MAJOR, &rowMajorFlags[0]);
1182 
1183         GLU_EXPECT_NO_ERROR(gl.getError(), "Active uniform query failed");
1184 
1185         // Translate to LayoutEntries
1186         layout.uniforms.resize(numActiveUniforms);
1187         for (int uniformNdx = 0; uniformNdx < numActiveUniforms; uniformNdx++)
1188         {
1189             UniformLayoutEntry &entry = layout.uniforms[uniformNdx];
1190             std::vector<char> nameBuf(nameLengths[uniformNdx]);
1191             glw::GLsizei nameLen = 0;
1192             int size             = 0;
1193             uint32_t type        = GL_NONE;
1194 
1195             gl.getActiveUniform(program, (uint32_t)uniformNdx, (glw::GLsizei)nameBuf.size(), &nameLen, &size, &type,
1196                                 &nameBuf[0]);
1197 
1198             GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform name query failed");
1199 
1200             // \note glGetActiveUniform() returns length without \0 and glGetActiveUniformsiv() with \0
1201             if (nameLen + 1 != nameLengths[uniformNdx] || size != sizes[uniformNdx] ||
1202                 type != (uint32_t)types[uniformNdx])
1203                 TCU_FAIL("Values returned by glGetActiveUniform() don't match with values queried with "
1204                          "glGetActiveUniformsiv().");
1205 
1206             entry.name         = std::string(&nameBuf[0]);
1207             entry.type         = glu::getDataTypeFromGLType(types[uniformNdx]);
1208             entry.size         = sizes[uniformNdx];
1209             entry.blockNdx     = blockIndices[uniformNdx];
1210             entry.offset       = offsets[uniformNdx];
1211             entry.arrayStride  = arrayStrides[uniformNdx];
1212             entry.matrixStride = matrixStrides[uniformNdx];
1213             entry.isRowMajor   = rowMajorFlags[uniformNdx] != GL_FALSE;
1214         }
1215     }
1216 }
1217 
copyUniformData(const UniformLayoutEntry & dstEntry,void * dstBlockPtr,const UniformLayoutEntry & srcEntry,const void * srcBlockPtr)1218 void copyUniformData(const UniformLayoutEntry &dstEntry, void *dstBlockPtr, const UniformLayoutEntry &srcEntry,
1219                      const void *srcBlockPtr)
1220 {
1221     uint8_t *dstBasePtr       = (uint8_t *)dstBlockPtr + dstEntry.offset;
1222     const uint8_t *srcBasePtr = (const uint8_t *)srcBlockPtr + srcEntry.offset;
1223 
1224     DE_ASSERT(dstEntry.size <= srcEntry.size);
1225     DE_ASSERT(dstEntry.type == srcEntry.type);
1226 
1227     int scalarSize     = glu::getDataTypeScalarSize(dstEntry.type);
1228     bool isMatrix      = glu::isDataTypeMatrix(dstEntry.type);
1229     const int compSize = sizeof(uint32_t);
1230 
1231     for (int elementNdx = 0; elementNdx < dstEntry.size; elementNdx++)
1232     {
1233         uint8_t *dstElemPtr       = dstBasePtr + elementNdx * dstEntry.arrayStride;
1234         const uint8_t *srcElemPtr = srcBasePtr + elementNdx * srcEntry.arrayStride;
1235 
1236         if (isMatrix)
1237         {
1238             int numRows = glu::getDataTypeMatrixNumRows(dstEntry.type);
1239             int numCols = glu::getDataTypeMatrixNumColumns(dstEntry.type);
1240 
1241             for (int colNdx = 0; colNdx < numCols; colNdx++)
1242             {
1243                 for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
1244                 {
1245                     uint8_t *dstCompPtr =
1246                         dstElemPtr + (dstEntry.isRowMajor ? rowNdx * dstEntry.matrixStride + colNdx * compSize :
1247                                                             colNdx * dstEntry.matrixStride + rowNdx * compSize);
1248                     const uint8_t *srcCompPtr =
1249                         srcElemPtr + (srcEntry.isRowMajor ? rowNdx * srcEntry.matrixStride + colNdx * compSize :
1250                                                             colNdx * srcEntry.matrixStride + rowNdx * compSize);
1251                     deMemcpy(dstCompPtr, srcCompPtr, compSize);
1252                 }
1253             }
1254         }
1255         else
1256             deMemcpy(dstElemPtr, srcElemPtr, scalarSize * compSize);
1257     }
1258 }
1259 
copyUniformData(const UniformLayout & dstLayout,const std::map<int,void * > & dstBlockPointers,const UniformLayout & srcLayout,const std::map<int,void * > & srcBlockPointers)1260 void copyUniformData(const UniformLayout &dstLayout, const std::map<int, void *> &dstBlockPointers,
1261                      const UniformLayout &srcLayout, const std::map<int, void *> &srcBlockPointers)
1262 {
1263     // \note Src layout is used as reference in case of activeUniforms happens to be incorrect in dstLayout blocks.
1264     int numBlocks = (int)srcLayout.blocks.size();
1265 
1266     for (int srcBlockNdx = 0; srcBlockNdx < numBlocks; srcBlockNdx++)
1267     {
1268         const BlockLayoutEntry &srcBlock = srcLayout.blocks[srcBlockNdx];
1269         const void *srcBlockPtr          = srcBlockPointers.find(srcBlockNdx)->second;
1270         int dstBlockNdx                  = dstLayout.getBlockIndex(srcBlock.name.c_str());
1271         void *dstBlockPtr                = dstBlockNdx >= 0 ? dstBlockPointers.find(dstBlockNdx)->second : DE_NULL;
1272 
1273         if (dstBlockNdx < 0)
1274             continue;
1275 
1276         for (vector<int>::const_iterator srcUniformNdxIter = srcBlock.activeUniformIndices.begin();
1277              srcUniformNdxIter != srcBlock.activeUniformIndices.end(); srcUniformNdxIter++)
1278         {
1279             const UniformLayoutEntry &srcEntry = srcLayout.uniforms[*srcUniformNdxIter];
1280             int dstUniformNdx                  = dstLayout.getUniformIndex(srcEntry.name.c_str());
1281 
1282             if (dstUniformNdx < 0)
1283                 continue;
1284 
1285             copyUniformData(dstLayout.uniforms[dstUniformNdx], dstBlockPtr, srcEntry, srcBlockPtr);
1286         }
1287     }
1288 }
1289 
1290 } // namespace
1291 
1292 class UniformBufferManager
1293 {
1294 public:
1295     UniformBufferManager(const glu::RenderContext &renderCtx);
1296     ~UniformBufferManager(void);
1297 
1298     uint32_t allocBuffer(void);
1299 
1300 private:
1301     UniformBufferManager(const UniformBufferManager &other);
1302     UniformBufferManager &operator=(const UniformBufferManager &other);
1303 
1304     const glu::RenderContext &m_renderCtx;
1305     std::vector<uint32_t> m_buffers;
1306 };
1307 
UniformBufferManager(const glu::RenderContext & renderCtx)1308 UniformBufferManager::UniformBufferManager(const glu::RenderContext &renderCtx) : m_renderCtx(renderCtx)
1309 {
1310 }
1311 
~UniformBufferManager(void)1312 UniformBufferManager::~UniformBufferManager(void)
1313 {
1314     if (!m_buffers.empty())
1315         m_renderCtx.getFunctions().deleteBuffers((glw::GLsizei)m_buffers.size(), &m_buffers[0]);
1316 }
1317 
allocBuffer(void)1318 uint32_t UniformBufferManager::allocBuffer(void)
1319 {
1320     uint32_t buf = 0;
1321 
1322     m_buffers.reserve(m_buffers.size() + 1);
1323     m_renderCtx.getFunctions().genBuffers(1, &buf);
1324     GLU_EXPECT_NO_ERROR(m_renderCtx.getFunctions().getError(), "Failed to allocate uniform buffer");
1325     m_buffers.push_back(buf);
1326 
1327     return buf;
1328 }
1329 
1330 } // namespace ub
1331 
1332 using namespace ub;
1333 
1334 // UniformBlockCase.
1335 
UniformBlockCase(Context & context,const char * name,const char * description,glu::GLSLVersion glslVersion,BufferMode bufferMode)1336 UniformBlockCase::UniformBlockCase(Context &context, const char *name, const char *description,
1337                                    glu::GLSLVersion glslVersion, BufferMode bufferMode)
1338     : TestCase(context, name, description)
1339     , m_glslVersion(glslVersion)
1340     , m_bufferMode(bufferMode)
1341 {
1342     // \todo [2013-05-25 pyry] Support other versions as well.
1343     DE_ASSERT(glslVersion == glu::GLSL_VERSION_300_ES || glslVersion == glu::GLSL_VERSION_330);
1344 }
1345 
~UniformBlockCase(void)1346 UniformBlockCase::~UniformBlockCase(void)
1347 {
1348 }
1349 
iterate(void)1350 UniformBlockCase::IterateResult UniformBlockCase::iterate(void)
1351 {
1352     TestLog &log             = m_testCtx.getLog();
1353     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1354     UniformLayout refLayout;        //!< std140 layout.
1355     vector<uint8_t> data;           //!< Data.
1356     map<int, void *> blockPointers; //!< Reference block pointers.
1357 
1358     // Initialize result to pass.
1359     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1360 
1361     // Compute reference layout.
1362     computeStd140Layout(refLayout, m_interface);
1363 
1364     // Assign storage for reference values.
1365     {
1366         int totalSize = 0;
1367         for (vector<BlockLayoutEntry>::const_iterator blockIter = refLayout.blocks.begin();
1368              blockIter != refLayout.blocks.end(); blockIter++)
1369             totalSize += blockIter->size;
1370         data.resize(totalSize);
1371 
1372         // Pointers for each block.
1373         int curOffset = 0;
1374         for (int blockNdx = 0; blockNdx < (int)refLayout.blocks.size(); blockNdx++)
1375         {
1376             blockPointers[blockNdx] = &data[0] + curOffset;
1377             curOffset += refLayout.blocks[blockNdx].size;
1378         }
1379     }
1380 
1381     // Generate values.
1382     generateValues(refLayout, blockPointers, 1 /* seed */);
1383 
1384     // Generate shaders and build program.
1385     std::ostringstream vtxSrc;
1386     std::ostringstream fragSrc;
1387 
1388     generateVertexShader(vtxSrc, m_glslVersion, m_interface, refLayout, blockPointers);
1389     generateFragmentShader(fragSrc, m_glslVersion, m_interface, refLayout, blockPointers);
1390 
1391     glu::ShaderProgram program(m_context.getRenderContext(),
1392                                glu::makeVtxFragSources(vtxSrc.str().c_str(), fragSrc.str().c_str()));
1393     log << program;
1394 
1395     if (!program.isOk())
1396     {
1397         // Compile failed.
1398         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compile failed");
1399         return STOP;
1400     }
1401 
1402     // Query layout from GL.
1403     UniformLayout glLayout;
1404     getGLUniformLayout(gl, glLayout, program.getProgram());
1405 
1406     // Print layout to log.
1407     log << TestLog::Section("ActiveUniformBlocks", "Active Uniform Blocks");
1408     for (int blockNdx = 0; blockNdx < (int)glLayout.blocks.size(); blockNdx++)
1409         log << TestLog::Message << blockNdx << ": " << glLayout.blocks[blockNdx] << TestLog::EndMessage;
1410     log << TestLog::EndSection;
1411 
1412     log << TestLog::Section("ActiveUniforms", "Active Uniforms");
1413     for (int uniformNdx = 0; uniformNdx < (int)glLayout.uniforms.size(); uniformNdx++)
1414         log << TestLog::Message << uniformNdx << ": " << glLayout.uniforms[uniformNdx] << TestLog::EndMessage;
1415     log << TestLog::EndSection;
1416 
1417     // Check that we can even try rendering with given layout.
1418     if (!checkLayoutIndices(glLayout) || !checkLayoutBounds(glLayout) || !compareTypes(refLayout, glLayout))
1419     {
1420         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid layout");
1421         return STOP; // It is not safe to use the given layout.
1422     }
1423 
1424     // Verify all std140 blocks.
1425     if (!compareStd140Blocks(refLayout, glLayout))
1426         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid std140 layout");
1427 
1428     // Verify all shared blocks - all uniforms should be active, and certain properties match.
1429     if (!compareSharedBlocks(refLayout, glLayout))
1430         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid shared layout");
1431 
1432     // Check consistency with index queries
1433     if (!checkIndexQueries(program.getProgram(), glLayout))
1434         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Inconsintent block index query results");
1435 
1436     // Use program.
1437     gl.useProgram(program.getProgram());
1438 
1439     // Assign binding points to all active uniform blocks.
1440     for (int blockNdx = 0; blockNdx < (int)glLayout.blocks.size(); blockNdx++)
1441     {
1442         uint32_t binding = (uint32_t)blockNdx; // \todo [2012-01-25 pyry] Randomize order?
1443         gl.uniformBlockBinding(program.getProgram(), (uint32_t)blockNdx, binding);
1444     }
1445 
1446     GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set uniform block bindings");
1447 
1448     // Allocate buffers, write data and bind to targets.
1449     UniformBufferManager bufferManager(m_context.getRenderContext());
1450     if (m_bufferMode == BUFFERMODE_PER_BLOCK)
1451     {
1452         int numBlocks = (int)glLayout.blocks.size();
1453         vector<vector<uint8_t>> glData(numBlocks);
1454         map<int, void *> glBlockPointers;
1455 
1456         for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1457         {
1458             glData[blockNdx].resize(glLayout.blocks[blockNdx].size);
1459             glBlockPointers[blockNdx] = &glData[blockNdx][0];
1460         }
1461 
1462         copyUniformData(glLayout, glBlockPointers, refLayout, blockPointers);
1463 
1464         for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1465         {
1466             uint32_t buffer  = bufferManager.allocBuffer();
1467             uint32_t binding = (uint32_t)blockNdx;
1468 
1469             gl.bindBuffer(GL_UNIFORM_BUFFER, buffer);
1470             gl.bufferData(GL_UNIFORM_BUFFER, (glw::GLsizeiptr)glData[blockNdx].size(), &glData[blockNdx][0],
1471                           GL_STATIC_DRAW);
1472             GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to upload uniform buffer data");
1473 
1474             gl.bindBufferBase(GL_UNIFORM_BUFFER, binding, buffer);
1475             GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase(GL_UNIFORM_BUFFER) failed");
1476         }
1477     }
1478     else
1479     {
1480         DE_ASSERT(m_bufferMode == BUFFERMODE_SINGLE);
1481 
1482         int totalSize        = 0;
1483         int curOffset        = 0;
1484         int numBlocks        = (int)glLayout.blocks.size();
1485         int bindingAlignment = m_context.getContextInfo().getInt(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT);
1486         map<int, int> glBlockOffsets;
1487 
1488         // Compute total size and offsets.
1489         curOffset = 0;
1490         for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1491         {
1492             if (bindingAlignment > 0)
1493                 curOffset = deRoundUp32(curOffset, bindingAlignment);
1494             glBlockOffsets[blockNdx] = curOffset;
1495             curOffset += glLayout.blocks[blockNdx].size;
1496         }
1497         totalSize = curOffset;
1498 
1499         // Assign block pointers.
1500         vector<uint8_t> glData(totalSize);
1501         map<int, void *> glBlockPointers;
1502 
1503         for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1504             glBlockPointers[blockNdx] = &glData[glBlockOffsets[blockNdx]];
1505 
1506         // Copy to gl format.
1507         copyUniformData(glLayout, glBlockPointers, refLayout, blockPointers);
1508 
1509         // Allocate buffer and upload data.
1510         uint32_t buffer = bufferManager.allocBuffer();
1511         gl.bindBuffer(GL_UNIFORM_BUFFER, buffer);
1512         if (!glData.empty())
1513             gl.bufferData(GL_UNIFORM_BUFFER, (glw::GLsizeiptr)glData.size(), &glData[0], GL_STATIC_DRAW);
1514 
1515         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to upload uniform buffer data");
1516 
1517         // Bind ranges to binding points.
1518         curOffset = 0;
1519         for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1520         {
1521             uint32_t binding = (uint32_t)blockNdx;
1522             gl.bindBufferRange(GL_UNIFORM_BUFFER, binding, buffer, (glw::GLintptr)glBlockOffsets[blockNdx],
1523                                (glw::GLsizeiptr)glLayout.blocks[blockNdx].size);
1524             GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferRange(GL_UNIFORM_BUFFER) failed");
1525             curOffset += glLayout.blocks[blockNdx].size;
1526         }
1527     }
1528 
1529     bool renderOk = render(program);
1530     if (!renderOk)
1531         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image compare failed");
1532 
1533     return STOP;
1534 }
1535 
compareStd140Blocks(const UniformLayout & refLayout,const UniformLayout & cmpLayout) const1536 bool UniformBlockCase::compareStd140Blocks(const UniformLayout &refLayout, const UniformLayout &cmpLayout) const
1537 {
1538     TestLog &log  = m_testCtx.getLog();
1539     bool isOk     = true;
1540     int numBlocks = m_interface.getNumUniformBlocks();
1541 
1542     for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1543     {
1544         const UniformBlock &block = m_interface.getUniformBlock(blockNdx);
1545         bool isArray              = block.isArray();
1546         std::string instanceName  = string(block.getBlockName()) + (isArray ? "[0]" : "");
1547         int refBlockNdx           = refLayout.getBlockIndex(instanceName.c_str());
1548         int cmpBlockNdx           = cmpLayout.getBlockIndex(instanceName.c_str());
1549         bool isUsed               = (block.getFlags() & (DECLARE_VERTEX | DECLARE_FRAGMENT)) != 0;
1550 
1551         if ((block.getFlags() & LAYOUT_STD140) == 0)
1552             continue; // Not std140 layout.
1553 
1554         DE_ASSERT(refBlockNdx >= 0);
1555 
1556         if (cmpBlockNdx < 0)
1557         {
1558             // Not found, should it?
1559             if (isUsed)
1560             {
1561                 log << TestLog::Message << "Error: Uniform block '" << instanceName << "' not found"
1562                     << TestLog::EndMessage;
1563                 isOk = false;
1564             }
1565 
1566             continue; // Skip block.
1567         }
1568 
1569         const BlockLayoutEntry &refBlockLayout = refLayout.blocks[refBlockNdx];
1570         const BlockLayoutEntry &cmpBlockLayout = cmpLayout.blocks[cmpBlockNdx];
1571 
1572         // \todo [2012-01-24 pyry] Verify that activeUniformIndices is correct.
1573         // \todo [2012-01-24 pyry] Verify all instances.
1574         if (refBlockLayout.activeUniformIndices.size() != cmpBlockLayout.activeUniformIndices.size())
1575         {
1576             log << TestLog::Message << "Error: Number of active uniforms differ in block '" << instanceName
1577                 << "' (expected " << refBlockLayout.activeUniformIndices.size() << ", got "
1578                 << cmpBlockLayout.activeUniformIndices.size() << ")" << TestLog::EndMessage;
1579             isOk = false;
1580         }
1581 
1582         for (vector<int>::const_iterator ndxIter = refBlockLayout.activeUniformIndices.begin();
1583              ndxIter != refBlockLayout.activeUniformIndices.end(); ndxIter++)
1584         {
1585             const UniformLayoutEntry &refEntry = refLayout.uniforms[*ndxIter];
1586             int cmpEntryNdx                    = cmpLayout.getUniformIndex(refEntry.name.c_str());
1587 
1588             if (cmpEntryNdx < 0)
1589             {
1590                 log << TestLog::Message << "Error: Uniform '" << refEntry.name << "' not found" << TestLog::EndMessage;
1591                 isOk = false;
1592                 continue;
1593             }
1594 
1595             const UniformLayoutEntry &cmpEntry = cmpLayout.uniforms[cmpEntryNdx];
1596 
1597             if (refEntry.type != cmpEntry.type || refEntry.size != cmpEntry.size ||
1598                 refEntry.offset != cmpEntry.offset || refEntry.arrayStride != cmpEntry.arrayStride ||
1599                 refEntry.matrixStride != cmpEntry.matrixStride || refEntry.isRowMajor != cmpEntry.isRowMajor)
1600             {
1601                 log << TestLog::Message << "Error: Layout mismatch in '" << refEntry.name << "':\n"
1602                     << "  expected: type = " << glu::getDataTypeName(refEntry.type) << ", size = " << refEntry.size
1603                     << ", offset = " << refEntry.offset << ", array stride = " << refEntry.arrayStride
1604                     << ", matrix stride = " << refEntry.matrixStride
1605                     << ", row major = " << (refEntry.isRowMajor ? "true" : "false") << "\n"
1606                     << "  got: type = " << glu::getDataTypeName(cmpEntry.type) << ", size = " << cmpEntry.size
1607                     << ", offset = " << cmpEntry.offset << ", array stride = " << cmpEntry.arrayStride
1608                     << ", matrix stride = " << cmpEntry.matrixStride
1609                     << ", row major = " << (cmpEntry.isRowMajor ? "true" : "false") << TestLog::EndMessage;
1610                 isOk = false;
1611             }
1612         }
1613     }
1614 
1615     return isOk;
1616 }
1617 
compareSharedBlocks(const UniformLayout & refLayout,const UniformLayout & cmpLayout) const1618 bool UniformBlockCase::compareSharedBlocks(const UniformLayout &refLayout, const UniformLayout &cmpLayout) const
1619 {
1620     TestLog &log  = m_testCtx.getLog();
1621     bool isOk     = true;
1622     int numBlocks = m_interface.getNumUniformBlocks();
1623 
1624     for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1625     {
1626         const UniformBlock &block = m_interface.getUniformBlock(blockNdx);
1627         bool isArray              = block.isArray();
1628         std::string instanceName  = string(block.getBlockName()) + (isArray ? "[0]" : "");
1629         int refBlockNdx           = refLayout.getBlockIndex(instanceName.c_str());
1630         int cmpBlockNdx           = cmpLayout.getBlockIndex(instanceName.c_str());
1631         bool isUsed               = (block.getFlags() & (DECLARE_VERTEX | DECLARE_FRAGMENT)) != 0;
1632 
1633         if ((block.getFlags() & LAYOUT_SHARED) == 0)
1634             continue; // Not shared layout.
1635 
1636         DE_ASSERT(refBlockNdx >= 0);
1637 
1638         if (cmpBlockNdx < 0)
1639         {
1640             // Not found, should it?
1641             if (isUsed)
1642             {
1643                 log << TestLog::Message << "Error: Uniform block '" << instanceName << "' not found"
1644                     << TestLog::EndMessage;
1645                 isOk = false;
1646             }
1647 
1648             continue; // Skip block.
1649         }
1650 
1651         const BlockLayoutEntry &refBlockLayout = refLayout.blocks[refBlockNdx];
1652         const BlockLayoutEntry &cmpBlockLayout = cmpLayout.blocks[cmpBlockNdx];
1653 
1654         if (refBlockLayout.activeUniformIndices.size() != cmpBlockLayout.activeUniformIndices.size())
1655         {
1656             log << TestLog::Message << "Error: Number of active uniforms differ in block '" << instanceName
1657                 << "' (expected " << refBlockLayout.activeUniformIndices.size() << ", got "
1658                 << cmpBlockLayout.activeUniformIndices.size() << ")" << TestLog::EndMessage;
1659             isOk = false;
1660         }
1661 
1662         for (vector<int>::const_iterator ndxIter = refBlockLayout.activeUniformIndices.begin();
1663              ndxIter != refBlockLayout.activeUniformIndices.end(); ndxIter++)
1664         {
1665             const UniformLayoutEntry &refEntry = refLayout.uniforms[*ndxIter];
1666             int cmpEntryNdx                    = cmpLayout.getUniformIndex(refEntry.name.c_str());
1667 
1668             if (cmpEntryNdx < 0)
1669             {
1670                 log << TestLog::Message << "Error: Uniform '" << refEntry.name << "' not found" << TestLog::EndMessage;
1671                 isOk = false;
1672                 continue;
1673             }
1674 
1675             const UniformLayoutEntry &cmpEntry = cmpLayout.uniforms[cmpEntryNdx];
1676 
1677             if (refEntry.type != cmpEntry.type || refEntry.size != cmpEntry.size ||
1678                 refEntry.isRowMajor != cmpEntry.isRowMajor)
1679             {
1680                 log << TestLog::Message << "Error: Layout mismatch in '" << refEntry.name << "':\n"
1681                     << "  expected: type = " << glu::getDataTypeName(refEntry.type) << ", size = " << refEntry.size
1682                     << ", row major = " << (refEntry.isRowMajor ? "true" : "false") << "\n"
1683                     << "  got: type = " << glu::getDataTypeName(cmpEntry.type) << ", size = " << cmpEntry.size
1684                     << ", row major = " << (cmpEntry.isRowMajor ? "true" : "false") << TestLog::EndMessage;
1685                 isOk = false;
1686             }
1687         }
1688     }
1689 
1690     return isOk;
1691 }
1692 
compareTypes(const UniformLayout & refLayout,const UniformLayout & cmpLayout) const1693 bool UniformBlockCase::compareTypes(const UniformLayout &refLayout, const UniformLayout &cmpLayout) const
1694 {
1695     TestLog &log  = m_testCtx.getLog();
1696     bool isOk     = true;
1697     int numBlocks = m_interface.getNumUniformBlocks();
1698 
1699     for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1700     {
1701         const UniformBlock &block = m_interface.getUniformBlock(blockNdx);
1702         bool isArray              = block.isArray();
1703         int numInstances          = isArray ? block.getArraySize() : 1;
1704 
1705         for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1706         {
1707             std::ostringstream instanceName;
1708 
1709             instanceName << block.getBlockName();
1710             if (isArray)
1711                 instanceName << "[" << instanceNdx << "]";
1712 
1713             int cmpBlockNdx = cmpLayout.getBlockIndex(instanceName.str().c_str());
1714 
1715             if (cmpBlockNdx < 0)
1716                 continue;
1717 
1718             const BlockLayoutEntry &cmpBlockLayout = cmpLayout.blocks[cmpBlockNdx];
1719 
1720             for (vector<int>::const_iterator ndxIter = cmpBlockLayout.activeUniformIndices.begin();
1721                  ndxIter != cmpBlockLayout.activeUniformIndices.end(); ndxIter++)
1722             {
1723                 const UniformLayoutEntry &cmpEntry = cmpLayout.uniforms[*ndxIter];
1724                 int refEntryNdx                    = refLayout.getUniformIndex(cmpEntry.name.c_str());
1725 
1726                 if (refEntryNdx < 0)
1727                 {
1728                     log << TestLog::Message << "Error: Uniform '" << cmpEntry.name << "' not found in reference layout"
1729                         << TestLog::EndMessage;
1730                     isOk = false;
1731                     continue;
1732                 }
1733 
1734                 const UniformLayoutEntry &refEntry = refLayout.uniforms[refEntryNdx];
1735 
1736                 // \todo [2012-11-26 pyry] Should we check other properties as well?
1737                 if (refEntry.type != cmpEntry.type)
1738                 {
1739                     log << TestLog::Message << "Error: Uniform type mismatch in '" << refEntry.name << "':\n"
1740                         << "  expected: " << glu::getDataTypeName(refEntry.type) << "\n"
1741                         << "  got: " << glu::getDataTypeName(cmpEntry.type) << TestLog::EndMessage;
1742                     isOk = false;
1743                 }
1744             }
1745         }
1746     }
1747 
1748     return isOk;
1749 }
1750 
checkLayoutIndices(const UniformLayout & layout) const1751 bool UniformBlockCase::checkLayoutIndices(const UniformLayout &layout) const
1752 {
1753     TestLog &log    = m_testCtx.getLog();
1754     int numUniforms = (int)layout.uniforms.size();
1755     int numBlocks   = (int)layout.blocks.size();
1756     bool isOk       = true;
1757 
1758     // Check uniform block indices.
1759     for (int uniformNdx = 0; uniformNdx < numUniforms; uniformNdx++)
1760     {
1761         const UniformLayoutEntry &uniform = layout.uniforms[uniformNdx];
1762 
1763         if (uniform.blockNdx < 0 || !deInBounds32(uniform.blockNdx, 0, numBlocks))
1764         {
1765             log << TestLog::Message << "Error: Invalid block index in uniform '" << uniform.name << "'"
1766                 << TestLog::EndMessage;
1767             isOk = false;
1768         }
1769     }
1770 
1771     // Check active uniforms.
1772     for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1773     {
1774         const BlockLayoutEntry &block = layout.blocks[blockNdx];
1775 
1776         for (vector<int>::const_iterator uniformIter = block.activeUniformIndices.begin();
1777              uniformIter != block.activeUniformIndices.end(); uniformIter++)
1778         {
1779             if (!deInBounds32(*uniformIter, 0, numUniforms))
1780             {
1781                 log << TestLog::Message << "Error: Invalid active uniform index " << *uniformIter << " in block '"
1782                     << block.name << "'" << TestLog::EndMessage;
1783                 isOk = false;
1784             }
1785         }
1786     }
1787 
1788     return isOk;
1789 }
1790 
checkLayoutBounds(const UniformLayout & layout) const1791 bool UniformBlockCase::checkLayoutBounds(const UniformLayout &layout) const
1792 {
1793     TestLog &log    = m_testCtx.getLog();
1794     int numUniforms = (int)layout.uniforms.size();
1795     bool isOk       = true;
1796 
1797     for (int uniformNdx = 0; uniformNdx < numUniforms; uniformNdx++)
1798     {
1799         const UniformLayoutEntry &uniform = layout.uniforms[uniformNdx];
1800 
1801         if (uniform.blockNdx < 0)
1802             continue;
1803 
1804         const BlockLayoutEntry &block = layout.blocks[uniform.blockNdx];
1805         bool isMatrix                 = glu::isDataTypeMatrix(uniform.type);
1806         int numVecs                   = isMatrix ? (uniform.isRowMajor ? glu::getDataTypeMatrixNumRows(uniform.type) :
1807                                                                          glu::getDataTypeMatrixNumColumns(uniform.type)) :
1808                                                    1;
1809         int numComps       = isMatrix ? (uniform.isRowMajor ? glu::getDataTypeMatrixNumColumns(uniform.type) :
1810                                                               glu::getDataTypeMatrixNumRows(uniform.type)) :
1811                                         glu::getDataTypeScalarSize(uniform.type);
1812         int numElements    = uniform.size;
1813         const int compSize = sizeof(uint32_t);
1814         int vecSize        = numComps * compSize;
1815 
1816         int minOffset = 0;
1817         int maxOffset = 0;
1818 
1819         // For negative strides.
1820         minOffset = de::min(minOffset, (numVecs - 1) * uniform.matrixStride);
1821         minOffset = de::min(minOffset, (numElements - 1) * uniform.arrayStride);
1822         minOffset = de::min(minOffset, (numElements - 1) * uniform.arrayStride + (numVecs - 1) * uniform.matrixStride);
1823 
1824         maxOffset = de::max(maxOffset, vecSize);
1825         maxOffset = de::max(maxOffset, (numVecs - 1) * uniform.matrixStride + vecSize);
1826         maxOffset = de::max(maxOffset, (numElements - 1) * uniform.arrayStride + vecSize);
1827         maxOffset = de::max(maxOffset,
1828                             (numElements - 1) * uniform.arrayStride + (numVecs - 1) * uniform.matrixStride + vecSize);
1829 
1830         if (uniform.offset + minOffset < 0 || uniform.offset + maxOffset > block.size)
1831         {
1832             log << TestLog::Message << "Error: Uniform '" << uniform.name << "' out of block bounds"
1833                 << TestLog::EndMessage;
1834             isOk = false;
1835         }
1836     }
1837 
1838     return isOk;
1839 }
1840 
checkIndexQueries(uint32_t program,const UniformLayout & layout) const1841 bool UniformBlockCase::checkIndexQueries(uint32_t program, const UniformLayout &layout) const
1842 {
1843     tcu::TestLog &log        = m_testCtx.getLog();
1844     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1845     bool allOk               = true;
1846 
1847     // \note Spec mandates that uniform blocks are assigned consecutive locations from 0
1848     //       to ACTIVE_UNIFORM_BLOCKS. BlockLayoutEntries are stored in that order in UniformLayout.
1849     for (int blockNdx = 0; blockNdx < (int)layout.blocks.size(); blockNdx++)
1850     {
1851         const BlockLayoutEntry &block = layout.blocks[blockNdx];
1852         const int queriedNdx          = gl.getUniformBlockIndex(program, block.name.c_str());
1853 
1854         if (queriedNdx != blockNdx)
1855         {
1856             log << TestLog::Message << "ERROR: glGetUniformBlockIndex(" << block.name << ") returned " << queriedNdx
1857                 << ", expected " << blockNdx << "!" << TestLog::EndMessage;
1858             allOk = false;
1859         }
1860 
1861         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformBlockIndex()");
1862     }
1863 
1864     return allOk;
1865 }
1866 
render(glu::ShaderProgram & program) const1867 bool UniformBlockCase::render(glu::ShaderProgram &program) const
1868 {
1869     tcu::TestLog &log        = m_testCtx.getLog();
1870     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1871     de::Random rnd(deStringHash(getName()));
1872     const tcu::RenderTarget &renderTarget = m_context.getRenderContext().getRenderTarget();
1873     const int viewportW                   = de::min(renderTarget.getWidth(), 128);
1874     const int viewportH                   = de::min(renderTarget.getHeight(), 128);
1875     const int viewportX                   = rnd.getInt(0, renderTarget.getWidth() - viewportW);
1876     const int viewportY                   = rnd.getInt(0, renderTarget.getHeight() - viewportH);
1877 
1878     // Draw
1879     {
1880         const float position[]   = {-1.0f, -1.0f, 0.0f, 1.0f, -1.0f, +1.0f, 0.0f, 1.0f,
1881                                     +1.0f, -1.0f, 0.0f, 1.0f, +1.0f, +1.0f, 0.0f, 1.0f};
1882         const uint16_t indices[] = {0, 1, 2, 2, 1, 3};
1883 
1884         gl.viewport(viewportX, viewportY, viewportW, viewportH);
1885 
1886         glu::VertexArrayBinding posArray = glu::va::Float("a_position", 4, 4, 0, &position[0]);
1887         glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posArray,
1888                   glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
1889         GLU_EXPECT_NO_ERROR(gl.getError(), "Draw failed");
1890     }
1891 
1892     // Verify that all pixels are white.
1893     {
1894         tcu::Surface pixels(viewportW, viewportH);
1895         int numFailedPixels = 0;
1896 
1897         glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, pixels.getAccess());
1898         GLU_EXPECT_NO_ERROR(gl.getError(), "Reading pixels failed");
1899 
1900         for (int y = 0; y < pixels.getHeight(); y++)
1901         {
1902             for (int x = 0; x < pixels.getWidth(); x++)
1903             {
1904                 if (pixels.getPixel(x, y) != tcu::RGBA::white())
1905                     numFailedPixels += 1;
1906             }
1907         }
1908 
1909         if (numFailedPixels > 0)
1910         {
1911             log << TestLog::Image("Image", "Rendered image", pixels);
1912             log << TestLog::Message << "Image comparison failed, got " << numFailedPixels << " non-white pixels"
1913                 << TestLog::EndMessage;
1914         }
1915 
1916         return numFailedPixels == 0;
1917     }
1918 }
1919 
1920 } // namespace deqp
1921