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