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