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