Merge "Merge "Merge "Try to determine renderable format in lifetime tests am: c0a5dc2...
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / ssbo / vktSSBOLayoutCase.cpp
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2015 The Khronos Group Inc.
6  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
7  * Copyright (c) 2016 The Android Open Source Project
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*!
22  * \file
23  * \brief SSBO layout case.
24  *//*--------------------------------------------------------------------*/
25
26 #include "vktSSBOLayoutCase.hpp"
27 #include "gluShaderProgram.hpp"
28 #include "gluContextInfo.hpp"
29 #include "gluShaderUtil.hpp"
30 #include "gluVarType.hpp"
31 #include "gluVarTypeUtil.hpp"
32 #include "tcuTestLog.hpp"
33 #include "deRandom.hpp"
34 #include "deStringUtil.hpp"
35 #include "deMemory.h"
36 #include "deString.h"
37 #include "deMath.h"
38 #include "deSharedPtr.hpp"
39
40 #include <algorithm>
41 #include <map>
42
43 #include "vkBuilderUtil.hpp"
44 #include "vkMemUtil.hpp"
45 #include "vkPrograms.hpp"
46 #include "vkQueryUtil.hpp"
47 #include "vkRef.hpp"
48 #include "vkRefUtil.hpp"
49 #include "vkTypeUtil.hpp"
50
51 namespace vkt
52 {
53 namespace ssbo
54 {
55
56 using tcu::TestLog;
57 using std::string;
58 using std::vector;
59 using std::map;
60 using glu::VarType;
61 using glu::StructType;
62 using glu::StructMember;
63
64 struct LayoutFlagsFmt
65 {
66         deUint32 flags;
67         LayoutFlagsFmt (deUint32 flags_) : flags(flags_) {}
68 };
69
70 std::ostream& operator<< (std::ostream& str, const LayoutFlagsFmt& fmt)
71 {
72         static const struct
73         {
74                 deUint32        bit;
75                 const char*     token;
76         } bitDesc[] =
77         {
78                 { LAYOUT_STD140,                "std140"                },
79                 { LAYOUT_STD430,                "std430"                },
80                 { LAYOUT_ROW_MAJOR,             "row_major"             },
81                 { LAYOUT_COLUMN_MAJOR,  "column_major"  }
82         };
83
84         deUint32 remBits = fmt.flags;
85         for (int descNdx = 0; descNdx < DE_LENGTH_OF_ARRAY(bitDesc); descNdx++)
86         {
87                 if (remBits & bitDesc[descNdx].bit)
88                 {
89                         if (remBits != fmt.flags)
90                                 str << ", ";
91                         str << bitDesc[descNdx].token;
92                         remBits &= ~bitDesc[descNdx].bit;
93                 }
94         }
95         DE_ASSERT(remBits == 0);
96         return str;
97 }
98
99 // BufferVar implementation.
100
101 BufferVar::BufferVar (const char* name, const VarType& type, deUint32 flags)
102         : m_name        (name)
103         , m_type        (type)
104         , m_flags       (flags)
105 {
106 }
107
108 // BufferBlock implementation.
109
110 BufferBlock::BufferBlock (const char* blockName)
111         : m_blockName   (blockName)
112         , m_arraySize   (-1)
113         , m_flags               (0)
114 {
115         setArraySize(0);
116 }
117
118 void BufferBlock::setArraySize (int arraySize)
119 {
120         DE_ASSERT(arraySize >= 0);
121         m_lastUnsizedArraySizes.resize(arraySize == 0 ? 1 : arraySize, 0);
122         m_arraySize = arraySize;
123 }
124
125 std::ostream& operator<< (std::ostream& stream, const BlockLayoutEntry& entry)
126 {
127         stream << entry.name << " { name = " << entry.name
128                    << ", size = " << entry.size
129                    << ", activeVarIndices = [";
130
131         for (vector<int>::const_iterator i = entry.activeVarIndices.begin(); i != entry.activeVarIndices.end(); i++)
132         {
133                 if (i != entry.activeVarIndices.begin())
134                         stream << ", ";
135                 stream << *i;
136         }
137
138         stream << "] }";
139         return stream;
140 }
141
142 static bool isUnsizedArray (const BufferVarLayoutEntry& entry)
143 {
144         DE_ASSERT(entry.arraySize != 0 || entry.topLevelArraySize != 0);
145         return entry.arraySize == 0 || entry.topLevelArraySize == 0;
146 }
147
148 std::ostream& operator<< (std::ostream& stream, const BufferVarLayoutEntry& entry)
149 {
150         stream << entry.name << " { type = " << glu::getDataTypeName(entry.type)
151                    << ", blockNdx = " << entry.blockNdx
152                    << ", offset = " << entry.offset
153                    << ", arraySize = " << entry.arraySize
154                    << ", arrayStride = " << entry.arrayStride
155                    << ", matrixStride = " << entry.matrixStride
156                    << ", topLevelArraySize = " << entry.topLevelArraySize
157                    << ", topLevelArrayStride = " << entry.topLevelArrayStride
158                    << ", isRowMajor = " << (entry.isRowMajor ? "true" : "false")
159                    << " }";
160         return stream;
161 }
162
163 // \todo [2012-01-24 pyry] Speed up lookups using hash.
164
165 int BufferLayout::getVariableIndex (const string& name) const
166 {
167         for (int ndx = 0; ndx < (int)bufferVars.size(); ndx++)
168         {
169                 if (bufferVars[ndx].name == name)
170                         return ndx;
171         }
172         return -1;
173 }
174
175 int BufferLayout::getBlockIndex (const string& name) const
176 {
177         for (int ndx = 0; ndx < (int)blocks.size(); ndx++)
178         {
179                 if (blocks[ndx].name == name)
180                         return ndx;
181         }
182         return -1;
183 }
184
185 // ShaderInterface implementation.
186
187 ShaderInterface::ShaderInterface (void)
188 {
189 }
190
191 ShaderInterface::~ShaderInterface (void)
192 {
193         for (std::vector<StructType*>::iterator i = m_structs.begin(); i != m_structs.end(); i++)
194                 delete *i;
195
196         for (std::vector<BufferBlock*>::iterator i = m_bufferBlocks.begin(); i != m_bufferBlocks.end(); i++)
197                 delete *i;
198 }
199
200 StructType& ShaderInterface::allocStruct (const char* name)
201 {
202         m_structs.reserve(m_structs.size()+1);
203         m_structs.push_back(new StructType(name));
204         return *m_structs.back();
205 }
206
207 struct StructNameEquals
208 {
209         std::string name;
210
211         StructNameEquals (const char* name_) : name(name_) {}
212
213         bool operator() (const StructType* type) const
214         {
215                 return type->getTypeName() && name == type->getTypeName();
216         }
217 };
218
219 const StructType* ShaderInterface::findStruct (const char* name) const
220 {
221         std::vector<StructType*>::const_iterator pos = std::find_if(m_structs.begin(), m_structs.end(), StructNameEquals(name));
222         return pos != m_structs.end() ? *pos : DE_NULL;
223 }
224
225 void ShaderInterface::getNamedStructs (std::vector<const StructType*>& structs) const
226 {
227         for (std::vector<StructType*>::const_iterator i = m_structs.begin(); i != m_structs.end(); i++)
228         {
229                 if ((*i)->getTypeName() != DE_NULL)
230                         structs.push_back(*i);
231         }
232 }
233
234 BufferBlock& ShaderInterface::allocBlock (const char* name)
235 {
236         m_bufferBlocks.reserve(m_bufferBlocks.size()+1);
237         m_bufferBlocks.push_back(new BufferBlock(name));
238         return *m_bufferBlocks.back();
239 }
240
241 namespace // Utilities
242 {
243 // Layout computation.
244
245 int getDataTypeByteSize (glu::DataType type)
246 {
247         return glu::getDataTypeScalarSize(type)*(int)sizeof(deUint32);
248 }
249
250 int getDataTypeByteAlignment (glu::DataType type)
251 {
252         switch (type)
253         {
254                 case glu::TYPE_FLOAT:
255                 case glu::TYPE_INT:
256                 case glu::TYPE_UINT:
257                 case glu::TYPE_BOOL:            return 1*(int)sizeof(deUint32);
258
259                 case glu::TYPE_FLOAT_VEC2:
260                 case glu::TYPE_INT_VEC2:
261                 case glu::TYPE_UINT_VEC2:
262                 case glu::TYPE_BOOL_VEC2:       return 2*(int)sizeof(deUint32);
263
264                 case glu::TYPE_FLOAT_VEC3:
265                 case glu::TYPE_INT_VEC3:
266                 case glu::TYPE_UINT_VEC3:
267                 case glu::TYPE_BOOL_VEC3:       // Fall-through to vec4
268
269                 case glu::TYPE_FLOAT_VEC4:
270                 case glu::TYPE_INT_VEC4:
271                 case glu::TYPE_UINT_VEC4:
272                 case glu::TYPE_BOOL_VEC4:       return 4*(int)sizeof(deUint32);
273
274                 default:
275                         DE_ASSERT(false);
276                         return 0;
277         }
278 }
279
280 static inline int deRoundUp32 (int a, int b)
281 {
282         int d = a/b;
283         return d*b == a ? a : (d+1)*b;
284 }
285
286 int computeStd140BaseAlignment (const VarType& type, deUint32 layoutFlags)
287 {
288         const int vec4Alignment = (int)sizeof(deUint32)*4;
289
290         if (type.isBasicType())
291         {
292                 glu::DataType basicType = type.getBasicType();
293
294                 if (glu::isDataTypeMatrix(basicType))
295                 {
296                         const bool      isRowMajor      = !!(layoutFlags & LAYOUT_ROW_MAJOR);
297                         const int       vecSize         = isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType)
298                                                                                                  : glu::getDataTypeMatrixNumRows(basicType);
299                         const int       vecAlign        = deAlign32(getDataTypeByteAlignment(glu::getDataTypeFloatVec(vecSize)), vec4Alignment);
300
301                         return vecAlign;
302                 }
303                 else
304                         return getDataTypeByteAlignment(basicType);
305         }
306         else if (type.isArrayType())
307         {
308                 int elemAlignment = computeStd140BaseAlignment(type.getElementType(), layoutFlags);
309
310                 // Round up to alignment of vec4
311                 return deAlign32(elemAlignment, vec4Alignment);
312         }
313         else
314         {
315                 DE_ASSERT(type.isStructType());
316
317                 int maxBaseAlignment = 0;
318
319                 for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++)
320                         maxBaseAlignment = de::max(maxBaseAlignment, computeStd140BaseAlignment(memberIter->getType(), layoutFlags));
321
322                 return deAlign32(maxBaseAlignment, vec4Alignment);
323         }
324 }
325
326 int computeStd430BaseAlignment (const VarType& type, deUint32 layoutFlags)
327 {
328         // Otherwise identical to std140 except that alignment of structures and arrays
329         // are not rounded up to alignment of vec4.
330
331         if (type.isBasicType())
332         {
333                 glu::DataType basicType = type.getBasicType();
334
335                 if (glu::isDataTypeMatrix(basicType))
336                 {
337                         const bool      isRowMajor      = !!(layoutFlags & LAYOUT_ROW_MAJOR);
338                         const int       vecSize         = isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType)
339                                                                                                  : glu::getDataTypeMatrixNumRows(basicType);
340                         const int       vecAlign        = getDataTypeByteAlignment(glu::getDataTypeFloatVec(vecSize));
341
342                         return vecAlign;
343                 }
344                 else
345                         return getDataTypeByteAlignment(basicType);
346         }
347         else if (type.isArrayType())
348         {
349                 return computeStd430BaseAlignment(type.getElementType(), layoutFlags);
350         }
351         else
352         {
353                 DE_ASSERT(type.isStructType());
354
355                 int maxBaseAlignment = 0;
356
357                 for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++)
358                         maxBaseAlignment = de::max(maxBaseAlignment, computeStd430BaseAlignment(memberIter->getType(), layoutFlags));
359
360                 return maxBaseAlignment;
361         }
362 }
363
364 inline deUint32 mergeLayoutFlags (deUint32 prevFlags, deUint32 newFlags)
365 {
366         const deUint32  packingMask             = LAYOUT_STD430|LAYOUT_STD140;
367         const deUint32  matrixMask              = LAYOUT_ROW_MAJOR|LAYOUT_COLUMN_MAJOR;
368
369         deUint32 mergedFlags = 0;
370
371         mergedFlags |= ((newFlags & packingMask)        ? newFlags : prevFlags) & packingMask;
372         mergedFlags |= ((newFlags & matrixMask)         ? newFlags : prevFlags) & matrixMask;
373
374         return mergedFlags;
375 }
376
377 //! Appends all child elements to layout, returns value that should be appended to offset.
378 int computeReferenceLayout (
379         BufferLayout&           layout,
380         int                                     curBlockNdx,
381         int                                     baseOffset,
382         const std::string&      curPrefix,
383         const VarType&          type,
384         deUint32                        layoutFlags)
385 {
386         // Reference layout uses std430 rules by default. std140 rules are
387         // choosen only for blocks that have std140 layout.
388         const bool      isStd140                        = (layoutFlags & LAYOUT_STD140) != 0;
389         const int       baseAlignment           = isStd140 ? computeStd140BaseAlignment(type, layoutFlags)
390                                                                                            : computeStd430BaseAlignment(type, layoutFlags);
391         int                     curOffset                       = deAlign32(baseOffset, baseAlignment);
392         const int       topLevelArraySize       = 1; // Default values
393         const int       topLevelArrayStride     = 0;
394
395         if (type.isBasicType())
396         {
397                 const glu::DataType             basicType       = type.getBasicType();
398                 BufferVarLayoutEntry    entry;
399
400                 entry.name                                      = curPrefix;
401                 entry.type                                      = basicType;
402                 entry.arraySize                         = 1;
403                 entry.arrayStride                       = 0;
404                 entry.matrixStride                      = 0;
405                 entry.topLevelArraySize         = topLevelArraySize;
406                 entry.topLevelArrayStride       = topLevelArrayStride;
407                 entry.blockNdx                          = curBlockNdx;
408
409                 if (glu::isDataTypeMatrix(basicType))
410                 {
411                         // Array of vectors as specified in rules 5 & 7.
412                         const bool      isRowMajor                      = !!(layoutFlags & LAYOUT_ROW_MAJOR);
413                         const int       numVecs                         = isRowMajor ? glu::getDataTypeMatrixNumRows(basicType)
414                                                                                                                  : glu::getDataTypeMatrixNumColumns(basicType);
415
416                         entry.offset            = curOffset;
417                         entry.matrixStride      = baseAlignment;
418                         entry.isRowMajor        = isRowMajor;
419
420                         curOffset += numVecs*baseAlignment;
421                 }
422                 else
423                 {
424                         // Scalar or vector.
425                         entry.offset = curOffset;
426
427                         curOffset += getDataTypeByteSize(basicType);
428                 }
429
430                 layout.bufferVars.push_back(entry);
431         }
432         else if (type.isArrayType())
433         {
434                 const VarType&  elemType        = type.getElementType();
435
436                 if (elemType.isBasicType() && !glu::isDataTypeMatrix(elemType.getBasicType()))
437                 {
438                         // Array of scalars or vectors.
439                         const glu::DataType             elemBasicType   = elemType.getBasicType();
440                         const int                               stride                  = baseAlignment;
441                         BufferVarLayoutEntry    entry;
442
443                         entry.name                                      = curPrefix + "[0]"; // Array variables are always postfixed with [0]
444                         entry.type                                      = elemBasicType;
445                         entry.blockNdx                          = curBlockNdx;
446                         entry.offset                            = curOffset;
447                         entry.arraySize                         = type.getArraySize();
448                         entry.arrayStride                       = stride;
449                         entry.matrixStride                      = 0;
450                         entry.topLevelArraySize         = topLevelArraySize;
451                         entry.topLevelArrayStride       = topLevelArrayStride;
452
453                         curOffset += stride*type.getArraySize();
454
455                         layout.bufferVars.push_back(entry);
456                 }
457                 else if (elemType.isBasicType() && glu::isDataTypeMatrix(elemType.getBasicType()))
458                 {
459                         // Array of matrices.
460                         const glu::DataType                     elemBasicType   = elemType.getBasicType();
461                         const bool                                      isRowMajor              = !!(layoutFlags & LAYOUT_ROW_MAJOR);
462                         const int                                       numVecs                 = isRowMajor ? glu::getDataTypeMatrixNumRows(elemBasicType)
463                                                                                                                                          : glu::getDataTypeMatrixNumColumns(elemBasicType);
464                         const int                                       vecStride               = baseAlignment;
465                         BufferVarLayoutEntry            entry;
466
467                         entry.name                                      = curPrefix + "[0]"; // Array variables are always postfixed with [0]
468                         entry.type                                      = elemBasicType;
469                         entry.blockNdx                          = curBlockNdx;
470                         entry.offset                            = curOffset;
471                         entry.arraySize                         = type.getArraySize();
472                         entry.arrayStride                       = vecStride*numVecs;
473                         entry.matrixStride                      = vecStride;
474                         entry.isRowMajor                        = isRowMajor;
475                         entry.topLevelArraySize         = topLevelArraySize;
476                         entry.topLevelArrayStride       = topLevelArrayStride;
477
478                         curOffset += numVecs*vecStride*type.getArraySize();
479
480                         layout.bufferVars.push_back(entry);
481                 }
482                 else
483                 {
484                         DE_ASSERT(elemType.isStructType() || elemType.isArrayType());
485
486                         for (int elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++)
487                                 curOffset += computeReferenceLayout(layout, curBlockNdx, curOffset, curPrefix + "[" + de::toString(elemNdx) + "]", type.getElementType(), layoutFlags);
488                 }
489         }
490         else
491         {
492                 DE_ASSERT(type.isStructType());
493
494                 for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++)
495                         curOffset += computeReferenceLayout(layout, curBlockNdx, curOffset, curPrefix + "." + memberIter->getName(), memberIter->getType(), layoutFlags);
496
497                 curOffset = deAlign32(curOffset, baseAlignment);
498         }
499
500         return curOffset-baseOffset;
501 }
502
503 //! Appends all child elements to layout, returns offset increment.
504 int computeReferenceLayout (BufferLayout& layout, int curBlockNdx, const std::string& blockPrefix, int baseOffset, const BufferVar& bufVar, deUint32 blockLayoutFlags)
505 {
506         const VarType&  varType                 = bufVar.getType();
507         const deUint32  combinedFlags   = mergeLayoutFlags(blockLayoutFlags, bufVar.getFlags());
508
509         if (varType.isArrayType())
510         {
511                 // Top-level arrays need special care.
512                 const int               topLevelArraySize       = varType.getArraySize() == VarType::UNSIZED_ARRAY ? 0 : varType.getArraySize();
513                 const string    prefix                          = blockPrefix + bufVar.getName() + "[0]";
514                 const bool              isStd140                        = (blockLayoutFlags & LAYOUT_STD140) != 0;
515                 const int               vec4Align                       = (int)sizeof(deUint32)*4;
516                 const int               baseAlignment           = isStd140 ? computeStd140BaseAlignment(varType, combinedFlags)
517                                                                                                            : computeStd430BaseAlignment(varType, combinedFlags);
518                 int                             curOffset                       = deAlign32(baseOffset, baseAlignment);
519                 const VarType&  elemType                        = varType.getElementType();
520
521                 if (elemType.isBasicType() && !glu::isDataTypeMatrix(elemType.getBasicType()))
522                 {
523                         // Array of scalars or vectors.
524                         const glu::DataType             elemBasicType   = elemType.getBasicType();
525                         const int                               elemBaseAlign   = getDataTypeByteAlignment(elemBasicType);
526                         const int                               stride                  = isStd140 ? deAlign32(elemBaseAlign, vec4Align) : elemBaseAlign;
527                         BufferVarLayoutEntry    entry;
528
529                         entry.name                                      = prefix;
530                         entry.topLevelArraySize         = 1;
531                         entry.topLevelArrayStride       = 0;
532                         entry.type                                      = elemBasicType;
533                         entry.blockNdx                          = curBlockNdx;
534                         entry.offset                            = curOffset;
535                         entry.arraySize                         = topLevelArraySize;
536                         entry.arrayStride                       = stride;
537                         entry.matrixStride                      = 0;
538
539                         layout.bufferVars.push_back(entry);
540
541                         curOffset += stride*topLevelArraySize;
542                 }
543                 else if (elemType.isBasicType() && glu::isDataTypeMatrix(elemType.getBasicType()))
544                 {
545                         // Array of matrices.
546                         const glu::DataType             elemBasicType   = elemType.getBasicType();
547                         const bool                              isRowMajor              = !!(combinedFlags & LAYOUT_ROW_MAJOR);
548                         const int                               vecSize                 = isRowMajor ? glu::getDataTypeMatrixNumColumns(elemBasicType)
549                                                                                                                                  : glu::getDataTypeMatrixNumRows(elemBasicType);
550                         const int                               numVecs                 = isRowMajor ? glu::getDataTypeMatrixNumRows(elemBasicType)
551                                                                                                                                  : glu::getDataTypeMatrixNumColumns(elemBasicType);
552                         const glu::DataType             vecType                 = glu::getDataTypeFloatVec(vecSize);
553                         const int                               vecBaseAlign    = getDataTypeByteAlignment(vecType);
554                         const int                               stride                  = isStd140 ? deAlign32(vecBaseAlign, vec4Align) : vecBaseAlign;
555                         BufferVarLayoutEntry    entry;
556
557                         entry.name                                      = prefix;
558                         entry.topLevelArraySize         = 1;
559                         entry.topLevelArrayStride       = 0;
560                         entry.type                                      = elemBasicType;
561                         entry.blockNdx                          = curBlockNdx;
562                         entry.offset                            = curOffset;
563                         entry.arraySize                         = topLevelArraySize;
564                         entry.arrayStride                       = stride*numVecs;
565                         entry.matrixStride                      = stride;
566                         entry.isRowMajor                        = isRowMajor;
567
568                         layout.bufferVars.push_back(entry);
569
570                         curOffset += stride*numVecs*topLevelArraySize;
571                 }
572                 else
573                 {
574                         DE_ASSERT(elemType.isStructType() || elemType.isArrayType());
575
576                         // Struct base alignment is not added multiple times as curOffset supplied to computeReferenceLayout
577                         // was already aligned correctly. Thus computeReferenceLayout should not add any extra padding
578                         // before struct. Padding after struct will be added as it should.
579                         //
580                         // Stride could be computed prior to creating child elements, but it would essentially require running
581                         // the layout computation twice. Instead we fix stride to child elements afterwards.
582
583                         const int       firstChildNdx   = (int)layout.bufferVars.size();
584                         const int       stride                  = computeReferenceLayout(layout, curBlockNdx, curOffset, prefix, varType.getElementType(), combinedFlags);
585
586                         for (int childNdx = firstChildNdx; childNdx < (int)layout.bufferVars.size(); childNdx++)
587                         {
588                                 layout.bufferVars[childNdx].topLevelArraySize   = topLevelArraySize;
589                                 layout.bufferVars[childNdx].topLevelArrayStride = stride;
590                         }
591
592                         curOffset += stride*topLevelArraySize;
593                 }
594
595                 return curOffset-baseOffset;
596         }
597         else
598                 return computeReferenceLayout(layout, curBlockNdx, baseOffset, blockPrefix + bufVar.getName(), varType, combinedFlags);
599 }
600
601 void computeReferenceLayout (BufferLayout& layout, const ShaderInterface& interface)
602 {
603         int numBlocks = interface.getNumBlocks();
604
605         for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
606         {
607                 const BufferBlock&      block                   = interface.getBlock(blockNdx);
608                 bool                            hasInstanceName = block.getInstanceName() != DE_NULL;
609                 std::string                     blockPrefix             = hasInstanceName ? (std::string(block.getBlockName()) + ".") : std::string("");
610                 int                                     curOffset               = 0;
611                 int                                     activeBlockNdx  = (int)layout.blocks.size();
612                 int                                     firstVarNdx             = (int)layout.bufferVars.size();
613
614                 for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++)
615                 {
616                         const BufferVar& bufVar = *varIter;
617                         curOffset += computeReferenceLayout(layout, activeBlockNdx,  blockPrefix, curOffset, bufVar, block.getFlags());
618                 }
619
620                 int     varIndicesEnd   = (int)layout.bufferVars.size();
621                 int     blockSize               = curOffset;
622                 int     numInstances    = block.isArray() ? block.getArraySize() : 1;
623
624                 // Create block layout entries for each instance.
625                 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
626                 {
627                         // Allocate entry for instance.
628                         layout.blocks.push_back(BlockLayoutEntry());
629                         BlockLayoutEntry& blockEntry = layout.blocks.back();
630
631                         blockEntry.name = block.getBlockName();
632                         blockEntry.size = blockSize;
633
634                         // Compute active variable set for block.
635                         for (int varNdx = firstVarNdx; varNdx < varIndicesEnd; varNdx++)
636                                 blockEntry.activeVarIndices.push_back(varNdx);
637
638                         if (block.isArray())
639                                 blockEntry.name += "[" + de::toString(instanceNdx) + "]";
640                 }
641         }
642 }
643
644 // Value generator.
645
646 void generateValue (const BufferVarLayoutEntry& entry, int unsizedArraySize, void* basePtr, de::Random& rnd)
647 {
648         const glu::DataType     scalarType              = glu::getDataTypeScalarType(entry.type);
649         const int                       scalarSize              = glu::getDataTypeScalarSize(entry.type);
650         const int                       arraySize               = entry.arraySize == 0 ? unsizedArraySize : entry.arraySize;
651         const int                       arrayStride             = entry.arrayStride;
652         const int                       topLevelSize    = entry.topLevelArraySize == 0 ? unsizedArraySize : entry.topLevelArraySize;
653         const int                       topLevelStride  = entry.topLevelArrayStride;
654         const bool                      isMatrix                = glu::isDataTypeMatrix(entry.type);
655         const int                       numVecs                 = isMatrix ? (entry.isRowMajor ? glu::getDataTypeMatrixNumRows(entry.type) : glu::getDataTypeMatrixNumColumns(entry.type)) : 1;
656         const int                       vecSize                 = scalarSize / numVecs;
657         const int                       compSize                = sizeof(deUint32);
658
659         DE_ASSERT(scalarSize%numVecs == 0);
660         DE_ASSERT(topLevelSize >= 0);
661         DE_ASSERT(arraySize >= 0);
662
663         for (int topElemNdx = 0; topElemNdx < topLevelSize; topElemNdx++)
664         {
665                 deUint8* const topElemPtr = (deUint8*)basePtr + entry.offset + topElemNdx*topLevelStride;
666
667                 for (int elemNdx = 0; elemNdx < arraySize; elemNdx++)
668                 {
669                         deUint8* const elemPtr = topElemPtr + elemNdx*arrayStride;
670
671                         for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
672                         {
673                                 deUint8* const vecPtr = elemPtr + (isMatrix ? vecNdx*entry.matrixStride : 0);
674
675                                 for (int compNdx = 0; compNdx < vecSize; compNdx++)
676                                 {
677                                         deUint8* const compPtr = vecPtr + compSize*compNdx;
678
679                                         switch (scalarType)
680                                         {
681                                                 case glu::TYPE_FLOAT:   *((float*)compPtr)              = (float)rnd.getInt(-9, 9);                                             break;
682                                                 case glu::TYPE_INT:             *((int*)compPtr)                = rnd.getInt(-9, 9);                                                    break;
683                                                 case glu::TYPE_UINT:    *((deUint32*)compPtr)   = (deUint32)rnd.getInt(0, 9);                                   break;
684                                                 // \note Random bit pattern is used for true values. Spec states that all non-zero values are
685                                                 //       interpreted as true but some implementations fail this.
686                                                 case glu::TYPE_BOOL:    *((deUint32*)compPtr)   = rnd.getBool() ? rnd.getUint32()|1u : 0u;              break;
687                                                 default:
688                                                         DE_ASSERT(false);
689                                         }
690                                 }
691                         }
692                 }
693         }
694 }
695
696 void generateValues (const BufferLayout& layout, const vector<BlockDataPtr>& blockPointers, deUint32 seed)
697 {
698         de::Random      rnd                     (seed);
699         const int       numBlocks       = (int)layout.blocks.size();
700
701         DE_ASSERT(numBlocks == (int)blockPointers.size());
702
703         for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
704         {
705                 const BlockLayoutEntry& blockLayout     = layout.blocks[blockNdx];
706                 const BlockDataPtr&             blockPtr        = blockPointers[blockNdx];
707                 const int                               numEntries      = (int)layout.blocks[blockNdx].activeVarIndices.size();
708
709                 for (int entryNdx = 0; entryNdx < numEntries; entryNdx++)
710                 {
711                         const int                                       varNdx          = blockLayout.activeVarIndices[entryNdx];
712                         const BufferVarLayoutEntry&     varEntry        = layout.bufferVars[varNdx];
713
714                         generateValue(varEntry, blockPtr.lastUnsizedArraySize, blockPtr.ptr, rnd);
715                 }
716         }
717 }
718
719 // Shader generator.
720
721 const char* getCompareFuncForType (glu::DataType type)
722 {
723         switch (type)
724         {
725                 case glu::TYPE_FLOAT:                   return "bool compare_float    (highp float a, highp float b)  { return abs(a - b) < 0.05; }\n";
726                 case glu::TYPE_FLOAT_VEC2:              return "bool compare_vec2     (highp vec2 a, highp vec2 b)    { return compare_float(a.x, b.x)&&compare_float(a.y, b.y); }\n";
727                 case glu::TYPE_FLOAT_VEC3:              return "bool compare_vec3     (highp vec3 a, highp vec3 b)    { return compare_float(a.x, b.x)&&compare_float(a.y, b.y)&&compare_float(a.z, b.z); }\n";
728                 case glu::TYPE_FLOAT_VEC4:              return "bool compare_vec4     (highp vec4 a, highp vec4 b)    { return compare_float(a.x, b.x)&&compare_float(a.y, b.y)&&compare_float(a.z, b.z)&&compare_float(a.w, b.w); }\n";
729                 case glu::TYPE_FLOAT_MAT2:              return "bool compare_mat2     (highp mat2 a, highp mat2 b)    { return compare_vec2(a[0], b[0])&&compare_vec2(a[1], b[1]); }\n";
730                 case glu::TYPE_FLOAT_MAT2X3:    return "bool compare_mat2x3   (highp mat2x3 a, highp mat2x3 b){ return compare_vec3(a[0], b[0])&&compare_vec3(a[1], b[1]); }\n";
731                 case glu::TYPE_FLOAT_MAT2X4:    return "bool compare_mat2x4   (highp mat2x4 a, highp mat2x4 b){ return compare_vec4(a[0], b[0])&&compare_vec4(a[1], b[1]); }\n";
732                 case glu::TYPE_FLOAT_MAT3X2:    return "bool compare_mat3x2   (highp mat3x2 a, highp mat3x2 b){ return compare_vec2(a[0], b[0])&&compare_vec2(a[1], b[1])&&compare_vec2(a[2], b[2]); }\n";
733                 case glu::TYPE_FLOAT_MAT3:              return "bool compare_mat3     (highp mat3 a, highp mat3 b)    { return compare_vec3(a[0], b[0])&&compare_vec3(a[1], b[1])&&compare_vec3(a[2], b[2]); }\n";
734                 case glu::TYPE_FLOAT_MAT3X4:    return "bool compare_mat3x4   (highp mat3x4 a, highp mat3x4 b){ return compare_vec4(a[0], b[0])&&compare_vec4(a[1], b[1])&&compare_vec4(a[2], b[2]); }\n";
735                 case glu::TYPE_FLOAT_MAT4X2:    return "bool compare_mat4x2   (highp mat4x2 a, highp mat4x2 b){ return compare_vec2(a[0], b[0])&&compare_vec2(a[1], b[1])&&compare_vec2(a[2], b[2])&&compare_vec2(a[3], b[3]); }\n";
736                 case glu::TYPE_FLOAT_MAT4X3:    return "bool compare_mat4x3   (highp mat4x3 a, highp mat4x3 b){ return compare_vec3(a[0], b[0])&&compare_vec3(a[1], b[1])&&compare_vec3(a[2], b[2])&&compare_vec3(a[3], b[3]); }\n";
737                 case glu::TYPE_FLOAT_MAT4:              return "bool compare_mat4     (highp mat4 a, highp mat4 b)    { return compare_vec4(a[0], b[0])&&compare_vec4(a[1], b[1])&&compare_vec4(a[2], b[2])&&compare_vec4(a[3], b[3]); }\n";
738                 case glu::TYPE_INT:                             return "bool compare_int      (highp int a, highp int b)      { return a == b; }\n";
739                 case glu::TYPE_INT_VEC2:                return "bool compare_ivec2    (highp ivec2 a, highp ivec2 b)  { return a == b; }\n";
740                 case glu::TYPE_INT_VEC3:                return "bool compare_ivec3    (highp ivec3 a, highp ivec3 b)  { return a == b; }\n";
741                 case glu::TYPE_INT_VEC4:                return "bool compare_ivec4    (highp ivec4 a, highp ivec4 b)  { return a == b; }\n";
742                 case glu::TYPE_UINT:                    return "bool compare_uint     (highp uint a, highp uint b)    { return a == b; }\n";
743                 case glu::TYPE_UINT_VEC2:               return "bool compare_uvec2    (highp uvec2 a, highp uvec2 b)  { return a == b; }\n";
744                 case glu::TYPE_UINT_VEC3:               return "bool compare_uvec3    (highp uvec3 a, highp uvec3 b)  { return a == b; }\n";
745                 case glu::TYPE_UINT_VEC4:               return "bool compare_uvec4    (highp uvec4 a, highp uvec4 b)  { return a == b; }\n";
746                 case glu::TYPE_BOOL:                    return "bool compare_bool     (bool a, bool b)                { return a == b; }\n";
747                 case glu::TYPE_BOOL_VEC2:               return "bool compare_bvec2    (bvec2 a, bvec2 b)              { return a == b; }\n";
748                 case glu::TYPE_BOOL_VEC3:               return "bool compare_bvec3    (bvec3 a, bvec3 b)              { return a == b; }\n";
749                 case glu::TYPE_BOOL_VEC4:               return "bool compare_bvec4    (bvec4 a, bvec4 b)              { return a == b; }\n";
750                 default:
751                         DE_ASSERT(false);
752                         return DE_NULL;
753         }
754 }
755
756 void getCompareDependencies (std::set<glu::DataType>& compareFuncs, glu::DataType basicType)
757 {
758         switch (basicType)
759         {
760                 case glu::TYPE_FLOAT_VEC2:
761                 case glu::TYPE_FLOAT_VEC3:
762                 case glu::TYPE_FLOAT_VEC4:
763                         compareFuncs.insert(glu::TYPE_FLOAT);
764                         compareFuncs.insert(basicType);
765                         break;
766
767                 case glu::TYPE_FLOAT_MAT2:
768                 case glu::TYPE_FLOAT_MAT2X3:
769                 case glu::TYPE_FLOAT_MAT2X4:
770                 case glu::TYPE_FLOAT_MAT3X2:
771                 case glu::TYPE_FLOAT_MAT3:
772                 case glu::TYPE_FLOAT_MAT3X4:
773                 case glu::TYPE_FLOAT_MAT4X2:
774                 case glu::TYPE_FLOAT_MAT4X3:
775                 case glu::TYPE_FLOAT_MAT4:
776                         compareFuncs.insert(glu::TYPE_FLOAT);
777                         compareFuncs.insert(glu::getDataTypeFloatVec(glu::getDataTypeMatrixNumRows(basicType)));
778                         compareFuncs.insert(basicType);
779                         break;
780
781                 default:
782                         compareFuncs.insert(basicType);
783                         break;
784         }
785 }
786
787 void collectUniqueBasicTypes (std::set<glu::DataType>& basicTypes, const VarType& type)
788 {
789         if (type.isStructType())
790         {
791                 for (StructType::ConstIterator iter = type.getStructPtr()->begin(); iter != type.getStructPtr()->end(); ++iter)
792                         collectUniqueBasicTypes(basicTypes, iter->getType());
793         }
794         else if (type.isArrayType())
795                 collectUniqueBasicTypes(basicTypes, type.getElementType());
796         else
797         {
798                 DE_ASSERT(type.isBasicType());
799                 basicTypes.insert(type.getBasicType());
800         }
801 }
802
803 void collectUniqueBasicTypes (std::set<glu::DataType>& basicTypes, const BufferBlock& bufferBlock)
804 {
805         for (BufferBlock::const_iterator iter = bufferBlock.begin(); iter != bufferBlock.end(); ++iter)
806                 collectUniqueBasicTypes(basicTypes, iter->getType());
807 }
808
809 void collectUniqueBasicTypes (std::set<glu::DataType>& basicTypes, const ShaderInterface& interface)
810 {
811         for (int ndx = 0; ndx < interface.getNumBlocks(); ++ndx)
812                 collectUniqueBasicTypes(basicTypes, interface.getBlock(ndx));
813 }
814
815 void generateCompareFuncs (std::ostream& str, const ShaderInterface& interface)
816 {
817         std::set<glu::DataType> types;
818         std::set<glu::DataType> compareFuncs;
819
820         // Collect unique basic types
821         collectUniqueBasicTypes(types, interface);
822
823         // Set of compare functions required
824         for (std::set<glu::DataType>::const_iterator iter = types.begin(); iter != types.end(); ++iter)
825         {
826                 getCompareDependencies(compareFuncs, *iter);
827         }
828
829         for (int type = 0; type < glu::TYPE_LAST; ++type)
830         {
831                 if (compareFuncs.find(glu::DataType(type)) != compareFuncs.end())
832                         str << getCompareFuncForType(glu::DataType(type));
833         }
834 }
835
836 struct Indent
837 {
838         int level;
839         Indent (int level_) : level(level_) {}
840 };
841
842 std::ostream& operator<< (std::ostream& str, const Indent& indent)
843 {
844         for (int i = 0; i < indent.level; i++)
845                 str << "\t";
846         return str;
847 }
848
849 void generateDeclaration (std::ostream& src, const BufferVar& bufferVar, int indentLevel)
850 {
851         // \todo [pyry] Qualifiers
852
853         if ((bufferVar.getFlags() & LAYOUT_MASK) != 0)
854                 src << "layout(" << LayoutFlagsFmt(bufferVar.getFlags() & LAYOUT_MASK) << ") ";
855
856         src << glu::declare(bufferVar.getType(), bufferVar.getName(), indentLevel);
857 }
858
859 void generateDeclaration (std::ostream& src, const BufferBlock& block, int bindingPoint)
860 {
861         src << "layout(";
862
863         if ((block.getFlags() & LAYOUT_MASK) != 0)
864                 src << LayoutFlagsFmt(block.getFlags() & LAYOUT_MASK) << ", ";
865
866         src << "binding = " << bindingPoint;
867
868         src << ") ";
869
870         src << "buffer " << block.getBlockName();
871         src << "\n{\n";
872
873         for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++)
874         {
875                 src << Indent(1);
876                 generateDeclaration(src, *varIter, 1 /* indent level */);
877                 src << ";\n";
878         }
879
880         src << "}";
881
882         if (block.getInstanceName() != DE_NULL)
883         {
884                 src << " " << block.getInstanceName();
885                 if (block.isArray())
886                         src << "[" << block.getArraySize() << "]";
887         }
888         else
889                 DE_ASSERT(!block.isArray());
890
891         src << ";\n";
892 }
893
894 void generateImmMatrixSrc (std::ostream& src, glu::DataType basicType, int matrixStride, bool isRowMajor, const void* valuePtr)
895 {
896         DE_ASSERT(glu::isDataTypeMatrix(basicType));
897
898         const int               compSize                = sizeof(deUint32);
899         const int               numRows                 = glu::getDataTypeMatrixNumRows(basicType);
900         const int               numCols                 = glu::getDataTypeMatrixNumColumns(basicType);
901
902         src << glu::getDataTypeName(basicType) << "(";
903
904         // Constructed in column-wise order.
905         for (int colNdx = 0; colNdx < numCols; colNdx++)
906         {
907                 for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
908                 {
909                         const deUint8*  compPtr = (const deUint8*)valuePtr + (isRowMajor ? rowNdx*matrixStride + colNdx*compSize
910                                                                                                                                                                 : colNdx*matrixStride + rowNdx*compSize);
911
912                         if (colNdx > 0 || rowNdx > 0)
913                                 src << ", ";
914
915                         src << de::floatToString(*((const float*)compPtr), 1);
916                 }
917         }
918
919         src << ")";
920 }
921
922 void generateImmMatrixSrc (std::ostream& src,
923                                                    glu::DataType basicType,
924                                                    int matrixStride,
925                                                    bool isRowMajor,
926                                                    const void* valuePtr,
927                                                    const char* resultVar,
928                                                    const char* typeName,
929                                                    const string shaderName)
930 {
931         const int               compSize                = sizeof(deUint32);
932         const int               numRows                 = glu::getDataTypeMatrixNumRows(basicType);
933         const int               numCols                 = glu::getDataTypeMatrixNumColumns(basicType);
934
935         typeName = "float";
936         for (int colNdex = 0; colNdex < numCols; colNdex++)
937         {
938                 for (int rowNdex = 0; rowNdex < numRows; rowNdex++)
939                 {
940                         src << "\t" << resultVar << " = " << resultVar << " && compare_" << typeName << "(" << shaderName << "[" << colNdex << "][" << rowNdex << "], ";
941                         const deUint8*  compPtr = (const deUint8*)valuePtr + (isRowMajor ? rowNdex*matrixStride + colNdex*compSize
942                                                                                                                                                                                 : colNdex*matrixStride + rowNdex*compSize);
943
944                         src << de::floatToString(*((const float*)compPtr), 1);
945                         src << ");\n";
946                 }
947         }
948
949         typeName = "vec";
950         for (int colNdex = 0; colNdex < numCols; colNdex++)
951         {
952                 src << "\t" << resultVar << " = " << resultVar << " && compare_" << typeName << numRows << "(" << shaderName << "[" << colNdex << "], " << typeName << numRows << "(";
953                 for (int rowNdex = 0; rowNdex < numRows; rowNdex++)
954                 {
955                         const deUint8*  compPtr = (const deUint8*)valuePtr + (isRowMajor ? (rowNdex * matrixStride + colNdex * compSize)
956                                                                                                                                   : (colNdex * matrixStride + rowNdex * compSize));
957                         src << de::floatToString(*((const float*)compPtr), 1);
958
959                         if (rowNdex < numRows-1)
960                                 src << ", ";
961                 }
962                 src << "));\n";
963         }
964 }
965
966 void generateImmScalarVectorSrc (std::ostream& src, glu::DataType basicType, const void* valuePtr)
967 {
968         DE_ASSERT(glu::isDataTypeFloatOrVec(basicType)  ||
969                           glu::isDataTypeIntOrIVec(basicType)   ||
970                           glu::isDataTypeUintOrUVec(basicType)  ||
971                           glu::isDataTypeBoolOrBVec(basicType));
972
973         const glu::DataType             scalarType              = glu::getDataTypeScalarType(basicType);
974         const int                               scalarSize              = glu::getDataTypeScalarSize(basicType);
975         const int                               compSize                = sizeof(deUint32);
976
977         if (scalarSize > 1)
978                 src << glu::getDataTypeName(basicType) << "(";
979
980         for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
981         {
982                 const deUint8* compPtr = (const deUint8*)valuePtr + scalarNdx*compSize;
983
984                 if (scalarNdx > 0)
985                         src << ", ";
986
987                 switch (scalarType)
988                 {
989                         case glu::TYPE_FLOAT:   src << de::floatToString(*((const float*)compPtr), 1);                  break;
990                         case glu::TYPE_INT:             src << *((const int*)compPtr);                                                                  break;
991                         case glu::TYPE_UINT:    src << *((const deUint32*)compPtr) << "u";                                              break;
992                         case glu::TYPE_BOOL:    src << (*((const deUint32*)compPtr) != 0u ? "true" : "false");  break;
993                         default:
994                                 DE_ASSERT(false);
995                 }
996         }
997
998         if (scalarSize > 1)
999                 src << ")";
1000 }
1001
1002 string getAPIName (const BufferBlock& block, const BufferVar& var, const glu::TypeComponentVector& accessPath)
1003 {
1004         std::ostringstream name;
1005
1006         if (block.getInstanceName())
1007                 name << block.getBlockName() << ".";
1008
1009         name << var.getName();
1010
1011         for (glu::TypeComponentVector::const_iterator pathComp = accessPath.begin(); pathComp != accessPath.end(); pathComp++)
1012         {
1013                 if (pathComp->type == glu::VarTypeComponent::STRUCT_MEMBER)
1014                 {
1015                         const VarType           curType         = glu::getVarType(var.getType(), accessPath.begin(), pathComp);
1016                         const StructType*       structPtr       = curType.getStructPtr();
1017
1018                         name << "." << structPtr->getMember(pathComp->index).getName();
1019                 }
1020                 else if (pathComp->type == glu::VarTypeComponent::ARRAY_ELEMENT)
1021                 {
1022                         if (pathComp == accessPath.begin() || (pathComp+1) == accessPath.end())
1023                                 name << "[0]"; // Top- / bottom-level array
1024                         else
1025                                 name << "[" << pathComp->index << "]";
1026                 }
1027                 else
1028                         DE_ASSERT(false);
1029         }
1030
1031         return name.str();
1032 }
1033
1034 string getShaderName (const BufferBlock& block, int instanceNdx, const BufferVar& var, const glu::TypeComponentVector& accessPath)
1035 {
1036         std::ostringstream name;
1037
1038         if (block.getInstanceName())
1039         {
1040                 name << block.getInstanceName();
1041
1042                 if (block.isArray())
1043                         name << "[" << instanceNdx << "]";
1044
1045                 name << ".";
1046         }
1047         else
1048                 DE_ASSERT(instanceNdx == 0);
1049
1050         name << var.getName();
1051
1052         for (glu::TypeComponentVector::const_iterator pathComp = accessPath.begin(); pathComp != accessPath.end(); pathComp++)
1053         {
1054                 if (pathComp->type == glu::VarTypeComponent::STRUCT_MEMBER)
1055                 {
1056                         const VarType           curType         = glu::getVarType(var.getType(), accessPath.begin(), pathComp);
1057                         const StructType*       structPtr       = curType.getStructPtr();
1058
1059                         name << "." << structPtr->getMember(pathComp->index).getName();
1060                 }
1061                 else if (pathComp->type == glu::VarTypeComponent::ARRAY_ELEMENT)
1062                         name << "[" << pathComp->index << "]";
1063                 else
1064                         DE_ASSERT(false);
1065         }
1066
1067         return name.str();
1068 }
1069
1070 int computeOffset (const BufferVarLayoutEntry& varLayout, const glu::TypeComponentVector& accessPath)
1071 {
1072         const int       topLevelNdx             = (accessPath.size() > 1 && accessPath.front().type == glu::VarTypeComponent::ARRAY_ELEMENT) ? accessPath.front().index : 0;
1073         const int       bottomLevelNdx  = (!accessPath.empty() && accessPath.back().type == glu::VarTypeComponent::ARRAY_ELEMENT) ? accessPath.back().index : 0;
1074
1075         return varLayout.offset + varLayout.topLevelArrayStride*topLevelNdx + varLayout.arrayStride*bottomLevelNdx;
1076 }
1077
1078 void generateCompareSrc (
1079         std::ostream&                           src,
1080         const char*                                     resultVar,
1081         const BufferLayout&                     bufferLayout,
1082         const BufferBlock&                      block,
1083         int                                                     instanceNdx,
1084         const BlockDataPtr&                     blockPtr,
1085         const BufferVar&                        bufVar,
1086         const glu::SubTypeAccess&       accessPath,
1087         MatrixLoadFlags                         matrixLoadFlag)
1088 {
1089         const VarType curType = accessPath.getType();
1090
1091         if (curType.isArrayType())
1092         {
1093                 const int arraySize = curType.getArraySize() == VarType::UNSIZED_ARRAY ? block.getLastUnsizedArraySize(instanceNdx) : curType.getArraySize();
1094
1095                 for (int elemNdx = 0; elemNdx < arraySize; elemNdx++)
1096                         generateCompareSrc(src, resultVar, bufferLayout, block, instanceNdx, blockPtr, bufVar, accessPath.element(elemNdx), LOAD_FULL_MATRIX);
1097         }
1098         else if (curType.isStructType())
1099         {
1100                 const int numMembers = curType.getStructPtr()->getNumMembers();
1101
1102                 for (int memberNdx = 0; memberNdx < numMembers; memberNdx++)
1103                         generateCompareSrc(src, resultVar, bufferLayout, block, instanceNdx, blockPtr, bufVar, accessPath.member(memberNdx), LOAD_FULL_MATRIX);
1104         }
1105         else
1106         {
1107                 DE_ASSERT(curType.isBasicType());
1108
1109                 const string    apiName = getAPIName(block, bufVar, accessPath.getPath());
1110                 const int               varNdx  = bufferLayout.getVariableIndex(apiName);
1111
1112                 DE_ASSERT(varNdx >= 0);
1113                 {
1114                         const BufferVarLayoutEntry&     varLayout               = bufferLayout.bufferVars[varNdx];
1115                         const string                            shaderName              = getShaderName(block, instanceNdx, bufVar, accessPath.getPath());
1116                         const glu::DataType                     basicType               = curType.getBasicType();
1117                         const bool                                      isMatrix                = glu::isDataTypeMatrix(basicType);
1118                         const char*                                     typeName                = glu::getDataTypeName(basicType);
1119                         const void*                                     valuePtr                = (const deUint8*)blockPtr.ptr + computeOffset(varLayout, accessPath.getPath());
1120
1121
1122                         if (isMatrix)
1123                         {
1124                                 if (matrixLoadFlag == LOAD_MATRIX_COMPONENTS)
1125                                         generateImmMatrixSrc(src, basicType, varLayout.matrixStride, varLayout.isRowMajor, valuePtr, resultVar, typeName, shaderName);
1126                                 else
1127                                 {
1128                                         src << "\t" << resultVar << " = " << resultVar << " && compare_" << typeName << "(" << shaderName << ", ";
1129                                         generateImmMatrixSrc (src, basicType, varLayout.matrixStride, varLayout.isRowMajor, valuePtr);
1130                                         src << ");\n";
1131                                 }
1132                         }
1133                         else
1134                         {
1135                                 src << "\t" << resultVar << " = " << resultVar << " && compare_" << typeName << "(" << shaderName << ", ";
1136                                 generateImmScalarVectorSrc(src, basicType, valuePtr);
1137                                 src << ");\n";
1138                         }
1139                 }
1140         }
1141 }
1142
1143 void generateCompareSrc (std::ostream& src, const char* resultVar, const ShaderInterface& interface, const BufferLayout& layout, const vector<BlockDataPtr>& blockPointers, MatrixLoadFlags matrixLoadFlag)
1144 {
1145         for (int declNdx = 0; declNdx < interface.getNumBlocks(); declNdx++)
1146         {
1147                 const BufferBlock&      block                   = interface.getBlock(declNdx);
1148                 const bool                      isArray                 = block.isArray();
1149                 const int                       numInstances    = isArray ? block.getArraySize() : 1;
1150
1151                 DE_ASSERT(!isArray || block.getInstanceName());
1152
1153                 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1154                 {
1155                         const string            instanceName    = block.getBlockName() + (isArray ? "[" + de::toString(instanceNdx) + "]" : string(""));
1156                         const int                       blockNdx                = layout.getBlockIndex(instanceName);
1157                         const BlockDataPtr&     blockPtr                = blockPointers[blockNdx];
1158
1159                         for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++)
1160                         {
1161                                 const BufferVar& bufVar = *varIter;
1162
1163                                 if ((bufVar.getFlags() & ACCESS_READ) == 0)
1164                                         continue; // Don't read from that variable.
1165
1166                                 generateCompareSrc(src, resultVar, layout, block, instanceNdx, blockPtr, bufVar, glu::SubTypeAccess(bufVar.getType()), matrixLoadFlag);
1167                         }
1168                 }
1169         }
1170 }
1171
1172 // \todo [2013-10-14 pyry] Almost identical to generateCompareSrc - unify?
1173
1174 void generateWriteSrc (
1175         std::ostream&                           src,
1176         const BufferLayout&                     bufferLayout,
1177         const BufferBlock&                      block,
1178         int                                                     instanceNdx,
1179         const BlockDataPtr&                     blockPtr,
1180         const BufferVar&                        bufVar,
1181         const glu::SubTypeAccess&       accessPath)
1182 {
1183         const VarType curType = accessPath.getType();
1184
1185         if (curType.isArrayType())
1186         {
1187                 const int arraySize = curType.getArraySize() == VarType::UNSIZED_ARRAY ? block.getLastUnsizedArraySize(instanceNdx) : curType.getArraySize();
1188
1189                 for (int elemNdx = 0; elemNdx < arraySize; elemNdx++)
1190                         generateWriteSrc(src, bufferLayout, block, instanceNdx, blockPtr, bufVar, accessPath.element(elemNdx));
1191         }
1192         else if (curType.isStructType())
1193         {
1194                 const int numMembers = curType.getStructPtr()->getNumMembers();
1195
1196                 for (int memberNdx = 0; memberNdx < numMembers; memberNdx++)
1197                         generateWriteSrc(src, bufferLayout, block, instanceNdx, blockPtr, bufVar, accessPath.member(memberNdx));
1198         }
1199         else
1200         {
1201                 DE_ASSERT(curType.isBasicType());
1202
1203                 const string    apiName = getAPIName(block, bufVar, accessPath.getPath());
1204                 const int               varNdx  = bufferLayout.getVariableIndex(apiName);
1205
1206                 DE_ASSERT(varNdx >= 0);
1207                 {
1208                         const BufferVarLayoutEntry&     varLayout               = bufferLayout.bufferVars[varNdx];
1209                         const string                            shaderName              = getShaderName(block, instanceNdx, bufVar, accessPath.getPath());
1210                         const glu::DataType                     basicType               = curType.getBasicType();
1211                         const bool                                      isMatrix                = glu::isDataTypeMatrix(basicType);
1212                         const void*                                     valuePtr                = (const deUint8*)blockPtr.ptr + computeOffset(varLayout, accessPath.getPath());
1213
1214                         src << "\t" << shaderName << " = ";
1215
1216                         if (isMatrix)
1217                                 generateImmMatrixSrc(src, basicType, varLayout.matrixStride, varLayout.isRowMajor, valuePtr);
1218                         else
1219                                 generateImmScalarVectorSrc(src, basicType, valuePtr);
1220
1221                         src << ";\n";
1222                 }
1223         }
1224 }
1225
1226 void generateWriteSrc (std::ostream& src, const ShaderInterface& interface, const BufferLayout& layout, const vector<BlockDataPtr>& blockPointers)
1227 {
1228         for (int declNdx = 0; declNdx < interface.getNumBlocks(); declNdx++)
1229         {
1230                 const BufferBlock&      block                   = interface.getBlock(declNdx);
1231                 const bool                      isArray                 = block.isArray();
1232                 const int                       numInstances    = isArray ? block.getArraySize() : 1;
1233
1234                 DE_ASSERT(!isArray || block.getInstanceName());
1235
1236                 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1237                 {
1238                         const string            instanceName    = block.getBlockName() + (isArray ? "[" + de::toString(instanceNdx) + "]" : string(""));
1239                         const int                       blockNdx                = layout.getBlockIndex(instanceName);
1240                         const BlockDataPtr&     blockPtr                = blockPointers[blockNdx];
1241
1242                         for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++)
1243                         {
1244                                 const BufferVar& bufVar = *varIter;
1245
1246                                 if ((bufVar.getFlags() & ACCESS_WRITE) == 0)
1247                                         continue; // Don't write to that variable.
1248
1249                                 generateWriteSrc(src, layout, block, instanceNdx, blockPtr, bufVar, glu::SubTypeAccess(bufVar.getType()));
1250                         }
1251                 }
1252         }
1253 }
1254
1255 string generateComputeShader (const ShaderInterface& interface, const BufferLayout& layout, const vector<BlockDataPtr>& comparePtrs, const vector<BlockDataPtr>& writePtrs, MatrixLoadFlags matrixLoadFlag)
1256 {
1257         std::ostringstream src;
1258
1259         src << "#version 310 es\n";
1260         src << "layout(local_size_x = 1) in;\n";
1261         src << "\n";
1262
1263         // Atomic counter for counting passed invocations.
1264         src << "layout(std140, binding = 0) buffer AcBlock { highp uint ac_numPassed; };\n\n";
1265
1266         std::vector<const StructType*> namedStructs;
1267         interface.getNamedStructs(namedStructs);
1268         for (std::vector<const StructType*>::const_iterator structIter = namedStructs.begin(); structIter != namedStructs.end(); structIter++)
1269                 src << glu::declare(*structIter) << ";\n";
1270
1271         {
1272                 for (int blockNdx = 0; blockNdx < interface.getNumBlocks(); blockNdx++)
1273                 {
1274                         const BufferBlock& block = interface.getBlock(blockNdx);
1275                         generateDeclaration(src, block, 1 + blockNdx);
1276                 }
1277         }
1278
1279         // Comparison utilities.
1280         src << "\n";
1281         generateCompareFuncs(src, interface);
1282
1283         src << "\n"
1284                    "void main (void)\n"
1285                    "{\n"
1286                    "    bool allOk = true;\n";
1287
1288         // Value compare.
1289         generateCompareSrc(src, "allOk", interface, layout, comparePtrs, matrixLoadFlag);
1290
1291         src << "        if (allOk)\n"
1292                 << "            ac_numPassed++;\n"
1293                 << "\n";
1294
1295         // Value write.
1296         generateWriteSrc(src, interface, layout, writePtrs);
1297
1298         src << "}\n";
1299
1300         return src.str();
1301 }
1302
1303 void copyBufferVarData (const BufferVarLayoutEntry& dstEntry, const BlockDataPtr& dstBlockPtr, const BufferVarLayoutEntry& srcEntry, const BlockDataPtr& srcBlockPtr)
1304 {
1305         DE_ASSERT(dstEntry.arraySize <= srcEntry.arraySize);
1306         DE_ASSERT(dstEntry.topLevelArraySize <= srcEntry.topLevelArraySize);
1307         DE_ASSERT(dstBlockPtr.lastUnsizedArraySize <= srcBlockPtr.lastUnsizedArraySize);
1308         DE_ASSERT(dstEntry.type == srcEntry.type);
1309
1310         deUint8* const                  dstBasePtr                      = (deUint8*)dstBlockPtr.ptr + dstEntry.offset;
1311         const deUint8* const    srcBasePtr                      = (const deUint8*)srcBlockPtr.ptr + srcEntry.offset;
1312         const int                               scalarSize                      = glu::getDataTypeScalarSize(dstEntry.type);
1313         const bool                              isMatrix                        = glu::isDataTypeMatrix(dstEntry.type);
1314         const int                               compSize                        = sizeof(deUint32);
1315         const int                               dstArraySize            = dstEntry.arraySize == 0 ? dstBlockPtr.lastUnsizedArraySize : dstEntry.arraySize;
1316         const int                               dstArrayStride          = dstEntry.arrayStride;
1317         const int                               dstTopLevelSize         = dstEntry.topLevelArraySize == 0 ? dstBlockPtr.lastUnsizedArraySize : dstEntry.topLevelArraySize;
1318         const int                               dstTopLevelStride       = dstEntry.topLevelArrayStride;
1319         const int                               srcArraySize            = srcEntry.arraySize == 0 ? srcBlockPtr.lastUnsizedArraySize : srcEntry.arraySize;
1320         const int                               srcArrayStride          = srcEntry.arrayStride;
1321         const int                               srcTopLevelSize         = srcEntry.topLevelArraySize == 0 ? srcBlockPtr.lastUnsizedArraySize : srcEntry.topLevelArraySize;
1322         const int                               srcTopLevelStride       = srcEntry.topLevelArrayStride;
1323
1324         DE_ASSERT(dstArraySize <= srcArraySize && dstTopLevelSize <= srcTopLevelSize);
1325         DE_UNREF(srcArraySize && srcTopLevelSize);
1326
1327         for (int topElemNdx = 0; topElemNdx < dstTopLevelSize; topElemNdx++)
1328         {
1329                 deUint8* const                  dstTopPtr       = dstBasePtr + topElemNdx*dstTopLevelStride;
1330                 const deUint8* const    srcTopPtr       = srcBasePtr + topElemNdx*srcTopLevelStride;
1331
1332                 for (int elementNdx = 0; elementNdx < dstArraySize; elementNdx++)
1333                 {
1334                         deUint8* const                  dstElemPtr      = dstTopPtr + elementNdx*dstArrayStride;
1335                         const deUint8* const    srcElemPtr      = srcTopPtr + elementNdx*srcArrayStride;
1336
1337                         if (isMatrix)
1338                         {
1339                                 const int       numRows = glu::getDataTypeMatrixNumRows(dstEntry.type);
1340                                 const int       numCols = glu::getDataTypeMatrixNumColumns(dstEntry.type);
1341
1342                                 for (int colNdx = 0; colNdx < numCols; colNdx++)
1343                                 {
1344                                         for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
1345                                         {
1346                                                 deUint8*                dstCompPtr      = dstElemPtr + (dstEntry.isRowMajor ? rowNdx*dstEntry.matrixStride + colNdx*compSize
1347                                                                                                                                                                                 : colNdx*dstEntry.matrixStride + rowNdx*compSize);
1348                                                 const deUint8*  srcCompPtr      = srcElemPtr + (srcEntry.isRowMajor ? rowNdx*srcEntry.matrixStride + colNdx*compSize
1349                                                                                                                                                                                 : colNdx*srcEntry.matrixStride + rowNdx*compSize);
1350
1351                                                 DE_ASSERT((deIntptr)(srcCompPtr + compSize) - (deIntptr)srcBlockPtr.ptr <= (deIntptr)srcBlockPtr.size);
1352                                                 DE_ASSERT((deIntptr)(dstCompPtr + compSize) - (deIntptr)dstBlockPtr.ptr <= (deIntptr)dstBlockPtr.size);
1353                                                 deMemcpy(dstCompPtr, srcCompPtr, compSize);
1354                                         }
1355                                 }
1356                         }
1357                         else
1358                         {
1359                                 DE_ASSERT((deIntptr)(srcElemPtr + scalarSize*compSize) - (deIntptr)srcBlockPtr.ptr <= (deIntptr)srcBlockPtr.size);
1360                                 DE_ASSERT((deIntptr)(dstElemPtr + scalarSize*compSize) - (deIntptr)dstBlockPtr.ptr <= (deIntptr)dstBlockPtr.size);
1361                                 deMemcpy(dstElemPtr, srcElemPtr, scalarSize*compSize);
1362                         }
1363                 }
1364         }
1365 }
1366
1367 void copyData (const BufferLayout& dstLayout, const vector<BlockDataPtr>& dstBlockPointers, const BufferLayout& srcLayout, const vector<BlockDataPtr>& srcBlockPointers)
1368 {
1369         // \note Src layout is used as reference in case of activeVarIndices happens to be incorrect in dstLayout blocks.
1370         int numBlocks = (int)srcLayout.blocks.size();
1371
1372         for (int srcBlockNdx = 0; srcBlockNdx < numBlocks; srcBlockNdx++)
1373         {
1374                 const BlockLayoutEntry&         srcBlock        = srcLayout.blocks[srcBlockNdx];
1375                 const BlockDataPtr&                     srcBlockPtr     = srcBlockPointers[srcBlockNdx];
1376                 int                                                     dstBlockNdx     = dstLayout.getBlockIndex(srcBlock.name.c_str());
1377
1378                 if (dstBlockNdx >= 0)
1379                 {
1380                         DE_ASSERT(de::inBounds(dstBlockNdx, 0, (int)dstBlockPointers.size()));
1381
1382                         const BlockDataPtr& dstBlockPtr = dstBlockPointers[dstBlockNdx];
1383
1384                         for (vector<int>::const_iterator srcVarNdxIter = srcBlock.activeVarIndices.begin(); srcVarNdxIter != srcBlock.activeVarIndices.end(); srcVarNdxIter++)
1385                         {
1386                                 const BufferVarLayoutEntry&     srcEntry        = srcLayout.bufferVars[*srcVarNdxIter];
1387                                 int                                                     dstVarNdx       = dstLayout.getVariableIndex(srcEntry.name.c_str());
1388
1389                                 if (dstVarNdx >= 0)
1390                                         copyBufferVarData(dstLayout.bufferVars[dstVarNdx], dstBlockPtr, srcEntry, srcBlockPtr);
1391                         }
1392                 }
1393         }
1394 }
1395
1396 void copyNonWrittenData (
1397         const BufferLayout&                     layout,
1398         const BufferBlock&                      block,
1399         int                                                     instanceNdx,
1400         const BlockDataPtr&                     srcBlockPtr,
1401         const BlockDataPtr&                     dstBlockPtr,
1402         const BufferVar&                        bufVar,
1403         const glu::SubTypeAccess&       accessPath)
1404 {
1405         const VarType curType = accessPath.getType();
1406
1407         if (curType.isArrayType())
1408         {
1409                 const int arraySize = curType.getArraySize() == VarType::UNSIZED_ARRAY ? block.getLastUnsizedArraySize(instanceNdx) : curType.getArraySize();
1410
1411                 for (int elemNdx = 0; elemNdx < arraySize; elemNdx++)
1412                         copyNonWrittenData(layout, block, instanceNdx, srcBlockPtr, dstBlockPtr, bufVar, accessPath.element(elemNdx));
1413         }
1414         else if (curType.isStructType())
1415         {
1416                 const int numMembers = curType.getStructPtr()->getNumMembers();
1417
1418                 for (int memberNdx = 0; memberNdx < numMembers; memberNdx++)
1419                         copyNonWrittenData(layout, block, instanceNdx, srcBlockPtr, dstBlockPtr, bufVar, accessPath.member(memberNdx));
1420         }
1421         else
1422         {
1423                 DE_ASSERT(curType.isBasicType());
1424
1425                 const string    apiName = getAPIName(block, bufVar, accessPath.getPath());
1426                 const int               varNdx  = layout.getVariableIndex(apiName);
1427
1428                 DE_ASSERT(varNdx >= 0);
1429                 {
1430                         const BufferVarLayoutEntry& varLayout = layout.bufferVars[varNdx];
1431                         copyBufferVarData(varLayout, dstBlockPtr, varLayout, srcBlockPtr);
1432                 }
1433         }
1434 }
1435
1436 void copyNonWrittenData (const ShaderInterface& interface, const BufferLayout& layout, const vector<BlockDataPtr>& srcPtrs, const vector<BlockDataPtr>& dstPtrs)
1437 {
1438         for (int declNdx = 0; declNdx < interface.getNumBlocks(); declNdx++)
1439         {
1440                 const BufferBlock&      block                   = interface.getBlock(declNdx);
1441                 const bool                      isArray                 = block.isArray();
1442                 const int                       numInstances    = isArray ? block.getArraySize() : 1;
1443
1444                 DE_ASSERT(!isArray || block.getInstanceName());
1445
1446                 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1447                 {
1448                         const string            instanceName    = block.getBlockName() + (isArray ? "[" + de::toString(instanceNdx) + "]" : string(""));
1449                         const int                       blockNdx                = layout.getBlockIndex(instanceName);
1450                         const BlockDataPtr&     srcBlockPtr             = srcPtrs[blockNdx];
1451                         const BlockDataPtr&     dstBlockPtr             = dstPtrs[blockNdx];
1452
1453                         for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++)
1454                         {
1455                                 const BufferVar& bufVar = *varIter;
1456
1457                                 if (bufVar.getFlags() & ACCESS_WRITE)
1458                                         continue;
1459
1460                                 copyNonWrittenData(layout, block, instanceNdx, srcBlockPtr, dstBlockPtr, bufVar, glu::SubTypeAccess(bufVar.getType()));
1461                         }
1462                 }
1463         }
1464 }
1465
1466 bool compareComponents (glu::DataType scalarType, const void* ref, const void* res, int numComps)
1467 {
1468         if (scalarType == glu::TYPE_FLOAT)
1469         {
1470                 const float threshold = 0.05f; // Same as used in shaders - should be fine for values being used.
1471
1472                 for (int ndx = 0; ndx < numComps; ndx++)
1473                 {
1474                         const float             refVal          = *((const float*)ref + ndx);
1475                         const float             resVal          = *((const float*)res + ndx);
1476
1477                         if (deFloatAbs(resVal - refVal) >= threshold)
1478                                 return false;
1479                 }
1480         }
1481         else if (scalarType == glu::TYPE_BOOL)
1482         {
1483                 for (int ndx = 0; ndx < numComps; ndx++)
1484                 {
1485                         const deUint32  refVal          = *((const deUint32*)ref + ndx);
1486                         const deUint32  resVal          = *((const deUint32*)res + ndx);
1487
1488                         if ((refVal != 0) != (resVal != 0))
1489                                 return false;
1490                 }
1491         }
1492         else
1493         {
1494                 DE_ASSERT(scalarType == glu::TYPE_INT || scalarType == glu::TYPE_UINT);
1495
1496                 for (int ndx = 0; ndx < numComps; ndx++)
1497                 {
1498                         const deUint32  refVal          = *((const deUint32*)ref + ndx);
1499                         const deUint32  resVal          = *((const deUint32*)res + ndx);
1500
1501                         if (refVal != resVal)
1502                                 return false;
1503                 }
1504         }
1505
1506         return true;
1507 }
1508
1509 bool compareBufferVarData (tcu::TestLog& log, const BufferVarLayoutEntry& refEntry, const BlockDataPtr& refBlockPtr, const BufferVarLayoutEntry& resEntry, const BlockDataPtr& resBlockPtr)
1510 {
1511         DE_ASSERT(resEntry.arraySize <= refEntry.arraySize);
1512         DE_ASSERT(resEntry.topLevelArraySize <= refEntry.topLevelArraySize);
1513         DE_ASSERT(resBlockPtr.lastUnsizedArraySize <= refBlockPtr.lastUnsizedArraySize);
1514         DE_ASSERT(resEntry.type == refEntry.type);
1515
1516         deUint8* const                  resBasePtr                      = (deUint8*)resBlockPtr.ptr + resEntry.offset;
1517         const deUint8* const    refBasePtr                      = (const deUint8*)refBlockPtr.ptr + refEntry.offset;
1518         const glu::DataType             scalarType                      = glu::getDataTypeScalarType(refEntry.type);
1519         const int                               scalarSize                      = glu::getDataTypeScalarSize(resEntry.type);
1520         const bool                              isMatrix                        = glu::isDataTypeMatrix(resEntry.type);
1521         const int                               compSize                        = sizeof(deUint32);
1522         const int                               maxPrints                       = 3;
1523         int                                             numFailed                       = 0;
1524
1525         const int                               resArraySize            = resEntry.arraySize == 0 ? resBlockPtr.lastUnsizedArraySize : resEntry.arraySize;
1526         const int                               resArrayStride          = resEntry.arrayStride;
1527         const int                               resTopLevelSize         = resEntry.topLevelArraySize == 0 ? resBlockPtr.lastUnsizedArraySize : resEntry.topLevelArraySize;
1528         const int                               resTopLevelStride       = resEntry.topLevelArrayStride;
1529         const int                               refArraySize            = refEntry.arraySize == 0 ? refBlockPtr.lastUnsizedArraySize : refEntry.arraySize;
1530         const int                               refArrayStride          = refEntry.arrayStride;
1531         const int                               refTopLevelSize         = refEntry.topLevelArraySize == 0 ? refBlockPtr.lastUnsizedArraySize : refEntry.topLevelArraySize;
1532         const int                               refTopLevelStride       = refEntry.topLevelArrayStride;
1533
1534         DE_ASSERT(resArraySize <= refArraySize && resTopLevelSize <= refTopLevelSize);
1535         DE_UNREF(refArraySize && refTopLevelSize);
1536
1537         for (int topElemNdx = 0; topElemNdx < resTopLevelSize; topElemNdx++)
1538         {
1539                 deUint8* const                  resTopPtr       = resBasePtr + topElemNdx*resTopLevelStride;
1540                 const deUint8* const    refTopPtr       = refBasePtr + topElemNdx*refTopLevelStride;
1541
1542                 for (int elementNdx = 0; elementNdx < resArraySize; elementNdx++)
1543                 {
1544                         deUint8* const                  resElemPtr      = resTopPtr + elementNdx*resArrayStride;
1545                         const deUint8* const    refElemPtr      = refTopPtr + elementNdx*refArrayStride;
1546
1547                         if (isMatrix)
1548                         {
1549                                 const int       numRows = glu::getDataTypeMatrixNumRows(resEntry.type);
1550                                 const int       numCols = glu::getDataTypeMatrixNumColumns(resEntry.type);
1551                                 bool            isOk    = true;
1552
1553                                 for (int colNdx = 0; colNdx < numCols; colNdx++)
1554                                 {
1555                                         for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
1556                                         {
1557                                                 deUint8*                resCompPtr      = resElemPtr + (resEntry.isRowMajor ? rowNdx*resEntry.matrixStride + colNdx*compSize
1558                                                                                                                                                                                 : colNdx*resEntry.matrixStride + rowNdx*compSize);
1559                                                 const deUint8*  refCompPtr      = refElemPtr + (refEntry.isRowMajor ? rowNdx*refEntry.matrixStride + colNdx*compSize
1560                                                                                                                                                                                 : colNdx*refEntry.matrixStride + rowNdx*compSize);
1561
1562                                                 DE_ASSERT((deIntptr)(refCompPtr + compSize) - (deIntptr)refBlockPtr.ptr <= (deIntptr)refBlockPtr.size);
1563                                                 DE_ASSERT((deIntptr)(resCompPtr + compSize) - (deIntptr)resBlockPtr.ptr <= (deIntptr)resBlockPtr.size);
1564
1565                                                 isOk = isOk && compareComponents(scalarType, resCompPtr, refCompPtr, 1);
1566                                         }
1567                                 }
1568
1569                                 if (!isOk)
1570                                 {
1571                                         numFailed += 1;
1572                                         if (numFailed < maxPrints)
1573                                         {
1574                                                 std::ostringstream expected, got;
1575                                                 generateImmMatrixSrc(expected, refEntry.type, refEntry.matrixStride, refEntry.isRowMajor, refElemPtr);
1576                                                 generateImmMatrixSrc(got, resEntry.type, resEntry.matrixStride, resEntry.isRowMajor, resElemPtr);
1577                                                 log << TestLog::Message << "ERROR: mismatch in " << refEntry.name << ", top-level ndx " << topElemNdx << ", bottom-level ndx " << elementNdx << ":\n"
1578                                                                                                 << "  expected " << expected.str() << "\n"
1579                                                                                                 << "  got " << got.str()
1580                                                         << TestLog::EndMessage;
1581                                         }
1582                                 }
1583                         }
1584                         else
1585                         {
1586                                 DE_ASSERT((deIntptr)(refElemPtr + scalarSize*compSize) - (deIntptr)refBlockPtr.ptr <= (deIntptr)refBlockPtr.size);
1587                                 DE_ASSERT((deIntptr)(resElemPtr + scalarSize*compSize) - (deIntptr)resBlockPtr.ptr <= (deIntptr)resBlockPtr.size);
1588
1589                                 const bool isOk = compareComponents(scalarType, resElemPtr, refElemPtr, scalarSize);
1590
1591                                 if (!isOk)
1592                                 {
1593                                         numFailed += 1;
1594                                         if (numFailed < maxPrints)
1595                                         {
1596                                                 std::ostringstream expected, got;
1597                                                 generateImmScalarVectorSrc(expected, refEntry.type, refElemPtr);
1598                                                 generateImmScalarVectorSrc(got, resEntry.type, resElemPtr);
1599                                                 log << TestLog::Message << "ERROR: mismatch in " << refEntry.name << ", top-level ndx " << topElemNdx << ", bottom-level ndx " << elementNdx << ":\n"
1600                                                                                                 << "  expected " << expected.str() << "\n"
1601                                                                                                 << "  got " << got.str()
1602                                                         << TestLog::EndMessage;
1603                                         }
1604                                 }
1605                         }
1606                 }
1607         }
1608
1609         if (numFailed >= maxPrints)
1610                 log << TestLog::Message << "... (" << numFailed << " failures for " << refEntry.name << " in total)" << TestLog::EndMessage;
1611
1612         return numFailed == 0;
1613 }
1614
1615 bool compareData (tcu::TestLog& log, const BufferLayout& refLayout, const vector<BlockDataPtr>& refBlockPointers, const BufferLayout& resLayout, const vector<BlockDataPtr>& resBlockPointers)
1616 {
1617         const int       numBlocks       = (int)refLayout.blocks.size();
1618         bool            allOk           = true;
1619
1620         for (int refBlockNdx = 0; refBlockNdx < numBlocks; refBlockNdx++)
1621         {
1622                 const BlockLayoutEntry&         refBlock        = refLayout.blocks[refBlockNdx];
1623                 const BlockDataPtr&                     refBlockPtr     = refBlockPointers[refBlockNdx];
1624                 int                                                     resBlockNdx     = resLayout.getBlockIndex(refBlock.name.c_str());
1625
1626                 if (resBlockNdx >= 0)
1627                 {
1628                         DE_ASSERT(de::inBounds(resBlockNdx, 0, (int)resBlockPointers.size()));
1629
1630                         const BlockDataPtr& resBlockPtr = resBlockPointers[resBlockNdx];
1631
1632                         for (vector<int>::const_iterator refVarNdxIter = refBlock.activeVarIndices.begin(); refVarNdxIter != refBlock.activeVarIndices.end(); refVarNdxIter++)
1633                         {
1634                                 const BufferVarLayoutEntry&     refEntry        = refLayout.bufferVars[*refVarNdxIter];
1635                                 int                                                     resVarNdx       = resLayout.getVariableIndex(refEntry.name.c_str());
1636
1637                                 if (resVarNdx >= 0)
1638                                 {
1639                                         const BufferVarLayoutEntry& resEntry = resLayout.bufferVars[resVarNdx];
1640                                         allOk = compareBufferVarData(log, refEntry, refBlockPtr, resEntry, resBlockPtr) && allOk;
1641                                 }
1642                         }
1643                 }
1644         }
1645
1646         return allOk;
1647 }
1648
1649 string getBlockAPIName (const BufferBlock& block, int instanceNdx)
1650 {
1651         DE_ASSERT(block.isArray() || instanceNdx == 0);
1652         return block.getBlockName() + (block.isArray() ? ("[" + de::toString(instanceNdx) + "]") : string());
1653 }
1654
1655 // \note Some implementations don't report block members in the order they are declared.
1656 //               For checking whether size has to be adjusted by some top-level array actual size,
1657 //               we only need to know a) whether there is a unsized top-level array, and b)
1658 //               what is stride of that array.
1659
1660 static bool hasUnsizedArray (const BufferLayout& layout, const BlockLayoutEntry& entry)
1661 {
1662         for (vector<int>::const_iterator varNdx = entry.activeVarIndices.begin(); varNdx != entry.activeVarIndices.end(); ++varNdx)
1663         {
1664                 if (isUnsizedArray(layout.bufferVars[*varNdx]))
1665                         return true;
1666         }
1667
1668         return false;
1669 }
1670
1671 static int getUnsizedArrayStride (const BufferLayout& layout, const BlockLayoutEntry& entry)
1672 {
1673         for (vector<int>::const_iterator varNdx = entry.activeVarIndices.begin(); varNdx != entry.activeVarIndices.end(); ++varNdx)
1674         {
1675                 const BufferVarLayoutEntry& varEntry = layout.bufferVars[*varNdx];
1676
1677                 if (varEntry.arraySize == 0)
1678                         return varEntry.arrayStride;
1679                 else if (varEntry.topLevelArraySize == 0)
1680                         return varEntry.topLevelArrayStride;
1681         }
1682
1683         return 0;
1684 }
1685
1686 vector<int> computeBufferSizes (const ShaderInterface& interface, const BufferLayout& layout)
1687 {
1688         vector<int> sizes(layout.blocks.size());
1689
1690         for (int declNdx = 0; declNdx < interface.getNumBlocks(); declNdx++)
1691         {
1692                 const BufferBlock&      block                   = interface.getBlock(declNdx);
1693                 const bool                      isArray                 = block.isArray();
1694                 const int                       numInstances    = isArray ? block.getArraySize() : 1;
1695
1696                 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1697                 {
1698                         const string    apiName         = getBlockAPIName(block, instanceNdx);
1699                         const int               blockNdx        = layout.getBlockIndex(apiName);
1700
1701                         if (blockNdx >= 0)
1702                         {
1703                                 const BlockLayoutEntry&         blockLayout             = layout.blocks[blockNdx];
1704                                 const int                                       baseSize                = blockLayout.size;
1705                                 const bool                                      isLastUnsized   = hasUnsizedArray(layout, blockLayout);
1706                                 const int                                       lastArraySize   = isLastUnsized ? block.getLastUnsizedArraySize(instanceNdx) : 0;
1707                                 const int                                       stride                  = isLastUnsized ? getUnsizedArrayStride(layout, blockLayout) : 0;
1708
1709                                 sizes[blockNdx] = baseSize + lastArraySize*stride;
1710                         }
1711                 }
1712         }
1713
1714         return sizes;
1715 }
1716
1717 BlockDataPtr getBlockDataPtr (const BufferLayout& layout, const BlockLayoutEntry& blockLayout, void* ptr, int bufferSize)
1718 {
1719         const bool      isLastUnsized   = hasUnsizedArray(layout, blockLayout);
1720         const int       baseSize                = blockLayout.size;
1721
1722         if (isLastUnsized)
1723         {
1724                 const int               lastArrayStride = getUnsizedArrayStride(layout, blockLayout);
1725                 const int               lastArraySize   = (bufferSize-baseSize) / (lastArrayStride ? lastArrayStride : 1);
1726
1727                 DE_ASSERT(baseSize + lastArraySize*lastArrayStride == bufferSize);
1728
1729                 return BlockDataPtr(ptr, bufferSize, lastArraySize);
1730         }
1731         else
1732                 return BlockDataPtr(ptr, bufferSize, 0);
1733 }
1734
1735 struct Buffer
1736 {
1737         deUint32                                buffer;
1738         int                                             size;
1739
1740         Buffer (deUint32 buffer_, int size_) : buffer(buffer_), size(size_) {}
1741         Buffer (void) : buffer(0), size(0) {}
1742 };
1743
1744 struct BlockLocation
1745 {
1746         int                                             index;
1747         int                                             offset;
1748         int                                             size;
1749
1750         BlockLocation (int index_, int offset_, int size_) : index(index_), offset(offset_), size(size_) {}
1751         BlockLocation (void) : index(0), offset(0), size(0) {}
1752 };
1753
1754 void initRefDataStorage (const ShaderInterface& interface, const BufferLayout& layout, RefDataStorage& storage)
1755 {
1756         DE_ASSERT(storage.data.empty() && storage.pointers.empty());
1757
1758         const vector<int>       bufferSizes = computeBufferSizes(interface, layout);
1759         int                                     totalSize       = 0;
1760
1761         for (vector<int>::const_iterator sizeIter = bufferSizes.begin(); sizeIter != bufferSizes.end(); ++sizeIter)
1762                 totalSize += *sizeIter;
1763
1764         storage.data.resize(totalSize);
1765
1766         // Pointers for each block.
1767         {
1768                 deUint8*        basePtr         = storage.data.empty() ? DE_NULL : &storage.data[0];
1769                 int                     curOffset       = 0;
1770
1771                 DE_ASSERT(bufferSizes.size() == layout.blocks.size());
1772                 DE_ASSERT(totalSize == 0 || basePtr);
1773
1774                 storage.pointers.resize(layout.blocks.size());
1775
1776                 for (int blockNdx = 0; blockNdx < (int)layout.blocks.size(); blockNdx++)
1777                 {
1778                         const BlockLayoutEntry& blockLayout             = layout.blocks[blockNdx];
1779                         const int                               bufferSize              = bufferSizes[blockNdx];
1780
1781                         storage.pointers[blockNdx] = getBlockDataPtr(layout, blockLayout, basePtr + curOffset, bufferSize);
1782
1783                         curOffset += bufferSize;
1784                 }
1785         }
1786 }
1787
1788
1789 vector<BlockDataPtr> blockLocationsToPtrs (const BufferLayout& layout, const vector<BlockLocation>& blockLocations, const vector<void*>& bufPtrs)
1790 {
1791         vector<BlockDataPtr> blockPtrs(blockLocations.size());
1792
1793         DE_ASSERT(layout.blocks.size() == blockLocations.size());
1794
1795         for (int blockNdx = 0; blockNdx < (int)layout.blocks.size(); blockNdx++)
1796         {
1797                 const BlockLayoutEntry& blockLayout             = layout.blocks[blockNdx];
1798                 const BlockLocation&    location                = blockLocations[blockNdx];
1799
1800                 blockPtrs[blockNdx] = getBlockDataPtr(layout, blockLayout, (deUint8*)bufPtrs[location.index] + location.offset, location.size);
1801         }
1802
1803         return blockPtrs;
1804 }
1805
1806 } // anonymous (utilities)
1807
1808 de::MovePtr<vk::Allocation> allocateAndBindMemory (Context& context, vk::VkBuffer buffer, vk::MemoryRequirement memReqs)
1809 {
1810         const vk::DeviceInterface&              vkd             = context.getDeviceInterface();
1811         const vk::VkMemoryRequirements  bufReqs = vk::getBufferMemoryRequirements(vkd, context.getDevice(), buffer);
1812         de::MovePtr<vk::Allocation>             memory  = context.getDefaultAllocator().allocate(bufReqs, memReqs);
1813
1814         vkd.bindBufferMemory(context.getDevice(), buffer, memory->getMemory(), memory->getOffset());
1815
1816         return memory;
1817 }
1818
1819 vk::Move<vk::VkBuffer> createBuffer (Context& context, vk::VkDeviceSize bufferSize, vk::VkBufferUsageFlags usageFlags)
1820 {
1821         const vk::VkDevice                      vkDevice                        = context.getDevice();
1822         const vk::DeviceInterface&      vk                                      = context.getDeviceInterface();
1823         const deUint32                  queueFamilyIndex        = context.getUniversalQueueFamilyIndex();
1824
1825         const vk::VkBufferCreateInfo    bufferInfo              =
1826         {
1827                 vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,       // VkStructureType              sType;
1828                 DE_NULL,                                                                        // const void*                  pNext;
1829                 0u,                                                                                     // VkBufferCreateFlags  flags;
1830                 bufferSize,                                                                     // VkDeviceSize                 size;
1831                 usageFlags,                                                                     // VkBufferUsageFlags   usage;
1832                 vk::VK_SHARING_MODE_EXCLUSIVE,                          // VkSharingMode                sharingMode;
1833                 1u,                                                                                     // deUint32                             queueFamilyCount;
1834                 &queueFamilyIndex                                                       // const deUint32*              pQueueFamilyIndices;
1835         };
1836
1837         return vk::createBuffer(vk, vkDevice, &bufferInfo);
1838 }
1839
1840 // SSBOLayoutCaseInstance
1841
1842 class SSBOLayoutCaseInstance : public TestInstance
1843 {
1844 public:
1845                                                                 SSBOLayoutCaseInstance  (Context&                                       context,
1846                                                                                                                 SSBOLayoutCase::BufferMode      bufferMode,
1847                                                                                                                 const ShaderInterface&          interface,
1848                                                                                                                 const BufferLayout&                     refLayout,
1849                                                                                                                 const RefDataStorage&           initialData,
1850                                                                                                                 const RefDataStorage&           writeData);
1851         virtual                                         ~SSBOLayoutCaseInstance (void);
1852         virtual tcu::TestStatus         iterate                                         (void);
1853
1854 private:
1855         SSBOLayoutCase::BufferMode      m_bufferMode;
1856         const ShaderInterface&          m_interface;
1857         const BufferLayout&                     m_refLayout;
1858         const RefDataStorage&           m_initialData;  // Initial data stored in buffer.
1859         const RefDataStorage&           m_writeData;    // Data written by compute shader.
1860
1861
1862         typedef de::SharedPtr<vk::Unique<vk::VkBuffer> >        VkBufferSp;
1863         typedef de::SharedPtr<vk::Allocation>                           AllocationSp;
1864
1865         std::vector<VkBufferSp>         m_uniformBuffers;
1866         std::vector<AllocationSp>       m_uniformAllocs;
1867 };
1868
1869 SSBOLayoutCaseInstance::SSBOLayoutCaseInstance (Context&                                        context,
1870                                                                                                 SSBOLayoutCase::BufferMode      bufferMode,
1871                                                                                                 const ShaderInterface&          interface,
1872                                                                                                 const BufferLayout&                     refLayout,
1873                                                                                                 const RefDataStorage&           initialData,
1874                                                                                                 const RefDataStorage&           writeData)
1875         : TestInstance  (context)
1876         , m_bufferMode  (bufferMode)
1877         , m_interface   (interface)
1878         , m_refLayout   (refLayout)
1879         , m_initialData (initialData)
1880         , m_writeData   (writeData)
1881 {
1882 }
1883
1884 SSBOLayoutCaseInstance::~SSBOLayoutCaseInstance (void)
1885 {
1886 }
1887
1888 tcu::TestStatus SSBOLayoutCaseInstance::iterate (void)
1889 {
1890         // todo: add compute stage availability check
1891         const vk::DeviceInterface&      vk                                      = m_context.getDeviceInterface();
1892         const vk::VkDevice                      device                          = m_context.getDevice();
1893         const vk::VkQueue                       queue                           = m_context.getUniversalQueue();
1894         const deUint32                          queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
1895
1896         // Create descriptor set
1897         const deUint32 acBufferSize = 1024;
1898         vk::Move<vk::VkBuffer> acBuffer (createBuffer(m_context, acBufferSize, vk:: VK_BUFFER_USAGE_STORAGE_BUFFER_BIT));
1899         de::UniquePtr<vk::Allocation> acBufferAlloc (allocateAndBindMemory(m_context, *acBuffer, vk::MemoryRequirement::HostVisible));
1900
1901         deMemset(acBufferAlloc->getHostPtr(), 0, acBufferSize);
1902         flushMappedMemoryRange(vk, device, acBufferAlloc->getMemory(), acBufferAlloc->getOffset(), acBufferSize);
1903
1904         vk::DescriptorSetLayoutBuilder setLayoutBuilder;
1905         vk::DescriptorPoolBuilder poolBuilder;
1906
1907         setLayoutBuilder
1908                 .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT);
1909
1910         int numBlocks = 0;
1911         const int numBindings = m_interface.getNumBlocks();
1912         for (int bindingNdx = 0; bindingNdx < numBindings; bindingNdx++)
1913         {
1914                 const BufferBlock& block = m_interface.getBlock(bindingNdx);
1915                 if (block.isArray())
1916                 {
1917                         setLayoutBuilder
1918                                 .addArrayBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, block.getArraySize(), vk::VK_SHADER_STAGE_COMPUTE_BIT);
1919                         numBlocks += block.getArraySize();
1920                 }
1921                 else
1922                 {
1923                         setLayoutBuilder
1924                                 .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT);
1925                         numBlocks += 1;
1926                 }
1927         }
1928
1929         poolBuilder
1930                 .addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, (deUint32)(1 + numBlocks));
1931
1932         const vk::Unique<vk::VkDescriptorSetLayout> descriptorSetLayout(setLayoutBuilder.build(vk, device));
1933         const vk::Unique<vk::VkDescriptorPool> descriptorPool(poolBuilder.build(vk, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
1934
1935         const vk::VkDescriptorSetAllocateInfo allocInfo =
1936         {
1937                 vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
1938                 DE_NULL,
1939                 *descriptorPool,
1940                 1u,
1941                 &descriptorSetLayout.get(),
1942         };
1943
1944         const vk::Unique<vk::VkDescriptorSet> descriptorSet(allocateDescriptorSet(vk, device, &allocInfo));
1945         const vk::VkDescriptorBufferInfo descriptorInfo = makeDescriptorBufferInfo(*acBuffer, 0ull, acBufferSize);
1946
1947         vk::DescriptorSetUpdateBuilder setUpdateBuilder;
1948         std::vector<vk::VkDescriptorBufferInfo> descriptors(numBlocks);
1949
1950         setUpdateBuilder
1951                 .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorInfo);
1952
1953         vector<BlockDataPtr>  mappedBlockPtrs;
1954
1955         // Upload base buffers
1956         const std::vector<int> bufferSizes      = computeBufferSizes(m_interface, m_refLayout);
1957         {
1958                 std::vector<void*>                              mapPtrs;
1959                 std::vector<BlockLocation>              blockLocations  (numBlocks);
1960
1961                 DE_ASSERT(bufferSizes.size() == m_refLayout.blocks.size());
1962
1963                 if (m_bufferMode == SSBOLayoutCase::BUFFERMODE_PER_BLOCK)
1964                 {
1965                         mapPtrs.resize(numBlocks);
1966                         for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1967                         {
1968                                 const deUint32 bufferSize = bufferSizes[blockNdx];
1969                                 DE_ASSERT(bufferSize > 0);
1970
1971                                 blockLocations[blockNdx] = BlockLocation(blockNdx, 0, bufferSize);
1972
1973                                 vk::Move<vk::VkBuffer>                          buffer          = createBuffer(m_context, bufferSize, vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
1974                                 de::MovePtr<vk::Allocation>                     alloc           = allocateAndBindMemory(m_context, *buffer, vk::MemoryRequirement::HostVisible);
1975
1976                                 descriptors[blockNdx] = makeDescriptorBufferInfo(*buffer, 0ull, bufferSize);
1977
1978                                 mapPtrs[blockNdx] = alloc->getHostPtr();
1979
1980                                 m_uniformBuffers.push_back(VkBufferSp(new vk::Unique<vk::VkBuffer>(buffer)));
1981                                 m_uniformAllocs.push_back(AllocationSp(alloc.release()));
1982                         }
1983                 }
1984                 else
1985                 {
1986                         DE_ASSERT(m_bufferMode == SSBOLayoutCase::BUFFERMODE_SINGLE);
1987
1988                         vk::VkPhysicalDeviceProperties properties;
1989                         m_context.getInstanceInterface().getPhysicalDeviceProperties(m_context.getPhysicalDevice(), &properties);
1990                         const int       bindingAlignment        = (int)properties.limits.minStorageBufferOffsetAlignment;
1991                         int                     curOffset                       = 0;
1992                         for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1993                         {
1994                                 const int bufferSize = bufferSizes[blockNdx];
1995                                 DE_ASSERT(bufferSize > 0);
1996
1997                                 if (bindingAlignment > 0)
1998                                         curOffset = deRoundUp32(curOffset, bindingAlignment);
1999
2000                                 blockLocations[blockNdx] = BlockLocation(0, curOffset, bufferSize);
2001                                 curOffset += bufferSize;
2002                         }
2003
2004                         const int                                               totalBufferSize = curOffset;
2005                         vk::Move<vk::VkBuffer>                  buffer                  = createBuffer(m_context, totalBufferSize, vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
2006                         de::MovePtr<vk::Allocation>             alloc                   = allocateAndBindMemory(m_context, *buffer, vk::MemoryRequirement::HostVisible);
2007
2008                         mapPtrs.push_back(alloc->getHostPtr());
2009
2010                         for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
2011                         {
2012                                 const deUint32                                          bufferSize      = bufferSizes[blockNdx];
2013                                 const deUint32                                          offset          = blockLocations[blockNdx].offset;
2014
2015                                 descriptors[blockNdx] = makeDescriptorBufferInfo(*buffer, offset, bufferSize);
2016                         }
2017
2018                         m_uniformBuffers.push_back(VkBufferSp(new vk::Unique<vk::VkBuffer>(buffer)));
2019                         m_uniformAllocs.push_back(AllocationSp(alloc.release()));
2020                 }
2021
2022                 // Update remaining bindings
2023                 {
2024                         int blockNdx = 0;
2025                         for (int bindingNdx = 0; bindingNdx < numBindings; ++bindingNdx)
2026                         {
2027                                 const BufferBlock&      block                           = m_interface.getBlock(bindingNdx);
2028                                 const int                       numBlocksInBinding      = (block.isArray() ? block.getArraySize() : 1);
2029
2030                                 setUpdateBuilder.writeArray(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(bindingNdx + 1),
2031                                         vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, numBlocksInBinding, &descriptors[blockNdx]);
2032
2033                                 blockNdx += numBlocksInBinding;
2034                         }
2035                 }
2036
2037                 // Copy the initial data to the storage buffers
2038                 {
2039                         mappedBlockPtrs = blockLocationsToPtrs(m_refLayout, blockLocations, mapPtrs);
2040                         copyData(m_refLayout, mappedBlockPtrs, m_refLayout, m_initialData.pointers);
2041
2042                         if (m_bufferMode == SSBOLayoutCase::BUFFERMODE_PER_BLOCK)
2043                         {
2044                                 DE_ASSERT(m_uniformAllocs.size() == bufferSizes.size());
2045                                 for (size_t allocNdx = 0; allocNdx < m_uniformAllocs.size(); allocNdx++)
2046                                 {
2047                                         const int size = bufferSizes[allocNdx];
2048                                         vk::Allocation* alloc = m_uniformAllocs[allocNdx].get();
2049                                         flushMappedMemoryRange(vk, device, alloc->getMemory(), alloc->getOffset(), size);
2050                                 }
2051                         }
2052                         else
2053                         {
2054                                 DE_ASSERT(m_bufferMode == SSBOLayoutCase::BUFFERMODE_SINGLE);
2055                                 DE_ASSERT(m_uniformAllocs.size() == 1);
2056                                 int totalSize = 0;
2057                                 for (size_t bufferNdx = 0; bufferNdx < bufferSizes.size(); bufferNdx++)
2058                                 {
2059                                         totalSize += bufferSizes[bufferNdx];
2060                                 }
2061
2062                                 DE_ASSERT(totalSize > 0);
2063                                 vk::Allocation* alloc = m_uniformAllocs[0].get();
2064                                 flushMappedMemoryRange(vk, device, alloc->getMemory(), alloc->getOffset(), totalSize);
2065                         }
2066                 }
2067         }
2068
2069         setUpdateBuilder.update(vk, device);
2070
2071         const vk::VkPipelineLayoutCreateInfo pipelineLayoutParams =
2072         {
2073                 vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,      // VkStructureType                              sType;
2074                 DE_NULL,                                                                                        // const void*                                  pNext;
2075                 (vk::VkPipelineLayoutCreateFlags)0,
2076                 1u,                                                                                                     // deUint32                                             descriptorSetCount;
2077                 &*descriptorSetLayout,                                                          // const VkDescriptorSetLayout* pSetLayouts;
2078                 0u,                                                                                                     // deUint32                                             pushConstantRangeCount;
2079                 DE_NULL,                                                                                        // const VkPushConstantRange*   pPushConstantRanges;
2080         };
2081         vk::Move<vk::VkPipelineLayout> pipelineLayout(createPipelineLayout(vk, device, &pipelineLayoutParams));
2082
2083         vk::Move<vk::VkShaderModule> shaderModule (createShaderModule(vk, device, m_context.getBinaryCollection().get("compute"), 0));
2084         const vk::VkPipelineShaderStageCreateInfo pipelineShaderStageParams =
2085         {
2086                 vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,// VkStructureType                              sType;
2087                 DE_NULL,                                                                                                // const void*                                  pNext;
2088                 (vk::VkPipelineShaderStageCreateFlags)0,
2089                 vk::VK_SHADER_STAGE_COMPUTE_BIT,                                                // VkShaderStage                                stage;
2090                 *shaderModule,                                                                                  // VkShader                                             shader;
2091                 "main",                                                                                                 //
2092                 DE_NULL,                                                                                                // const VkSpecializationInfo*  pSpecializationInfo;
2093         };
2094         const vk::VkComputePipelineCreateInfo pipelineCreateInfo =
2095         {
2096                 vk::VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,     // VkStructureType                                      sType;
2097                 DE_NULL,                                                                                        // const void*                                          pNext;
2098                 0,                                                                                                      // VkPipelineCreateFlags                        flags;
2099                 pipelineShaderStageParams,                                                      // VkPipelineShaderStageCreateInfo      stage;
2100                 *pipelineLayout,                                                                        // VkPipelineLayout                                     layout;
2101                 DE_NULL,                                                                                        // VkPipeline                                           basePipelineHandle;
2102                 0,                                                                                                      // deInt32                                                      basePipelineIndex;
2103         };
2104         vk::Move<vk::VkPipeline> pipeline(createComputePipeline(vk, device, DE_NULL, &pipelineCreateInfo));
2105
2106         vk::Move<vk::VkCommandPool> cmdPool (createCommandPool(vk, device, vk::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
2107         vk::Move<vk::VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
2108
2109         const vk::VkCommandBufferBeginInfo cmdBufBeginParams =
2110         {
2111                 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,        //      VkStructureType                         sType;
2112                 DE_NULL,                                                                                        //      const void*                                     pNext;
2113                 0u,                                                                                                     //      VkCmdBufferOptimizeFlags        flags;
2114                 (const vk::VkCommandBufferInheritanceInfo*)DE_NULL,
2115         };
2116         VK_CHECK(vk.beginCommandBuffer(*cmdBuffer, &cmdBufBeginParams));
2117
2118         vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
2119         vk.cmdBindDescriptorSets(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
2120
2121         vk.cmdDispatch(*cmdBuffer, 1, 1, 1);
2122
2123         // Add barriers for shader writes to storage buffers before host access
2124         std::vector<vk::VkBufferMemoryBarrier> barriers;
2125         if (m_bufferMode == SSBOLayoutCase::BUFFERMODE_PER_BLOCK)
2126         {
2127                 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
2128                 {
2129                         const vk::VkBuffer uniformBuffer = m_uniformBuffers[blockNdx].get()->get();
2130
2131                         const vk::VkBufferMemoryBarrier barrier =
2132                         {
2133                                 vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
2134                                 DE_NULL,
2135                                 vk::VK_ACCESS_SHADER_WRITE_BIT,
2136                                 vk::VK_ACCESS_HOST_READ_BIT,
2137                                 VK_QUEUE_FAMILY_IGNORED,
2138                                 VK_QUEUE_FAMILY_IGNORED,
2139                                 uniformBuffer,
2140                                 0u,
2141                                 static_cast<vk::VkDeviceSize>(bufferSizes[blockNdx])
2142                         };
2143                         barriers.push_back(barrier);
2144                 }
2145         }
2146         else
2147         {
2148                 const vk::VkBuffer uniformBuffer = m_uniformBuffers[0].get()->get();
2149
2150                 vk::VkDeviceSize totalSize      = 0;
2151                 for (size_t bufferNdx = 0; bufferNdx < bufferSizes.size(); bufferNdx++)
2152                         totalSize += bufferSizes[bufferNdx];
2153
2154                 const vk::VkBufferMemoryBarrier barrier =
2155                 {
2156                         vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
2157                         DE_NULL,
2158                         vk::VK_ACCESS_SHADER_WRITE_BIT,
2159                         vk::VK_ACCESS_HOST_READ_BIT,
2160                         VK_QUEUE_FAMILY_IGNORED,
2161                         VK_QUEUE_FAMILY_IGNORED,
2162                         uniformBuffer,
2163                         0u,
2164                         totalSize
2165                 };
2166                 barriers.push_back(barrier);
2167         }
2168         vk.cmdPipelineBarrier(*cmdBuffer, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, vk::VK_PIPELINE_STAGE_HOST_BIT, (vk::VkDependencyFlags)0,
2169                                                   0u, DE_NULL, static_cast<deUint32>(barriers.size()), &barriers[0], 0u, DE_NULL);
2170
2171         VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
2172
2173         vk::Move<vk::VkFence> fence (createFence(vk, device));
2174
2175         const vk::VkSubmitInfo  submitInfo  =
2176         {
2177                 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
2178                 DE_NULL,
2179                 0u,
2180                 (const vk::VkSemaphore*)DE_NULL,
2181                 (const vk::VkPipelineStageFlags*)DE_NULL,
2182                 1u,
2183                 &cmdBuffer.get(),
2184                 0u,
2185                 (const vk::VkSemaphore*)DE_NULL,
2186         };
2187
2188         VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfo, *fence));
2189         VK_CHECK(vk.waitForFences(device, 1u, &fence.get(), DE_TRUE, ~0ull));
2190
2191         // Read back ac_numPassed data
2192         bool counterOk;
2193         {
2194                 const int refCount = 1;
2195                 int resCount = 0;
2196
2197                 resCount = *(const int*)((const deUint8*)acBufferAlloc->getHostPtr());
2198
2199                 counterOk = (refCount == resCount);
2200                 if (!counterOk)
2201                 {
2202                         m_context.getTestContext().getLog() << TestLog::Message << "Error: ac_numPassed = " << resCount << ", expected " << refCount << TestLog::EndMessage;
2203                 }
2204         }
2205
2206         // Validate result
2207         const bool compareOk = compareData(m_context.getTestContext().getLog(), m_refLayout, m_writeData.pointers, m_refLayout, mappedBlockPtrs);
2208
2209         if (compareOk && counterOk)
2210                 return tcu::TestStatus::pass("Result comparison and counter values are OK");
2211         else if (!compareOk && counterOk)
2212                 return tcu::TestStatus::fail("Result comparison failed");
2213         else if (compareOk && !counterOk)
2214                 return tcu::TestStatus::fail("Counter value incorrect");
2215         else
2216                 return tcu::TestStatus::fail("Result comparison and counter values are incorrect");
2217 }
2218
2219 // SSBOLayoutCase.
2220
2221 SSBOLayoutCase::SSBOLayoutCase (tcu::TestContext& testCtx, const char* name, const char* description, BufferMode bufferMode, MatrixLoadFlags matrixLoadFlag)
2222         : TestCase                      (testCtx, name, description)
2223         , m_bufferMode          (bufferMode)
2224         , m_matrixLoadFlag      (matrixLoadFlag)
2225 {
2226 }
2227
2228 SSBOLayoutCase::~SSBOLayoutCase (void)
2229 {
2230 }
2231
2232 void SSBOLayoutCase::initPrograms (vk::SourceCollections& programCollection) const
2233 {
2234         DE_ASSERT(!m_computeShaderSrc.empty());
2235
2236         programCollection.glslSources.add("compute") << glu::ComputeSource(m_computeShaderSrc);
2237 }
2238
2239 TestInstance* SSBOLayoutCase::createInstance (Context& context) const
2240 {
2241         return new SSBOLayoutCaseInstance(context, m_bufferMode, m_interface, m_refLayout, m_initialData, m_writeData);
2242 }
2243
2244 void SSBOLayoutCase::init ()
2245 {
2246         computeReferenceLayout  (m_refLayout, m_interface);
2247         initRefDataStorage              (m_interface, m_refLayout, m_initialData);
2248         initRefDataStorage              (m_interface, m_refLayout, m_writeData);
2249         generateValues                  (m_refLayout, m_initialData.pointers, deStringHash(getName()) ^ 0xad2f7214);
2250         generateValues                  (m_refLayout, m_writeData.pointers, deStringHash(getName()) ^ 0x25ca4e7);
2251         copyNonWrittenData              (m_interface, m_refLayout, m_initialData.pointers, m_writeData.pointers);
2252
2253         m_computeShaderSrc = generateComputeShader(m_interface, m_refLayout, m_initialData.pointers, m_writeData.pointers, m_matrixLoadFlag);
2254
2255 }
2256
2257 } // ssbo
2258 } // vkt