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