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