Fix PIPELINE_STAGE_TOP_OF_PIPE_BIT usage in api tests
[platform/upstream/VK-GL-CTS.git] / modules / gles31 / functional / es31fSSBOLayoutCase.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.1 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 SSBO layout case.
22  *//*--------------------------------------------------------------------*/
23
24 #include "es31fSSBOLayoutCase.hpp"
25 #include "gluRenderContext.hpp"
26 #include "gluShaderProgram.hpp"
27 #include "gluPixelTransfer.hpp"
28 #include "gluContextInfo.hpp"
29 #include "gluRenderContext.hpp"
30 #include "gluProgramInterfaceQuery.hpp"
31 #include "gluObjectWrapper.hpp"
32 #include "gluVarTypeUtil.hpp"
33 #include "glwFunctions.hpp"
34 #include "glwEnums.hpp"
35 #include "tcuTestLog.hpp"
36 #include "tcuSurface.hpp"
37 #include "tcuRenderTarget.hpp"
38 #include "deRandom.hpp"
39 #include "deStringUtil.hpp"
40 #include "deMemory.h"
41 #include "deString.h"
42 #include "deMath.h"
43
44 #include <algorithm>
45 #include <map>
46
47 using tcu::TestLog;
48 using std::string;
49 using std::vector;
50 using std::map;
51
52 namespace deqp
53 {
54 namespace gles31
55 {
56
57 using glu::VarType;
58 using glu::StructType;
59 using glu::StructMember;
60
61 namespace bb
62 {
63
64 struct LayoutFlagsFmt
65 {
66         deUint32 flags;
67         LayoutFlagsFmt (deUint32 flags_) : flags(flags_) {}
68 };
69
70 std::ostream& operator<< (std::ostream& str, const LayoutFlagsFmt& fmt)
71 {
72         static const struct
73         {
74                 deUint32        bit;
75                 const char*     token;
76         } bitDesc[] =
77         {
78                 { LAYOUT_SHARED,                "shared"                },
79                 { LAYOUT_PACKED,                "packed"                },
80                 { LAYOUT_STD140,                "std140"                },
81                 { LAYOUT_STD430,                "std430"                },
82                 { LAYOUT_ROW_MAJOR,             "row_major"             },
83                 { LAYOUT_COLUMN_MAJOR,  "column_major"  }
84         };
85
86         deUint32 remBits = fmt.flags;
87         for (int descNdx = 0; descNdx < DE_LENGTH_OF_ARRAY(bitDesc); descNdx++)
88         {
89                 if (remBits & bitDesc[descNdx].bit)
90                 {
91                         if (remBits != fmt.flags)
92                                 str << ", ";
93                         str << bitDesc[descNdx].token;
94                         remBits &= ~bitDesc[descNdx].bit;
95                 }
96         }
97         DE_ASSERT(remBits == 0);
98         return str;
99 }
100
101 // BufferVar implementation.
102
103 BufferVar::BufferVar (const char* name, const VarType& type, deUint32 flags)
104         : m_name        (name)
105         , m_type        (type)
106         , m_flags       (flags)
107 {
108 }
109
110 // BufferBlock implementation.
111
112 BufferBlock::BufferBlock (const char* blockName)
113         : m_blockName   (blockName)
114         , m_arraySize   (-1)
115         , m_flags               (0)
116 {
117         setArraySize(0);
118 }
119
120 void BufferBlock::setArraySize (int arraySize)
121 {
122         DE_ASSERT(arraySize >= 0);
123         m_lastUnsizedArraySizes.resize(arraySize == 0 ? 1 : arraySize, 0);
124         m_arraySize = arraySize;
125 }
126
127 struct BlockLayoutEntry
128 {
129         BlockLayoutEntry (void)
130                 : size(0)
131         {
132         }
133
134         std::string                     name;
135         int                                     size;
136         std::vector<int>        activeVarIndices;
137 };
138
139 std::ostream& operator<< (std::ostream& stream, const BlockLayoutEntry& entry)
140 {
141         stream << entry.name << " { name = " << entry.name
142                    << ", size = " << entry.size
143                    << ", activeVarIndices = [";
144
145         for (vector<int>::const_iterator i = entry.activeVarIndices.begin(); i != entry.activeVarIndices.end(); i++)
146         {
147                 if (i != entry.activeVarIndices.begin())
148                         stream << ", ";
149                 stream << *i;
150         }
151
152         stream << "] }";
153         return stream;
154 }
155
156 struct BufferVarLayoutEntry
157 {
158         BufferVarLayoutEntry (void)
159                 : type                                  (glu::TYPE_LAST)
160                 , blockNdx                              (-1)
161                 , offset                                (-1)
162                 , arraySize                             (-1)
163                 , arrayStride                   (-1)
164                 , matrixStride                  (-1)
165                 , topLevelArraySize             (-1)
166                 , topLevelArrayStride   (-1)
167                 , isRowMajor                    (false)
168         {
169         }
170
171         std::string                     name;
172         glu::DataType           type;
173         int                                     blockNdx;
174         int                                     offset;
175         int                                     arraySize;
176         int                                     arrayStride;
177         int                                     matrixStride;
178         int                                     topLevelArraySize;
179         int                                     topLevelArrayStride;
180         bool                            isRowMajor;
181 };
182
183 static bool isUnsizedArray (const BufferVarLayoutEntry& entry)
184 {
185         DE_ASSERT(entry.arraySize != 0 || entry.topLevelArraySize != 0);
186         return entry.arraySize == 0 || entry.topLevelArraySize == 0;
187 }
188
189 std::ostream& operator<< (std::ostream& stream, const BufferVarLayoutEntry& entry)
190 {
191         stream << entry.name << " { type = " << glu::getDataTypeName(entry.type)
192                    << ", blockNdx = " << entry.blockNdx
193                    << ", offset = " << entry.offset
194                    << ", arraySize = " << entry.arraySize
195                    << ", arrayStride = " << entry.arrayStride
196                    << ", matrixStride = " << entry.matrixStride
197                    << ", topLevelArraySize = " << entry.topLevelArraySize
198                    << ", topLevelArrayStride = " << entry.topLevelArrayStride
199                    << ", isRowMajor = " << (entry.isRowMajor ? "true" : "false")
200                    << " }";
201         return stream;
202 }
203
204 class BufferLayout
205 {
206 public:
207         std::vector<BlockLayoutEntry>           blocks;
208         std::vector<BufferVarLayoutEntry>       bufferVars;
209
210         int                                                                     getVariableIndex                (const string& name) const;
211         int                                                                     getBlockIndex                   (const string& name) const;
212 };
213
214 // \todo [2012-01-24 pyry] Speed up lookups using hash.
215
216 int BufferLayout::getVariableIndex (const string& name) const
217 {
218         for (int ndx = 0; ndx < (int)bufferVars.size(); ndx++)
219         {
220                 if (bufferVars[ndx].name == name)
221                         return ndx;
222         }
223         return -1;
224 }
225
226 int BufferLayout::getBlockIndex (const string& name) const
227 {
228         for (int ndx = 0; ndx < (int)blocks.size(); ndx++)
229         {
230                 if (blocks[ndx].name == name)
231                         return ndx;
232         }
233         return -1;
234 }
235
236 // ShaderInterface implementation.
237
238 ShaderInterface::ShaderInterface (void)
239 {
240 }
241
242 ShaderInterface::~ShaderInterface (void)
243 {
244         for (std::vector<StructType*>::iterator i = m_structs.begin(); i != m_structs.end(); i++)
245                 delete *i;
246
247         for (std::vector<BufferBlock*>::iterator i = m_bufferBlocks.begin(); i != m_bufferBlocks.end(); i++)
248                 delete *i;
249 }
250
251 StructType& ShaderInterface::allocStruct (const char* name)
252 {
253         m_structs.reserve(m_structs.size()+1);
254         m_structs.push_back(new StructType(name));
255         return *m_structs.back();
256 }
257
258 struct StructNameEquals
259 {
260         std::string name;
261
262         StructNameEquals (const char* name_) : name(name_) {}
263
264         bool operator() (const StructType* type) const
265         {
266                 return type->getTypeName() && name == type->getTypeName();
267         }
268 };
269
270 const StructType* ShaderInterface::findStruct (const char* name) const
271 {
272         std::vector<StructType*>::const_iterator pos = std::find_if(m_structs.begin(), m_structs.end(), StructNameEquals(name));
273         return pos != m_structs.end() ? *pos : DE_NULL;
274 }
275
276 void ShaderInterface::getNamedStructs (std::vector<const StructType*>& structs) const
277 {
278         for (std::vector<StructType*>::const_iterator i = m_structs.begin(); i != m_structs.end(); i++)
279         {
280                 if ((*i)->getTypeName() != DE_NULL)
281                         structs.push_back(*i);
282         }
283 }
284
285 BufferBlock& ShaderInterface::allocBlock (const char* name)
286 {
287         m_bufferBlocks.reserve(m_bufferBlocks.size()+1);
288         m_bufferBlocks.push_back(new BufferBlock(name));
289         return *m_bufferBlocks.back();
290 }
291
292 // BlockDataPtr
293
294 struct BlockDataPtr
295 {
296         void*           ptr;
297         int                     size;                                           //!< Redundant, for debugging purposes.
298         int                     lastUnsizedArraySize;
299
300         BlockDataPtr (void* ptr_, int size_, int lastUnsizedArraySize_)
301                 : ptr                                   (ptr_)
302                 , size                                  (size_)
303                 , lastUnsizedArraySize  (lastUnsizedArraySize_)
304         {
305         }
306
307         BlockDataPtr (void)
308                 : ptr                                   (DE_NULL)
309                 , size                                  (0)
310                 , lastUnsizedArraySize  (0)
311         {
312         }
313 };
314
315 namespace // Utilities
316 {
317
318 int findBlockIndex (const BufferLayout& layout, const string& name)
319 {
320         for (int ndx = 0; ndx < (int)layout.blocks.size(); ndx++)
321         {
322                 if (layout.blocks[ndx].name == name)
323                         return ndx;
324         }
325         return -1;
326 }
327
328 // Layout computation.
329
330 int getDataTypeByteSize (glu::DataType type)
331 {
332         return glu::getDataTypeScalarSize(type)*(int)sizeof(deUint32);
333 }
334
335 int getDataTypeByteAlignment (glu::DataType type)
336 {
337         switch (type)
338         {
339                 case glu::TYPE_FLOAT:
340                 case glu::TYPE_INT:
341                 case glu::TYPE_UINT:
342                 case glu::TYPE_BOOL:            return 1*(int)sizeof(deUint32);
343
344                 case glu::TYPE_FLOAT_VEC2:
345                 case glu::TYPE_INT_VEC2:
346                 case glu::TYPE_UINT_VEC2:
347                 case glu::TYPE_BOOL_VEC2:       return 2*(int)sizeof(deUint32);
348
349                 case glu::TYPE_FLOAT_VEC3:
350                 case glu::TYPE_INT_VEC3:
351                 case glu::TYPE_UINT_VEC3:
352                 case glu::TYPE_BOOL_VEC3:       // Fall-through to vec4
353
354                 case glu::TYPE_FLOAT_VEC4:
355                 case glu::TYPE_INT_VEC4:
356                 case glu::TYPE_UINT_VEC4:
357                 case glu::TYPE_BOOL_VEC4:       return 4*(int)sizeof(deUint32);
358
359                 default:
360                         DE_ASSERT(false);
361                         return 0;
362         }
363 }
364
365 static inline int deRoundUp32 (int a, int b)
366 {
367         int d = a/b;
368         return d*b == a ? a : (d+1)*b;
369 }
370
371 int computeStd140BaseAlignment (const VarType& type, deUint32 layoutFlags)
372 {
373         const int vec4Alignment = (int)sizeof(deUint32)*4;
374
375         if (type.isBasicType())
376         {
377                 glu::DataType basicType = type.getBasicType();
378
379                 if (glu::isDataTypeMatrix(basicType))
380                 {
381                         const bool      isRowMajor      = !!(layoutFlags & LAYOUT_ROW_MAJOR);
382                         const int       vecSize         = isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType)
383                                                                                                  : glu::getDataTypeMatrixNumRows(basicType);
384                         const int       vecAlign        = deAlign32(getDataTypeByteAlignment(glu::getDataTypeFloatVec(vecSize)), vec4Alignment);
385
386                         return vecAlign;
387                 }
388                 else
389                         return getDataTypeByteAlignment(basicType);
390         }
391         else if (type.isArrayType())
392         {
393                 int elemAlignment = computeStd140BaseAlignment(type.getElementType(), layoutFlags);
394
395                 // Round up to alignment of vec4
396                 return deAlign32(elemAlignment, vec4Alignment);
397         }
398         else
399         {
400                 DE_ASSERT(type.isStructType());
401
402                 int maxBaseAlignment = 0;
403
404                 for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++)
405                         maxBaseAlignment = de::max(maxBaseAlignment, computeStd140BaseAlignment(memberIter->getType(), layoutFlags));
406
407                 return deAlign32(maxBaseAlignment, vec4Alignment);
408         }
409 }
410
411 int computeStd430BaseAlignment (const VarType& type, deUint32 layoutFlags)
412 {
413         // Otherwise identical to std140 except that alignment of structures and arrays
414         // are not rounded up to alignment of vec4.
415
416         if (type.isBasicType())
417         {
418                 glu::DataType basicType = type.getBasicType();
419
420                 if (glu::isDataTypeMatrix(basicType))
421                 {
422                         const bool      isRowMajor      = !!(layoutFlags & LAYOUT_ROW_MAJOR);
423                         const int       vecSize         = isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType)
424                                                                                                  : glu::getDataTypeMatrixNumRows(basicType);
425                         const int       vecAlign        = getDataTypeByteAlignment(glu::getDataTypeFloatVec(vecSize));
426
427                         return vecAlign;
428                 }
429                 else
430                         return getDataTypeByteAlignment(basicType);
431         }
432         else if (type.isArrayType())
433         {
434                 return computeStd430BaseAlignment(type.getElementType(), layoutFlags);
435         }
436         else
437         {
438                 DE_ASSERT(type.isStructType());
439
440                 int maxBaseAlignment = 0;
441
442                 for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++)
443                         maxBaseAlignment = de::max(maxBaseAlignment, computeStd430BaseAlignment(memberIter->getType(), layoutFlags));
444
445                 return maxBaseAlignment;
446         }
447 }
448
449 inline deUint32 mergeLayoutFlags (deUint32 prevFlags, deUint32 newFlags)
450 {
451         const deUint32  packingMask             = LAYOUT_PACKED|LAYOUT_SHARED|LAYOUT_STD140|LAYOUT_STD430;
452         const deUint32  matrixMask              = LAYOUT_ROW_MAJOR|LAYOUT_COLUMN_MAJOR;
453
454         deUint32 mergedFlags = 0;
455
456         mergedFlags |= ((newFlags & packingMask)        ? newFlags : prevFlags) & packingMask;
457         mergedFlags |= ((newFlags & matrixMask)         ? newFlags : prevFlags) & matrixMask;
458
459         return mergedFlags;
460 }
461
462 //! Appends all child elements to layout, returns value that should be appended to offset.
463 int computeReferenceLayout (
464         BufferLayout&           layout,
465         int                                     curBlockNdx,
466         int                                     baseOffset,
467         const std::string&      curPrefix,
468         const VarType&          type,
469         deUint32                        layoutFlags)
470 {
471         // Reference layout uses std430 rules by default. std140 rules are
472         // choosen only for blocks that have std140 layout.
473         const bool      isStd140                        = (layoutFlags & LAYOUT_STD140) != 0;
474         const int       baseAlignment           = isStd140 ? computeStd140BaseAlignment(type, layoutFlags)
475                                                                                            : computeStd430BaseAlignment(type, layoutFlags);
476         int                     curOffset                       = deAlign32(baseOffset, baseAlignment);
477         const int       topLevelArraySize       = 1; // Default values
478         const int       topLevelArrayStride     = 0;
479
480         if (type.isBasicType())
481         {
482                 const glu::DataType             basicType       = type.getBasicType();
483                 BufferVarLayoutEntry    entry;
484
485                 entry.name                                      = curPrefix;
486                 entry.type                                      = basicType;
487                 entry.arraySize                         = 1;
488                 entry.arrayStride                       = 0;
489                 entry.matrixStride                      = 0;
490                 entry.topLevelArraySize         = topLevelArraySize;
491                 entry.topLevelArrayStride       = topLevelArrayStride;
492                 entry.blockNdx                          = curBlockNdx;
493
494                 if (glu::isDataTypeMatrix(basicType))
495                 {
496                         // Array of vectors as specified in rules 5 & 7.
497                         const bool      isRowMajor                      = !!(layoutFlags & LAYOUT_ROW_MAJOR);
498                         const int       numVecs                         = isRowMajor ? glu::getDataTypeMatrixNumRows(basicType)
499                                                                                                                  : glu::getDataTypeMatrixNumColumns(basicType);
500
501                         entry.offset            = curOffset;
502                         entry.matrixStride      = baseAlignment;
503                         entry.isRowMajor        = isRowMajor;
504
505                         curOffset += numVecs*baseAlignment;
506                 }
507                 else
508                 {
509                         // Scalar or vector.
510                         entry.offset = curOffset;
511
512                         curOffset += getDataTypeByteSize(basicType);
513                 }
514
515                 layout.bufferVars.push_back(entry);
516         }
517         else if (type.isArrayType())
518         {
519                 const VarType&  elemType        = type.getElementType();
520
521                 if (elemType.isBasicType() && !glu::isDataTypeMatrix(elemType.getBasicType()))
522                 {
523                         // Array of scalars or vectors.
524                         const glu::DataType             elemBasicType   = elemType.getBasicType();
525                         const int                               stride                  = baseAlignment;
526                         BufferVarLayoutEntry    entry;
527
528                         entry.name                                      = curPrefix + "[0]"; // Array variables are always postfixed with [0]
529                         entry.type                                      = elemBasicType;
530                         entry.blockNdx                          = curBlockNdx;
531                         entry.offset                            = curOffset;
532                         entry.arraySize                         = type.getArraySize();
533                         entry.arrayStride                       = stride;
534                         entry.matrixStride                      = 0;
535                         entry.topLevelArraySize         = topLevelArraySize;
536                         entry.topLevelArrayStride       = topLevelArrayStride;
537
538                         curOffset += stride*type.getArraySize();
539
540                         layout.bufferVars.push_back(entry);
541                 }
542                 else if (elemType.isBasicType() && glu::isDataTypeMatrix(elemType.getBasicType()))
543                 {
544                         // Array of matrices.
545                         const glu::DataType                     elemBasicType   = elemType.getBasicType();
546                         const bool                                      isRowMajor              = !!(layoutFlags & LAYOUT_ROW_MAJOR);
547                         const int                                       numVecs                 = isRowMajor ? glu::getDataTypeMatrixNumRows(elemBasicType)
548                                                                                                                                          : glu::getDataTypeMatrixNumColumns(elemBasicType);
549                         const int                                       vecStride               = baseAlignment;
550                         BufferVarLayoutEntry            entry;
551
552                         entry.name                                      = curPrefix + "[0]"; // Array variables are always postfixed with [0]
553                         entry.type                                      = elemBasicType;
554                         entry.blockNdx                          = curBlockNdx;
555                         entry.offset                            = curOffset;
556                         entry.arraySize                         = type.getArraySize();
557                         entry.arrayStride                       = vecStride*numVecs;
558                         entry.matrixStride                      = vecStride;
559                         entry.isRowMajor                        = isRowMajor;
560                         entry.topLevelArraySize         = topLevelArraySize;
561                         entry.topLevelArrayStride       = topLevelArrayStride;
562
563                         curOffset += numVecs*vecStride*type.getArraySize();
564
565                         layout.bufferVars.push_back(entry);
566                 }
567                 else
568                 {
569                         DE_ASSERT(elemType.isStructType() || elemType.isArrayType());
570
571                         for (int elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++)
572                                 curOffset += computeReferenceLayout(layout, curBlockNdx, curOffset, curPrefix + "[" + de::toString(elemNdx) + "]", type.getElementType(), layoutFlags);
573                 }
574         }
575         else
576         {
577                 DE_ASSERT(type.isStructType());
578
579                 for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++)
580                         curOffset += computeReferenceLayout(layout, curBlockNdx, curOffset, curPrefix + "." + memberIter->getName(), memberIter->getType(), layoutFlags);
581
582                 curOffset = deAlign32(curOffset, baseAlignment);
583         }
584
585         return curOffset-baseOffset;
586 }
587
588 //! Appends all child elements to layout, returns offset increment.
589 int computeReferenceLayout (BufferLayout& layout, int curBlockNdx, const std::string& blockPrefix, int baseOffset, const BufferVar& bufVar, deUint32 blockLayoutFlags)
590 {
591         const VarType&  varType                 = bufVar.getType();
592         const deUint32  combinedFlags   = mergeLayoutFlags(blockLayoutFlags, bufVar.getFlags());
593
594         if (varType.isArrayType())
595         {
596                 // Top-level arrays need special care.
597                 const int               topLevelArraySize       = varType.getArraySize() == VarType::UNSIZED_ARRAY ? 0 : varType.getArraySize();
598                 const string    prefix                          = blockPrefix + bufVar.getName() + "[0]";
599                 const bool              isStd140                        = (blockLayoutFlags & LAYOUT_STD140) != 0;
600                 const int               vec4Align                       = (int)sizeof(deUint32)*4;
601                 const int               baseAlignment           = isStd140 ? computeStd140BaseAlignment(varType, combinedFlags)
602                                                                                                            : computeStd430BaseAlignment(varType, combinedFlags);
603                 int                             curOffset                       = deAlign32(baseOffset, baseAlignment);
604                 const VarType&  elemType                        = varType.getElementType();
605
606                 if (elemType.isBasicType() && !glu::isDataTypeMatrix(elemType.getBasicType()))
607                 {
608                         // Array of scalars or vectors.
609                         const glu::DataType             elemBasicType   = elemType.getBasicType();
610                         const int                               elemBaseAlign   = getDataTypeByteAlignment(elemBasicType);
611                         const int                               stride                  = isStd140 ? deAlign32(elemBaseAlign, vec4Align) : elemBaseAlign;
612                         BufferVarLayoutEntry    entry;
613
614                         entry.name                                      = prefix;
615                         entry.topLevelArraySize         = 1;
616                         entry.topLevelArrayStride       = 0;
617                         entry.type                                      = elemBasicType;
618                         entry.blockNdx                          = curBlockNdx;
619                         entry.offset                            = curOffset;
620                         entry.arraySize                         = topLevelArraySize;
621                         entry.arrayStride                       = stride;
622                         entry.matrixStride                      = 0;
623
624                         layout.bufferVars.push_back(entry);
625
626                         curOffset += stride*topLevelArraySize;
627                 }
628                 else if (elemType.isBasicType() && glu::isDataTypeMatrix(elemType.getBasicType()))
629                 {
630                         // Array of matrices.
631                         const glu::DataType             elemBasicType   = elemType.getBasicType();
632                         const bool                              isRowMajor              = !!(combinedFlags & LAYOUT_ROW_MAJOR);
633                         const int                               vecSize                 = isRowMajor ? glu::getDataTypeMatrixNumColumns(elemBasicType)
634                                                                                                                                  : glu::getDataTypeMatrixNumRows(elemBasicType);
635                         const int                               numVecs                 = isRowMajor ? glu::getDataTypeMatrixNumRows(elemBasicType)
636                                                                                                                                  : glu::getDataTypeMatrixNumColumns(elemBasicType);
637                         const glu::DataType             vecType                 = glu::getDataTypeFloatVec(vecSize);
638                         const int                               vecBaseAlign    = getDataTypeByteAlignment(vecType);
639                         const int                               stride                  = isStd140 ? deAlign32(vecBaseAlign, vec4Align) : vecBaseAlign;
640                         BufferVarLayoutEntry    entry;
641
642                         entry.name                                      = prefix;
643                         entry.topLevelArraySize         = 1;
644                         entry.topLevelArrayStride       = 0;
645                         entry.type                                      = elemBasicType;
646                         entry.blockNdx                          = curBlockNdx;
647                         entry.offset                            = curOffset;
648                         entry.arraySize                         = topLevelArraySize;
649                         entry.arrayStride                       = stride*numVecs;
650                         entry.matrixStride                      = stride;
651                         entry.isRowMajor                        = isRowMajor;
652
653                         layout.bufferVars.push_back(entry);
654
655                         curOffset += stride*numVecs*topLevelArraySize;
656                 }
657                 else
658                 {
659                         DE_ASSERT(elemType.isStructType() || elemType.isArrayType());
660
661                         // Struct base alignment is not added multiple times as curOffset supplied to computeReferenceLayout
662                         // was already aligned correctly. Thus computeReferenceLayout should not add any extra padding
663                         // before struct. Padding after struct will be added as it should.
664                         //
665                         // Stride could be computed prior to creating child elements, but it would essentially require running
666                         // the layout computation twice. Instead we fix stride to child elements afterwards.
667
668                         const int       firstChildNdx   = (int)layout.bufferVars.size();
669                         const int       stride                  = computeReferenceLayout(layout, curBlockNdx, curOffset, prefix, varType.getElementType(), combinedFlags);
670
671                         for (int childNdx = firstChildNdx; childNdx < (int)layout.bufferVars.size(); childNdx++)
672                         {
673                                 layout.bufferVars[childNdx].topLevelArraySize   = topLevelArraySize;
674                                 layout.bufferVars[childNdx].topLevelArrayStride = stride;
675                         }
676
677                         curOffset += stride*topLevelArraySize;
678                 }
679
680                 return curOffset-baseOffset;
681         }
682         else
683                 return computeReferenceLayout(layout, curBlockNdx, baseOffset, blockPrefix + bufVar.getName(), varType, combinedFlags);
684 }
685
686 void computeReferenceLayout (BufferLayout& layout, const ShaderInterface& interface)
687 {
688         int numBlocks = interface.getNumBlocks();
689
690         for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
691         {
692                 const BufferBlock&      block                   = interface.getBlock(blockNdx);
693                 bool                            hasInstanceName = block.getInstanceName() != DE_NULL;
694                 std::string                     blockPrefix             = hasInstanceName ? (std::string(block.getBlockName()) + ".") : std::string("");
695                 int                                     curOffset               = 0;
696                 int                                     activeBlockNdx  = (int)layout.blocks.size();
697                 int                                     firstVarNdx             = (int)layout.bufferVars.size();
698
699                 for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++)
700                 {
701                         const BufferVar& bufVar = *varIter;
702                         curOffset += computeReferenceLayout(layout, activeBlockNdx,  blockPrefix, curOffset, bufVar, block.getFlags());
703                 }
704
705                 int     varIndicesEnd   = (int)layout.bufferVars.size();
706                 int     blockSize               = curOffset;
707                 int     numInstances    = block.isArray() ? block.getArraySize() : 1;
708
709                 // Create block layout entries for each instance.
710                 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
711                 {
712                         // Allocate entry for instance.
713                         layout.blocks.push_back(BlockLayoutEntry());
714                         BlockLayoutEntry& blockEntry = layout.blocks.back();
715
716                         blockEntry.name = block.getBlockName();
717                         blockEntry.size = blockSize;
718
719                         // Compute active variable set for block.
720                         for (int varNdx = firstVarNdx; varNdx < varIndicesEnd; varNdx++)
721                                 blockEntry.activeVarIndices.push_back(varNdx);
722
723                         if (block.isArray())
724                                 blockEntry.name += "[" + de::toString(instanceNdx) + "]";
725                 }
726         }
727 }
728
729 // Value generator.
730
731 void generateValue (const BufferVarLayoutEntry& entry, int unsizedArraySize, void* basePtr, de::Random& rnd)
732 {
733         const glu::DataType     scalarType              = glu::getDataTypeScalarType(entry.type);
734         const int                       scalarSize              = glu::getDataTypeScalarSize(entry.type);
735         const int                       arraySize               = entry.arraySize == 0 ? unsizedArraySize : entry.arraySize;
736         const int                       arrayStride             = entry.arrayStride;
737         const int                       topLevelSize    = entry.topLevelArraySize == 0 ? unsizedArraySize : entry.topLevelArraySize;
738         const int                       topLevelStride  = entry.topLevelArrayStride;
739         const bool                      isMatrix                = glu::isDataTypeMatrix(entry.type);
740         const int                       numVecs                 = isMatrix ? (entry.isRowMajor ? glu::getDataTypeMatrixNumRows(entry.type) : glu::getDataTypeMatrixNumColumns(entry.type)) : 1;
741         const int                       vecSize                 = scalarSize / numVecs;
742         const int                       compSize                = sizeof(deUint32);
743
744         DE_ASSERT(scalarSize%numVecs == 0);
745         DE_ASSERT(topLevelSize >= 0);
746         DE_ASSERT(arraySize >= 0);
747
748         for (int topElemNdx = 0; topElemNdx < topLevelSize; topElemNdx++)
749         {
750                 deUint8* const topElemPtr = (deUint8*)basePtr + entry.offset + topElemNdx*topLevelStride;
751
752                 for (int elemNdx = 0; elemNdx < arraySize; elemNdx++)
753                 {
754                         deUint8* const elemPtr = topElemPtr + elemNdx*arrayStride;
755
756                         for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
757                         {
758                                 deUint8* const vecPtr = elemPtr + (isMatrix ? vecNdx*entry.matrixStride : 0);
759
760                                 for (int compNdx = 0; compNdx < vecSize; compNdx++)
761                                 {
762                                         deUint8* const compPtr = vecPtr + compSize*compNdx;
763
764                                         switch (scalarType)
765                                         {
766                                                 case glu::TYPE_FLOAT:   *((float*)compPtr)              = (float)rnd.getInt(-9, 9);                                             break;
767                                                 case glu::TYPE_INT:             *((int*)compPtr)                = rnd.getInt(-9, 9);                                                    break;
768                                                 case glu::TYPE_UINT:    *((deUint32*)compPtr)   = (deUint32)rnd.getInt(0, 9);                                   break;
769                                                 // \note Random bit pattern is used for true values. Spec states that all non-zero values are
770                                                 //       interpreted as true but some implementations fail this.
771                                                 case glu::TYPE_BOOL:    *((deUint32*)compPtr)   = rnd.getBool() ? rnd.getUint32()|1u : 0u;              break;
772                                                 default:
773                                                         DE_ASSERT(false);
774                                         }
775                                 }
776                         }
777                 }
778         }
779 }
780
781 void generateValues (const BufferLayout& layout, const vector<BlockDataPtr>& blockPointers, deUint32 seed)
782 {
783         de::Random      rnd                     (seed);
784         const int       numBlocks       = (int)layout.blocks.size();
785
786         DE_ASSERT(numBlocks == (int)blockPointers.size());
787
788         for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
789         {
790                 const BlockLayoutEntry& blockLayout     = layout.blocks[blockNdx];
791                 const BlockDataPtr&             blockPtr        = blockPointers[blockNdx];
792                 const int                               numEntries      = (int)layout.blocks[blockNdx].activeVarIndices.size();
793
794                 for (int entryNdx = 0; entryNdx < numEntries; entryNdx++)
795                 {
796                         const int                                       varNdx          = blockLayout.activeVarIndices[entryNdx];
797                         const BufferVarLayoutEntry&     varEntry        = layout.bufferVars[varNdx];
798
799                         generateValue(varEntry, blockPtr.lastUnsizedArraySize, blockPtr.ptr, rnd);
800                 }
801         }
802 }
803
804 // Shader generator.
805
806 const char* getCompareFuncForType (glu::DataType type)
807 {
808         switch (type)
809         {
810                 case glu::TYPE_FLOAT:                   return "bool compare_float    (highp float a, highp float b)  { return abs(a - b) < 0.05; }\n";
811                 case glu::TYPE_FLOAT_VEC2:              return "bool compare_vec2     (highp vec2 a, highp vec2 b)    { return compare_float(a.x, b.x)&&compare_float(a.y, b.y); }\n";
812                 case glu::TYPE_FLOAT_VEC3:              return "bool 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";
813                 case glu::TYPE_FLOAT_VEC4:              return "bool 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";
814                 case glu::TYPE_FLOAT_MAT2:              return "bool compare_mat2     (highp mat2 a, highp mat2 b)    { return compare_vec2(a[0], b[0])&&compare_vec2(a[1], b[1]); }\n";
815                 case glu::TYPE_FLOAT_MAT2X3:    return "bool compare_mat2x3   (highp mat2x3 a, highp mat2x3 b){ return compare_vec3(a[0], b[0])&&compare_vec3(a[1], b[1]); }\n";
816                 case glu::TYPE_FLOAT_MAT2X4:    return "bool compare_mat2x4   (highp mat2x4 a, highp mat2x4 b){ return compare_vec4(a[0], b[0])&&compare_vec4(a[1], b[1]); }\n";
817                 case glu::TYPE_FLOAT_MAT3X2:    return "bool 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";
818                 case glu::TYPE_FLOAT_MAT3:              return "bool 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";
819                 case glu::TYPE_FLOAT_MAT3X4:    return "bool 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";
820                 case glu::TYPE_FLOAT_MAT4X2:    return "bool 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";
821                 case glu::TYPE_FLOAT_MAT4X3:    return "bool 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";
822                 case glu::TYPE_FLOAT_MAT4:              return "bool 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";
823                 case glu::TYPE_INT:                             return "bool compare_int      (highp int a, highp int b)      { return a == b; }\n";
824                 case glu::TYPE_INT_VEC2:                return "bool compare_ivec2    (highp ivec2 a, highp ivec2 b)  { return a == b; }\n";
825                 case glu::TYPE_INT_VEC3:                return "bool compare_ivec3    (highp ivec3 a, highp ivec3 b)  { return a == b; }\n";
826                 case glu::TYPE_INT_VEC4:                return "bool compare_ivec4    (highp ivec4 a, highp ivec4 b)  { return a == b; }\n";
827                 case glu::TYPE_UINT:                    return "bool compare_uint     (highp uint a, highp uint b)    { return a == b; }\n";
828                 case glu::TYPE_UINT_VEC2:               return "bool compare_uvec2    (highp uvec2 a, highp uvec2 b)  { return a == b; }\n";
829                 case glu::TYPE_UINT_VEC3:               return "bool compare_uvec3    (highp uvec3 a, highp uvec3 b)  { return a == b; }\n";
830                 case glu::TYPE_UINT_VEC4:               return "bool compare_uvec4    (highp uvec4 a, highp uvec4 b)  { return a == b; }\n";
831                 case glu::TYPE_BOOL:                    return "bool compare_bool     (bool a, bool b)                { return a == b; }\n";
832                 case glu::TYPE_BOOL_VEC2:               return "bool compare_bvec2    (bvec2 a, bvec2 b)              { return a == b; }\n";
833                 case glu::TYPE_BOOL_VEC3:               return "bool compare_bvec3    (bvec3 a, bvec3 b)              { return a == b; }\n";
834                 case glu::TYPE_BOOL_VEC4:               return "bool compare_bvec4    (bvec4 a, bvec4 b)              { return a == b; }\n";
835                 default:
836                         DE_ASSERT(false);
837                         return DE_NULL;
838         }
839 }
840
841 void getCompareDependencies (std::set<glu::DataType>& compareFuncs, glu::DataType basicType)
842 {
843         switch (basicType)
844         {
845                 case glu::TYPE_FLOAT_VEC2:
846                 case glu::TYPE_FLOAT_VEC3:
847                 case glu::TYPE_FLOAT_VEC4:
848                         compareFuncs.insert(glu::TYPE_FLOAT);
849                         compareFuncs.insert(basicType);
850                         break;
851
852                 case glu::TYPE_FLOAT_MAT2:
853                 case glu::TYPE_FLOAT_MAT2X3:
854                 case glu::TYPE_FLOAT_MAT2X4:
855                 case glu::TYPE_FLOAT_MAT3X2:
856                 case glu::TYPE_FLOAT_MAT3:
857                 case glu::TYPE_FLOAT_MAT3X4:
858                 case glu::TYPE_FLOAT_MAT4X2:
859                 case glu::TYPE_FLOAT_MAT4X3:
860                 case glu::TYPE_FLOAT_MAT4:
861                         compareFuncs.insert(glu::TYPE_FLOAT);
862                         compareFuncs.insert(glu::getDataTypeFloatVec(glu::getDataTypeMatrixNumRows(basicType)));
863                         compareFuncs.insert(basicType);
864                         break;
865
866                 default:
867                         compareFuncs.insert(basicType);
868                         break;
869         }
870 }
871
872 void collectUniqueBasicTypes (std::set<glu::DataType>& basicTypes, const VarType& type)
873 {
874         if (type.isStructType())
875         {
876                 for (StructType::ConstIterator iter = type.getStructPtr()->begin(); iter != type.getStructPtr()->end(); ++iter)
877                         collectUniqueBasicTypes(basicTypes, iter->getType());
878         }
879         else if (type.isArrayType())
880                 collectUniqueBasicTypes(basicTypes, type.getElementType());
881         else
882         {
883                 DE_ASSERT(type.isBasicType());
884                 basicTypes.insert(type.getBasicType());
885         }
886 }
887
888 void collectUniqueBasicTypes (std::set<glu::DataType>& basicTypes, const BufferBlock& bufferBlock)
889 {
890         for (BufferBlock::const_iterator iter = bufferBlock.begin(); iter != bufferBlock.end(); ++iter)
891                 collectUniqueBasicTypes(basicTypes, iter->getType());
892 }
893
894 void collectUniqueBasicTypes (std::set<glu::DataType>& basicTypes, const ShaderInterface& interface)
895 {
896         for (int ndx = 0; ndx < interface.getNumBlocks(); ++ndx)
897                 collectUniqueBasicTypes(basicTypes, interface.getBlock(ndx));
898 }
899
900 void generateCompareFuncs (std::ostream& str, const ShaderInterface& interface)
901 {
902         std::set<glu::DataType> types;
903         std::set<glu::DataType> compareFuncs;
904
905         // Collect unique basic types
906         collectUniqueBasicTypes(types, interface);
907
908         // Set of compare functions required
909         for (std::set<glu::DataType>::const_iterator iter = types.begin(); iter != types.end(); ++iter)
910         {
911                 getCompareDependencies(compareFuncs, *iter);
912         }
913
914         for (int type = 0; type < glu::TYPE_LAST; ++type)
915         {
916                 if (compareFuncs.find(glu::DataType(type)) != compareFuncs.end())
917                         str << getCompareFuncForType(glu::DataType(type));
918         }
919 }
920
921 struct Indent
922 {
923         int level;
924         Indent (int level_) : level(level_) {}
925 };
926
927 std::ostream& operator<< (std::ostream& str, const Indent& indent)
928 {
929         for (int i = 0; i < indent.level; i++)
930                 str << "\t";
931         return str;
932 }
933
934 void generateDeclaration (std::ostream& src, const BufferVar& bufferVar, int indentLevel)
935 {
936         // \todo [pyry] Qualifiers
937
938         if ((bufferVar.getFlags() & LAYOUT_MASK) != 0)
939                 src << "layout(" << LayoutFlagsFmt(bufferVar.getFlags() & LAYOUT_MASK) << ") ";
940
941         src << glu::declare(bufferVar.getType(), bufferVar.getName(), indentLevel);
942 }
943
944 void generateDeclaration (std::ostream& src, const BufferBlock& block, int bindingPoint)
945 {
946         src << "layout(";
947
948         if ((block.getFlags() & LAYOUT_MASK) != 0)
949                 src << LayoutFlagsFmt(block.getFlags() & LAYOUT_MASK) << ", ";
950
951         src << "binding = " << bindingPoint;
952
953         src << ") ";
954
955         src << "buffer " << block.getBlockName();
956         src << "\n{\n";
957
958         for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++)
959         {
960                 src << Indent(1);
961                 generateDeclaration(src, *varIter, 1 /* indent level */);
962                 src << ";\n";
963         }
964
965         src << "}";
966
967         if (block.getInstanceName() != DE_NULL)
968         {
969                 src << " " << block.getInstanceName();
970                 if (block.isArray())
971                         src << "[" << block.getArraySize() << "]";
972         }
973         else
974                 DE_ASSERT(!block.isArray());
975
976         src << ";\n";
977 }
978
979 void generateImmMatrixSrc (std::ostream& src, glu::DataType basicType, int matrixStride, bool isRowMajor, const void* valuePtr)
980 {
981         DE_ASSERT(glu::isDataTypeMatrix(basicType));
982
983         const int               compSize                = sizeof(deUint32);
984         const int               numRows                 = glu::getDataTypeMatrixNumRows(basicType);
985         const int               numCols                 = glu::getDataTypeMatrixNumColumns(basicType);
986
987         src << glu::getDataTypeName(basicType) << "(";
988
989         // Constructed in column-wise order.
990         for (int colNdx = 0; colNdx < numCols; colNdx++)
991         {
992                 for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
993                 {
994                         const deUint8*  compPtr = (const deUint8*)valuePtr + (isRowMajor ? rowNdx*matrixStride + colNdx*compSize
995                                                                                                                                                                 : colNdx*matrixStride + rowNdx*compSize);
996
997                         if (colNdx > 0 || rowNdx > 0)
998                                 src << ", ";
999
1000                         src << de::floatToString(*((const float*)compPtr), 1);
1001                 }
1002         }
1003
1004         src << ")";
1005 }
1006
1007 void generateImmScalarVectorSrc (std::ostream& src, glu::DataType basicType, const void* valuePtr)
1008 {
1009         DE_ASSERT(glu::isDataTypeFloatOrVec(basicType)  ||
1010                           glu::isDataTypeIntOrIVec(basicType)   ||
1011                           glu::isDataTypeUintOrUVec(basicType)  ||
1012                           glu::isDataTypeBoolOrBVec(basicType));
1013
1014         const glu::DataType             scalarType              = glu::getDataTypeScalarType(basicType);
1015         const int                               scalarSize              = glu::getDataTypeScalarSize(basicType);
1016         const int                               compSize                = sizeof(deUint32);
1017
1018         if (scalarSize > 1)
1019                 src << glu::getDataTypeName(basicType) << "(";
1020
1021         for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
1022         {
1023                 const deUint8* compPtr = (const deUint8*)valuePtr + scalarNdx*compSize;
1024
1025                 if (scalarNdx > 0)
1026                         src << ", ";
1027
1028                 switch (scalarType)
1029                 {
1030                         case glu::TYPE_FLOAT:   src << de::floatToString(*((const float*)compPtr), 1);                  break;
1031                         case glu::TYPE_INT:             src << *((const int*)compPtr);                                                                  break;
1032                         case glu::TYPE_UINT:    src << *((const deUint32*)compPtr) << "u";                                              break;
1033                         case glu::TYPE_BOOL:    src << (*((const deUint32*)compPtr) != 0u ? "true" : "false");  break;
1034                         default:
1035                                 DE_ASSERT(false);
1036                 }
1037         }
1038
1039         if (scalarSize > 1)
1040                 src << ")";
1041 }
1042
1043 string getAPIName (const BufferBlock& block, const BufferVar& var, const glu::TypeComponentVector& accessPath)
1044 {
1045         std::ostringstream name;
1046
1047         if (block.getInstanceName())
1048                 name << block.getBlockName() << ".";
1049
1050         name << var.getName();
1051
1052         for (glu::TypeComponentVector::const_iterator pathComp = accessPath.begin(); pathComp != accessPath.end(); pathComp++)
1053         {
1054                 if (pathComp->type == glu::VarTypeComponent::STRUCT_MEMBER)
1055                 {
1056                         const VarType           curType         = glu::getVarType(var.getType(), accessPath.begin(), pathComp);
1057                         const StructType*       structPtr       = curType.getStructPtr();
1058
1059                         name << "." << structPtr->getMember(pathComp->index).getName();
1060                 }
1061                 else if (pathComp->type == glu::VarTypeComponent::ARRAY_ELEMENT)
1062                 {
1063                         if (pathComp == accessPath.begin() || (pathComp+1) == accessPath.end())
1064                                 name << "[0]"; // Top- / bottom-level array
1065                         else
1066                                 name << "[" << pathComp->index << "]";
1067                 }
1068                 else
1069                         DE_ASSERT(false);
1070         }
1071
1072         return name.str();
1073 }
1074
1075 string getShaderName (const BufferBlock& block, int instanceNdx, const BufferVar& var, const glu::TypeComponentVector& accessPath)
1076 {
1077         std::ostringstream name;
1078
1079         if (block.getInstanceName())
1080         {
1081                 name << block.getInstanceName();
1082
1083                 if (block.isArray())
1084                         name << "[" << instanceNdx << "]";
1085
1086                 name << ".";
1087         }
1088         else
1089                 DE_ASSERT(instanceNdx == 0);
1090
1091         name << var.getName();
1092
1093         for (glu::TypeComponentVector::const_iterator pathComp = accessPath.begin(); pathComp != accessPath.end(); pathComp++)
1094         {
1095                 if (pathComp->type == glu::VarTypeComponent::STRUCT_MEMBER)
1096                 {
1097                         const VarType           curType         = glu::getVarType(var.getType(), accessPath.begin(), pathComp);
1098                         const StructType*       structPtr       = curType.getStructPtr();
1099
1100                         name << "." << structPtr->getMember(pathComp->index).getName();
1101                 }
1102                 else if (pathComp->type == glu::VarTypeComponent::ARRAY_ELEMENT)
1103                         name << "[" << pathComp->index << "]";
1104                 else
1105                         DE_ASSERT(false);
1106         }
1107
1108         return name.str();
1109 }
1110
1111 int computeOffset (const BufferVarLayoutEntry& varLayout, const glu::TypeComponentVector& accessPath)
1112 {
1113         const int       topLevelNdx             = (accessPath.size() > 1 && accessPath.front().type == glu::VarTypeComponent::ARRAY_ELEMENT) ? accessPath.front().index : 0;
1114         const int       bottomLevelNdx  = (!accessPath.empty() && accessPath.back().type == glu::VarTypeComponent::ARRAY_ELEMENT) ? accessPath.back().index : 0;
1115
1116         return varLayout.offset + varLayout.topLevelArrayStride*topLevelNdx + varLayout.arrayStride*bottomLevelNdx;
1117 }
1118
1119 void generateCompareSrc (
1120         std::ostream&                           src,
1121         const char*                                     resultVar,
1122         const BufferLayout&                     bufferLayout,
1123         const BufferBlock&                      block,
1124         int                                                     instanceNdx,
1125         const BlockDataPtr&                     blockPtr,
1126         const BufferVar&                        bufVar,
1127         const glu::SubTypeAccess&       accessPath)
1128 {
1129         const VarType curType = accessPath.getType();
1130
1131         if (curType.isArrayType())
1132         {
1133                 const int arraySize = curType.getArraySize() == VarType::UNSIZED_ARRAY ? block.getLastUnsizedArraySize(instanceNdx) : curType.getArraySize();
1134
1135                 for (int elemNdx = 0; elemNdx < arraySize; elemNdx++)
1136                         generateCompareSrc(src, resultVar, bufferLayout, block, instanceNdx, blockPtr, bufVar, accessPath.element(elemNdx));
1137         }
1138         else if (curType.isStructType())
1139         {
1140                 const int numMembers = curType.getStructPtr()->getNumMembers();
1141
1142                 for (int memberNdx = 0; memberNdx < numMembers; memberNdx++)
1143                         generateCompareSrc(src, resultVar, bufferLayout, block, instanceNdx, blockPtr, bufVar, accessPath.member(memberNdx));
1144         }
1145         else
1146         {
1147                 DE_ASSERT(curType.isBasicType());
1148
1149                 const string    apiName = getAPIName(block, bufVar, accessPath.getPath());
1150                 const int               varNdx  = bufferLayout.getVariableIndex(apiName);
1151
1152                 DE_ASSERT(varNdx >= 0);
1153                 {
1154                         const BufferVarLayoutEntry&     varLayout               = bufferLayout.bufferVars[varNdx];
1155                         const string                            shaderName              = getShaderName(block, instanceNdx, bufVar, accessPath.getPath());
1156                         const glu::DataType                     basicType               = curType.getBasicType();
1157                         const bool                                      isMatrix                = glu::isDataTypeMatrix(basicType);
1158                         const char*                                     typeName                = glu::getDataTypeName(basicType);
1159                         const void*                                     valuePtr                = (const deUint8*)blockPtr.ptr + computeOffset(varLayout, accessPath.getPath());
1160
1161                         src << "\t" << resultVar << " = " << resultVar << " && compare_" << typeName << "(" << shaderName << ", ";
1162
1163                         if (isMatrix)
1164                                 generateImmMatrixSrc(src, basicType, varLayout.matrixStride, varLayout.isRowMajor, valuePtr);
1165                         else
1166                                 generateImmScalarVectorSrc(src, basicType, valuePtr);
1167
1168                         src << ");\n";
1169                 }
1170         }
1171 }
1172
1173 void generateCompareSrc (std::ostream& src, const char* resultVar, const ShaderInterface& interface, const BufferLayout& layout, const vector<BlockDataPtr>& blockPointers)
1174 {
1175         for (int declNdx = 0; declNdx < interface.getNumBlocks(); declNdx++)
1176         {
1177                 const BufferBlock&      block                   = interface.getBlock(declNdx);
1178                 const bool                      isArray                 = block.isArray();
1179                 const int                       numInstances    = isArray ? block.getArraySize() : 1;
1180
1181                 DE_ASSERT(!isArray || block.getInstanceName());
1182
1183                 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1184                 {
1185                         const string            instanceName    = block.getBlockName() + (isArray ? "[" + de::toString(instanceNdx) + "]" : string(""));
1186                         const int                       blockNdx                = layout.getBlockIndex(instanceName);
1187                         const BlockDataPtr&     blockPtr                = blockPointers[blockNdx];
1188
1189                         for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++)
1190                         {
1191                                 const BufferVar& bufVar = *varIter;
1192
1193                                 if ((bufVar.getFlags() & ACCESS_READ) == 0)
1194                                         continue; // Don't read from that variable.
1195
1196                                 generateCompareSrc(src, resultVar, layout, block, instanceNdx, blockPtr, bufVar, glu::SubTypeAccess(bufVar.getType()));
1197                         }
1198                 }
1199         }
1200 }
1201
1202 // \todo [2013-10-14 pyry] Almost identical to generateCompareSrc - unify?
1203
1204 void generateWriteSrc (
1205         std::ostream&                           src,
1206         const BufferLayout&                     bufferLayout,
1207         const BufferBlock&                      block,
1208         int                                                     instanceNdx,
1209         const BlockDataPtr&                     blockPtr,
1210         const BufferVar&                        bufVar,
1211         const glu::SubTypeAccess&       accessPath)
1212 {
1213         const VarType curType = accessPath.getType();
1214
1215         if (curType.isArrayType())
1216         {
1217                 const int arraySize = curType.getArraySize() == VarType::UNSIZED_ARRAY ? block.getLastUnsizedArraySize(instanceNdx) : curType.getArraySize();
1218
1219                 for (int elemNdx = 0; elemNdx < arraySize; elemNdx++)
1220                         generateWriteSrc(src, bufferLayout, block, instanceNdx, blockPtr, bufVar, accessPath.element(elemNdx));
1221         }
1222         else if (curType.isStructType())
1223         {
1224                 const int numMembers = curType.getStructPtr()->getNumMembers();
1225
1226                 for (int memberNdx = 0; memberNdx < numMembers; memberNdx++)
1227                         generateWriteSrc(src, bufferLayout, block, instanceNdx, blockPtr, bufVar, accessPath.member(memberNdx));
1228         }
1229         else
1230         {
1231                 DE_ASSERT(curType.isBasicType());
1232
1233                 const string    apiName = getAPIName(block, bufVar, accessPath.getPath());
1234                 const int               varNdx  = bufferLayout.getVariableIndex(apiName);
1235
1236                 DE_ASSERT(varNdx >= 0);
1237                 {
1238                         const BufferVarLayoutEntry&     varLayout               = bufferLayout.bufferVars[varNdx];
1239                         const string                            shaderName              = getShaderName(block, instanceNdx, bufVar, accessPath.getPath());
1240                         const glu::DataType                     basicType               = curType.getBasicType();
1241                         const bool                                      isMatrix                = glu::isDataTypeMatrix(basicType);
1242                         const void*                                     valuePtr                = (const deUint8*)blockPtr.ptr + computeOffset(varLayout, accessPath.getPath());
1243
1244                         src << "\t" << shaderName << " = ";
1245
1246                         if (isMatrix)
1247                                 generateImmMatrixSrc(src, basicType, varLayout.matrixStride, varLayout.isRowMajor, valuePtr);
1248                         else
1249                                 generateImmScalarVectorSrc(src, basicType, valuePtr);
1250
1251                         src << ";\n";
1252                 }
1253         }
1254 }
1255
1256 void generateWriteSrc (std::ostream& src, const ShaderInterface& interface, const BufferLayout& layout, const vector<BlockDataPtr>& blockPointers)
1257 {
1258         for (int declNdx = 0; declNdx < interface.getNumBlocks(); declNdx++)
1259         {
1260                 const BufferBlock&      block                   = interface.getBlock(declNdx);
1261                 const bool                      isArray                 = block.isArray();
1262                 const int                       numInstances    = isArray ? block.getArraySize() : 1;
1263
1264                 DE_ASSERT(!isArray || block.getInstanceName());
1265
1266                 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1267                 {
1268                         const string            instanceName    = block.getBlockName() + (isArray ? "[" + de::toString(instanceNdx) + "]" : string(""));
1269                         const int                       blockNdx                = layout.getBlockIndex(instanceName);
1270                         const BlockDataPtr&     blockPtr                = blockPointers[blockNdx];
1271
1272                         for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++)
1273                         {
1274                                 const BufferVar& bufVar = *varIter;
1275
1276                                 if ((bufVar.getFlags() & ACCESS_WRITE) == 0)
1277                                         continue; // Don't write to that variable.
1278
1279                                 generateWriteSrc(src, layout, block, instanceNdx, blockPtr, bufVar, glu::SubTypeAccess(bufVar.getType()));
1280                         }
1281                 }
1282         }
1283 }
1284
1285 string generateComputeShader (glu::GLSLVersion glslVersion, const ShaderInterface& interface, const BufferLayout& layout, const vector<BlockDataPtr>& comparePtrs, const vector<BlockDataPtr>& writePtrs)
1286 {
1287         std::ostringstream src;
1288
1289         DE_ASSERT(glslVersion == glu::GLSL_VERSION_310_ES || glslVersion == glu::GLSL_VERSION_430);
1290
1291         src << glu::getGLSLVersionDeclaration(glslVersion) << "\n";
1292         src << "layout(local_size_x = 1) in;\n";
1293         src << "\n";
1294
1295         std::vector<const StructType*> namedStructs;
1296         interface.getNamedStructs(namedStructs);
1297         for (std::vector<const StructType*>::const_iterator structIter = namedStructs.begin(); structIter != namedStructs.end(); structIter++)
1298                 src << glu::declare(*structIter) << ";\n";
1299
1300         {
1301                 int bindingPoint = 0;
1302
1303                 for (int blockNdx = 0; blockNdx < interface.getNumBlocks(); blockNdx++)
1304                 {
1305                         const BufferBlock& block = interface.getBlock(blockNdx);
1306                         generateDeclaration(src, block, bindingPoint);
1307
1308                         bindingPoint += block.isArray() ? block.getArraySize() : 1;
1309                 }
1310         }
1311
1312         // Atomic counter for counting passed invocations.
1313         src << "\nlayout(binding = 0) uniform atomic_uint ac_numPassed;\n";
1314
1315         // Comparison utilities.
1316         src << "\n";
1317         generateCompareFuncs(src, interface);
1318
1319         src << "\n"
1320                    "void main (void)\n"
1321                    "{\n"
1322                    "    bool allOk = true;\n";
1323
1324         // Value compare.
1325         generateCompareSrc(src, "allOk", interface, layout, comparePtrs);
1326
1327         src << "        if (allOk)\n"
1328                 << "            atomicCounterIncrement(ac_numPassed);\n"
1329                 << "\n";
1330
1331         // Value write.
1332         generateWriteSrc(src, interface, layout, writePtrs);
1333
1334         src << "}\n";
1335
1336         return src.str();
1337 }
1338
1339 void getGLBufferLayout (const glw::Functions& gl, BufferLayout& layout, deUint32 program)
1340 {
1341         int             numActiveBufferVars     = 0;
1342         int             numActiveBlocks         = 0;
1343
1344         gl.getProgramInterfaceiv(program, GL_BUFFER_VARIABLE,           GL_ACTIVE_RESOURCES,    &numActiveBufferVars);
1345         gl.getProgramInterfaceiv(program, GL_SHADER_STORAGE_BLOCK,      GL_ACTIVE_RESOURCES,    &numActiveBlocks);
1346
1347         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to get number of buffer variables and buffer blocks");
1348
1349         // Block entries.
1350         layout.blocks.resize(numActiveBlocks);
1351         for (int blockNdx = 0; blockNdx < numActiveBlocks; blockNdx++)
1352         {
1353                 BlockLayoutEntry&       entry                           = layout.blocks[blockNdx];
1354                 const deUint32          queryParams[]           = { GL_BUFFER_DATA_SIZE, GL_NUM_ACTIVE_VARIABLES, GL_NAME_LENGTH };
1355                 int                                     returnValues[]          = { 0, 0, 0 };
1356
1357                 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(queryParams) == DE_LENGTH_OF_ARRAY(returnValues));
1358
1359                 {
1360                         int returnLength = 0;
1361                         gl.getProgramResourceiv(program, GL_SHADER_STORAGE_BLOCK, (deUint32)blockNdx, DE_LENGTH_OF_ARRAY(queryParams), &queryParams[0], DE_LENGTH_OF_ARRAY(returnValues), &returnLength, &returnValues[0]);
1362                         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceiv(GL_SHADER_STORAGE_BLOCK) failed");
1363
1364                         if (returnLength != DE_LENGTH_OF_ARRAY(returnValues))
1365                                 throw tcu::TestError("glGetProgramResourceiv(GL_SHADER_STORAGE_BLOCK) returned wrong number of values");
1366                 }
1367
1368                 entry.size = returnValues[0];
1369
1370                 // Query active variables
1371                 if (returnValues[1] > 0)
1372                 {
1373                         const int               numBlockVars    = returnValues[1];
1374                         const deUint32  queryArg                = GL_ACTIVE_VARIABLES;
1375                         int                             retLength               = 0;
1376
1377                         entry.activeVarIndices.resize(numBlockVars);
1378                         gl.getProgramResourceiv(program, GL_SHADER_STORAGE_BLOCK, (deUint32)blockNdx, 1, &queryArg, numBlockVars, &retLength, &entry.activeVarIndices[0]);
1379                         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceiv(GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_VARIABLES) failed");
1380
1381                         if (retLength != numBlockVars)
1382                                 throw tcu::TestError("glGetProgramResourceiv(GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_VARIABLES) returned wrong number of values");
1383                 }
1384
1385                 // Query name
1386                 if (returnValues[2] > 0)
1387                 {
1388                         const int               nameLen         = returnValues[2];
1389                         int                             retLen          = 0;
1390                         vector<char>    name            (nameLen);
1391
1392                         gl.getProgramResourceName(program, GL_SHADER_STORAGE_BLOCK, (deUint32)blockNdx, (glw::GLsizei)name.size(), &retLen, &name[0]);
1393                         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceName(GL_SHADER_STORAGE_BLOCK) failed");
1394
1395                         if (retLen+1 != nameLen)
1396                                 throw tcu::TestError("glGetProgramResourceName(GL_SHADER_STORAGE_BLOCK) returned invalid name. Number of characters written is inconsistent with NAME_LENGTH property.");
1397                         if (name[nameLen-1] != 0)
1398                                 throw tcu::TestError("glGetProgramResourceName(GL_SHADER_STORAGE_BLOCK) returned invalid name. Expected null terminator at index " + de::toString(nameLen-1));
1399
1400                         entry.name = &name[0];
1401                 }
1402                 else
1403                         throw tcu::TestError("glGetProgramResourceiv() returned invalid GL_NAME_LENGTH");
1404         }
1405
1406         layout.bufferVars.resize(numActiveBufferVars);
1407         for (int bufVarNdx = 0; bufVarNdx < numActiveBufferVars; bufVarNdx++)
1408         {
1409                 BufferVarLayoutEntry&   entry                           = layout.bufferVars[bufVarNdx];
1410                 const deUint32                  queryParams[] =
1411                 {
1412                         GL_BLOCK_INDEX,                                 // 0
1413                         GL_TYPE,                                                // 1
1414                         GL_OFFSET,                                              // 2
1415                         GL_ARRAY_SIZE,                                  // 3
1416                         GL_ARRAY_STRIDE,                                // 4
1417                         GL_MATRIX_STRIDE,                               // 5
1418                         GL_TOP_LEVEL_ARRAY_SIZE,                // 6
1419                         GL_TOP_LEVEL_ARRAY_STRIDE,              // 7
1420                         GL_IS_ROW_MAJOR,                                // 8
1421                         GL_NAME_LENGTH                                  // 9
1422                 };
1423                 int returnValues[DE_LENGTH_OF_ARRAY(queryParams)];
1424
1425                 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(queryParams) == DE_LENGTH_OF_ARRAY(returnValues));
1426
1427                 {
1428                         int returnLength = 0;
1429                         gl.getProgramResourceiv(program, GL_BUFFER_VARIABLE, (deUint32)bufVarNdx, DE_LENGTH_OF_ARRAY(queryParams), &queryParams[0], DE_LENGTH_OF_ARRAY(returnValues), &returnLength, &returnValues[0]);
1430                         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceiv(GL_BUFFER_VARIABLE) failed");
1431
1432                         if (returnLength != DE_LENGTH_OF_ARRAY(returnValues))
1433                                 throw tcu::TestError("glGetProgramResourceiv(GL_BUFFER_VARIABLE) returned wrong number of values");
1434                 }
1435
1436                 // Map values
1437                 entry.blockNdx                          = returnValues[0];
1438                 entry.type                                      = glu::getDataTypeFromGLType(returnValues[1]);
1439                 entry.offset                            = returnValues[2];
1440                 entry.arraySize                         = returnValues[3];
1441                 entry.arrayStride                       = returnValues[4];
1442                 entry.matrixStride                      = returnValues[5];
1443                 entry.topLevelArraySize         = returnValues[6];
1444                 entry.topLevelArrayStride       = returnValues[7];
1445                 entry.isRowMajor                        = returnValues[8] != 0;
1446
1447                 // Query name
1448                 DE_ASSERT(queryParams[9] == GL_NAME_LENGTH);
1449                 if (returnValues[9] > 0)
1450                 {
1451                         const int               nameLen         = returnValues[9];
1452                         int                             retLen          = 0;
1453                         vector<char>    name            (nameLen);
1454
1455                         gl.getProgramResourceName(program, GL_BUFFER_VARIABLE, (deUint32)bufVarNdx, (glw::GLsizei)name.size(), &retLen, &name[0]);
1456                         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceName(GL_BUFFER_VARIABLE) failed");
1457
1458                         if (retLen+1 != nameLen)
1459                                 throw tcu::TestError("glGetProgramResourceName(GL_BUFFER_VARIABLE) returned invalid name. Number of characters written is inconsistent with NAME_LENGTH property.");
1460                         if (name[nameLen-1] != 0)
1461                                 throw tcu::TestError("glGetProgramResourceName(GL_BUFFER_VARIABLE) returned invalid name. Expected null terminator at index " + de::toString(nameLen-1));
1462
1463                         entry.name = &name[0];
1464                 }
1465                 else
1466                         throw tcu::TestError("glGetProgramResourceiv() returned invalid GL_NAME_LENGTH");
1467         }
1468 }
1469
1470 void copyBufferVarData (const BufferVarLayoutEntry& dstEntry, const BlockDataPtr& dstBlockPtr, const BufferVarLayoutEntry& srcEntry, const BlockDataPtr& srcBlockPtr)
1471 {
1472         DE_ASSERT(dstEntry.arraySize <= srcEntry.arraySize);
1473         DE_ASSERT(dstEntry.topLevelArraySize <= srcEntry.topLevelArraySize);
1474         DE_ASSERT(dstBlockPtr.lastUnsizedArraySize <= srcBlockPtr.lastUnsizedArraySize);
1475         DE_ASSERT(dstEntry.type == srcEntry.type);
1476
1477         deUint8* const                  dstBasePtr                      = (deUint8*)dstBlockPtr.ptr + dstEntry.offset;
1478         const deUint8* const    srcBasePtr                      = (const deUint8*)srcBlockPtr.ptr + srcEntry.offset;
1479         const int                               scalarSize                      = glu::getDataTypeScalarSize(dstEntry.type);
1480         const bool                              isMatrix                        = glu::isDataTypeMatrix(dstEntry.type);
1481         const int                               compSize                        = sizeof(deUint32);
1482         const int                               dstArraySize            = dstEntry.arraySize == 0 ? dstBlockPtr.lastUnsizedArraySize : dstEntry.arraySize;
1483         const int                               dstArrayStride          = dstEntry.arrayStride;
1484         const int                               dstTopLevelSize         = dstEntry.topLevelArraySize == 0 ? dstBlockPtr.lastUnsizedArraySize : dstEntry.topLevelArraySize;
1485         const int                               dstTopLevelStride       = dstEntry.topLevelArrayStride;
1486         const int                               srcArraySize            = srcEntry.arraySize == 0 ? srcBlockPtr.lastUnsizedArraySize : srcEntry.arraySize;
1487         const int                               srcArrayStride          = srcEntry.arrayStride;
1488         const int                               srcTopLevelSize         = srcEntry.topLevelArraySize == 0 ? srcBlockPtr.lastUnsizedArraySize : srcEntry.topLevelArraySize;
1489         const int                               srcTopLevelStride       = srcEntry.topLevelArrayStride;
1490
1491         DE_ASSERT(dstArraySize <= srcArraySize && dstTopLevelSize <= srcTopLevelSize);
1492         DE_UNREF(srcArraySize && srcTopLevelSize);
1493
1494         for (int topElemNdx = 0; topElemNdx < dstTopLevelSize; topElemNdx++)
1495         {
1496                 deUint8* const                  dstTopPtr       = dstBasePtr + topElemNdx*dstTopLevelStride;
1497                 const deUint8* const    srcTopPtr       = srcBasePtr + topElemNdx*srcTopLevelStride;
1498
1499                 for (int elementNdx = 0; elementNdx < dstArraySize; elementNdx++)
1500                 {
1501                         deUint8* const                  dstElemPtr      = dstTopPtr + elementNdx*dstArrayStride;
1502                         const deUint8* const    srcElemPtr      = srcTopPtr + elementNdx*srcArrayStride;
1503
1504                         if (isMatrix)
1505                         {
1506                                 const int       numRows = glu::getDataTypeMatrixNumRows(dstEntry.type);
1507                                 const int       numCols = glu::getDataTypeMatrixNumColumns(dstEntry.type);
1508
1509                                 for (int colNdx = 0; colNdx < numCols; colNdx++)
1510                                 {
1511                                         for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
1512                                         {
1513                                                 deUint8*                dstCompPtr      = dstElemPtr + (dstEntry.isRowMajor ? rowNdx*dstEntry.matrixStride + colNdx*compSize
1514                                                                                                                                                                                 : colNdx*dstEntry.matrixStride + rowNdx*compSize);
1515                                                 const deUint8*  srcCompPtr      = srcElemPtr + (srcEntry.isRowMajor ? rowNdx*srcEntry.matrixStride + colNdx*compSize
1516                                                                                                                                                                                 : colNdx*srcEntry.matrixStride + rowNdx*compSize);
1517
1518                                                 DE_ASSERT((deIntptr)(srcCompPtr + compSize) - (deIntptr)srcBlockPtr.ptr <= (deIntptr)srcBlockPtr.size);
1519                                                 DE_ASSERT((deIntptr)(dstCompPtr + compSize) - (deIntptr)dstBlockPtr.ptr <= (deIntptr)dstBlockPtr.size);
1520                                                 deMemcpy(dstCompPtr, srcCompPtr, compSize);
1521                                         }
1522                                 }
1523                         }
1524                         else
1525                         {
1526                                 DE_ASSERT((deIntptr)(srcElemPtr + scalarSize*compSize) - (deIntptr)srcBlockPtr.ptr <= (deIntptr)srcBlockPtr.size);
1527                                 DE_ASSERT((deIntptr)(dstElemPtr + scalarSize*compSize) - (deIntptr)dstBlockPtr.ptr <= (deIntptr)dstBlockPtr.size);
1528                                 deMemcpy(dstElemPtr, srcElemPtr, scalarSize*compSize);
1529                         }
1530                 }
1531         }
1532 }
1533
1534 void copyData (const BufferLayout& dstLayout, const vector<BlockDataPtr>& dstBlockPointers, const BufferLayout& srcLayout, const vector<BlockDataPtr>& srcBlockPointers)
1535 {
1536         // \note Src layout is used as reference in case of activeVarIndices happens to be incorrect in dstLayout blocks.
1537         int numBlocks = (int)srcLayout.blocks.size();
1538
1539         for (int srcBlockNdx = 0; srcBlockNdx < numBlocks; srcBlockNdx++)
1540         {
1541                 const BlockLayoutEntry&         srcBlock        = srcLayout.blocks[srcBlockNdx];
1542                 const BlockDataPtr&                     srcBlockPtr     = srcBlockPointers[srcBlockNdx];
1543                 int                                                     dstBlockNdx     = dstLayout.getBlockIndex(srcBlock.name.c_str());
1544
1545                 if (dstBlockNdx >= 0)
1546                 {
1547                         DE_ASSERT(de::inBounds(dstBlockNdx, 0, (int)dstBlockPointers.size()));
1548
1549                         const BlockDataPtr& dstBlockPtr = dstBlockPointers[dstBlockNdx];
1550
1551                         for (vector<int>::const_iterator srcVarNdxIter = srcBlock.activeVarIndices.begin(); srcVarNdxIter != srcBlock.activeVarIndices.end(); srcVarNdxIter++)
1552                         {
1553                                 const BufferVarLayoutEntry&     srcEntry        = srcLayout.bufferVars[*srcVarNdxIter];
1554                                 int                                                     dstVarNdx       = dstLayout.getVariableIndex(srcEntry.name.c_str());
1555
1556                                 if (dstVarNdx >= 0)
1557                                         copyBufferVarData(dstLayout.bufferVars[dstVarNdx], dstBlockPtr, srcEntry, srcBlockPtr);
1558                         }
1559                 }
1560         }
1561 }
1562
1563 void copyNonWrittenData (
1564         const BufferLayout&                     layout,
1565         const BufferBlock&                      block,
1566         int                                                     instanceNdx,
1567         const BlockDataPtr&                     srcBlockPtr,
1568         const BlockDataPtr&                     dstBlockPtr,
1569         const BufferVar&                        bufVar,
1570         const glu::SubTypeAccess&       accessPath)
1571 {
1572         const VarType curType = accessPath.getType();
1573
1574         if (curType.isArrayType())
1575         {
1576                 const int arraySize = curType.getArraySize() == VarType::UNSIZED_ARRAY ? block.getLastUnsizedArraySize(instanceNdx) : curType.getArraySize();
1577
1578                 for (int elemNdx = 0; elemNdx < arraySize; elemNdx++)
1579                         copyNonWrittenData(layout, block, instanceNdx, srcBlockPtr, dstBlockPtr, bufVar, accessPath.element(elemNdx));
1580         }
1581         else if (curType.isStructType())
1582         {
1583                 const int numMembers = curType.getStructPtr()->getNumMembers();
1584
1585                 for (int memberNdx = 0; memberNdx < numMembers; memberNdx++)
1586                         copyNonWrittenData(layout, block, instanceNdx, srcBlockPtr, dstBlockPtr, bufVar, accessPath.member(memberNdx));
1587         }
1588         else
1589         {
1590                 DE_ASSERT(curType.isBasicType());
1591
1592                 const string    apiName = getAPIName(block, bufVar, accessPath.getPath());
1593                 const int               varNdx  = layout.getVariableIndex(apiName);
1594
1595                 DE_ASSERT(varNdx >= 0);
1596                 {
1597                         const BufferVarLayoutEntry& varLayout = layout.bufferVars[varNdx];
1598                         copyBufferVarData(varLayout, dstBlockPtr, varLayout, srcBlockPtr);
1599                 }
1600         }
1601 }
1602
1603 void copyNonWrittenData (const ShaderInterface& interface, const BufferLayout& layout, const vector<BlockDataPtr>& srcPtrs, const vector<BlockDataPtr>& dstPtrs)
1604 {
1605         for (int declNdx = 0; declNdx < interface.getNumBlocks(); declNdx++)
1606         {
1607                 const BufferBlock&      block                   = interface.getBlock(declNdx);
1608                 const bool                      isArray                 = block.isArray();
1609                 const int                       numInstances    = isArray ? block.getArraySize() : 1;
1610
1611                 DE_ASSERT(!isArray || block.getInstanceName());
1612
1613                 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1614                 {
1615                         const string            instanceName    = block.getBlockName() + (isArray ? "[" + de::toString(instanceNdx) + "]" : string(""));
1616                         const int                       blockNdx                = layout.getBlockIndex(instanceName);
1617                         const BlockDataPtr&     srcBlockPtr             = srcPtrs[blockNdx];
1618                         const BlockDataPtr&     dstBlockPtr             = dstPtrs[blockNdx];
1619
1620                         for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++)
1621                         {
1622                                 const BufferVar& bufVar = *varIter;
1623
1624                                 if (bufVar.getFlags() & ACCESS_WRITE)
1625                                         continue;
1626
1627                                 copyNonWrittenData(layout, block, instanceNdx, srcBlockPtr, dstBlockPtr, bufVar, glu::SubTypeAccess(bufVar.getType()));
1628                         }
1629                 }
1630         }
1631 }
1632
1633 bool compareComponents (glu::DataType scalarType, const void* ref, const void* res, int numComps)
1634 {
1635         if (scalarType == glu::TYPE_FLOAT)
1636         {
1637                 const float threshold = 0.05f; // Same as used in shaders - should be fine for values being used.
1638
1639                 for (int ndx = 0; ndx < numComps; ndx++)
1640                 {
1641                         const float             refVal          = *((const float*)ref + ndx);
1642                         const float             resVal          = *((const float*)res + ndx);
1643
1644                         if (!(deFloatAbs(resVal - refVal) <= threshold))
1645                                 return false;
1646                 }
1647         }
1648         else if (scalarType == glu::TYPE_BOOL)
1649         {
1650                 for (int ndx = 0; ndx < numComps; ndx++)
1651                 {
1652                         const deUint32  refVal          = *((const deUint32*)ref + ndx);
1653                         const deUint32  resVal          = *((const deUint32*)res + ndx);
1654
1655                         if ((refVal != 0) != (resVal != 0))
1656                                 return false;
1657                 }
1658         }
1659         else
1660         {
1661                 DE_ASSERT(scalarType == glu::TYPE_INT || scalarType == glu::TYPE_UINT);
1662
1663                 for (int ndx = 0; ndx < numComps; ndx++)
1664                 {
1665                         const deUint32  refVal          = *((const deUint32*)ref + ndx);
1666                         const deUint32  resVal          = *((const deUint32*)res + ndx);
1667
1668                         if (refVal != resVal)
1669                                 return false;
1670                 }
1671         }
1672
1673         return true;
1674 }
1675
1676 bool compareBufferVarData (tcu::TestLog& log, const BufferVarLayoutEntry& refEntry, const BlockDataPtr& refBlockPtr, const BufferVarLayoutEntry& resEntry, const BlockDataPtr& resBlockPtr)
1677 {
1678         DE_ASSERT(resEntry.arraySize <= refEntry.arraySize);
1679         DE_ASSERT(resEntry.topLevelArraySize <= refEntry.topLevelArraySize);
1680         DE_ASSERT(resBlockPtr.lastUnsizedArraySize <= refBlockPtr.lastUnsizedArraySize);
1681         DE_ASSERT(resEntry.type == refEntry.type);
1682
1683         deUint8* const                  resBasePtr                      = (deUint8*)resBlockPtr.ptr + resEntry.offset;
1684         const deUint8* const    refBasePtr                      = (const deUint8*)refBlockPtr.ptr + refEntry.offset;
1685         const glu::DataType             scalarType                      = glu::getDataTypeScalarType(refEntry.type);
1686         const int                               scalarSize                      = glu::getDataTypeScalarSize(resEntry.type);
1687         const bool                              isMatrix                        = glu::isDataTypeMatrix(resEntry.type);
1688         const int                               compSize                        = sizeof(deUint32);
1689         const int                               maxPrints                       = 3;
1690         int                                             numFailed                       = 0;
1691
1692         const int                               resArraySize            = resEntry.arraySize == 0 ? resBlockPtr.lastUnsizedArraySize : resEntry.arraySize;
1693         const int                               resArrayStride          = resEntry.arrayStride;
1694         const int                               resTopLevelSize         = resEntry.topLevelArraySize == 0 ? resBlockPtr.lastUnsizedArraySize : resEntry.topLevelArraySize;
1695         const int                               resTopLevelStride       = resEntry.topLevelArrayStride;
1696         const int                               refArraySize            = refEntry.arraySize == 0 ? refBlockPtr.lastUnsizedArraySize : refEntry.arraySize;
1697         const int                               refArrayStride          = refEntry.arrayStride;
1698         const int                               refTopLevelSize         = refEntry.topLevelArraySize == 0 ? refBlockPtr.lastUnsizedArraySize : refEntry.topLevelArraySize;
1699         const int                               refTopLevelStride       = refEntry.topLevelArrayStride;
1700
1701         DE_ASSERT(resArraySize <= refArraySize && resTopLevelSize <= refTopLevelSize);
1702         DE_UNREF(refArraySize && refTopLevelSize);
1703
1704         for (int topElemNdx = 0; topElemNdx < resTopLevelSize; topElemNdx++)
1705         {
1706                 deUint8* const                  resTopPtr       = resBasePtr + topElemNdx*resTopLevelStride;
1707                 const deUint8* const    refTopPtr       = refBasePtr + topElemNdx*refTopLevelStride;
1708
1709                 for (int elementNdx = 0; elementNdx < resArraySize; elementNdx++)
1710                 {
1711                         deUint8* const                  resElemPtr      = resTopPtr + elementNdx*resArrayStride;
1712                         const deUint8* const    refElemPtr      = refTopPtr + elementNdx*refArrayStride;
1713
1714                         if (isMatrix)
1715                         {
1716                                 const int       numRows = glu::getDataTypeMatrixNumRows(resEntry.type);
1717                                 const int       numCols = glu::getDataTypeMatrixNumColumns(resEntry.type);
1718                                 bool            isOk    = true;
1719
1720                                 for (int colNdx = 0; colNdx < numCols; colNdx++)
1721                                 {
1722                                         for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
1723                                         {
1724                                                 deUint8*                resCompPtr      = resElemPtr + (resEntry.isRowMajor ? rowNdx*resEntry.matrixStride + colNdx*compSize
1725                                                                                                                                                                                 : colNdx*resEntry.matrixStride + rowNdx*compSize);
1726                                                 const deUint8*  refCompPtr      = refElemPtr + (refEntry.isRowMajor ? rowNdx*refEntry.matrixStride + colNdx*compSize
1727                                                                                                                                                                                 : colNdx*refEntry.matrixStride + rowNdx*compSize);
1728
1729                                                 DE_ASSERT((deIntptr)(refCompPtr + compSize) - (deIntptr)refBlockPtr.ptr <= (deIntptr)refBlockPtr.size);
1730                                                 DE_ASSERT((deIntptr)(resCompPtr + compSize) - (deIntptr)resBlockPtr.ptr <= (deIntptr)resBlockPtr.size);
1731
1732                                                 isOk = isOk && compareComponents(scalarType, resCompPtr, refCompPtr, 1);
1733                                         }
1734                                 }
1735
1736                                 if (!isOk)
1737                                 {
1738                                         numFailed += 1;
1739                                         if (numFailed < maxPrints)
1740                                         {
1741                                                 std::ostringstream expected, got;
1742                                                 generateImmMatrixSrc(expected, refEntry.type, refEntry.matrixStride, refEntry.isRowMajor, refElemPtr);
1743                                                 generateImmMatrixSrc(got, resEntry.type, resEntry.matrixStride, resEntry.isRowMajor, resElemPtr);
1744                                                 log << TestLog::Message << "ERROR: mismatch in " << refEntry.name << ", top-level ndx " << topElemNdx << ", bottom-level ndx " << elementNdx << ":\n"
1745                                                                                                 << "  expected " << expected.str() << "\n"
1746                                                                                                 << "  got " << got.str()
1747                                                         << TestLog::EndMessage;
1748                                         }
1749                                 }
1750                         }
1751                         else
1752                         {
1753                                 DE_ASSERT((deIntptr)(refElemPtr + scalarSize*compSize) - (deIntptr)refBlockPtr.ptr <= (deIntptr)refBlockPtr.size);
1754                                 DE_ASSERT((deIntptr)(resElemPtr + scalarSize*compSize) - (deIntptr)resBlockPtr.ptr <= (deIntptr)resBlockPtr.size);
1755
1756                                 const bool isOk = compareComponents(scalarType, resElemPtr, refElemPtr, scalarSize);
1757
1758                                 if (!isOk)
1759                                 {
1760                                         numFailed += 1;
1761                                         if (numFailed < maxPrints)
1762                                         {
1763                                                 std::ostringstream expected, got;
1764                                                 generateImmScalarVectorSrc(expected, refEntry.type, refElemPtr);
1765                                                 generateImmScalarVectorSrc(got, resEntry.type, resElemPtr);
1766                                                 log << TestLog::Message << "ERROR: mismatch in " << refEntry.name << ", top-level ndx " << topElemNdx << ", bottom-level ndx " << elementNdx << ":\n"
1767                                                                                                 << "  expected " << expected.str() << "\n"
1768                                                                                                 << "  got " << got.str()
1769                                                         << TestLog::EndMessage;
1770                                         }
1771                                 }
1772                         }
1773                 }
1774         }
1775
1776         if (numFailed >= maxPrints)
1777                 log << TestLog::Message << "... (" << numFailed << " failures for " << refEntry.name << " in total)" << TestLog::EndMessage;
1778
1779         return numFailed == 0;
1780 }
1781
1782 bool compareData (tcu::TestLog& log, const BufferLayout& refLayout, const vector<BlockDataPtr>& refBlockPointers, const BufferLayout& resLayout, const vector<BlockDataPtr>& resBlockPointers)
1783 {
1784         const int       numBlocks       = (int)refLayout.blocks.size();
1785         bool            allOk           = true;
1786
1787         for (int refBlockNdx = 0; refBlockNdx < numBlocks; refBlockNdx++)
1788         {
1789                 const BlockLayoutEntry&         refBlock        = refLayout.blocks[refBlockNdx];
1790                 const BlockDataPtr&                     refBlockPtr     = refBlockPointers[refBlockNdx];
1791                 int                                                     resBlockNdx     = resLayout.getBlockIndex(refBlock.name.c_str());
1792
1793                 if (resBlockNdx >= 0)
1794                 {
1795                         DE_ASSERT(de::inBounds(resBlockNdx, 0, (int)resBlockPointers.size()));
1796
1797                         const BlockDataPtr& resBlockPtr = resBlockPointers[resBlockNdx];
1798
1799                         for (vector<int>::const_iterator refVarNdxIter = refBlock.activeVarIndices.begin(); refVarNdxIter != refBlock.activeVarIndices.end(); refVarNdxIter++)
1800                         {
1801                                 const BufferVarLayoutEntry&     refEntry        = refLayout.bufferVars[*refVarNdxIter];
1802                                 int                                                     resVarNdx       = resLayout.getVariableIndex(refEntry.name.c_str());
1803
1804                                 if (resVarNdx >= 0)
1805                                 {
1806                                         const BufferVarLayoutEntry& resEntry = resLayout.bufferVars[resVarNdx];
1807                                         allOk = compareBufferVarData(log, refEntry, refBlockPtr, resEntry, resBlockPtr) && allOk;
1808                                 }
1809                         }
1810                 }
1811         }
1812
1813         return allOk;
1814 }
1815
1816 string getBlockAPIName (const BufferBlock& block, int instanceNdx)
1817 {
1818         DE_ASSERT(block.isArray() || instanceNdx == 0);
1819         return block.getBlockName() + (block.isArray() ? ("[" + de::toString(instanceNdx) + "]") : string());
1820 }
1821
1822 // \note Some implementations don't report block members in the order they are declared.
1823 //               For checking whether size has to be adjusted by some top-level array actual size,
1824 //               we only need to know a) whether there is a unsized top-level array, and b)
1825 //               what is stride of that array.
1826
1827 static bool hasUnsizedArray (const BufferLayout& layout, const BlockLayoutEntry& entry)
1828 {
1829         for (vector<int>::const_iterator varNdx = entry.activeVarIndices.begin(); varNdx != entry.activeVarIndices.end(); ++varNdx)
1830         {
1831                 if (isUnsizedArray(layout.bufferVars[*varNdx]))
1832                         return true;
1833         }
1834
1835         return false;
1836 }
1837
1838 static int getUnsizedArrayStride (const BufferLayout& layout, const BlockLayoutEntry& entry)
1839 {
1840         for (vector<int>::const_iterator varNdx = entry.activeVarIndices.begin(); varNdx != entry.activeVarIndices.end(); ++varNdx)
1841         {
1842                 const BufferVarLayoutEntry& varEntry = layout.bufferVars[*varNdx];
1843
1844                 if (varEntry.arraySize == 0)
1845                         return varEntry.arrayStride;
1846                 else if (varEntry.topLevelArraySize == 0)
1847                         return varEntry.topLevelArrayStride;
1848         }
1849
1850         return 0;
1851 }
1852
1853 vector<int> computeBufferSizes (const ShaderInterface& interface, const BufferLayout& layout)
1854 {
1855         vector<int> sizes(layout.blocks.size());
1856
1857         for (int declNdx = 0; declNdx < interface.getNumBlocks(); declNdx++)
1858         {
1859                 const BufferBlock&      block                   = interface.getBlock(declNdx);
1860                 const bool                      isArray                 = block.isArray();
1861                 const int                       numInstances    = isArray ? block.getArraySize() : 1;
1862
1863                 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1864                 {
1865                         const string    apiName         = getBlockAPIName(block, instanceNdx);
1866                         const int               blockNdx        = layout.getBlockIndex(apiName);
1867
1868                         if (blockNdx >= 0)
1869                         {
1870                                 const BlockLayoutEntry&         blockLayout             = layout.blocks[blockNdx];
1871                                 const int                                       baseSize                = blockLayout.size;
1872                                 const bool                                      isLastUnsized   = hasUnsizedArray(layout, blockLayout);
1873                                 const int                                       lastArraySize   = isLastUnsized ? block.getLastUnsizedArraySize(instanceNdx) : 0;
1874                                 const int                                       stride                  = isLastUnsized ? getUnsizedArrayStride(layout, blockLayout) : 0;
1875
1876                                 sizes[blockNdx] = baseSize + lastArraySize*stride;
1877                         }
1878                 }
1879         }
1880
1881         return sizes;
1882 }
1883
1884 BlockDataPtr getBlockDataPtr (const BufferLayout& layout, const BlockLayoutEntry& blockLayout, void* ptr, int bufferSize)
1885 {
1886         const bool      isLastUnsized   = hasUnsizedArray(layout, blockLayout);
1887         const int       baseSize                = blockLayout.size;
1888
1889         if (isLastUnsized)
1890         {
1891                 const int               lastArrayStride = getUnsizedArrayStride(layout, blockLayout);
1892                 const int               lastArraySize   = (bufferSize-baseSize) / (lastArrayStride ? lastArrayStride : 1);
1893
1894                 DE_ASSERT(baseSize + lastArraySize*lastArrayStride == bufferSize);
1895
1896                 return BlockDataPtr(ptr, bufferSize, lastArraySize);
1897         }
1898         else
1899                 return BlockDataPtr(ptr, bufferSize, 0);
1900 }
1901
1902 struct RefDataStorage
1903 {
1904         vector<deUint8>                 data;
1905         vector<BlockDataPtr>    pointers;
1906 };
1907
1908 struct Buffer
1909 {
1910         deUint32                                buffer;
1911         int                                             size;
1912
1913         Buffer (deUint32 buffer_, int size_) : buffer(buffer_), size(size_) {}
1914         Buffer (void) : buffer(0), size(0) {}
1915 };
1916
1917 struct BlockLocation
1918 {
1919         int                                             index;
1920         int                                             offset;
1921         int                                             size;
1922
1923         BlockLocation (int index_, int offset_, int size_) : index(index_), offset(offset_), size(size_) {}
1924         BlockLocation (void) : index(0), offset(0), size(0) {}
1925 };
1926
1927 void initRefDataStorage (const ShaderInterface& interface, const BufferLayout& layout, RefDataStorage& storage)
1928 {
1929         DE_ASSERT(storage.data.empty() && storage.pointers.empty());
1930
1931         const vector<int>       bufferSizes = computeBufferSizes(interface, layout);
1932         int                                     totalSize       = 0;
1933
1934         for (vector<int>::const_iterator sizeIter = bufferSizes.begin(); sizeIter != bufferSizes.end(); ++sizeIter)
1935                 totalSize += *sizeIter;
1936
1937         storage.data.resize(totalSize);
1938
1939         // Pointers for each block.
1940         {
1941                 deUint8*        basePtr         = storage.data.empty() ? DE_NULL : &storage.data[0];
1942                 int                     curOffset       = 0;
1943
1944                 DE_ASSERT(bufferSizes.size() == layout.blocks.size());
1945                 DE_ASSERT(totalSize == 0 || basePtr);
1946
1947                 storage.pointers.resize(layout.blocks.size());
1948
1949                 for (int blockNdx = 0; blockNdx < (int)layout.blocks.size(); blockNdx++)
1950                 {
1951                         const BlockLayoutEntry& blockLayout             = layout.blocks[blockNdx];
1952                         const int                               bufferSize              = bufferSizes[blockNdx];
1953
1954                         storage.pointers[blockNdx] = getBlockDataPtr(layout, blockLayout, basePtr + curOffset, bufferSize);
1955
1956                         curOffset += bufferSize;
1957                 }
1958         }
1959 }
1960
1961 vector<BlockDataPtr> blockLocationsToPtrs (const BufferLayout& layout, const vector<BlockLocation>& blockLocations, const vector<void*>& bufPtrs)
1962 {
1963         vector<BlockDataPtr> blockPtrs(blockLocations.size());
1964
1965         DE_ASSERT(layout.blocks.size() == blockLocations.size());
1966
1967         for (int blockNdx = 0; blockNdx < (int)layout.blocks.size(); blockNdx++)
1968         {
1969                 const BlockLayoutEntry& blockLayout             = layout.blocks[blockNdx];
1970                 const BlockLocation&    location                = blockLocations[blockNdx];
1971
1972                 blockPtrs[blockNdx] = getBlockDataPtr(layout, blockLayout, (deUint8*)bufPtrs[location.index] + location.offset, location.size);
1973         }
1974
1975         return blockPtrs;
1976 }
1977
1978 vector<void*> mapBuffers (const glw::Functions& gl, const vector<Buffer>& buffers, deUint32 access)
1979 {
1980         vector<void*> mapPtrs(buffers.size(), DE_NULL);
1981
1982         try
1983         {
1984                 for (int ndx = 0; ndx < (int)buffers.size(); ndx++)
1985                 {
1986                         if (buffers[ndx].size > 0)
1987                         {
1988                                 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, buffers[ndx].buffer);
1989                                 mapPtrs[ndx] = gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, buffers[ndx].size, access);
1990                                 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to map buffer");
1991                                 TCU_CHECK(mapPtrs[ndx]);
1992                         }
1993                         else
1994                                 mapPtrs[ndx] = DE_NULL;
1995                 }
1996
1997                 return mapPtrs;
1998         }
1999         catch (...)
2000         {
2001                 for (int ndx = 0; ndx < (int)buffers.size(); ndx++)
2002                 {
2003                         if (mapPtrs[ndx])
2004                         {
2005                                 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, buffers[ndx].buffer);
2006                                 gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
2007                         }
2008                 }
2009
2010                 throw;
2011         }
2012 }
2013
2014 void unmapBuffers (const glw::Functions& gl, const vector<Buffer>& buffers)
2015 {
2016         for (int ndx = 0; ndx < (int)buffers.size(); ndx++)
2017         {
2018                 if (buffers[ndx].size > 0)
2019                 {
2020                         gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, buffers[ndx].buffer);
2021                         gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
2022                 }
2023         }
2024
2025         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to unmap buffer");
2026 }
2027
2028 } // anonymous (utilities)
2029
2030 class BufferManager
2031 {
2032 public:
2033                                                                 BufferManager   (const glu::RenderContext& renderCtx);
2034                                                                 ~BufferManager  (void);
2035
2036         deUint32                                        allocBuffer             (void);
2037
2038 private:
2039                                                                 BufferManager   (const BufferManager& other);
2040         BufferManager&                          operator=               (const BufferManager& other);
2041
2042         const glu::RenderContext&       m_renderCtx;
2043         std::vector<deUint32>           m_buffers;
2044 };
2045
2046 BufferManager::BufferManager (const glu::RenderContext& renderCtx)
2047         : m_renderCtx(renderCtx)
2048 {
2049 }
2050
2051 BufferManager::~BufferManager (void)
2052 {
2053         if (!m_buffers.empty())
2054                 m_renderCtx.getFunctions().deleteBuffers((glw::GLsizei)m_buffers.size(), &m_buffers[0]);
2055 }
2056
2057 deUint32 BufferManager::allocBuffer (void)
2058 {
2059         deUint32 buf = 0;
2060
2061         m_buffers.reserve(m_buffers.size()+1);
2062         m_renderCtx.getFunctions().genBuffers(1, &buf);
2063         GLU_EXPECT_NO_ERROR(m_renderCtx.getFunctions().getError(), "Failed to allocate buffer");
2064         m_buffers.push_back(buf);
2065
2066         return buf;
2067 }
2068
2069 } // bb
2070
2071 using namespace bb;
2072
2073 // SSBOLayoutCase.
2074
2075 SSBOLayoutCase::SSBOLayoutCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* description, glu::GLSLVersion glslVersion, BufferMode bufferMode)
2076         : TestCase              (testCtx, name, description)
2077         , m_renderCtx   (renderCtx)
2078         , m_glslVersion (glslVersion)
2079         , m_bufferMode  (bufferMode)
2080 {
2081         DE_ASSERT(glslVersion == glu::GLSL_VERSION_310_ES || glslVersion == glu::GLSL_VERSION_430);
2082 }
2083
2084 SSBOLayoutCase::~SSBOLayoutCase (void)
2085 {
2086 }
2087
2088 SSBOLayoutCase::IterateResult SSBOLayoutCase::iterate (void)
2089 {
2090         TestLog&                                        log                             = m_testCtx.getLog();
2091         const glw::Functions&           gl                              = m_renderCtx.getFunctions();
2092
2093         BufferLayout                            refLayout;              // std140 / std430 layout.
2094         BufferLayout                            glLayout;               // Layout reported by GL.
2095         RefDataStorage                          initialData;    // Initial data stored in buffer.
2096         RefDataStorage                          writeData;              // Data written by compute shader.
2097
2098         BufferManager                           bufferManager   (m_renderCtx);
2099         vector<Buffer>                          buffers;                // Buffers allocated for storage
2100         vector<BlockLocation>           blockLocations; // Block locations in storage (index, offset)
2101
2102         // Initialize result to pass.
2103         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2104
2105         computeReferenceLayout  (refLayout, m_interface);
2106         initRefDataStorage              (m_interface, refLayout, initialData);
2107         initRefDataStorage              (m_interface, refLayout, writeData);
2108         generateValues                  (refLayout, initialData.pointers, deStringHash(getName()) ^ 0xad2f7214);
2109         generateValues                  (refLayout, writeData.pointers, deStringHash(getName()) ^ 0x25ca4e7);
2110         copyNonWrittenData              (m_interface, refLayout, initialData.pointers, writeData.pointers);
2111
2112         const glu::ShaderProgram program(m_renderCtx, glu::ProgramSources() << glu::ComputeSource(generateComputeShader(m_glslVersion, m_interface, refLayout, initialData.pointers, writeData.pointers)));
2113         log << program;
2114
2115         if (!program.isOk())
2116         {
2117                 // Compile failed.
2118                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compile failed");
2119                 return STOP;
2120         }
2121
2122         // Query layout from GL.
2123         getGLBufferLayout(gl, glLayout, program.getProgram());
2124
2125         // Print layout to log.
2126         {
2127                 tcu::ScopedLogSection section(log, "ActiveBufferBlocks", "Active Buffer Blocks");
2128                 for (int blockNdx = 0; blockNdx < (int)glLayout.blocks.size(); blockNdx++)
2129                         log << TestLog::Message << blockNdx << ": " << glLayout.blocks[blockNdx] << TestLog::EndMessage;
2130         }
2131
2132         {
2133                 tcu::ScopedLogSection section(log, "ActiveBufferVars", "Active Buffer Variables");
2134                 for (int varNdx = 0; varNdx < (int)glLayout.bufferVars.size(); varNdx++)
2135                         log << TestLog::Message << varNdx << ": " << glLayout.bufferVars[varNdx] << TestLog::EndMessage;
2136         }
2137
2138         // Verify layouts.
2139         {
2140                 if (!checkLayoutIndices(glLayout) || !checkLayoutBounds(glLayout) || !compareTypes(refLayout, glLayout))
2141                 {
2142                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid layout");
2143                         return STOP; // It is not safe to use the given layout.
2144                 }
2145
2146                 if (!compareStdBlocks(refLayout, glLayout))
2147                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid std140 or std430 layout");
2148
2149                 if (!compareSharedBlocks(refLayout, glLayout))
2150                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid shared layout");
2151
2152                 if (!checkIndexQueries(program.getProgram(), glLayout))
2153                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Inconsintent block index query results");
2154         }
2155
2156         // Allocate GL buffers & compute placement.
2157         {
2158                 const int                       numBlocks               = (int)glLayout.blocks.size();
2159                 const vector<int>       bufferSizes             = computeBufferSizes(m_interface, glLayout);
2160
2161                 DE_ASSERT(bufferSizes.size() == glLayout.blocks.size());
2162
2163                 blockLocations.resize(numBlocks);
2164
2165                 if (m_bufferMode == BUFFERMODE_PER_BLOCK)
2166                 {
2167                         buffers.resize(numBlocks);
2168
2169                         for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
2170                         {
2171                                 const int bufferSize = bufferSizes[blockNdx];
2172
2173                                 buffers[blockNdx].size = bufferSize;
2174                                 blockLocations[blockNdx] = BlockLocation(blockNdx, 0, bufferSize);
2175                         }
2176                 }
2177                 else
2178                 {
2179                         DE_ASSERT(m_bufferMode == BUFFERMODE_SINGLE);
2180
2181                         int             bindingAlignment        = 0;
2182                         int             totalSize                       = 0;
2183
2184                         gl.getIntegerv(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &bindingAlignment);
2185
2186                         {
2187                                 int curOffset = 0;
2188                                 DE_ASSERT(bufferSizes.size() == glLayout.blocks.size());
2189                                 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
2190                                 {
2191                                         const int bufferSize = bufferSizes[blockNdx];
2192
2193                                         if (bindingAlignment > 0)
2194                                                 curOffset = deRoundUp32(curOffset, bindingAlignment);
2195
2196                                         blockLocations[blockNdx] = BlockLocation(0, curOffset, bufferSize);
2197                                         curOffset += bufferSize;
2198                                 }
2199                                 totalSize = curOffset;
2200                         }
2201
2202                         buffers.resize(1);
2203                         buffers[0].size = totalSize;
2204                 }
2205
2206                 for (int bufNdx = 0; bufNdx < (int)buffers.size(); bufNdx++)
2207                 {
2208                         const int               bufferSize      = buffers[bufNdx].size;
2209                         const deUint32  buffer          = bufferManager.allocBuffer();
2210
2211                         gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, buffer);
2212                         gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_STATIC_DRAW);
2213                         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to allocate buffer");
2214
2215                         buffers[bufNdx].buffer = buffer;
2216                 }
2217         }
2218
2219         {
2220                 const vector<void*>                     mapPtrs                 = mapBuffers(gl, buffers, GL_MAP_WRITE_BIT);
2221                 const vector<BlockDataPtr>      mappedBlockPtrs = blockLocationsToPtrs(glLayout, blockLocations, mapPtrs);
2222
2223                 copyData(glLayout, mappedBlockPtrs, refLayout, initialData.pointers);
2224
2225                 unmapBuffers(gl, buffers);
2226         }
2227
2228         {
2229                 int bindingPoint = 0;
2230
2231                 for (int blockDeclNdx = 0; blockDeclNdx < m_interface.getNumBlocks(); blockDeclNdx++)
2232                 {
2233                         const BufferBlock&      block           = m_interface.getBlock(blockDeclNdx);
2234                         const int                       numInst         = block.isArray() ? block.getArraySize() : 1;
2235
2236                         for (int instNdx = 0; instNdx < numInst; instNdx++)
2237                         {
2238                                 const string    instName        = getBlockAPIName(block, instNdx);
2239                                 const int               layoutNdx       = findBlockIndex(glLayout, instName);
2240
2241                                 if (layoutNdx >= 0)
2242                                 {
2243                                         const BlockLocation& blockLoc = blockLocations[layoutNdx];
2244
2245                                         if (blockLoc.size > 0)
2246                                                 gl.bindBufferRange(GL_SHADER_STORAGE_BUFFER, bindingPoint, buffers[blockLoc.index].buffer, blockLoc.offset, blockLoc.size);
2247                                 }
2248
2249                                 bindingPoint += 1;
2250                         }
2251                 }
2252         }
2253
2254         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to bind buffers");
2255
2256         {
2257                 const bool execOk = execute(program.getProgram());
2258
2259                 if (execOk)
2260                 {
2261                         const vector<void*>                     mapPtrs                 = mapBuffers(gl, buffers, GL_MAP_READ_BIT);
2262                         const vector<BlockDataPtr>      mappedBlockPtrs = blockLocationsToPtrs(glLayout, blockLocations, mapPtrs);
2263
2264                         const bool                                      compareOk               = compareData(m_testCtx.getLog(), refLayout, writeData.pointers, glLayout, mappedBlockPtrs);
2265
2266                         unmapBuffers(gl, buffers);
2267
2268                         if (!compareOk)
2269                                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Result comparison failed");
2270                 }
2271                 else
2272                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader execution failed");
2273         }
2274
2275         return STOP;
2276 }
2277
2278 bool SSBOLayoutCase::compareStdBlocks (const BufferLayout& refLayout, const BufferLayout& cmpLayout) const
2279 {
2280         TestLog&        log                     = m_testCtx.getLog();
2281         bool            isOk            = true;
2282         int                     numBlocks       = m_interface.getNumBlocks();
2283
2284         for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
2285         {
2286                 const BufferBlock&              block                   = m_interface.getBlock(blockNdx);
2287                 bool                                    isArray                 = block.isArray();
2288                 std::string                             instanceName    = string(block.getBlockName()) + (isArray ? "[0]" : "");
2289                 int                                             refBlockNdx             = refLayout.getBlockIndex(instanceName.c_str());
2290                 int                                             cmpBlockNdx             = cmpLayout.getBlockIndex(instanceName.c_str());
2291
2292                 if ((block.getFlags() & (LAYOUT_STD140|LAYOUT_STD430)) == 0)
2293                         continue; // Not std* layout.
2294
2295                 DE_ASSERT(refBlockNdx >= 0);
2296
2297                 if (cmpBlockNdx < 0)
2298                 {
2299                         // Not found.
2300                         log << TestLog::Message << "Error: Buffer block '" << instanceName << "' not found" << TestLog::EndMessage;
2301                         isOk = false;
2302                         continue;
2303                 }
2304
2305                 const BlockLayoutEntry&         refBlockLayout  = refLayout.blocks[refBlockNdx];
2306                 const BlockLayoutEntry&         cmpBlockLayout  = cmpLayout.blocks[cmpBlockNdx];
2307
2308                 // \todo [2012-01-24 pyry] Verify that activeVarIndices is correct.
2309                 // \todo [2012-01-24 pyry] Verify all instances.
2310                 if (refBlockLayout.activeVarIndices.size() != cmpBlockLayout.activeVarIndices.size())
2311                 {
2312                         log << TestLog::Message << "Error: Number of active variables differ in block '" << instanceName
2313                                 << "' (expected " << refBlockLayout.activeVarIndices.size()
2314                                 << ", got " << cmpBlockLayout.activeVarIndices.size()
2315                                 << ")" << TestLog::EndMessage;
2316                         isOk = false;
2317                 }
2318
2319                 for (vector<int>::const_iterator ndxIter = refBlockLayout.activeVarIndices.begin(); ndxIter != refBlockLayout.activeVarIndices.end(); ndxIter++)
2320                 {
2321                         const BufferVarLayoutEntry&     refEntry        = refLayout.bufferVars[*ndxIter];
2322                         int                                                     cmpEntryNdx     = cmpLayout.getVariableIndex(refEntry.name.c_str());
2323
2324                         if (cmpEntryNdx < 0)
2325                         {
2326                                 log << TestLog::Message << "Error: Buffer variable '" << refEntry.name << "' not found" << TestLog::EndMessage;
2327                                 isOk = false;
2328                                 continue;
2329                         }
2330
2331                         const BufferVarLayoutEntry&     cmpEntry        = cmpLayout.bufferVars[cmpEntryNdx];
2332
2333                         if (refEntry.type                                       != cmpEntry.type                                ||
2334                                 refEntry.arraySize                              != cmpEntry.arraySize                   ||
2335                                 refEntry.offset                                 != cmpEntry.offset                              ||
2336                                 refEntry.arrayStride                    != cmpEntry.arrayStride                 ||
2337                                 refEntry.matrixStride                   != cmpEntry.matrixStride                ||
2338                                 refEntry.topLevelArraySize              != cmpEntry.topLevelArraySize   ||
2339                                 refEntry.topLevelArrayStride    != cmpEntry.topLevelArrayStride ||
2340                                 refEntry.isRowMajor                             != cmpEntry.isRowMajor)
2341                         {
2342                                 log << TestLog::Message << "Error: Layout mismatch in '" << refEntry.name << "':\n"
2343                                         << "  expected: " << refEntry << "\n"
2344                                         << "  got: " << cmpEntry
2345                                         << TestLog::EndMessage;
2346                                 isOk = false;
2347                         }
2348                 }
2349         }
2350
2351         return isOk;
2352 }
2353
2354 bool SSBOLayoutCase::compareSharedBlocks (const BufferLayout& refLayout, const BufferLayout& cmpLayout) const
2355 {
2356         TestLog&        log                     = m_testCtx.getLog();
2357         bool            isOk            = true;
2358         int                     numBlocks       = m_interface.getNumBlocks();
2359
2360         for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
2361         {
2362                 const BufferBlock&              block                   = m_interface.getBlock(blockNdx);
2363                 bool                                    isArray                 = block.isArray();
2364                 std::string                             instanceName    = string(block.getBlockName()) + (isArray ? "[0]" : "");
2365                 int                                             refBlockNdx             = refLayout.getBlockIndex(instanceName.c_str());
2366                 int                                             cmpBlockNdx             = cmpLayout.getBlockIndex(instanceName.c_str());
2367
2368                 if ((block.getFlags() & LAYOUT_SHARED) == 0)
2369                         continue; // Not shared layout.
2370
2371                 DE_ASSERT(refBlockNdx >= 0);
2372
2373                 if (cmpBlockNdx < 0)
2374                 {
2375                         // Not found, should it?
2376                         log << TestLog::Message << "Error: Buffer block '" << instanceName << "' not found" << TestLog::EndMessage;
2377                         isOk = false;
2378                         continue;
2379                 }
2380
2381                 const BlockLayoutEntry&         refBlockLayout  = refLayout.blocks[refBlockNdx];
2382                 const BlockLayoutEntry&         cmpBlockLayout  = cmpLayout.blocks[cmpBlockNdx];
2383
2384                 if (refBlockLayout.activeVarIndices.size() != cmpBlockLayout.activeVarIndices.size())
2385                 {
2386                         log << TestLog::Message << "Error: Number of active variables differ in block '" << instanceName
2387                                 << "' (expected " << refBlockLayout.activeVarIndices.size()
2388                                 << ", got " << cmpBlockLayout.activeVarIndices.size()
2389                                 << ")" << TestLog::EndMessage;
2390                         isOk = false;
2391                 }
2392
2393                 for (vector<int>::const_iterator ndxIter = refBlockLayout.activeVarIndices.begin(); ndxIter != refBlockLayout.activeVarIndices.end(); ndxIter++)
2394                 {
2395                         const BufferVarLayoutEntry&     refEntry        = refLayout.bufferVars[*ndxIter];
2396                         int                                                     cmpEntryNdx     = cmpLayout.getVariableIndex(refEntry.name.c_str());
2397
2398                         if (cmpEntryNdx < 0)
2399                         {
2400                                 log << TestLog::Message << "Error: Buffer variable '" << refEntry.name << "' not found" << TestLog::EndMessage;
2401                                 isOk = false;
2402                                 continue;
2403                         }
2404
2405                         const BufferVarLayoutEntry&     cmpEntry        = cmpLayout.bufferVars[cmpEntryNdx];
2406
2407                         if (refEntry.type                               != cmpEntry.type                                ||
2408                                 refEntry.arraySize                      != cmpEntry.arraySize                   ||
2409                                 refEntry.topLevelArraySize      != cmpEntry.topLevelArraySize   ||
2410                                 refEntry.isRowMajor     != cmpEntry.isRowMajor)
2411                         {
2412                                 log << TestLog::Message << "Error: Type / array size mismatch in '" << refEntry.name << "':\n"
2413                                         << "  expected: " << refEntry << "\n"
2414                                         << "  got: " << cmpEntry
2415                                         << TestLog::EndMessage;
2416                                 isOk = false;
2417                         }
2418                 }
2419         }
2420
2421         return isOk;
2422 }
2423
2424 bool SSBOLayoutCase::compareTypes (const BufferLayout& refLayout, const BufferLayout& cmpLayout) const
2425 {
2426         TestLog&        log                     = m_testCtx.getLog();
2427         bool            isOk            = true;
2428         int                     numBlocks       = m_interface.getNumBlocks();
2429
2430         for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
2431         {
2432                 const BufferBlock&              block                   = m_interface.getBlock(blockNdx);
2433                 bool                                    isArray                 = block.isArray();
2434                 int                                             numInstances    = isArray ? block.getArraySize() : 1;
2435
2436                 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
2437                 {
2438                         std::ostringstream instanceName;
2439
2440                         instanceName << block.getBlockName();
2441                         if (isArray)
2442                                 instanceName << "[" << instanceNdx << "]";
2443
2444                         int cmpBlockNdx = cmpLayout.getBlockIndex(instanceName.str().c_str());
2445
2446                         if (cmpBlockNdx < 0)
2447                                 continue;
2448
2449                         const BlockLayoutEntry& cmpBlockLayout = cmpLayout.blocks[cmpBlockNdx];
2450
2451                         for (vector<int>::const_iterator ndxIter = cmpBlockLayout.activeVarIndices.begin(); ndxIter != cmpBlockLayout.activeVarIndices.end(); ndxIter++)
2452                         {
2453                                 const BufferVarLayoutEntry&     cmpEntry        = cmpLayout.bufferVars[*ndxIter];
2454                                 int                                                     refEntryNdx     = refLayout.getVariableIndex(cmpEntry.name.c_str());
2455
2456                                 if (refEntryNdx < 0)
2457                                 {
2458                                         log << TestLog::Message << "Error: Buffer variable '" << cmpEntry.name << "' not found in reference layout" << TestLog::EndMessage;
2459                                         isOk = false;
2460                                         continue;
2461                                 }
2462
2463                                 const BufferVarLayoutEntry&     refEntry        = refLayout.bufferVars[refEntryNdx];
2464
2465                                 if (refEntry.type != cmpEntry.type)
2466                                 {
2467                                         log << TestLog::Message << "Error: Buffer variable type mismatch in '" << refEntry.name << "':\n"
2468                                                 << "  expected: " << glu::getDataTypeName(refEntry.type) << "\n"
2469                                                 << "  got: " << glu::getDataTypeName(cmpEntry.type)
2470                                                 << TestLog::EndMessage;
2471                                         isOk = false;
2472                                 }
2473
2474                                 if (refEntry.arraySize < cmpEntry.arraySize)
2475                                 {
2476                                         log << TestLog::Message << "Error: Invalid array size in '" << refEntry.name << "': expected <= " << refEntry.arraySize << TestLog::EndMessage;
2477                                         isOk = false;
2478                                 }
2479
2480                                 if (refEntry.topLevelArraySize < cmpEntry.topLevelArraySize)
2481                                 {
2482                                         log << TestLog::Message << "Error: Invalid top-level array size in '" << refEntry.name << "': expected <= " << refEntry.topLevelArraySize << TestLog::EndMessage;
2483                                         isOk = false;
2484                                 }
2485                         }
2486                 }
2487         }
2488
2489         return isOk;
2490 }
2491
2492 bool SSBOLayoutCase::checkLayoutIndices (const BufferLayout& layout) const
2493 {
2494         TestLog&        log                     = m_testCtx.getLog();
2495         int                     numVars         = (int)layout.bufferVars.size();
2496         int                     numBlocks       = (int)layout.blocks.size();
2497         bool            isOk            = true;
2498
2499         // Check variable block indices.
2500         for (int varNdx = 0; varNdx < numVars; varNdx++)
2501         {
2502                 const BufferVarLayoutEntry& bufVar = layout.bufferVars[varNdx];
2503
2504                 if (bufVar.blockNdx < 0 || !deInBounds32(bufVar.blockNdx, 0, numBlocks))
2505                 {
2506                         log << TestLog::Message << "Error: Invalid block index in buffer variable '" << bufVar.name << "'" << TestLog::EndMessage;
2507                         isOk = false;
2508                 }
2509         }
2510
2511         // Check active variables.
2512         for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
2513         {
2514                 const BlockLayoutEntry& block = layout.blocks[blockNdx];
2515
2516                 for (vector<int>::const_iterator varNdxIter = block.activeVarIndices.begin(); varNdxIter != block.activeVarIndices.end(); varNdxIter++)
2517                 {
2518                         if (!deInBounds32(*varNdxIter, 0, numVars))
2519                         {
2520                                 log << TestLog::Message << "Error: Invalid active variable index " << *varNdxIter << " in block '" << block.name << "'" << TestLog::EndMessage;
2521                                 isOk = false;
2522                         }
2523                 }
2524         }
2525
2526         return isOk;
2527 }
2528
2529 bool SSBOLayoutCase::checkLayoutBounds (const BufferLayout& layout) const
2530 {
2531         TestLog&        log                     = m_testCtx.getLog();
2532         const int       numVars         = (int)layout.bufferVars.size();
2533         bool            isOk            = true;
2534
2535         for (int varNdx = 0; varNdx < numVars; varNdx++)
2536         {
2537                 const BufferVarLayoutEntry& var = layout.bufferVars[varNdx];
2538
2539                 if (var.blockNdx < 0 || isUnsizedArray(var))
2540                         continue;
2541
2542                 const BlockLayoutEntry&         block                   = layout.blocks[var.blockNdx];
2543                 const bool                                      isMatrix                = glu::isDataTypeMatrix(var.type);
2544                 const int                                       numVecs                 = isMatrix ? (var.isRowMajor ? glu::getDataTypeMatrixNumRows(var.type) : glu::getDataTypeMatrixNumColumns(var.type)) : 1;
2545                 const int                                       numComps                = isMatrix ? (var.isRowMajor ? glu::getDataTypeMatrixNumColumns(var.type) : glu::getDataTypeMatrixNumRows(var.type)) : glu::getDataTypeScalarSize(var.type);
2546                 const int                                       numElements             = var.arraySize;
2547                 const int                                       topLevelSize    = var.topLevelArraySize;
2548                 const int                                       arrayStride             = var.arrayStride;
2549                 const int                                       topLevelStride  = var.topLevelArrayStride;
2550                 const int                                       compSize                = sizeof(deUint32);
2551                 const int                                       vecSize                 = numComps*compSize;
2552
2553                 int                                                     minOffset               = 0;
2554                 int                                                     maxOffset               = 0;
2555
2556                 // For negative strides.
2557                 minOffset       = de::min(minOffset, (numVecs-1)*var.matrixStride);
2558                 minOffset       = de::min(minOffset, (numElements-1)*arrayStride);
2559                 minOffset       = de::min(minOffset, (topLevelSize-1)*topLevelStride + (numElements-1)*arrayStride + (numVecs-1)*var.matrixStride);
2560
2561                 maxOffset       = de::max(maxOffset, vecSize);
2562                 maxOffset       = de::max(maxOffset, (numVecs-1)*var.matrixStride + vecSize);
2563                 maxOffset       = de::max(maxOffset, (numElements-1)*arrayStride + vecSize);
2564                 maxOffset       = de::max(maxOffset, (topLevelSize-1)*topLevelStride + (numElements-1)*arrayStride + vecSize);
2565                 maxOffset       = de::max(maxOffset, (topLevelSize-1)*topLevelStride + (numElements-1)*arrayStride + (numVecs-1)*var.matrixStride + vecSize);
2566
2567                 if (var.offset+minOffset < 0 || var.offset+maxOffset > block.size)
2568                 {
2569                         log << TestLog::Message << "Error: Variable '" << var.name << "' out of block bounds" << TestLog::EndMessage;
2570                         isOk = false;
2571                 }
2572         }
2573
2574         return isOk;
2575 }
2576
2577 bool SSBOLayoutCase::checkIndexQueries (deUint32 program, const BufferLayout& layout) const
2578 {
2579         tcu::TestLog&                           log                     = m_testCtx.getLog();
2580         const glw::Functions&           gl                      = m_renderCtx.getFunctions();
2581         bool                                            allOk           = true;
2582
2583         // \note Spec mandates that buffer blocks are assigned consecutive locations from 0.
2584         //               BlockLayoutEntries are stored in that order in UniformLayout.
2585         for (int blockNdx = 0; blockNdx < (int)layout.blocks.size(); blockNdx++)
2586         {
2587                 const BlockLayoutEntry&         block           = layout.blocks[blockNdx];
2588                 const int                                       queriedNdx      = gl.getProgramResourceIndex(program, GL_SHADER_STORAGE_BLOCK, block.name.c_str());
2589
2590                 if (queriedNdx != blockNdx)
2591                 {
2592                         log << TestLog::Message << "ERROR: glGetProgramResourceIndex(" << block.name << ") returned " << queriedNdx << ", expected " << blockNdx << "!" << TestLog::EndMessage;
2593                         allOk = false;
2594                 }
2595
2596                 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformBlockIndex()");
2597         }
2598
2599         return allOk;
2600 }
2601
2602 bool SSBOLayoutCase::execute (deUint32 program)
2603 {
2604         const glw::Functions&                           gl                              = m_renderCtx.getFunctions();
2605         const deUint32                                          numPassedLoc    = gl.getProgramResourceIndex(program, GL_UNIFORM, "ac_numPassed");
2606         const glu::InterfaceVariableInfo        acVarInfo               = numPassedLoc != GL_INVALID_INDEX ? glu::getProgramInterfaceVariableInfo(gl, program, GL_UNIFORM, numPassedLoc)
2607                                                                                                                                                                                    : glu::InterfaceVariableInfo();
2608         const glu::InterfaceBlockInfo           acBufferInfo    = acVarInfo.atomicCounterBufferIndex != GL_INVALID_INDEX ? glu::getProgramInterfaceBlockInfo(gl, program, GL_ATOMIC_COUNTER_BUFFER, acVarInfo.atomicCounterBufferIndex)
2609                                                                                                                                                                                                                                  : glu::InterfaceBlockInfo();
2610         const glu::Buffer                                       acBuffer                (m_renderCtx);
2611         bool                                                            isOk                    = true;
2612
2613         if (numPassedLoc == GL_INVALID_INDEX)
2614                 throw tcu::TestError("No location for ac_numPassed found");
2615
2616         if (acBufferInfo.index == GL_INVALID_INDEX)
2617                 throw tcu::TestError("ac_numPassed buffer index is GL_INVALID_INDEX");
2618
2619         if (acBufferInfo.dataSize == 0)
2620                 throw tcu::TestError("ac_numPassed buffer size = 0");
2621
2622         // Initialize atomic counter buffer.
2623         {
2624                 vector<deUint8> emptyData(acBufferInfo.dataSize, 0);
2625
2626                 gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, *acBuffer);
2627                 gl.bufferData(GL_ATOMIC_COUNTER_BUFFER, (glw::GLsizeiptr)emptyData.size(), &emptyData[0], GL_STATIC_READ);
2628                 gl.bindBufferBase(GL_ATOMIC_COUNTER_BUFFER, acBufferInfo.index, *acBuffer);
2629                 GLU_EXPECT_NO_ERROR(gl.getError(), "Setting up buffer for ac_numPassed failed");
2630         }
2631
2632         gl.useProgram(program);
2633         gl.dispatchCompute(1, 1, 1);
2634         GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute() failed");
2635
2636         // Read back ac_numPassed data.
2637         {
2638                 const void*     mapPtr          = gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, acBufferInfo.dataSize, GL_MAP_READ_BIT);
2639                 const int       refCount        = 1;
2640                 int                     resCount        = 0;
2641
2642                 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER) failed");
2643                 TCU_CHECK(mapPtr);
2644
2645                 resCount = *(const int*)((const deUint8*)mapPtr + acVarInfo.offset);
2646
2647                 gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
2648                 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER) failed");
2649
2650                 if (refCount != resCount)
2651                 {
2652                         m_testCtx.getLog() << TestLog::Message << "ERROR: ac_numPassed = " << resCount << ", expected " << refCount << TestLog::EndMessage;
2653                         isOk = false;
2654                 }
2655         }
2656
2657         GLU_EXPECT_NO_ERROR(gl.getError(), "Shader execution failed");
2658
2659         return isOk;
2660 }
2661
2662 } // gles31
2663 } // deqp