ad70d7186ec40b3019e98549c6497d9a9c4542b3
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / transform_feedback / vktTransformFeedbackFuzzLayoutCase.cpp
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2015 The Khronos Group Inc.
6  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
7  * Copyright (c) 2016 The Android Open Source Project
8  * Copyright (c) 2018 The Khronos Group Inc.
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  *//*!
23  * \file
24  * \brief Vulkan Transform Feedback Fuzz Layout Tests
25  *//*--------------------------------------------------------------------*/
26
27 #include "vktTransformFeedbackFuzzLayoutCase.hpp"
28
29 #include "vkPrograms.hpp"
30
31 #include "gluVarType.hpp"
32 #include "tcuTestLog.hpp"
33 #include "tcuSurface.hpp"
34 #include "deRandom.hpp"
35 #include "deStringUtil.hpp"
36
37 #include "tcuTextureUtil.hpp"
38 #include "deSharedPtr.hpp"
39 #include "deFloat16.h"
40
41 #include "vkMemUtil.hpp"
42 #include "vkQueryUtil.hpp"
43 #include "vkTypeUtil.hpp"
44 #include "vkRef.hpp"
45 #include "vkRefUtil.hpp"
46 #include "vkBuilderUtil.hpp"
47 #include "vkCmdUtil.hpp"
48 #include "vkObjUtil.hpp"
49
50 #include <map>
51 #include <set>
52 #include <vector>
53 #include <iostream>
54 #include <iomanip>
55
56 namespace vkt
57 {
58 namespace TransformFeedback
59 {
60
61 using namespace vk;
62
63 typedef std::map<int, int> BufferGeneralMapping;
64
65 typedef std::pair<int, int>                             UsedRange;
66 typedef std::vector<UsedRange>                  UsedRangeList;
67 typedef std::map<int, UsedRangeList>    BufferUsedRangesMap;
68
69 // VarType implementation.
70
71 VarType::VarType (void)
72         : m_type        (TYPE_LAST)
73         , m_flags       (0)
74 {
75 }
76
77 VarType::VarType (const VarType& other)
78         : m_type        (TYPE_LAST)
79         , m_flags       (0)
80 {
81         *this = other;
82 }
83
84 VarType::VarType (glu::DataType basicType, deUint32 flags)
85         : m_type        (TYPE_BASIC)
86         , m_flags       (flags)
87 {
88         m_data.basicType = basicType;
89 }
90
91 VarType::VarType (const VarType& elementType, int arraySize)
92         : m_type        (TYPE_ARRAY)
93         , m_flags       (0)
94 {
95         m_data.array.size                       = arraySize;
96         m_data.array.elementType        = new VarType(elementType);
97 }
98
99 VarType::VarType (const StructType* structPtr, deUint32 flags)
100         : m_type        (TYPE_STRUCT)
101         , m_flags       (flags)
102 {
103         m_data.structPtr = structPtr;
104 }
105
106 VarType::~VarType (void)
107 {
108         if (m_type == TYPE_ARRAY)
109                 delete m_data.array.elementType;
110 }
111
112 VarType& VarType::operator= (const VarType& other)
113 {
114         if (this == &other)
115                 return *this; // Self-assignment.
116
117         VarType *oldElementType = m_type == TYPE_ARRAY ? m_data.array.elementType : DE_NULL;
118
119         m_type  = other.m_type;
120         m_flags = other.m_flags;
121         m_data  = Data();
122
123         if (m_type == TYPE_ARRAY)
124         {
125                 m_data.array.elementType        = new VarType(*other.m_data.array.elementType);
126                 m_data.array.size                       = other.m_data.array.size;
127         }
128         else
129                 m_data = other.m_data;
130
131         delete oldElementType;
132
133         return *this;
134 }
135
136 // StructType implementation.
137 void StructType::addMember (const std::string& name, const VarType& type, deUint32 flags)
138 {
139         m_members.push_back(StructMember(name, type, flags));
140 }
141
142 // InterfaceBlockMember implementation.
143 InterfaceBlockMember::InterfaceBlockMember (const std::string& name, const VarType& type, deUint32 flags)
144         : m_name        (name)
145         , m_type        (type)
146         , m_flags       (flags)
147 {
148 }
149
150 // InterfaceBlock implementation.
151 InterfaceBlock::InterfaceBlock (const std::string& blockName)
152         : m_blockName   (blockName)
153         , m_xfbBuffer   (0)
154         , m_arraySize   (0)
155         , m_flags               (0)
156 {
157 }
158
159 std::ostream& operator<< (std::ostream& stream, const BlockLayoutEntry& entry)
160 {
161         stream << entry.name << " { name = " << entry.name
162                    << ", buffer = " << entry.xfbBuffer
163                    << ", offset = " << entry.xfbOffset
164                    << ", size = " << entry.xfbSize
165                    << ", blockDeclarationNdx = " << entry.blockDeclarationNdx
166                    << ", instanceNdx = " << entry.instanceNdx
167                    << ", activeInterfaceIndices = [";
168
169         for (std::vector<int>::const_iterator i = entry.activeInterfaceIndices.begin(); i != entry.activeInterfaceIndices.end(); i++)
170         {
171                 if (i != entry.activeInterfaceIndices.begin())
172                         stream << ", ";
173                 stream << *i;
174         }
175
176         stream << "] }";
177         return stream;
178 }
179
180 std::ostream& operator<< (std::ostream& stream, const InterfaceLayoutEntry& entry)
181 {
182         stream << entry.name << " { type = " << glu::getDataTypeName(entry.type)
183                    << ", arraySize = " << entry.arraySize
184                    << ", blockNdx = " << entry.blockLayoutNdx
185                    << ", offset = " << entry.offset
186                    << ", arrayStride = " << entry.arrayStride
187                    << ", matrixStride = " << entry.matrixStride
188                    << " }";
189
190         return stream;
191 }
192
193 std::ostream& operator<< (std::ostream& str, const InterfaceLayout& layout)
194 {
195         const int       numBlocks       = (int)layout.blocks.size();
196
197         str << "Blocks:" << std::endl;
198         for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
199                 str << layout.blocks[blockNdx] << std::endl;
200         str << std::endl;
201
202         str << "Interfaces:" << std::endl;
203         for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
204         {
205                 int             numEntries      = (int)layout.blocks[blockNdx].activeInterfaceIndices.size();
206
207                 for (int entryNdx = 0; entryNdx < numEntries; entryNdx++)
208                 {
209                         const InterfaceLayoutEntry&     entry   = layout.interfaces[layout.blocks[blockNdx].activeInterfaceIndices[entryNdx]];
210
211                         str << blockNdx << ":" << entryNdx << " " << entry << std::endl;
212                 }
213         }
214         str << std::endl;
215
216         return str;
217 }
218
219 int InterfaceLayout::getInterfaceLayoutIndex (int blockNdx, const std::string& name) const
220 {
221         for (int ndx = 0; ndx < (int)interfaces.size(); ndx++)
222         {
223                 if (blocks[interfaces[ndx].blockLayoutNdx].blockDeclarationNdx == blockNdx && interfaces[ndx].name == name)
224                         return ndx;
225         }
226
227         return -1;
228 }
229
230 int InterfaceLayout::getBlockLayoutIndex (int blockNdx, int instanceNdx) const
231 {
232         for (int ndx = 0; ndx < (int)blocks.size(); ndx++)
233         {
234                 if (blocks[ndx].blockDeclarationNdx == blockNdx && blocks[ndx].instanceNdx == instanceNdx)
235                         return ndx;
236         }
237
238         return -1;
239 }
240
241 // ShaderInterface implementation.
242
243 ShaderInterface::ShaderInterface (void)
244 {
245 }
246
247 ShaderInterface::~ShaderInterface (void)
248 {
249 }
250
251 StructType& ShaderInterface::allocStruct (const std::string& name)
252 {
253         m_structs.push_back(StructTypeSP(new StructType(name)));
254         return *m_structs.back();
255 }
256
257 struct StructNameEquals
258 {
259         std::string name;
260
261         StructNameEquals (const std::string& name_) : name(name_) {}
262
263         bool operator() (const StructTypeSP type) const
264         {
265                 return type->hasTypeName() && name == type->getTypeName();
266         }
267 };
268
269 void ShaderInterface::getNamedStructs (std::vector<const StructType*>& structs) const
270 {
271         for (std::vector<StructTypeSP>::const_iterator i = m_structs.begin(); i != m_structs.end(); i++)
272         {
273                 if ((*i)->hasTypeName())
274                         structs.push_back((*i).get());
275         }
276 }
277
278 InterfaceBlock& ShaderInterface::allocBlock (const std::string& name)
279 {
280         m_interfaceBlocks.push_back(InterfaceBlockSP(new InterfaceBlock(name)));
281
282         return *m_interfaceBlocks.back();
283 }
284
285 namespace // Utilities
286 {
287
288 struct PrecisionFlagsFmt
289 {
290         deUint32 flags;
291         PrecisionFlagsFmt (deUint32 flags_) : flags(flags_) {}
292 };
293
294 void dumpBytes (std::ostream& str, const std::string& msg, const void* dataBytes, size_t size, const void* dataMask = DE_NULL)
295 {
296         const deUint8*          data    = (const deUint8*)dataBytes;
297         const deUint8*          mask    = (const deUint8*)dataMask;
298         std::ios::fmtflags      flags;
299
300         str << msg;
301
302         flags = str.flags ( std::ios::hex | std::ios::uppercase );
303         {
304                 for (size_t i = 0; i < size; i++)
305                 {
306                         if (i%16 == 0) str << std::endl << std::setfill('0') << std::setw(8) << i << ":";
307                         else if (i%8 == 0) str << "  ";
308                         else if (i%4 == 0) str << " ";
309
310                         str << " " << std::setfill('0') << std::setw(2);
311
312                         if (mask == DE_NULL || mask[i] != 0)
313                                 str << (deUint32)data[i];
314                         else
315                                 str << "__";
316                 }
317                 str << std::endl << std::endl;
318         }
319         str.flags ( flags );
320 }
321
322 std::ostream& operator<< (std::ostream& str, const PrecisionFlagsFmt& fmt)
323 {
324         // Precision.
325         DE_ASSERT(dePop32(fmt.flags & (PRECISION_LOW|PRECISION_MEDIUM|PRECISION_HIGH)) <= 1);
326         str << (fmt.flags & PRECISION_LOW               ? "lowp"        :
327                         fmt.flags & PRECISION_MEDIUM    ? "mediump"     :
328                         fmt.flags & PRECISION_HIGH              ? "highp"       : "");
329         return str;
330 }
331
332 struct LayoutFlagsFmt
333 {
334         deUint32 flags;
335         deUint32 buffer;
336         deUint32 stride;
337         deUint32 offset;
338
339         LayoutFlagsFmt  (const deUint32 flags_,
340                                          const deUint32 buffer_,
341                                          const deUint32 stride_,
342                                          const deUint32 offset_)
343                 : flags         (flags_)
344                 , buffer        (buffer_)
345                 , stride        (stride_)
346                 , offset        (offset_)
347         {
348         }
349 };
350
351 std::ostream& operator<< (std::ostream& str, const LayoutFlagsFmt& fmt)
352 {
353         static const struct
354         {
355                 deUint32        bit;
356                 const char*     token;
357         } bitDesc[] =
358         {
359                 { LAYOUT_XFBBUFFER,     "xfb_buffer"    },
360                 { LAYOUT_XFBOFFSET,     "xfb_offset"    },
361                 { LAYOUT_XFBSTRIDE,     "xfb_stride"    },
362         };
363
364         deUint32 remBits = fmt.flags;
365         for (int descNdx = 0; descNdx < DE_LENGTH_OF_ARRAY(bitDesc); descNdx++)
366         {
367                 if (remBits & bitDesc[descNdx].bit)
368                 {
369                         str << bitDesc[descNdx].token;
370
371                         if (bitDesc[descNdx].bit == LAYOUT_XFBBUFFER) str << " = " << fmt.buffer;
372                         if (bitDesc[descNdx].bit == LAYOUT_XFBOFFSET) str << " = " << fmt.offset;
373                         if (bitDesc[descNdx].bit == LAYOUT_XFBSTRIDE) str << " = " << fmt.stride;
374
375                         remBits &= ~bitDesc[descNdx].bit;
376
377                         if (remBits != 0)
378                                 str << ", ";
379                 }
380         }
381         DE_ASSERT(remBits == 0);
382         return str;
383 }
384
385 std::ostream& operator<< (std::ostream& str, const DeviceSizeVector& vec)
386 {
387         str << " [";
388
389         for (size_t vecNdx = 0; vecNdx < vec.size(); vecNdx++)
390                 str << (deUint64)vec[vecNdx] << (vecNdx + 1 < vec.size() ? ", " : "]");
391
392         return str;
393 }
394
395 // Layout computation.
396
397 int getDataTypeByteSize (glu::DataType type)
398 {
399         if (getDataTypeScalarType(type) == glu::TYPE_DOUBLE)
400         {
401                 return glu::getDataTypeScalarSize(type)*(int)sizeof(deUint64);
402         }
403         else
404         {
405                 return glu::getDataTypeScalarSize(type)*(int)sizeof(deUint32);
406         }
407 }
408
409 int getDataTypeArrayStride (glu::DataType type)
410 {
411         DE_ASSERT(!glu::isDataTypeMatrix(type));
412
413         return getDataTypeByteSize(type);
414 }
415
416 int getDataTypeArrayStrideForLocation (glu::DataType type)
417 {
418         DE_ASSERT(!glu::isDataTypeMatrix(type));
419
420         const int baseStride    = getDataTypeByteSize(type);
421         const int vec4Alignment = (int)sizeof(deUint32) * 4;
422
423         return deAlign32(baseStride, vec4Alignment);
424 }
425
426 int computeInterfaceBlockMemberAlignment (const VarType& type)
427 {
428         if (type.isBasicType())
429         {
430                 glu::DataType basicType = type.getBasicType();
431
432                 if (glu::isDataTypeMatrix(basicType) || isDataTypeVector(basicType))
433                         basicType = glu::getDataTypeScalarType(basicType);
434
435                 switch (basicType)
436                 {
437                         case glu::TYPE_FLOAT:
438                         case glu::TYPE_INT:
439                         case glu::TYPE_UINT:    return sizeof(deUint32);
440                         case glu::TYPE_DOUBLE:  return sizeof(deUint64);
441                         default:                                TCU_THROW(InternalError, "Invalid type");
442                 }
443         }
444         else if (type.isArrayType())
445         {
446                 return computeInterfaceBlockMemberAlignment(type.getElementType());
447         }
448         else if (type.isStructType())
449         {
450                 int maxAlignment = 0;
451
452                 for (StructType::ConstIterator memberIter = type.getStruct().begin(); memberIter != type.getStruct().end(); memberIter++)
453                         maxAlignment = de::max(maxAlignment, computeInterfaceBlockMemberAlignment(memberIter->getType()));
454
455                 return maxAlignment;
456         }
457         else
458                 TCU_THROW(InternalError, "Invalid type");
459 }
460
461 void createMask (void* maskBasePtr, const InterfaceLayoutEntry& entry, const void* basePtr0, const void* basePtr)
462 {
463         const glu::DataType     scalarType      = glu::getDataTypeScalarType(entry.type);
464         const int                       scalarSize      = glu::getDataTypeScalarSize(entry.type);
465         const bool                      isMatrix        = glu::isDataTypeMatrix(entry.type);
466         const int                       numVecs         = isMatrix ? glu::getDataTypeMatrixNumColumns(entry.type) : 1;
467         const int                       vecSize         = scalarSize / numVecs;
468         const bool                      isArray         = entry.arraySize > 1;
469         const size_t            compSize        = getDataTypeByteSize(scalarType);
470
471         DE_ASSERT(scalarSize%numVecs == 0);
472
473         for (int elemNdx = 0; elemNdx < entry.arraySize; elemNdx++)
474         {
475                 deUint8* elemPtr = (deUint8*)basePtr + entry.offset + (isArray ? elemNdx*entry.arrayStride : 0);
476
477                 for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
478                 {
479                         deUint8* vecPtr = elemPtr + (isMatrix ? vecNdx*entry.matrixStride : 0);
480
481                         for (int compNdx = 0; compNdx < vecSize; compNdx++)
482                         {
483                                 const deUint8*  compPtr         = vecPtr + compSize*compNdx;
484                                 const size_t    offset          = compPtr - (deUint8*)basePtr0;
485                                 deUint8*                maskPtr         = (deUint8*)maskBasePtr + offset;
486
487                                 switch (scalarType)
488                                 {
489                                         case glu::TYPE_DOUBLE:
490                                         case glu::TYPE_FLOAT:
491                                         case glu::TYPE_INT:
492                                         case glu::TYPE_UINT:
493                                         {
494                                                 for (size_t ndx = 0; ndx < compSize; ++ndx)
495                                                         ++maskPtr[ndx];
496
497                                                 break;
498                                         }
499                                         default:
500                                                 DE_ASSERT(false);
501                                 }
502                         }
503                 }
504         }
505 }
506
507 std::vector<deUint8> createMask (const InterfaceLayout& layout, const std::map<int, void*>& blockPointers, const void* basePtr0, const size_t baseSize)
508 {
509         std::vector<deUint8>    mask            (baseSize, 0);
510         const int                               numBlocks       ((int)layout.blocks.size());
511
512         for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
513         {
514                 void*   basePtr         = blockPointers.find(blockNdx)->second;
515                 int             numEntries      = (int)layout.blocks[blockNdx].activeInterfaceIndices.size();
516
517                 for (int entryNdx = 0; entryNdx < numEntries; entryNdx++)
518                 {
519                         const InterfaceLayoutEntry&     entry   = layout.interfaces[layout.blocks[blockNdx].activeInterfaceIndices[entryNdx]];
520
521                         if (entry.validate)
522                                 createMask (&mask[0], entry, basePtr0, basePtr);
523                 }
524         }
525
526         return mask;
527 }
528
529 int computeInterfaceBlockAlignment(const InterfaceBlock& interfaceBlock)
530 {
531         int baseAlignment = 0;
532
533         for (InterfaceBlock::ConstIterator memberIter = interfaceBlock.begin(); memberIter != interfaceBlock.end(); memberIter++)
534         {
535                 const InterfaceBlockMember& member = *memberIter;
536
537                 baseAlignment = std::max(baseAlignment, computeInterfaceBlockMemberAlignment(member.getType()));
538         }
539
540         return baseAlignment;
541 }
542
543 static inline bool isOverlaped(const int a1, const int b1, const int a2, const int b2)
544 {
545         DE_ASSERT(b1 > 0 && b2 > 0);
546
547         const int b1s = b1 - 1;
548         const int b2s = b2 - 1;
549
550         return  deInRange32(a1,  a2, b2s) ||
551                         deInRange32(b1s, a2, b2s) ||
552                         deInRange32(a2,  a1, b1s) ||
553                         deInRange32(b2s, a1, b1s);
554 }
555
556 void computeXfbLayout (InterfaceLayout& layout, int& curOffset, int& curLocation, int curBlockNdx, const std::string& curPrefix, const VarType& type, deUint32 layoutFlags)
557 {
558         const int       locationAlignSize       = 16;
559         const bool      validate                        = 0 == (layoutFlags & (FIELD_MISSING|FIELD_UNASSIGNED));
560         int                     baseAlignment           = computeInterfaceBlockMemberAlignment(type);
561
562         DE_ASSERT(baseAlignment == sizeof(deUint32) || baseAlignment == sizeof(deUint64));
563
564         curOffset = deAlign32(curOffset, baseAlignment);
565
566         if (type.isBasicType())
567         {
568                 const glu::DataType             basicType                               = type.getBasicType();
569                 int                                             fieldSize                               = 0;
570                 int                                             fieldSizeForLocation    = 0;
571                 InterfaceLayoutEntry    entry;
572
573                 entry.name                              = curPrefix;
574                 entry.type                              = basicType;
575                 entry.arraySize                 = 1;
576                 entry.arrayStride               = 0;
577                 entry.matrixStride              = 0;
578                 entry.blockLayoutNdx    = curBlockNdx;
579                 entry.locationNdx               = 0;
580                 entry.validate                  = validate;
581
582                 if (glu::isDataTypeMatrix(basicType))
583                 {
584                         // Array of vectors
585                         const int                               vecSize                         = glu::getDataTypeMatrixNumRows(basicType);
586                         const int                               numVecs                         = glu::getDataTypeMatrixNumColumns(basicType);
587                         const glu::DataType             elemType                        = glu::getDataTypeScalarType(basicType);
588                         const int                               stride                          = getDataTypeArrayStride(glu::getDataTypeVector(elemType, vecSize));
589                         const int                               strideForLocation       = getDataTypeArrayStrideForLocation(glu::getDataTypeVector(elemType, vecSize));
590
591                         entry.matrixStride              = stride;
592
593                         fieldSize                               = numVecs * stride;
594                         fieldSizeForLocation    = numVecs * strideForLocation;
595                 }
596                 else
597                 {
598                         // Scalar or vector.
599                         fieldSize                               = getDataTypeByteSize(basicType);
600                         fieldSizeForLocation    = deAlign32(fieldSize, locationAlignSize);
601                 }
602
603                 entry.offset            = curOffset;
604                 entry.locationNdx       = curLocation;
605
606                 curOffset += fieldSize;
607                 curLocation += deDivRoundUp32(fieldSizeForLocation, locationAlignSize);
608
609                 layout.interfaces.push_back(entry);
610         }
611         else if (type.isArrayType())
612         {
613                 const VarType&  elemType        = type.getElementType();
614
615                 if (elemType.isBasicType() && !glu::isDataTypeMatrix(elemType.getBasicType()))
616                 {
617                         // Array of scalars or vectors.
618                         const glu::DataType             elemBasicType                   = elemType.getBasicType();
619                         const int                               stride                                  = getDataTypeArrayStride(elemBasicType);
620                         const int                               fieldSize                               = stride * type.getArraySize();
621                         const int                               strideForLocation               = getDataTypeArrayStrideForLocation(elemBasicType);
622                         const int                               fieldSizeForLocation    = strideForLocation * type.getArraySize();
623                         InterfaceLayoutEntry    entry;
624
625                         entry.name                              = curPrefix + "[0]"; // Array interfaces are always postfixed with [0]
626                         entry.type                              = elemBasicType;
627                         entry.blockLayoutNdx    = curBlockNdx;
628                         entry.offset                    = curOffset;
629                         entry.arraySize                 = type.getArraySize();
630                         entry.arrayStride               = stride;
631                         entry.matrixStride              = 0;
632                         entry.locationNdx               = curLocation;
633                         entry.validate                  = validate;
634
635                         curOffset += fieldSize;
636                         curLocation += deDivRoundUp32(fieldSizeForLocation, locationAlignSize);
637
638                         layout.interfaces.push_back(entry);
639                 }
640                 else if (elemType.isBasicType() && glu::isDataTypeMatrix(elemType.getBasicType()))
641                 {
642                         // Array of matrices.
643                         const glu::DataType             elemBasicType                   = elemType.getBasicType();
644                         const glu::DataType             scalarType                              = glu::getDataTypeScalarType(elemBasicType);
645                         const int                               vecSize                                 = glu::getDataTypeMatrixNumRows(elemBasicType);
646                         const int                               numVecs                                 = glu::getDataTypeMatrixNumColumns(elemBasicType);
647                         const int                               stride                                  = getDataTypeArrayStride(glu::getDataTypeVector(scalarType, vecSize));
648                         const int                               fieldSize                               = numVecs * type.getArraySize() * stride;
649                         const int                               strideForLocation               = getDataTypeArrayStrideForLocation(glu::getDataTypeVector(scalarType, vecSize));
650                         const int                               fieldSizeForLocation    = numVecs * type.getArraySize() * strideForLocation;
651                         InterfaceLayoutEntry    entry;
652
653                         entry.name                              = curPrefix + "[0]"; // Array interfaces are always postfixed with [0]
654                         entry.type                              = elemBasicType;
655                         entry.blockLayoutNdx    = curBlockNdx;
656                         entry.offset                    = curOffset;
657                         entry.arraySize                 = type.getArraySize();
658                         entry.arrayStride               = stride*numVecs;
659                         entry.matrixStride              = stride;
660                         entry.locationNdx               = curLocation;
661                         entry.validate                  = validate;
662
663                         curOffset += fieldSize;
664                         curLocation += deDivRoundUp32(fieldSizeForLocation, locationAlignSize);
665
666                         layout.interfaces.push_back(entry);
667                 }
668                 else
669                 {
670                         DE_ASSERT(elemType.isStructType() || elemType.isArrayType());
671
672                         for (int elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++)
673                                 computeXfbLayout(layout, curOffset, curLocation, curBlockNdx, curPrefix + "[" + de::toString(elemNdx) + "]", type.getElementType(), layoutFlags);
674                 }
675         }
676         else
677         {
678                 DE_ASSERT(type.isStructType());
679
680                 for (StructType::ConstIterator memberIter = type.getStruct().begin(); memberIter != type.getStruct().end(); memberIter++)
681                         computeXfbLayout(layout, curOffset, curLocation, curBlockNdx, curPrefix + "." + memberIter->getName(), memberIter->getType(), (memberIter->getFlags() | layoutFlags) & FIELD_OPTIONS);
682
683                 curOffset = deAlign32(curOffset, baseAlignment);
684         }
685 }
686
687 void computeXfbLayout (InterfaceLayout& layout, ShaderInterface& shaderInterface, BufferGeneralMapping& perBufferXfbOffsets, deUint32& locationsUsed)
688 {
689         const int                               numInterfaceBlocks      = shaderInterface.getNumInterfaceBlocks();
690         int                                             curLocation                     = 0;
691         BufferGeneralMapping    bufferAlignments;
692         BufferGeneralMapping    buffersList;
693         BufferGeneralMapping    bufferStrideGroup;
694         BufferUsedRangesMap             bufferUsedRanges;
695
696         for (int blockNdx = 0; blockNdx < numInterfaceBlocks; blockNdx++)
697         {
698                 const InterfaceBlock&   interfaceBlock  = shaderInterface.getInterfaceBlock(blockNdx);
699                 const int                               xfbBuffer               = interfaceBlock.getXfbBuffer();
700
701                 buffersList[xfbBuffer] = 1;
702                 bufferStrideGroup[xfbBuffer] = xfbBuffer;
703         }
704
705         for (BufferGeneralMapping::const_iterator xfbBuffersIter = buffersList.begin(); xfbBuffersIter != buffersList.end(); xfbBuffersIter++)
706         {
707                 const int       xfbBufferAnalyzed       = xfbBuffersIter->first;
708
709                 for (int blockNdx = 0; blockNdx < numInterfaceBlocks; blockNdx++)
710                 {
711                         InterfaceBlock& interfaceBlock  = shaderInterface.getInterfaceBlockForModify(blockNdx);
712
713                         if (interfaceBlock.getXfbBuffer() == xfbBufferAnalyzed)
714                         {
715                                 const bool                      hasInstanceName         = interfaceBlock.hasInstanceName();
716                                 const std::string       blockPrefix                     = hasInstanceName ? (interfaceBlock.getBlockName() + ".") : "";
717                                 const int                       numInstances            = interfaceBlock.isArray() ? interfaceBlock.getArraySize() : 1;
718                                 int                                     activeBlockNdx          = (int)layout.blocks.size();
719                                 int                                     startInterfaceNdx       = (int)layout.interfaces.size();
720                                 int                                     startLocationNdx        = (int)curLocation;
721                                 int                                     interfaceAlignement     = computeInterfaceBlockAlignment(interfaceBlock);
722                                 int                                     curOffset                       = 0;
723                                 int                                     blockSize                       = 0;
724
725                                 do
726                                 {
727                                         const int               xfbFirstInstanceBuffer                  = interfaceBlock.getXfbBuffer();
728                                         int&                    xfbFirstInstanceBufferOffset    = perBufferXfbOffsets[xfbFirstInstanceBuffer];
729                                         const int               savedLayoutInterfacesNdx                = (int)layout.interfaces.size();
730                                         const int               savedCurOffset                                  = curOffset;
731                                         const int               savedCurLocation                                = curLocation;
732                                         UsedRangeList&  usedRanges                                              = bufferUsedRanges[xfbFirstInstanceBuffer];
733                                         bool                    fitIntoBuffer                                   = true;
734
735                                         // GLSL 4.60
736                                         // Further, if applied to an aggregate containing a double, the offset must also be a multiple of 8,
737                                         // and the space taken in the buffer will be a multiple of 8.
738                                         xfbFirstInstanceBufferOffset    = deAlign32(xfbFirstInstanceBufferOffset, interfaceAlignement);
739
740                                         for (InterfaceBlock::ConstIterator memberIter = interfaceBlock.begin(); memberIter != interfaceBlock.end(); memberIter++)
741                                         {
742                                                 const InterfaceBlockMember& member      = *memberIter;
743
744                                                 computeXfbLayout(layout, curOffset, curLocation, activeBlockNdx, blockPrefix + member.getName(), member.getType(), member.getFlags() & FIELD_OPTIONS);
745                                         }
746
747                                         // GLSL 4.60
748                                         // Further, if applied to an aggregate containing a double, the offset must also be a multiple of 8,
749                                         // and the space taken in the buffer will be a multiple of 8.
750                                         blockSize       = deAlign32(curOffset, interfaceAlignement);
751
752                                         // Overlapping check
753                                         for (UsedRangeList::const_iterator      usedRangeIt = usedRanges.begin();
754                                                                                                                 usedRangeIt != usedRanges.end();
755                                                                                                                 ++usedRangeIt)
756                                         {
757                                                 const int&      usedRangeStart  = usedRangeIt->first;
758                                                 const int&      usedRangeEnd    = usedRangeIt->second;
759                                                 const int       genRangeStart   = xfbFirstInstanceBufferOffset;
760                                                 const int       genRangeEnd             = xfbFirstInstanceBufferOffset + blockSize;
761
762                                                 // Validate if block has overlapping
763                                                 if (isOverlaped(genRangeStart, genRangeEnd, usedRangeStart, usedRangeEnd))
764                                                 {
765                                                         // Restart from obstacle interface end
766                                                         fitIntoBuffer                                   = false;
767
768                                                         DE_ASSERT(xfbFirstInstanceBufferOffset > usedRangeEnd);
769
770                                                         // Bump up interface start to the end of used range
771                                                         xfbFirstInstanceBufferOffset    = usedRangeEnd;
772
773                                                         // Undo allocation
774                                                         curOffset                                               = savedCurOffset;
775                                                         curLocation                                             = savedCurLocation;
776
777                                                         layout.interfaces.resize(savedLayoutInterfacesNdx);
778                                                 }
779                                         }
780
781                                         if (fitIntoBuffer)
782                                                 break;
783                                 } while (true);
784
785                                 const int       xfbFirstInstanceBuffer                  = interfaceBlock.getXfbBuffer();
786                                 const int       xfbFirstInstanceBufferOffset    = perBufferXfbOffsets[xfbFirstInstanceBuffer];
787                                 const int       endInterfaceNdx                                 = (int)layout.interfaces.size();
788                                 const int       blockSizeInLocations                    = curLocation - startLocationNdx;
789
790                                 curLocation -= blockSizeInLocations;
791
792                                 if (numInstances > 1)
793                                         interfaceBlock.setFlag(LAYOUT_XFBSTRIDE);
794
795                                 // Create block layout entries for each instance.
796                                 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
797                                 {
798                                         // Allocate entry for instance.
799                                         layout.blocks.push_back(BlockLayoutEntry());
800
801                                         BlockLayoutEntry&       blockEntry              = layout.blocks.back();
802                                         const int                       xfbBuffer               = xfbFirstInstanceBuffer + instanceNdx;
803                                         int&                            xfbBufferOffset = perBufferXfbOffsets[xfbBuffer];
804
805                                         DE_ASSERT(xfbBufferOffset <= xfbFirstInstanceBufferOffset);
806
807                                         xfbBufferOffset                                 = xfbFirstInstanceBufferOffset;
808
809                                         blockEntry.name                                 = interfaceBlock.getBlockName();
810                                         blockEntry.xfbBuffer                    = xfbBuffer;
811                                         blockEntry.xfbOffset                    = xfbBufferOffset;
812                                         blockEntry.xfbSize                              = blockSize;
813                                         blockEntry.blockDeclarationNdx  = blockNdx;
814                                         blockEntry.instanceNdx                  = instanceNdx;
815                                         blockEntry.locationNdx                  = curLocation;
816                                         blockEntry.locationSize                 = blockSizeInLocations;
817
818                                         xfbBufferOffset += blockSize;
819                                         curLocation             += blockSizeInLocations;
820
821                                         // Compute active interface set for block.
822                                         for (int interfaceNdx = startInterfaceNdx; interfaceNdx < endInterfaceNdx; interfaceNdx++)
823                                                 blockEntry.activeInterfaceIndices.push_back(interfaceNdx);
824
825                                         if (interfaceBlock.isArray())
826                                                 blockEntry.name += "[" + de::toString(instanceNdx) + "]";
827
828                                         bufferUsedRanges[xfbBuffer].push_back(UsedRange(blockEntry.xfbOffset, blockEntry.xfbOffset + blockEntry.xfbSize));
829
830                                         // Store maximum per-buffer alignment
831                                         bufferAlignments[xfbBuffer] = std::max(interfaceAlignement, bufferAlignments[xfbBuffer]);
832
833                                         // Buffers bound through instanced arrays must have same stride (and alignment)
834                                         bufferStrideGroup[xfbBuffer] = bufferStrideGroup[xfbFirstInstanceBuffer];
835                                 }
836                         }
837                 }
838         }
839
840         // All XFB buffers within group must have same stride
841         {
842                 BufferGeneralMapping groupStride;
843
844                 for (BufferGeneralMapping::const_iterator xfbBuffersIter = perBufferXfbOffsets.begin(); xfbBuffersIter != perBufferXfbOffsets.end(); xfbBuffersIter++)
845                 {
846                         const int       xfbBuffer       = xfbBuffersIter->first;
847                         const int       xfbStride       = perBufferXfbOffsets[xfbBuffer];
848                         const int       group           = bufferStrideGroup[xfbBuffer];
849
850                         groupStride[group] = std::max(groupStride[group], xfbStride);
851                 }
852
853                 for (BufferGeneralMapping::const_iterator xfbBuffersIter = perBufferXfbOffsets.begin(); xfbBuffersIter != perBufferXfbOffsets.end(); xfbBuffersIter++)
854                 {
855                         const int       xfbBuffer       = xfbBuffersIter->first;
856                         const int       group           = bufferStrideGroup[xfbBuffer];
857
858                         perBufferXfbOffsets[xfbBuffer] = groupStride[group];
859                 }
860         }
861
862         // All XFB buffers within group must have same stride alignment
863         {
864                 BufferGeneralMapping groupAlignment;
865
866                 for (BufferGeneralMapping::const_iterator xfbBuffersIter = perBufferXfbOffsets.begin(); xfbBuffersIter != perBufferXfbOffsets.end(); xfbBuffersIter++)
867                 {
868                         const int       xfbBuffer       = xfbBuffersIter->first;
869                         const int       group           = bufferStrideGroup[xfbBuffer];
870                         const int       xfbAlign        = bufferAlignments[xfbBuffer];
871
872                         groupAlignment[group] = std::max(groupAlignment[group], xfbAlign);
873                 }
874
875                 for (BufferGeneralMapping::const_iterator xfbBuffersIter = perBufferXfbOffsets.begin(); xfbBuffersIter != perBufferXfbOffsets.end(); xfbBuffersIter++)
876                 {
877                         const int       xfbBuffer       = xfbBuffersIter->first;
878                         const int       group           = bufferStrideGroup[xfbBuffer];
879
880                         bufferAlignments[xfbBuffer] = groupAlignment[group];
881                 }
882         }
883
884         // GLSL 4.60
885         // If the buffer is capturing any outputs with double-precision components, the stride must be a multiple of 8, ...
886         for (BufferGeneralMapping::const_iterator xfbBuffersIter = perBufferXfbOffsets.begin(); xfbBuffersIter != perBufferXfbOffsets.end(); xfbBuffersIter++)
887         {
888                 const int       xfbBuffer       = xfbBuffersIter->first;
889                 const int       xfbAlign        = bufferAlignments[xfbBuffer];
890                 int&            xfbOffset       = perBufferXfbOffsets[xfbBuffer];
891
892                 xfbOffset       = deAlign32(xfbOffset, xfbAlign);
893         }
894
895         // Keep stride in interface blocks
896         for (int blockNdx = 0; blockNdx < (int)layout.blocks.size(); blockNdx++)
897                 layout.blocks[blockNdx].xfbStride       = perBufferXfbOffsets[layout.blocks[blockNdx].xfbBuffer];
898
899         locationsUsed = static_cast<deUint32>(curLocation);
900 }
901
902 // Value generator.
903
904 void generateValue (const InterfaceLayoutEntry& entry, void* basePtr, de::Random& rnd)
905 {
906         const glu::DataType     scalarType      = glu::getDataTypeScalarType(entry.type);
907         const int                       scalarSize      = glu::getDataTypeScalarSize(entry.type);
908         const bool                      isMatrix        = glu::isDataTypeMatrix(entry.type);
909         const int                       numVecs         = isMatrix ? glu::getDataTypeMatrixNumColumns(entry.type) : 1;
910         const int                       vecSize         = scalarSize / numVecs;
911         const bool                      isArray         = entry.arraySize > 1;
912         const size_t            compSize        = getDataTypeByteSize(scalarType);
913
914         DE_ASSERT(scalarSize%numVecs == 0);
915
916         for (int elemNdx = 0; elemNdx < entry.arraySize; elemNdx++)
917         {
918                 deUint8* elemPtr = (deUint8*)basePtr + entry.offset + (isArray ? elemNdx*entry.arrayStride : 0);
919
920                 for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
921                 {
922                         deUint8* vecPtr = elemPtr + (isMatrix ? vecNdx*entry.matrixStride : 0);
923
924                         for (int compNdx = 0; compNdx < vecSize; compNdx++)
925                         {
926                                 deUint8*        compPtr = vecPtr + compSize*compNdx;
927                                 const int       sign    = rnd.getBool() ? +1 : -1;
928                                 const int       value   = rnd.getInt(1, 127);
929
930                                 switch (scalarType)
931                                 {
932                                         case glu::TYPE_DOUBLE:  *((double*)compPtr)             = (double)  (sign * value);     break;
933                                         case glu::TYPE_FLOAT:   *((float*)compPtr)              = (float)   (sign * value);     break;
934                                         case glu::TYPE_INT:             *((deInt32*)compPtr)    = (deInt32) (sign * value);     break;
935                                         case glu::TYPE_UINT:    *((deUint32*)compPtr)   = (deUint32)(       value);     break;
936                                         default:
937                                                 DE_ASSERT(false);
938                                 }
939                         }
940                 }
941         }
942 }
943
944 void generateValues (const InterfaceLayout& layout, const std::map<int, void*>& blockPointers, deUint32 seed)
945 {
946         de::Random      rnd                     (seed);
947         int                     numBlocks       = (int)layout.blocks.size();
948
949         for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
950         {
951                 void*   basePtr         = blockPointers.find(blockNdx)->second;
952                 int             numEntries      = (int)layout.blocks[blockNdx].activeInterfaceIndices.size();
953
954                 for (int entryNdx = 0; entryNdx < numEntries; entryNdx++)
955                 {
956                         const InterfaceLayoutEntry& entry = layout.interfaces[layout.blocks[blockNdx].activeInterfaceIndices[entryNdx]];
957
958                         if (entry.validate)
959                                 generateValue(entry, basePtr, rnd);
960                 }
961         }
962 }
963
964 // Shader generator.
965
966 struct Indent
967 {
968         int level;
969         Indent (int level_) : level(level_) {}
970 };
971
972 std::ostream& operator<< (std::ostream& str, const Indent& indent)
973 {
974         for (int i = 0; i < indent.level; i++)
975                 str << "\t";
976         return str;
977 }
978
979 void    generateDeclaration                     (std::ostringstream& src, const VarType& type, const std::string& name, int indentLevel, deUint32 unusedHints, deUint32 flagsMask, deUint32 buffer, deUint32 stride, deUint32 offset);
980 void    generateDeclaration                     (std::ostringstream& src, const InterfaceBlockMember& member, int indentLevel, deUint32 buffer, deUint32 stride, deUint32 offset);
981 void    generateDeclaration                     (std::ostringstream& src, const StructType& structType, int indentLevel);
982
983 void    generateLocalDeclaration        (std::ostringstream& src, const StructType& structType, int indentLevel);
984 void    generateFullDeclaration         (std::ostringstream& src, const StructType& structType, int indentLevel);
985
986 void generateDeclaration (std::ostringstream& src, const StructType& structType, int indentLevel)
987 {
988         DE_ASSERT(structType.hasTypeName());
989         generateFullDeclaration(src, structType, indentLevel);
990         src << ";\n";
991 }
992
993 void generateFullDeclaration (std::ostringstream& src, const StructType& structType, int indentLevel)
994 {
995         src << "struct";
996         if (structType.hasTypeName())
997                 src << " " << structType.getTypeName();
998         src << "\n" << Indent(indentLevel) << "{\n";
999
1000         for (StructType::ConstIterator memberIter = structType.begin(); memberIter != structType.end(); memberIter++)
1001         {
1002                 src << Indent(indentLevel + 1);
1003                 generateDeclaration(src, memberIter->getType(), memberIter->getName(), indentLevel + 1, memberIter->getFlags() & FIELD_OPTIONS, ~LAYOUT_MASK, 0u, 0u, 0u);
1004         }
1005
1006         src << Indent(indentLevel) << "}";
1007 }
1008
1009 void generateLocalDeclaration (std::ostringstream& src, const StructType& structType, int /* indentLevel */)
1010 {
1011         src << structType.getTypeName();
1012 }
1013
1014 void generateLayoutAndPrecisionDeclaration (std::ostringstream& src, deUint32 flags, deUint32 buffer, deUint32 stride, deUint32 offset)
1015 {
1016         if ((flags & LAYOUT_MASK) != 0)
1017                 src << "layout(" << LayoutFlagsFmt(flags & LAYOUT_MASK, buffer, stride, offset) << ") ";
1018
1019         if ((flags & PRECISION_MASK) != 0)
1020                 src << PrecisionFlagsFmt(flags & PRECISION_MASK) << " ";
1021 }
1022
1023 void generateDeclaration (std::ostringstream& src, const VarType& type, const std::string& name, int indentLevel, deUint32 fieldHints, deUint32 flagsMask, deUint32 buffer, deUint32 stride, deUint32 offset)
1024 {
1025         if (fieldHints & FIELD_MISSING)
1026                 src << "// ";
1027
1028         generateLayoutAndPrecisionDeclaration(src, type.getFlags() & flagsMask, buffer, stride, offset);
1029
1030         if (type.isBasicType())
1031                 src << glu::getDataTypeName(type.getBasicType()) << " " << name;
1032         else if (type.isArrayType())
1033         {
1034                 std::vector<int>        arraySizes;
1035                 const VarType*          curType         = &type;
1036                 while (curType->isArrayType())
1037                 {
1038                         arraySizes.push_back(curType->getArraySize());
1039                         curType = &curType->getElementType();
1040                 }
1041
1042                 generateLayoutAndPrecisionDeclaration(src, curType->getFlags() & flagsMask, buffer, stride, offset);
1043
1044                 if (curType->isBasicType())
1045                         src << glu::getDataTypeName(curType->getBasicType());
1046                 else
1047                 {
1048                         DE_ASSERT(curType->isStructType());
1049                         generateLocalDeclaration(src, curType->getStruct(), indentLevel+1);
1050                 }
1051
1052                 src << " " << name;
1053
1054                 for (std::vector<int>::const_iterator sizeIter = arraySizes.begin(); sizeIter != arraySizes.end(); sizeIter++)
1055                         src << "[" << *sizeIter << "]";
1056         }
1057         else
1058         {
1059                 generateLocalDeclaration(src, type.getStruct(), indentLevel+1);
1060                 src << " " << name;
1061         }
1062
1063         src << ";";
1064
1065         // Print out unused hints.
1066         if (fieldHints & FIELD_MISSING)
1067                 src << " // missing field";
1068         else if (fieldHints & FIELD_UNASSIGNED)
1069                 src << " // unassigned";
1070
1071         src << "\n";
1072 }
1073
1074 void generateDeclaration (std::ostringstream& src, const InterfaceBlockMember& member, int indentLevel, deUint32 buffer, deUint32 stride, deUint32 offset)
1075 {
1076         if ((member.getFlags() & LAYOUT_MASK) != 0)
1077                 src << "layout(" << LayoutFlagsFmt(member.getFlags() & LAYOUT_MASK, buffer, stride, offset) << ") ";
1078
1079         generateDeclaration(src, member.getType(), member.getName(), indentLevel, member.getFlags() & FIELD_OPTIONS, ~0u, buffer, stride, offset);
1080 }
1081
1082 deUint32 getBlockMemberOffset (int blockNdx, const InterfaceBlock& block, const InterfaceBlockMember& member, const InterfaceLayout& layout)
1083 {
1084         std::ostringstream      name;
1085         const VarType*          curType = &member.getType();
1086
1087         if (block.getInstanceName().length() != 0)
1088                 name << block.getBlockName() << ".";    // \note InterfaceLayoutEntry uses block name rather than instance name
1089
1090         name << member.getName();
1091
1092         while (!curType->isBasicType())
1093         {
1094                 if (curType->isArrayType())
1095                 {
1096                         name << "[0]";
1097                         curType = &curType->getElementType();
1098                 }
1099
1100                 if (curType->isStructType())
1101                 {
1102                         const StructType::ConstIterator firstMember = curType->getStruct().begin();
1103
1104                         name << "." << firstMember->getName();
1105                         curType = &firstMember->getType();
1106                 }
1107         }
1108
1109         const int interfaceLayoutNdx = layout.getInterfaceLayoutIndex(blockNdx, name.str());
1110         DE_ASSERT(interfaceLayoutNdx >= 0);
1111
1112         return layout.interfaces[interfaceLayoutNdx].offset;
1113 }
1114
1115 template<typename T>
1116 void semiShuffle (std::vector<T>& v)
1117 {
1118         const std::vector<T>    src     = v;
1119         int                                             i       = -1;
1120         int                                             n       = static_cast<int>(src.size());
1121
1122         v.clear();
1123
1124         while (n)
1125         {
1126                 i += n;
1127                 v.push_back(src[i]);
1128                 n = (n > 0 ? 1 - n : -1 - n);
1129         }
1130 }
1131
1132 template<typename T>
1133 //! \note Stores pointers to original elements
1134 class Traverser
1135 {
1136 public:
1137         template<typename Iter>
1138         Traverser (const Iter beg, const Iter end, const bool shuffled)
1139         {
1140                 for (Iter it = beg; it != end; ++it)
1141                         m_elements.push_back(&(*it));
1142
1143                 if (shuffled)
1144                         semiShuffle(m_elements);
1145
1146                 m_next = m_elements.begin();
1147         }
1148
1149         T* next (void)
1150         {
1151                 if (m_next != m_elements.end())
1152                         return *m_next++;
1153                 else
1154                         return DE_NULL;
1155         }
1156
1157 private:
1158         typename std::vector<T*>                                        m_elements;
1159         typename std::vector<T*>::const_iterator        m_next;
1160 };
1161
1162 void generateDeclaration (std::ostringstream& src, int blockNdx, const InterfaceBlock& block, const InterfaceLayout& layout, bool shuffleUniformMembers)
1163 {
1164         const int indentOne             = 1;
1165         const int ndx                   = layout.getBlockLayoutIndex(blockNdx, 0);
1166         const int locationNdx   = layout.blocks[ndx].locationNdx;
1167         const int xfbOffset             = layout.blocks[ndx].xfbOffset;
1168         const int xfbBuffer             = layout.blocks[ndx].xfbBuffer;
1169         const int xfbStride             = layout.blocks[ndx].xfbStride;
1170
1171         src << "layout(";
1172         src << "location = " << locationNdx;
1173         if ((block.getFlags() & LAYOUT_MASK) != 0)
1174                 src << ", " << LayoutFlagsFmt(block.getFlags() & LAYOUT_MASK, xfbBuffer, xfbStride, xfbOffset);
1175         src << ") out " << block.getBlockName();
1176
1177         src << " //"
1178                 << " sizeInBytes=" << layout.blocks[ndx].xfbSize
1179                 << " sizeInLocations=" << layout.blocks[ndx].locationSize;
1180
1181         src << "\n{\n";
1182
1183         Traverser<const InterfaceBlockMember> interfaces(block.begin(), block.end(), shuffleUniformMembers);
1184
1185         while (const InterfaceBlockMember* pUniform = interfaces.next())
1186         {
1187                 src << Indent(indentOne);
1188                 generateDeclaration(src, *pUniform, indentOne, xfbBuffer, xfbStride, xfbOffset + getBlockMemberOffset(blockNdx, block, *pUniform, layout));
1189         }
1190
1191         src << "}";
1192
1193         if (block.hasInstanceName())
1194         {
1195                 src << " " << block.getInstanceName();
1196                 if (block.isArray())
1197                         src << "[" << block.getArraySize() << "]";
1198         }
1199         else
1200                 DE_ASSERT(!block.isArray());
1201
1202         src << ";\n";
1203 }
1204
1205 int generateValueSrc (std::ostringstream& src, const InterfaceLayoutEntry& entry, const void* basePtr, int elementNdx)
1206 {
1207         const glu::DataType     scalarType      = glu::getDataTypeScalarType(entry.type);
1208         const int                       scalarSize      = glu::getDataTypeScalarSize(entry.type);
1209         const bool                      isArray         = entry.arraySize > 1;
1210         const deUint8*          elemPtr         = (const deUint8*)basePtr + entry.offset + (isArray ? elementNdx * entry.arrayStride : 0);
1211         const size_t            compSize        = getDataTypeByteSize(scalarType);
1212
1213         if (scalarSize > 1)
1214                 src << glu::getDataTypeName(entry.type) << "(";
1215
1216         if (glu::isDataTypeMatrix(entry.type))
1217         {
1218                 const int       numRows = glu::getDataTypeMatrixNumRows(entry.type);
1219                 const int       numCols = glu::getDataTypeMatrixNumColumns(entry.type);
1220
1221                 DE_ASSERT(scalarType == glu::TYPE_FLOAT || scalarType == glu::TYPE_DOUBLE);
1222
1223                 // Constructed in column-wise order.
1224                 for (int colNdx = 0; colNdx < numCols; colNdx++)
1225                 {
1226                         for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
1227                         {
1228                                 const deUint8*  compPtr = elemPtr + (colNdx * entry.matrixStride + rowNdx * compSize);
1229                                 const float             compVal = (scalarType == glu::TYPE_FLOAT) ? *((const float*)compPtr)
1230                                                                                 : (scalarType == glu::TYPE_DOUBLE) ? (float)*((const double*)compPtr)
1231                                                                                 : 0.0f;
1232
1233                                 if (colNdx > 0 || rowNdx > 0)
1234                                         src << ", ";
1235
1236                                 src << de::floatToString(compVal, 1);
1237                         }
1238                 }
1239         }
1240         else
1241         {
1242                 for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
1243                 {
1244                         const deUint8* compPtr = elemPtr + scalarNdx * compSize;
1245
1246                         if (scalarNdx > 0)
1247                                 src << ", ";
1248
1249                         switch (scalarType)
1250                         {
1251                                 case glu::TYPE_DOUBLE:  src << de::floatToString((float)(*((const double*)compPtr)), 1);        break;
1252                                 case glu::TYPE_FLOAT:   src << de::floatToString(*((const float*)compPtr), 1) << "f";           break;
1253                                 case glu::TYPE_INT:             src << *((const int*)compPtr);                                                                          break;
1254                                 case glu::TYPE_UINT:    src << *((const deUint32*)compPtr) << "u";                                                      break;
1255                                 default:                                DE_ASSERT(false && "Invalid type");                                                                     break;
1256                         }
1257                 }
1258         }
1259
1260         if (scalarSize > 1)
1261                 src << ")";
1262
1263         return static_cast<int>(elemPtr - static_cast<const deUint8*>(basePtr));
1264 }
1265
1266 void writeMatrixTypeSrc (int                                                    columnCount,
1267                                                  int                                                    rowCount,
1268                                                  std::string                                    type,
1269                                                  std::ostringstream&                    src,
1270                                                  const std::string&                             srcName,
1271                                                  const void*                                    basePtr,
1272                                                  const InterfaceLayoutEntry&    entry,
1273                                                  bool                                                   vector)
1274 {
1275         if (vector)     // generateTestSrcMatrixPerVec
1276         {
1277                 for (int colNdx = 0; colNdx < columnCount; colNdx++)
1278                 {
1279                         src << "\t" << srcName << "[" << colNdx << "] = ";
1280
1281                         if (glu::isDataTypeMatrix(entry.type))
1282                         {
1283                                 const glu::DataType     scalarType      = glu::getDataTypeScalarType(entry.type);
1284                                 const int                       scalarSize      = glu::getDataTypeScalarSize(entry.type);
1285                                 const deUint8*          compPtr         = (const deUint8*)basePtr + entry.offset;
1286
1287                                 if (scalarSize > 1)
1288                                         src << type << "(";
1289
1290                                 for (int rowNdx = 0; rowNdx < rowCount; rowNdx++)
1291                                 {
1292                                         const float             compVal = (scalarType == glu::TYPE_FLOAT) ? *((const float*)compPtr)
1293                                                                                         : (scalarType == glu::TYPE_DOUBLE) ? (float)*((const double*)compPtr)
1294                                                                                         : 0.0f;
1295
1296                                         src << de::floatToString(compVal, 1);
1297
1298                                         if (rowNdx < rowCount-1)
1299                                                 src << ", ";
1300                                 }
1301
1302                                 src << ");\n";
1303                         }
1304                         else
1305                         {
1306                                 generateValueSrc(src, entry, basePtr, 0);
1307                                 src << "[" << colNdx << "];\n";
1308                         }
1309                 }
1310         }
1311         else            // generateTestSrcMatrixPerElement
1312         {
1313                 const glu::DataType     scalarType      = glu::getDataTypeScalarType(entry.type);
1314
1315                 for (int colNdx = 0; colNdx < columnCount; colNdx++)
1316                 {
1317                         for (int rowNdx = 0; rowNdx < rowCount; rowNdx++)
1318                         {
1319                                 src << "\t" << srcName << "[" << colNdx << "][" << rowNdx << "] = ";
1320                                 if (glu::isDataTypeMatrix(entry.type))
1321                                 {
1322                                         const deUint8*  elemPtr         = (const deUint8*)basePtr + entry.offset;
1323                                         const size_t    compSize        = getDataTypeByteSize(scalarType);
1324                                         const deUint8*  compPtr         = elemPtr + (colNdx * entry.matrixStride + rowNdx * compSize);
1325                                         const float             compVal         = (scalarType == glu::TYPE_FLOAT) ? *((const float*)compPtr)
1326                                                                                                 : (scalarType == glu::TYPE_DOUBLE) ? (float)*((const double*)compPtr)
1327                                                                                                 : 0.0f;
1328
1329                                         src << de::floatToString(compVal, 1) << ";\n";
1330                                 }
1331                                 else
1332                                 {
1333                                         generateValueSrc(src, entry, basePtr, 0);
1334                                         src << "[" << colNdx << "][" << rowNdx << "];\n";
1335                                 }
1336                         }
1337                 }
1338         }
1339 }
1340
1341 void generateTestSrcMatrixPerVec (std::ostringstream&                   src,
1342                                                                   glu::DataType                                 elementType,
1343                                                                   const std::string&                    srcName,
1344                                                                   const void*                                   basePtr,
1345                                                                   const InterfaceLayoutEntry&   entry)
1346 {
1347         switch (elementType)
1348         {
1349                 case glu::TYPE_FLOAT_MAT2:              writeMatrixTypeSrc(2, 2, "vec2", src, srcName, basePtr, entry, true);   break;
1350                 case glu::TYPE_FLOAT_MAT2X3:    writeMatrixTypeSrc(2, 3, "vec3", src, srcName, basePtr, entry, true);   break;
1351                 case glu::TYPE_FLOAT_MAT2X4:    writeMatrixTypeSrc(2, 4, "vec4", src, srcName, basePtr, entry, true);   break;
1352                 case glu::TYPE_FLOAT_MAT3X4:    writeMatrixTypeSrc(3, 4, "vec4", src, srcName, basePtr, entry, true);   break;
1353                 case glu::TYPE_FLOAT_MAT4:              writeMatrixTypeSrc(4, 4, "vec4", src, srcName, basePtr, entry, true);   break;
1354                 case glu::TYPE_FLOAT_MAT4X2:    writeMatrixTypeSrc(4, 2, "vec2", src, srcName, basePtr, entry, true);   break;
1355                 case glu::TYPE_FLOAT_MAT4X3:    writeMatrixTypeSrc(4, 3, "vec3", src, srcName, basePtr, entry, true);   break;
1356                 default:                                                DE_ASSERT(false && "Invalid type");                                                                             break;
1357         }
1358 }
1359
1360 void generateTestSrcMatrixPerElement (std::ostringstream&                       src,
1361                                                                           glu::DataType                                 elementType,
1362                                                                           const std::string&                    srcName,
1363                                                                           const void*                                   basePtr,
1364                                                                           const InterfaceLayoutEntry&   entry)
1365 {
1366         std::string type = "float";
1367         switch (elementType)
1368         {
1369                 case glu::TYPE_FLOAT_MAT2:              writeMatrixTypeSrc(2, 2, type, src, srcName, basePtr, entry, false);    break;
1370                 case glu::TYPE_FLOAT_MAT2X3:    writeMatrixTypeSrc(2, 3, type, src, srcName, basePtr, entry, false);    break;
1371                 case glu::TYPE_FLOAT_MAT2X4:    writeMatrixTypeSrc(2, 4, type, src, srcName, basePtr, entry, false);    break;
1372                 case glu::TYPE_FLOAT_MAT3X4:    writeMatrixTypeSrc(3, 4, type, src, srcName, basePtr, entry, false);    break;
1373                 case glu::TYPE_FLOAT_MAT4:              writeMatrixTypeSrc(4, 4, type, src, srcName, basePtr, entry, false);    break;
1374                 case glu::TYPE_FLOAT_MAT4X2:    writeMatrixTypeSrc(4, 2, type, src, srcName, basePtr, entry, false);    break;
1375                 case glu::TYPE_FLOAT_MAT4X3:    writeMatrixTypeSrc(4, 3, type, src, srcName, basePtr, entry, false);    break;
1376                 default:                                                DE_ASSERT(false && "Invalid type");                                                                             break;
1377         }
1378 }
1379
1380 void generateSingleAssignment (std::ostringstream&                      src,
1381                                                            glu::DataType                                elementType,
1382                                                            const std::string&                   srcName,
1383                                                            const void*                                  basePtr,
1384                                                            const InterfaceLayoutEntry&  entry,
1385                                                            MatrixLoadFlags                              matrixLoadFlag)
1386 {
1387         if (matrixLoadFlag == LOAD_FULL_MATRIX)
1388         {
1389                 src << "\t" << srcName << " = ";
1390                 generateValueSrc(src, entry, basePtr, 0);
1391                 src << ";\n";
1392         }
1393         else
1394         {
1395                 if (glu::isDataTypeMatrix(elementType))
1396                 {
1397                         generateTestSrcMatrixPerVec             (src, elementType, srcName, basePtr, entry);
1398                         generateTestSrcMatrixPerElement (src, elementType, srcName, basePtr, entry);
1399                 }
1400         }
1401 }
1402
1403 void generateAssignment (std::ostringstream&    src,
1404                                                  const InterfaceLayout& layout,
1405                                                  const VarType&                 type,
1406                                                  const std::string&             srcName,
1407                                                  const std::string&             apiName,
1408                                                  int                                    blockNdx,
1409                                                  const void*                    basePtr,
1410                                                  MatrixLoadFlags                matrixLoadFlag)
1411 {
1412         if (type.isBasicType() || (type.isArrayType() && type.getElementType().isBasicType()))
1413         {
1414                 // Basic type or array of basic types.
1415                 bool                                            isArray                         = type.isArrayType();
1416                 glu::DataType                           elementType                     = isArray ? type.getElementType().getBasicType() : type.getBasicType();
1417                 std::string                                     fullApiName                     = std::string(apiName) + (isArray ? "[0]" : ""); // Arrays are always postfixed with [0]
1418                 int                                                     interfaceLayoutNdx      = layout.getInterfaceLayoutIndex(blockNdx, fullApiName);
1419                 const InterfaceLayoutEntry&     entry                           = layout.interfaces[interfaceLayoutNdx];
1420
1421                 if (isArray)
1422                 {
1423                         for (int elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++)
1424                         {
1425                                 src << "\t" << srcName << "[" << elemNdx << "] = ";
1426                                 generateValueSrc(src, entry, basePtr, elemNdx);
1427                                 src << ";\n";
1428                         }
1429                 }
1430                 else
1431                 {
1432                         generateSingleAssignment(src, elementType, srcName, basePtr, entry, matrixLoadFlag);
1433                 }
1434         }
1435         else if (type.isArrayType())
1436         {
1437                 const VarType& elementType = type.getElementType();
1438
1439                 for (int elementNdx = 0; elementNdx < type.getArraySize(); elementNdx++)
1440                 {
1441                         const std::string op                            = std::string("[") + de::toString(elementNdx) + "]";
1442                         const std::string elementSrcName        = std::string(srcName) + op;
1443                         const std::string elementApiName        = std::string(apiName) + op;
1444
1445                         generateAssignment(src, layout, elementType, elementSrcName, elementApiName, blockNdx, basePtr, LOAD_FULL_MATRIX);
1446                 }
1447         }
1448         else
1449         {
1450                 DE_ASSERT(type.isStructType());
1451
1452                 for (StructType::ConstIterator memberIter = type.getStruct().begin(); memberIter != type.getStruct().end(); memberIter++)
1453                 {
1454                         const StructMember&     member                  = *memberIter;
1455                         const std::string       op                              = std::string(".") + member.getName();
1456                         const std::string       memberSrcName   = std::string(srcName) + op;
1457                         const std::string       memberApiName   = std::string(apiName) + op;
1458
1459                         if (0 == (member.getFlags() & (FIELD_UNASSIGNED | FIELD_MISSING)))
1460                                 generateAssignment(src, layout, memberIter->getType(), memberSrcName, memberApiName, blockNdx, basePtr, LOAD_FULL_MATRIX);
1461                 }
1462         }
1463 }
1464
1465 void generateAssignment (std::ostringstream&                    src,
1466                                                  const InterfaceLayout&                 layout,
1467                                                  const ShaderInterface&                 shaderInterface,
1468                                                  const std::map<int, void*>&    blockPointers,
1469                                                  MatrixLoadFlags                                matrixLoadFlag)
1470 {
1471         for (int blockNdx = 0; blockNdx < shaderInterface.getNumInterfaceBlocks(); blockNdx++)
1472         {
1473                 const InterfaceBlock& block = shaderInterface.getInterfaceBlock(blockNdx);
1474
1475                 bool                    hasInstanceName = block.hasInstanceName();
1476                 bool                    isArray                 = block.isArray();
1477                 int                             numInstances    = isArray ? block.getArraySize() : 1;
1478                 std::string             apiPrefix               = hasInstanceName ? block.getBlockName() + "." : std::string("");
1479
1480                 DE_ASSERT(!isArray || hasInstanceName);
1481
1482                 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1483                 {
1484                         std::string             instancePostfix         = isArray ? std::string("[") + de::toString(instanceNdx) + "]" : std::string("");
1485                         std::string             blockInstanceName       = block.getBlockName() + instancePostfix;
1486                         std::string             srcPrefix                       = hasInstanceName ? block.getInstanceName() + instancePostfix + "." : std::string("");
1487                         int                             blockLayoutNdx          = layout.getBlockLayoutIndex(blockNdx, instanceNdx);
1488                         void*                   basePtr                         = blockPointers.find(blockLayoutNdx)->second;
1489
1490                         for (InterfaceBlock::ConstIterator interfaceMemberIter = block.begin(); interfaceMemberIter != block.end(); interfaceMemberIter++)
1491                         {
1492                                 const InterfaceBlockMember& interfaceMember = *interfaceMemberIter;
1493
1494                                 if ((interfaceMember.getFlags() & (FIELD_MISSING | FIELD_UNASSIGNED)) == 0)
1495                                 {
1496                                         std::string srcName = srcPrefix + interfaceMember.getName();
1497                                         std::string apiName = apiPrefix + interfaceMember.getName();
1498
1499                                         generateAssignment(src, layout, interfaceMember.getType(), srcName, apiName, blockNdx, basePtr, matrixLoadFlag);
1500                                 }
1501                         }
1502                 }
1503         }
1504 }
1505
1506 std::string generatePassthroughShader ()
1507 {
1508         std::ostringstream      src;
1509
1510         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n";
1511
1512         src << "\n"
1513                    "void main (void)\n"
1514                    "{\n"
1515                    "}\n";
1516
1517         return src.str();
1518 }
1519
1520 std::string generateTestShader (const ShaderInterface& shaderInterface, const InterfaceLayout& layout, const std::map<int, void*>& blockPointers, MatrixLoadFlags matrixLoadFlag, TestStageFlags testStageFlags, bool shuffleUniformMembers)
1521 {
1522         std::ostringstream                              src;
1523         std::vector<const StructType*>  namedStructs;
1524
1525         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n\n";
1526
1527         if (testStageFlags == TEST_STAGE_GEOMETRY)
1528         {
1529                 src << "layout(points) in;\n"
1530                         << "layout(points, max_vertices = 1) out;\n\n";
1531         }
1532
1533         shaderInterface.getNamedStructs(namedStructs);
1534         for (std::vector<const StructType*>::const_iterator structIter = namedStructs.begin(); structIter != namedStructs.end(); structIter++)
1535                 generateDeclaration(src, **structIter, 0);
1536
1537         for (int blockNdx = 0; blockNdx < shaderInterface.getNumInterfaceBlocks(); blockNdx++)
1538         {
1539                 const InterfaceBlock& block = shaderInterface.getInterfaceBlock(blockNdx);
1540
1541                 generateDeclaration(src, blockNdx, block, layout, shuffleUniformMembers);
1542         }
1543
1544         src << "\n"
1545                    "void main (void)\n"
1546                    "{\n";
1547
1548         generateAssignment(src, layout, shaderInterface, blockPointers, matrixLoadFlag);
1549
1550         if (testStageFlags == TEST_STAGE_GEOMETRY)
1551         {
1552                 src << "\n"
1553                         << "\tEmitVertex();\n"
1554                         << "\tEndPrimitive();\n";
1555         }
1556
1557         src << "}\n";
1558
1559         return src.str();
1560 }
1561
1562 Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface&           vk,
1563                                                                            const VkDevice                               device,
1564                                                                            const VkPipelineLayout               pipelineLayout,
1565                                                                            const VkRenderPass                   renderPass,
1566                                                                            const VkShaderModule                 vertexModule,
1567                                                                            const VkShaderModule                 geometryModule,
1568                                                                            const VkExtent2D                             renderSize)
1569 {
1570         const std::vector<VkViewport>                           viewports                                               (1, makeViewport(renderSize));
1571         const std::vector<VkRect2D>                                     scissors                                                (1, makeRect2D(renderSize));
1572         const VkPipelineVertexInputStateCreateInfo      vertexInputStateCreateInfo      =
1573         {
1574                 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,      // VkStructureType                                                              sType
1575                 DE_NULL,                                                                                                        // const void*                                                                  pNext
1576                 (VkPipelineVertexInputStateCreateFlags)0,                                       // VkPipelineVertexInputStateCreateFlags                flags
1577                 0u,                                                                                                                     // deUint32                                                                             vertexBindingDescriptionCount
1578                 DE_NULL,                                                                                                        // const VkVertexInputBindingDescription*               pVertexBindingDescriptions
1579                 0u,                                                                                                                     // deUint32                                                                             vertexAttributeDescriptionCount
1580                 DE_NULL,                                                                                                        // const VkVertexInputAttributeDescription*             pVertexAttributeDescriptions
1581         };
1582
1583         return makeGraphicsPipeline(vk,                                                                 // const DeviceInterface&                                               vk
1584                                                                 device,                                                         // const VkDevice                                                               device
1585                                                                 pipelineLayout,                                         // const VkPipelineLayout                                               pipelineLayout
1586                                                                 vertexModule,                                           // const VkShaderModule                                                 vertexShaderModule
1587                                                                 DE_NULL,                                                        // const VkShaderModule                                                 tessellationControlModule
1588                                                                 DE_NULL,                                                        // const VkShaderModule                                                 tessellationEvalModule
1589                                                                 geometryModule,                                         // const VkShaderModule                                                 geometryShaderModule
1590                                                                 DE_NULL,                                                        // const VkShaderModule                                                 m_maxGeometryBlocksShaderModule
1591                                                                 renderPass,                                                     // const VkRenderPass                                                   renderPass
1592                                                                 viewports,                                                      // const std::vector<VkViewport>&                               viewports
1593                                                                 scissors,                                                       // const std::vector<VkRect2D>&                                 scissors
1594                                                                 VK_PRIMITIVE_TOPOLOGY_POINT_LIST,       // const VkPrimitiveTopology                                    topology
1595                                                                 0u,                                                                     // const deUint32                                                               subpass
1596                                                                 0u,                                                                     // const deUint32                                                               patchControlPoints
1597                                                                 &vertexInputStateCreateInfo);           // const VkPipelineVertexInputStateCreateInfo*  vertexInputStateCreateInfo
1598 }
1599
1600 // InterfaceBlockCaseInstance
1601
1602 class InterfaceBlockCaseInstance : public vkt::TestInstance
1603 {
1604 public:
1605                                                                         InterfaceBlockCaseInstance      (Context&                                                       context,
1606                                                                                                                                  const InterfaceLayout&                         layout,
1607                                                                                                                                  const std::map<int, void*>&            blockPointers,
1608                                                                                                                                  const std::vector<deUint8>&            data,
1609                                                                                                                                  const std::vector<VkDeviceSize>&       tfBufBindingOffsets,
1610                                                                                                                                  const std::vector<VkDeviceSize>&       tfBufBindingSizes,
1611                                                                                                                                  const deUint32                                         locationsRequired,
1612                                                                                                                                  const TestStageFlags                           testStageFlags);
1613
1614         virtual                                                 ~InterfaceBlockCaseInstance     (void);
1615         virtual tcu::TestStatus                 iterate                                         (void);
1616
1617 private:
1618         Move<VkShaderModule>                    getGeometryShaderModule         (const DeviceInterface& vk,
1619                                                                                                                                  const VkDevice                 device);
1620
1621         bool                                                    usesFloat64                                     (void);
1622         std::string                                             validateValue                           (const InterfaceLayoutEntry& entry, const void* basePtr0, const void* basePtr, const void* receivedBasePtr);
1623         std::string                                             validateValues                          (const void* recievedDataPtr);
1624
1625         typedef de::SharedPtr<vk::Unique<vk::VkBuffer> >        VkBufferSp;
1626         typedef de::SharedPtr<vk::Allocation>                           AllocationSp;
1627
1628         const InterfaceLayout&                  m_layout;
1629         const std::vector<deUint8>&             m_data;
1630         const DeviceSizeVector&                 m_tfBufBindingOffsets;
1631         const DeviceSizeVector&                 m_tfBufBindingSizes;
1632         const std::map<int, void*>&             m_blockPointers;
1633         const deUint32                                  m_locationsRequired;
1634         const TestStageFlags                    m_testStageFlags;
1635         const VkExtent2D                                m_imageExtent2D;
1636 };
1637
1638 InterfaceBlockCaseInstance::InterfaceBlockCaseInstance (Context&                                                        ctx,
1639                                                                                                                 const InterfaceLayout&                          layout,
1640                                                                                                                 const std::map<int, void*>&                     blockPointers,
1641                                                                                                                 const std::vector<deUint8>&                     data,
1642                                                                                                                 const std::vector<VkDeviceSize>&        tfBufBindingOffsets,
1643                                                                                                                 const std::vector<VkDeviceSize>&        tfBufBindingSizes,
1644                                                                                                                 const deUint32                                          locationsRequired,
1645                                                                                                                 const TestStageFlags                            testStageFlags)
1646         : vkt::TestInstance             (ctx)
1647         , m_layout                              (layout)
1648         , m_data                                (data)
1649         , m_tfBufBindingOffsets (tfBufBindingOffsets)
1650         , m_tfBufBindingSizes   (tfBufBindingSizes)
1651         , m_blockPointers               (blockPointers)
1652         , m_locationsRequired   (locationsRequired)
1653         , m_testStageFlags              (testStageFlags)
1654         , m_imageExtent2D               (makeExtent2D(256u, 256u))
1655 {
1656         const deUint32                                                                                  componentsPerLocation           = 4u;
1657         const deUint32                                                                                  componentsRequired                      = m_locationsRequired * componentsPerLocation;
1658         const InstanceInterface&                                                                vki                                                     = m_context.getInstanceInterface();
1659         const VkPhysicalDevice                                                                  physDevice                                      = m_context.getPhysicalDevice();
1660         const VkPhysicalDeviceTransformFeedbackFeaturesEXT&             transformFeedbackFeatures       = m_context.getTransformFeedbackFeatures();
1661         const VkPhysicalDeviceLimits                                                    limits                                          = getPhysicalDeviceProperties(vki, physDevice).limits;
1662         VkPhysicalDeviceTransformFeedbackPropertiesEXT                  transformFeedbackProperties;
1663         VkPhysicalDeviceProperties2                                                             deviceProperties2;
1664
1665         if (transformFeedbackFeatures.transformFeedback == DE_FALSE)
1666                 TCU_THROW(NotSupportedError, "transformFeedback feature is not supported");
1667
1668         deMemset(&deviceProperties2, 0, sizeof(deviceProperties2));
1669         deMemset(&transformFeedbackProperties, 0x00, sizeof(transformFeedbackProperties));
1670
1671         deviceProperties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1672         deviceProperties2.pNext = &transformFeedbackProperties;
1673
1674         transformFeedbackProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT;
1675         transformFeedbackProperties.pNext = DE_NULL;
1676
1677         vki.getPhysicalDeviceProperties2(physDevice, &deviceProperties2);
1678
1679         if (transformFeedbackProperties.maxTransformFeedbackBuffers < tfBufBindingSizes.size())
1680                 TCU_THROW(NotSupportedError, "maxTransformFeedbackBuffers=" + de::toString(transformFeedbackProperties.maxTransformFeedbackBuffers) + " is less than required (" + de::toString(tfBufBindingSizes.size()) + ")");
1681
1682         if (transformFeedbackProperties.maxTransformFeedbackBufferDataSize < m_data.size())
1683                 TCU_THROW(NotSupportedError, "maxTransformFeedbackBufferDataSize=" + de::toString(transformFeedbackProperties.maxTransformFeedbackBufferDataSize) + " is less than required (" + de::toString(m_data.size()) + ")");
1684
1685         if (m_testStageFlags == TEST_STAGE_VERTEX)
1686         {
1687                 if (limits.maxVertexOutputComponents < componentsRequired)
1688                         TCU_THROW(NotSupportedError, "maxVertexOutputComponents=" + de::toString(limits.maxVertexOutputComponents) + " is less than required (" + de::toString(componentsRequired) + ")");
1689         }
1690
1691         if (m_testStageFlags == TEST_STAGE_GEOMETRY)
1692         {
1693                 if (limits.maxGeometryOutputComponents < componentsRequired)
1694                         TCU_THROW(NotSupportedError, "maxGeometryOutputComponents=" + de::toString(limits.maxGeometryOutputComponents) + " is less than required (" + de::toString(componentsRequired) + ")");
1695         }
1696
1697         if (usesFloat64())
1698                 m_context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SHADER_FLOAT64);
1699 }
1700
1701 InterfaceBlockCaseInstance::~InterfaceBlockCaseInstance (void)
1702 {
1703 }
1704
1705 bool InterfaceBlockCaseInstance::usesFloat64 (void)
1706 {
1707         for (size_t layoutNdx = 0; layoutNdx< m_layout.interfaces.size(); ++layoutNdx)
1708                 if (isDataTypeDoubleType(m_layout.interfaces[layoutNdx].type))
1709                         return true;
1710
1711         return false;
1712 }
1713
1714 Move<VkShaderModule> InterfaceBlockCaseInstance::getGeometryShaderModule (const DeviceInterface&        vk,
1715                                                                                                                                                   const VkDevice                        device)
1716 {
1717         if (m_testStageFlags == TEST_STAGE_GEOMETRY)
1718                 return createShaderModule(vk, device, m_context.getBinaryCollection().get("geom"), 0u);
1719
1720         return Move<VkShaderModule>();
1721 }
1722
1723 tcu::TestStatus InterfaceBlockCaseInstance::iterate (void)
1724 {
1725         const DeviceInterface&                  vk                                      = m_context.getDeviceInterface();
1726         const VkDevice                                  device                          = m_context.getDevice();
1727         const deUint32                                  queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
1728         const VkQueue                                   queue                           = m_context.getUniversalQueue();
1729         Allocator&                                              allocator                       = m_context.getDefaultAllocator();
1730
1731         const Move<VkShaderModule>              vertModule                      (createShaderModule             (vk, device, m_context.getBinaryCollection().get("vert"), 0u));
1732         const Move<VkShaderModule>              geomModule                      (getGeometryShaderModule(vk, device));
1733         const Move<VkRenderPass>                renderPass                      (makeRenderPass                 (vk, device, VK_FORMAT_UNDEFINED));
1734         const Move<VkFramebuffer>               framebuffer                     (makeFramebuffer                (vk, device, *renderPass, 0u, DE_NULL, m_imageExtent2D.width, m_imageExtent2D.height));
1735         const Move<VkPipelineLayout>    pipelineLayout          (makePipelineLayout             (vk, device));
1736         const Move<VkPipeline>                  pipeline                        (makeGraphicsPipeline   (vk, device, *pipelineLayout, *renderPass, *vertModule, *geomModule, m_imageExtent2D));
1737         const Move<VkCommandPool>               cmdPool                         (createCommandPool              (vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1738         const Move<VkCommandBuffer>             cmdBuffer                       (allocateCommandBuffer  (vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
1739
1740         const VkBufferCreateInfo                tfBufCreateInfo         = makeBufferCreateInfo(m_data.size(), VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT);
1741         const Move<VkBuffer>                    tfBuf                           = createBuffer(vk, device, &tfBufCreateInfo);
1742         const de::MovePtr<Allocation>   tfBufAllocation         = allocator.allocate(getBufferMemoryRequirements(vk, device, *tfBuf), MemoryRequirement::HostVisible);
1743         const deUint32                                  tfBufBindingCount       = static_cast<deUint32>(m_tfBufBindingOffsets.size());
1744         const std::vector<VkBuffer>             tfBufBindings           (tfBufBindingCount, *tfBuf);
1745
1746         DE_ASSERT(tfBufBindings.size() == tfBufBindingCount);
1747
1748         VK_CHECK(vk.bindBufferMemory(device, *tfBuf, tfBufAllocation->getMemory(), tfBufAllocation->getOffset()));
1749
1750         deMemset(tfBufAllocation->getHostPtr(), 0, m_data.size());
1751         flushMappedMemoryRange(vk, device, tfBufAllocation->getMemory(), tfBufAllocation->getOffset(), VK_WHOLE_SIZE);
1752
1753         beginCommandBuffer(vk, *cmdBuffer);
1754         {
1755                 beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_imageExtent2D));
1756                 {
1757                         vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
1758
1759                         vk.cmdBindTransformFeedbackBuffersEXT(*cmdBuffer, 0, tfBufBindingCount, &tfBufBindings[0], &m_tfBufBindingOffsets[0], &m_tfBufBindingSizes[0]);
1760
1761                         vk.cmdBeginTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
1762                         {
1763                                 vk.cmdDraw(*cmdBuffer, 1u, 1u, 0u, 0u);
1764                         }
1765                         vk.cmdEndTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
1766                 }
1767                 endRenderPass(vk, *cmdBuffer);
1768         }
1769         endCommandBuffer(vk, *cmdBuffer);
1770         submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1771
1772         invalidateMappedMemoryRange(vk, device, tfBufAllocation->getMemory(), tfBufAllocation->getOffset(), VK_WHOLE_SIZE);
1773
1774         std::string result = validateValues(tfBufAllocation->getHostPtr());
1775
1776         if (!result.empty())
1777                 return tcu::TestStatus::fail(result);
1778
1779         return tcu::TestStatus::pass("Pass");
1780 }
1781
1782 std::string InterfaceBlockCaseInstance::validateValue (const InterfaceLayoutEntry& entry, const void* basePtr0, const void* basePtr, const void* receivedBasePtr)
1783 {
1784         const glu::DataType     scalarType      = glu::getDataTypeScalarType(entry.type);
1785         const int                       scalarSize      = glu::getDataTypeScalarSize(entry.type);
1786         const bool                      isMatrix        = glu::isDataTypeMatrix(entry.type);
1787         const int                       numVecs         = isMatrix ? glu::getDataTypeMatrixNumColumns(entry.type) : 1;
1788         const int                       vecSize         = scalarSize / numVecs;
1789         const bool                      isArray         = entry.arraySize > 1;
1790         const size_t            compSize        = getDataTypeByteSize(scalarType);
1791         std::string                     result;
1792
1793         DE_ASSERT(scalarSize%numVecs == 0);
1794
1795         for (int elemNdx = 0; elemNdx < entry.arraySize; elemNdx++)
1796         {
1797                 deUint8* elemPtr = (deUint8*)basePtr + entry.offset + (isArray ? elemNdx*entry.arrayStride : 0);
1798
1799                 for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
1800                 {
1801                         deUint8* vecPtr = elemPtr + (isMatrix ? vecNdx*entry.matrixStride : 0);
1802
1803                         for (int compNdx = 0; compNdx < vecSize; compNdx++)
1804                         {
1805                                 const deUint8*  compPtr         = vecPtr + compSize*compNdx;
1806                                 const size_t    offset          = compPtr - (deUint8*)basePtr0;
1807                                 const deUint8*  receivedPtr     = (deUint8*)receivedBasePtr + offset;
1808
1809                                 switch (scalarType)
1810                                 {
1811                                         case glu::TYPE_DOUBLE:
1812                                         {
1813                                                 const double expected   = *((double*)compPtr);
1814                                                 const double received   = *((double*)receivedPtr);
1815
1816                                                 if (deAbs(received - expected) > 0.05)
1817                                                         result = "Mismatch at offset " + de::toString(offset) + " expected " + de::toString(expected) + " received " + de::toString(received);
1818
1819                                                 break;
1820                                         }
1821                                         case glu::TYPE_FLOAT:
1822                                         {
1823                                                 const float expected    = *((float*)compPtr);
1824                                                 const float received    = *((float*)receivedPtr);
1825
1826                                                 if (deAbs(received - expected) > 0.05)
1827                                                         result = "Mismatch at offset " + de::toString(offset) + " expected " + de::toString(expected) + " received " + de::toString(received);
1828
1829                                                 break;
1830                                         }
1831                                         case glu::TYPE_INT:
1832                                         {
1833                                                 const deInt32 expected  = *((deInt32*)compPtr);
1834                                                 const deInt32 received  = *((deInt32*)receivedPtr);
1835
1836                                                 if (received != expected)
1837                                                         result = "Mismatch at offset " + de::toString(offset) + " expected " + de::toString(expected) + " received " + de::toString(received);
1838
1839                                                 break;
1840                                         }
1841                                         case glu::TYPE_UINT:
1842                                         {
1843                                                 const deUint32 expected = *((deUint32*)compPtr);
1844                                                 const deUint32 received = *((deUint32*)receivedPtr);
1845
1846                                                 if (received != expected)
1847                                                         result = "Mismatch at offset " + de::toString(offset) + " expected " + de::toString(expected) + " received " + de::toString(received);
1848
1849                                                 break;
1850                                         }
1851                                         default:
1852                                                 DE_ASSERT(false);
1853                                 }
1854
1855                                 if (!result.empty())
1856                                 {
1857                                         result += " (elemNdx=" + de::toString(elemNdx) + " vecNdx=" + de::toString(vecNdx) + " compNdx=" + de::toString(compNdx) + ")";
1858
1859                                         return result;
1860                                 }
1861                         }
1862                 }
1863         }
1864
1865         return result;
1866 }
1867
1868 std::string InterfaceBlockCaseInstance::validateValues (const void* recievedDataPtr)
1869 {
1870         const int       numBlocks       = (int)m_layout.blocks.size();
1871
1872         for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1873         {
1874                 void*   basePtr         = m_blockPointers.find(blockNdx)->second;
1875                 int             numEntries      = (int)m_layout.blocks[blockNdx].activeInterfaceIndices.size();
1876
1877                 for (int entryNdx = 0; entryNdx < numEntries; entryNdx++)
1878                 {
1879                         const InterfaceLayoutEntry&     entry   = m_layout.interfaces[m_layout.blocks[blockNdx].activeInterfaceIndices[entryNdx]];
1880                         const std::string                       result  = entry.validate ? validateValue(entry, &m_data[0], basePtr, recievedDataPtr) : "";
1881
1882                         if (!result.empty())
1883                         {
1884                                 tcu::TestLog&                   log             = m_context.getTestContext().getLog();
1885                                 std::vector<deUint8>    mask    = createMask(m_layout, m_blockPointers, &m_data[0], m_data.size());
1886                                 std::ostringstream              str;
1887
1888                                 str << "Error at entry '" << entry.name << "' block '" << m_layout.blocks[blockNdx].name << "'" << std::endl;
1889                                 str << result << std::endl;
1890
1891                                 str << m_layout;
1892
1893                                 str << "Xfb buffer offsets: " << m_tfBufBindingOffsets << std::endl;
1894                                 str << "Xfb buffer sizes: " << m_tfBufBindingSizes << std::endl << std::endl;
1895
1896                                 dumpBytes(str, "Expected:", &m_data[0], m_data.size(), &mask[0]);
1897                                 dumpBytes(str, "Retrieved:", recievedDataPtr, m_data.size(), &mask[0]);
1898
1899                                 dumpBytes(str, "Expected (unfiltered):", &m_data[0], m_data.size());
1900                                 dumpBytes(str, "Retrieved (unfiltered):", recievedDataPtr, m_data.size());
1901
1902                                 log << tcu::TestLog::Message << str.str() << tcu::TestLog::EndMessage;
1903
1904                                 return result;
1905                         }
1906                 }
1907         }
1908
1909         return std::string();
1910 }
1911
1912 } // anonymous (utilities)
1913
1914 // InterfaceBlockCase.
1915
1916 InterfaceBlockCase::InterfaceBlockCase (tcu::TestContext&       testCtx,
1917                                                                                 const std::string&      name,
1918                                                                                 const std::string&      description,
1919                                                                                 MatrixLoadFlags         matrixLoadFlag,
1920                                                                                 TestStageFlags          testStageFlags,
1921                                                                                 bool                            shuffleInterfaceMembers)
1922         : TestCase                                      (testCtx, name, description)
1923         , m_matrixLoadFlag                      (matrixLoadFlag)
1924         , m_testStageFlags                      (testStageFlags)
1925         , m_shuffleInterfaceMembers     (shuffleInterfaceMembers)
1926         , m_locationsRequired           (0)
1927 {
1928 }
1929
1930 InterfaceBlockCase::~InterfaceBlockCase (void)
1931 {
1932 }
1933
1934 void InterfaceBlockCase::initPrograms (vk::SourceCollections& programCollection) const
1935 {
1936         DE_ASSERT(!m_vertShaderSource.empty());
1937
1938         programCollection.glslSources.add("vert") << glu::VertexSource(m_vertShaderSource);
1939
1940         if (!m_geomShaderSource.empty())
1941                 programCollection.glslSources.add("geom") << glu::GeometrySource(m_geomShaderSource);
1942 }
1943
1944 TestInstance* InterfaceBlockCase::createInstance (Context& context) const
1945 {
1946         return new InterfaceBlockCaseInstance(context, m_interfaceLayout, m_blockPointers, m_data, m_tfBufBindingOffsets, m_tfBufBindingSizes, m_locationsRequired, m_testStageFlags);
1947 }
1948
1949 void InterfaceBlockCase::init (void)
1950 {
1951         BufferGeneralMapping    xfbBufferSize;
1952         std::string                             notSupportedComment;
1953
1954         // Compute reference layout.
1955         computeXfbLayout(m_interfaceLayout, m_interface, xfbBufferSize, m_locationsRequired);
1956
1957         // Assign storage for reference values.
1958         // m_data contains all xfb buffers starting with all interfaces of first xfb_buffer, then all interfaces of next xfb_buffer
1959         {
1960                 BufferGeneralMapping    xfbBufferOffsets;
1961                 int                                             totalSize                       = 0;
1962                 int                                             maxXfb                          = 0;
1963
1964                 for (BufferGeneralMapping::const_iterator xfbBuffersIter = xfbBufferSize.begin(); xfbBuffersIter != xfbBufferSize.end(); xfbBuffersIter++)
1965                 {
1966                         xfbBufferOffsets[xfbBuffersIter->first] = totalSize;
1967                         totalSize += xfbBuffersIter->second;
1968                         maxXfb = std::max(maxXfb, xfbBuffersIter->first);
1969                 }
1970                 m_data.resize(totalSize);
1971
1972                 DE_ASSERT(de::inBounds(maxXfb, 0, 256)); // Not correlated with spec: just make sure vectors won't be huge
1973
1974                 m_tfBufBindingSizes.resize(maxXfb + 1);
1975                 for (BufferGeneralMapping::const_iterator xfbBuffersIter = xfbBufferSize.begin(); xfbBuffersIter != xfbBufferSize.end(); xfbBuffersIter++)
1976                         m_tfBufBindingSizes[xfbBuffersIter->first] = xfbBuffersIter->second;
1977
1978                 m_tfBufBindingOffsets.resize(maxXfb + 1);
1979                 for (BufferGeneralMapping::const_iterator xfbBuffersIter = xfbBufferOffsets.begin(); xfbBuffersIter != xfbBufferOffsets.end(); xfbBuffersIter++)
1980                         m_tfBufBindingOffsets[xfbBuffersIter->first] = xfbBuffersIter->second;
1981
1982                 // Pointers for each block.
1983                 for (int blockNdx = 0; blockNdx < (int)m_interfaceLayout.blocks.size(); blockNdx++)
1984                 {
1985                         const int dataXfbBufferStartOffset      = xfbBufferOffsets[m_interfaceLayout.blocks[blockNdx].xfbBuffer];
1986                         const int offset                                        = dataXfbBufferStartOffset + m_interfaceLayout.blocks[blockNdx].xfbOffset;
1987
1988                         m_blockPointers[blockNdx] = &m_data[0] + offset;
1989                 }
1990         }
1991
1992         // Generate values.
1993         generateValues(m_interfaceLayout, m_blockPointers, 1 /* seed */);
1994
1995         // Overlap validation
1996         {
1997                 std::vector<deUint8>    mask    = createMask(m_interfaceLayout, m_blockPointers, &m_data[0], m_data.size());
1998
1999                 for (size_t maskNdx = 0; maskNdx < mask.size(); ++maskNdx)
2000                         DE_ASSERT(mask[maskNdx] <= 1);
2001         }
2002
2003         if (m_testStageFlags == TEST_STAGE_VERTEX)
2004         {
2005                 m_vertShaderSource = generateTestShader(m_interface, m_interfaceLayout, m_blockPointers, m_matrixLoadFlag, m_testStageFlags, m_shuffleInterfaceMembers);
2006                 m_geomShaderSource = "";
2007         }
2008         else if (m_testStageFlags == TEST_STAGE_GEOMETRY)
2009         {
2010                 m_vertShaderSource = generatePassthroughShader();
2011                 m_geomShaderSource = generateTestShader(m_interface, m_interfaceLayout, m_blockPointers, m_matrixLoadFlag, m_testStageFlags, m_shuffleInterfaceMembers);
2012         }
2013         else
2014         {
2015                 DE_ASSERT(false && "Unknown test stage specified");
2016         }
2017 }
2018
2019 } // TransformFeedback
2020 } // vkt