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
VarType(void)71 VarType::VarType (void)
72 : m_type (TYPE_LAST)
73 , m_flags (0)
74 {
75 }
76
VarType(const VarType & other)77 VarType::VarType (const VarType& other)
78 : m_type (TYPE_LAST)
79 , m_flags (0)
80 {
81 *this = other;
82 }
83
VarType(glu::DataType basicType,deUint32 flags)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
VarType(const VarType & elementType,int arraySize)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
VarType(const StructType * structPtr,deUint32 flags)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
~VarType(void)106 VarType::~VarType (void)
107 {
108 if (m_type == TYPE_ARRAY)
109 delete m_data.array.elementType;
110 }
111
operator =(const VarType & other)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.
addMember(const std::string & name,const VarType & type,deUint32 flags)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.
InterfaceBlockMember(const std::string & name,const VarType & type,deUint32 flags)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.
InterfaceBlock(const std::string & blockName)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
operator <<(std::ostream & stream,const BlockLayoutEntry & entry)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
operator <<(std::ostream & stream,const InterfaceLayoutEntry & entry)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
operator <<(std::ostream & str,const InterfaceLayout & layout)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
getInterfaceLayoutIndex(int blockNdx,const std::string & name) const219 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
getBlockLayoutIndex(int blockNdx,int instanceNdx) const230 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
ShaderInterface(void)243 ShaderInterface::ShaderInterface (void)
244 {
245 }
246
~ShaderInterface(void)247 ShaderInterface::~ShaderInterface (void)
248 {
249 }
250
allocStruct(const std::string & name)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
StructNameEqualsvkt::TransformFeedback::StructNameEquals261 StructNameEquals (const std::string& name_) : name(name_) {}
262
operator ()vkt::TransformFeedback::StructNameEquals263 bool operator() (const StructTypeSP type) const
264 {
265 return type->hasTypeName() && name == type->getTypeName();
266 }
267 };
268
getNamedStructs(std::vector<const StructType * > & structs) const269 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
allocBlock(const std::string & name)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;
PrecisionFlagsFmtvkt::TransformFeedback::__anona5d2d2920111::PrecisionFlagsFmt291 PrecisionFlagsFmt (deUint32 flags_) : flags(flags_) {}
292 };
293
dumpBytes(std::ostream & str,const std::string & msg,const void * dataBytes,size_t size,const void * dataMask=DE_NULL)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
operator <<(std::ostream & str,const PrecisionFlagsFmt & fmt)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
LayoutFlagsFmtvkt::TransformFeedback::__anona5d2d2920111::LayoutFlagsFmt339 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
operator <<(std::ostream & str,const LayoutFlagsFmt & fmt)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
operator <<(std::ostream & str,const DeviceSizeVector & vec)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
getDataTypeByteSize(glu::DataType type)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
getDataTypeArrayStride(glu::DataType type)409 int getDataTypeArrayStride (glu::DataType type)
410 {
411 DE_ASSERT(!glu::isDataTypeMatrix(type));
412
413 return getDataTypeByteSize(type);
414 }
415
getDataTypeArrayStrideForLocation(glu::DataType type)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
computeInterfaceBlockMemberAlignment(const VarType & type)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
createMask(void * maskBasePtr,const InterfaceLayoutEntry & entry,const void * basePtr0,const void * basePtr)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
createMask(const InterfaceLayout & layout,const std::map<int,void * > & blockPointers,const void * basePtr0,const size_t baseSize)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
computeInterfaceBlockAlignment(const InterfaceBlock & interfaceBlock)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
isOverlaped(const int a1,const int b1,const int a2,const int b2)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
computeXfbLayout(InterfaceLayout & layout,int & curOffset,int & curLocation,int curBlockNdx,const std::string & curPrefix,const VarType & type,deUint32 layoutFlags)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
computeXfbLayout(InterfaceLayout & layout,ShaderInterface & shaderInterface,BufferGeneralMapping & perBufferXfbOffsets,deUint32 & locationsUsed)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
generateValue(const InterfaceLayoutEntry & entry,void * basePtr,de::Random & rnd)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
generateValues(const InterfaceLayout & layout,const std::map<int,void * > & blockPointers,deUint32 seed)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;
Indentvkt::TransformFeedback::__anona5d2d2920111::Indent969 Indent (int level_) : level(level_) {}
970 };
971
operator <<(std::ostream & str,const Indent & indent)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
generateDeclaration(std::ostringstream & src,const StructType & structType,int indentLevel)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
generateFullDeclaration(std::ostringstream & src,const StructType & structType,int indentLevel)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
generateLocalDeclaration(std::ostringstream & src,const StructType & structType,int)1009 void generateLocalDeclaration (std::ostringstream& src, const StructType& structType, int /* indentLevel */)
1010 {
1011 src << structType.getTypeName();
1012 }
1013
generateLayoutAndPrecisionDeclaration(std::ostringstream & src,deUint32 flags,deUint32 buffer,deUint32 stride,deUint32 offset)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
generateDeclaration(std::ostringstream & src,const VarType & type,const std::string & name,int indentLevel,deUint32 fieldHints,deUint32 flagsMask,deUint32 buffer,deUint32 stride,deUint32 offset)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
generateDeclaration(std::ostringstream & src,const InterfaceBlockMember & member,int indentLevel,deUint32 buffer,deUint32 stride,deUint32 offset)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
getBlockMemberOffset(int blockNdx,const InterfaceBlock & block,const InterfaceBlockMember & member,const InterfaceLayout & layout)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>
semiShuffle(std::vector<T> & v)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>
Traverser(const Iter beg,const Iter end,const bool shuffled)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
next(void)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
generateDeclaration(std::ostringstream & src,int blockNdx,const InterfaceBlock & block,const InterfaceLayout & layout,bool shuffleUniformMembers)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
generateValueSrc(std::ostringstream & src,const InterfaceLayoutEntry & entry,const void * basePtr,int elementNdx)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
writeMatrixTypeSrc(int columnCount,int rowCount,std::string type,std::ostringstream & src,const std::string & srcName,const void * basePtr,const InterfaceLayoutEntry & entry,bool vector)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
generateTestSrcMatrixPerVec(std::ostringstream & src,glu::DataType elementType,const std::string & srcName,const void * basePtr,const InterfaceLayoutEntry & entry)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
generateTestSrcMatrixPerElement(std::ostringstream & src,glu::DataType elementType,const std::string & srcName,const void * basePtr,const InterfaceLayoutEntry & entry)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
generateSingleAssignment(std::ostringstream & src,glu::DataType elementType,const std::string & srcName,const void * basePtr,const InterfaceLayoutEntry & entry,MatrixLoadFlags matrixLoadFlag)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
generateAssignment(std::ostringstream & src,const InterfaceLayout & layout,const VarType & type,const std::string & srcName,const std::string & apiName,int blockNdx,const void * basePtr,MatrixLoadFlags matrixLoadFlag)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
generateAssignment(std::ostringstream & src,const InterfaceLayout & layout,const ShaderInterface & shaderInterface,const std::map<int,void * > & blockPointers,MatrixLoadFlags matrixLoadFlag)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
generatePassthroughShader()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
generateTestShader(const ShaderInterface & shaderInterface,const InterfaceLayout & layout,const std::map<int,void * > & blockPointers,MatrixLoadFlags matrixLoadFlag,TestStageFlags testStageFlags,bool shuffleUniformMembers)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
makeGraphicsPipeline(const DeviceInterface & vk,const VkDevice device,const VkPipelineLayout pipelineLayout,const VkRenderPass renderPass,const VkShaderModule vertexModule,const VkShaderModule geometryModule,const VkExtent2D renderSize)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
InterfaceBlockCaseInstance(Context & ctx,const InterfaceLayout & layout,const std::map<int,void * > & blockPointers,const std::vector<deUint8> & data,const std::vector<VkDeviceSize> & tfBufBindingOffsets,const std::vector<VkDeviceSize> & tfBufBindingSizes,const deUint32 locationsRequired,const TestStageFlags testStageFlags)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 + 7u; // Add 7 for built-in components
1658 const InstanceInterface& vki = m_context.getInstanceInterface();
1659 const VkPhysicalDevice physDevice = m_context.getPhysicalDevice();
1660 const VkPhysicalDeviceFeatures features = getPhysicalDeviceFeatures(vki, physDevice);
1661 const VkPhysicalDeviceTransformFeedbackFeaturesEXT& transformFeedbackFeatures = m_context.getTransformFeedbackFeaturesEXT();
1662 const VkPhysicalDeviceLimits limits = getPhysicalDeviceProperties(vki, physDevice).limits;
1663 VkPhysicalDeviceTransformFeedbackPropertiesEXT transformFeedbackProperties;
1664 VkPhysicalDeviceProperties2 deviceProperties2;
1665
1666 if (transformFeedbackFeatures.transformFeedback == DE_FALSE)
1667 TCU_THROW(NotSupportedError, "transformFeedback feature is not supported");
1668
1669 deMemset(&deviceProperties2, 0, sizeof(deviceProperties2));
1670 deMemset(&transformFeedbackProperties, 0x00, sizeof(transformFeedbackProperties));
1671
1672 deviceProperties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1673 deviceProperties2.pNext = &transformFeedbackProperties;
1674
1675 transformFeedbackProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT;
1676 transformFeedbackProperties.pNext = DE_NULL;
1677
1678 vki.getPhysicalDeviceProperties2(physDevice, &deviceProperties2);
1679
1680 if (transformFeedbackProperties.maxTransformFeedbackBuffers < tfBufBindingSizes.size())
1681 TCU_THROW(NotSupportedError, "maxTransformFeedbackBuffers=" + de::toString(transformFeedbackProperties.maxTransformFeedbackBuffers) + " is less than required (" + de::toString(tfBufBindingSizes.size()) + ")");
1682
1683 if (transformFeedbackProperties.maxTransformFeedbackBufferDataSize < m_data.size())
1684 TCU_THROW(NotSupportedError, "maxTransformFeedbackBufferDataSize=" + de::toString(transformFeedbackProperties.maxTransformFeedbackBufferDataSize) + " is less than required (" + de::toString(m_data.size()) + ")");
1685
1686 if (m_testStageFlags == TEST_STAGE_VERTEX)
1687 {
1688 if (limits.maxVertexOutputComponents < componentsRequired)
1689 TCU_THROW(NotSupportedError, "maxVertexOutputComponents=" + de::toString(limits.maxVertexOutputComponents) + " is less than required (" + de::toString(componentsRequired) + ")");
1690 }
1691
1692 if (m_testStageFlags == TEST_STAGE_GEOMETRY)
1693 {
1694 if (!features.geometryShader)
1695 TCU_THROW(NotSupportedError, "Missing feature: geometryShader");
1696
1697 if (limits.maxGeometryOutputComponents < componentsRequired)
1698 TCU_THROW(NotSupportedError, "maxGeometryOutputComponents=" + de::toString(limits.maxGeometryOutputComponents) + " is less than required (" + de::toString(componentsRequired) + ")");
1699 }
1700
1701 if (usesFloat64())
1702 m_context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SHADER_FLOAT64);
1703 }
1704
~InterfaceBlockCaseInstance(void)1705 InterfaceBlockCaseInstance::~InterfaceBlockCaseInstance (void)
1706 {
1707 }
1708
usesFloat64(void)1709 bool InterfaceBlockCaseInstance::usesFloat64 (void)
1710 {
1711 for (size_t layoutNdx = 0; layoutNdx< m_layout.interfaces.size(); ++layoutNdx)
1712 if (isDataTypeDoubleType(m_layout.interfaces[layoutNdx].type))
1713 return true;
1714
1715 return false;
1716 }
1717
getGeometryShaderModule(const DeviceInterface & vk,const VkDevice device)1718 Move<VkShaderModule> InterfaceBlockCaseInstance::getGeometryShaderModule (const DeviceInterface& vk,
1719 const VkDevice device)
1720 {
1721 if (m_testStageFlags == TEST_STAGE_GEOMETRY)
1722 return createShaderModule(vk, device, m_context.getBinaryCollection().get("geom"), 0u);
1723
1724 return Move<VkShaderModule>();
1725 }
1726
iterate(void)1727 tcu::TestStatus InterfaceBlockCaseInstance::iterate (void)
1728 {
1729 const DeviceInterface& vk = m_context.getDeviceInterface();
1730 const VkDevice device = m_context.getDevice();
1731 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
1732 const VkQueue queue = m_context.getUniversalQueue();
1733 Allocator& allocator = m_context.getDefaultAllocator();
1734
1735 const Move<VkShaderModule> vertModule (createShaderModule (vk, device, m_context.getBinaryCollection().get("vert"), 0u));
1736 const Move<VkShaderModule> geomModule (getGeometryShaderModule(vk, device));
1737 const Move<VkRenderPass> renderPass (makeRenderPass (vk, device, VK_FORMAT_UNDEFINED));
1738 const Move<VkFramebuffer> framebuffer (makeFramebuffer (vk, device, *renderPass, 0u, DE_NULL, m_imageExtent2D.width, m_imageExtent2D.height));
1739 const Move<VkPipelineLayout> pipelineLayout (makePipelineLayout (vk, device));
1740 const Move<VkPipeline> pipeline (makeGraphicsPipeline (vk, device, *pipelineLayout, *renderPass, *vertModule, *geomModule, m_imageExtent2D));
1741 const Move<VkCommandPool> cmdPool (createCommandPool (vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1742 const Move<VkCommandBuffer> cmdBuffer (allocateCommandBuffer (vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
1743
1744 const VkBufferCreateInfo tfBufCreateInfo = makeBufferCreateInfo(m_data.size(), VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT);
1745 const Move<VkBuffer> tfBuf = createBuffer(vk, device, &tfBufCreateInfo);
1746 const de::MovePtr<Allocation> tfBufAllocation = allocator.allocate(getBufferMemoryRequirements(vk, device, *tfBuf), MemoryRequirement::HostVisible);
1747 const deUint32 tfBufBindingCount = static_cast<deUint32>(m_tfBufBindingOffsets.size());
1748 const std::vector<VkBuffer> tfBufBindings (tfBufBindingCount, *tfBuf);
1749
1750 DE_ASSERT(tfBufBindings.size() == tfBufBindingCount);
1751
1752 VK_CHECK(vk.bindBufferMemory(device, *tfBuf, tfBufAllocation->getMemory(), tfBufAllocation->getOffset()));
1753
1754 deMemset(tfBufAllocation->getHostPtr(), 0, m_data.size());
1755 flushMappedMemoryRange(vk, device, tfBufAllocation->getMemory(), tfBufAllocation->getOffset(), VK_WHOLE_SIZE);
1756
1757 beginCommandBuffer(vk, *cmdBuffer);
1758 {
1759 beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_imageExtent2D));
1760 {
1761 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
1762
1763 vk.cmdBindTransformFeedbackBuffersEXT(*cmdBuffer, 0, tfBufBindingCount, &tfBufBindings[0], &m_tfBufBindingOffsets[0], &m_tfBufBindingSizes[0]);
1764
1765 vk.cmdBeginTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
1766 {
1767 vk.cmdDraw(*cmdBuffer, 1u, 1u, 0u, 0u);
1768 }
1769 vk.cmdEndTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
1770 }
1771 endRenderPass(vk, *cmdBuffer);
1772
1773 const VkMemoryBarrier tfMemoryBarrier =
1774 {
1775 VK_STRUCTURE_TYPE_MEMORY_BARRIER, // VkStructureType sType;
1776 DE_NULL, // const void* pNext;
1777 VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, // VkAccessFlags outputMask;
1778 VK_ACCESS_HOST_READ_BIT // VkAccessFlags inputMask;
1779 };
1780 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &tfMemoryBarrier, 0u, DE_NULL, 0u, DE_NULL);
1781 }
1782 endCommandBuffer(vk, *cmdBuffer);
1783 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1784
1785 invalidateMappedMemoryRange(vk, device, tfBufAllocation->getMemory(), tfBufAllocation->getOffset(), VK_WHOLE_SIZE);
1786
1787 std::string result = validateValues(tfBufAllocation->getHostPtr());
1788
1789 if (!result.empty())
1790 return tcu::TestStatus::fail(result);
1791
1792 return tcu::TestStatus::pass("Pass");
1793 }
1794
validateValue(const InterfaceLayoutEntry & entry,const void * basePtr0,const void * basePtr,const void * receivedBasePtr)1795 std::string InterfaceBlockCaseInstance::validateValue (const InterfaceLayoutEntry& entry, const void* basePtr0, const void* basePtr, const void* receivedBasePtr)
1796 {
1797 const glu::DataType scalarType = glu::getDataTypeScalarType(entry.type);
1798 const int scalarSize = glu::getDataTypeScalarSize(entry.type);
1799 const bool isMatrix = glu::isDataTypeMatrix(entry.type);
1800 const int numVecs = isMatrix ? glu::getDataTypeMatrixNumColumns(entry.type) : 1;
1801 const int vecSize = scalarSize / numVecs;
1802 const bool isArray = entry.arraySize > 1;
1803 const size_t compSize = getDataTypeByteSize(scalarType);
1804 std::string result;
1805
1806 DE_ASSERT(scalarSize%numVecs == 0);
1807
1808 for (int elemNdx = 0; elemNdx < entry.arraySize; elemNdx++)
1809 {
1810 deUint8* elemPtr = (deUint8*)basePtr + entry.offset + (isArray ? elemNdx*entry.arrayStride : 0);
1811
1812 for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
1813 {
1814 deUint8* vecPtr = elemPtr + (isMatrix ? vecNdx*entry.matrixStride : 0);
1815
1816 for (int compNdx = 0; compNdx < vecSize; compNdx++)
1817 {
1818 const deUint8* compPtr = vecPtr + compSize*compNdx;
1819 const size_t offset = compPtr - (deUint8*)basePtr0;
1820 const deUint8* receivedPtr = (deUint8*)receivedBasePtr + offset;
1821
1822 switch (scalarType)
1823 {
1824 case glu::TYPE_DOUBLE:
1825 {
1826 const double expected = *((double*)compPtr);
1827 const double received = *((double*)receivedPtr);
1828
1829 if (deAbs(received - expected) > 0.05)
1830 result = "Mismatch at offset " + de::toString(offset) + " expected " + de::toString(expected) + " received " + de::toString(received);
1831
1832 break;
1833 }
1834 case glu::TYPE_FLOAT:
1835 {
1836 const float expected = *((float*)compPtr);
1837 const float received = *((float*)receivedPtr);
1838
1839 if (deAbs(received - expected) > 0.05)
1840 result = "Mismatch at offset " + de::toString(offset) + " expected " + de::toString(expected) + " received " + de::toString(received);
1841
1842 break;
1843 }
1844 case glu::TYPE_INT:
1845 {
1846 const deInt32 expected = *((deInt32*)compPtr);
1847 const deInt32 received = *((deInt32*)receivedPtr);
1848
1849 if (received != expected)
1850 result = "Mismatch at offset " + de::toString(offset) + " expected " + de::toString(expected) + " received " + de::toString(received);
1851
1852 break;
1853 }
1854 case glu::TYPE_UINT:
1855 {
1856 const deUint32 expected = *((deUint32*)compPtr);
1857 const deUint32 received = *((deUint32*)receivedPtr);
1858
1859 if (received != expected)
1860 result = "Mismatch at offset " + de::toString(offset) + " expected " + de::toString(expected) + " received " + de::toString(received);
1861
1862 break;
1863 }
1864 default:
1865 DE_ASSERT(false);
1866 }
1867
1868 if (!result.empty())
1869 {
1870 result += " (elemNdx=" + de::toString(elemNdx) + " vecNdx=" + de::toString(vecNdx) + " compNdx=" + de::toString(compNdx) + ")";
1871
1872 return result;
1873 }
1874 }
1875 }
1876 }
1877
1878 return result;
1879 }
1880
validateValues(const void * recievedDataPtr)1881 std::string InterfaceBlockCaseInstance::validateValues (const void* recievedDataPtr)
1882 {
1883 const int numBlocks = (int)m_layout.blocks.size();
1884
1885 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1886 {
1887 void* basePtr = m_blockPointers.find(blockNdx)->second;
1888 int numEntries = (int)m_layout.blocks[blockNdx].activeInterfaceIndices.size();
1889
1890 for (int entryNdx = 0; entryNdx < numEntries; entryNdx++)
1891 {
1892 const InterfaceLayoutEntry& entry = m_layout.interfaces[m_layout.blocks[blockNdx].activeInterfaceIndices[entryNdx]];
1893 const std::string result = entry.validate ? validateValue(entry, &m_data[0], basePtr, recievedDataPtr) : "";
1894
1895 if (!result.empty())
1896 {
1897 tcu::TestLog& log = m_context.getTestContext().getLog();
1898 std::vector<deUint8> mask = createMask(m_layout, m_blockPointers, &m_data[0], m_data.size());
1899 std::ostringstream str;
1900
1901 str << "Error at entry '" << entry.name << "' block '" << m_layout.blocks[blockNdx].name << "'" << std::endl;
1902 str << result << std::endl;
1903
1904 str << m_layout;
1905
1906 str << "Xfb buffer offsets: " << m_tfBufBindingOffsets << std::endl;
1907 str << "Xfb buffer sizes: " << m_tfBufBindingSizes << std::endl << std::endl;
1908
1909 dumpBytes(str, "Expected:", &m_data[0], m_data.size(), &mask[0]);
1910 dumpBytes(str, "Retrieved:", recievedDataPtr, m_data.size(), &mask[0]);
1911
1912 dumpBytes(str, "Expected (unfiltered):", &m_data[0], m_data.size());
1913 dumpBytes(str, "Retrieved (unfiltered):", recievedDataPtr, m_data.size());
1914
1915 log << tcu::TestLog::Message << str.str() << tcu::TestLog::EndMessage;
1916
1917 return result;
1918 }
1919 }
1920 }
1921
1922 return std::string();
1923 }
1924
1925 } // anonymous (utilities)
1926
1927 // InterfaceBlockCase.
1928
InterfaceBlockCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,MatrixLoadFlags matrixLoadFlag,TestStageFlags testStageFlags,bool shuffleInterfaceMembers)1929 InterfaceBlockCase::InterfaceBlockCase (tcu::TestContext& testCtx,
1930 const std::string& name,
1931 const std::string& description,
1932 MatrixLoadFlags matrixLoadFlag,
1933 TestStageFlags testStageFlags,
1934 bool shuffleInterfaceMembers)
1935 : TestCase (testCtx, name, description)
1936 , m_matrixLoadFlag (matrixLoadFlag)
1937 , m_testStageFlags (testStageFlags)
1938 , m_shuffleInterfaceMembers (shuffleInterfaceMembers)
1939 , m_locationsRequired (0)
1940 {
1941 }
1942
~InterfaceBlockCase(void)1943 InterfaceBlockCase::~InterfaceBlockCase (void)
1944 {
1945 }
1946
initPrograms(vk::SourceCollections & programCollection) const1947 void InterfaceBlockCase::initPrograms (vk::SourceCollections& programCollection) const
1948 {
1949 DE_ASSERT(!m_vertShaderSource.empty());
1950
1951 programCollection.glslSources.add("vert") << glu::VertexSource(m_vertShaderSource);
1952
1953 if (!m_geomShaderSource.empty())
1954 programCollection.glslSources.add("geom") << glu::GeometrySource(m_geomShaderSource);
1955 }
1956
createInstance(Context & context) const1957 TestInstance* InterfaceBlockCase::createInstance (Context& context) const
1958 {
1959 return new InterfaceBlockCaseInstance(context, m_interfaceLayout, m_blockPointers, m_data, m_tfBufBindingOffsets, m_tfBufBindingSizes, m_locationsRequired, m_testStageFlags);
1960 }
1961
delayedInit(void)1962 void InterfaceBlockCase::delayedInit (void)
1963 {
1964 BufferGeneralMapping xfbBufferSize;
1965 std::string notSupportedComment;
1966
1967 // Compute reference layout.
1968 computeXfbLayout(m_interfaceLayout, m_interface, xfbBufferSize, m_locationsRequired);
1969
1970 // Assign storage for reference values.
1971 // m_data contains all xfb buffers starting with all interfaces of first xfb_buffer, then all interfaces of next xfb_buffer
1972 {
1973 BufferGeneralMapping xfbBufferOffsets;
1974 int totalSize = 0;
1975 int maxXfb = 0;
1976
1977 for (BufferGeneralMapping::const_iterator xfbBuffersIter = xfbBufferSize.begin(); xfbBuffersIter != xfbBufferSize.end(); xfbBuffersIter++)
1978 {
1979 xfbBufferOffsets[xfbBuffersIter->first] = totalSize;
1980 totalSize += xfbBuffersIter->second;
1981 maxXfb = std::max(maxXfb, xfbBuffersIter->first);
1982 }
1983 m_data.resize(totalSize);
1984
1985 DE_ASSERT(de::inBounds(maxXfb, 0, 256)); // Not correlated with spec: just make sure vectors won't be huge
1986
1987 m_tfBufBindingSizes.resize(maxXfb + 1);
1988 for (BufferGeneralMapping::const_iterator xfbBuffersIter = xfbBufferSize.begin(); xfbBuffersIter != xfbBufferSize.end(); xfbBuffersIter++)
1989 m_tfBufBindingSizes[xfbBuffersIter->first] = xfbBuffersIter->second;
1990
1991 m_tfBufBindingOffsets.resize(maxXfb + 1);
1992 for (BufferGeneralMapping::const_iterator xfbBuffersIter = xfbBufferOffsets.begin(); xfbBuffersIter != xfbBufferOffsets.end(); xfbBuffersIter++)
1993 m_tfBufBindingOffsets[xfbBuffersIter->first] = xfbBuffersIter->second;
1994
1995 // Pointers for each block.
1996 for (int blockNdx = 0; blockNdx < (int)m_interfaceLayout.blocks.size(); blockNdx++)
1997 {
1998 const int dataXfbBufferStartOffset = xfbBufferOffsets[m_interfaceLayout.blocks[blockNdx].xfbBuffer];
1999 const int offset = dataXfbBufferStartOffset + m_interfaceLayout.blocks[blockNdx].xfbOffset;
2000
2001 m_blockPointers[blockNdx] = &m_data[0] + offset;
2002 }
2003 }
2004
2005 // Generate values.
2006 generateValues(m_interfaceLayout, m_blockPointers, 1 /* seed */);
2007
2008 // Overlap validation
2009 {
2010 std::vector<deUint8> mask = createMask(m_interfaceLayout, m_blockPointers, &m_data[0], m_data.size());
2011
2012 for (size_t maskNdx = 0; maskNdx < mask.size(); ++maskNdx)
2013 DE_ASSERT(mask[maskNdx] <= 1);
2014 }
2015
2016 if (m_testStageFlags == TEST_STAGE_VERTEX)
2017 {
2018 m_vertShaderSource = generateTestShader(m_interface, m_interfaceLayout, m_blockPointers, m_matrixLoadFlag, m_testStageFlags, m_shuffleInterfaceMembers);
2019 m_geomShaderSource = "";
2020 }
2021 else if (m_testStageFlags == TEST_STAGE_GEOMETRY)
2022 {
2023 m_vertShaderSource = generatePassthroughShader();
2024 m_geomShaderSource = generateTestShader(m_interface, m_interfaceLayout, m_blockPointers, m_matrixLoadFlag, m_testStageFlags, m_shuffleInterfaceMembers);
2025 }
2026 else
2027 {
2028 DE_ASSERT(false && "Unknown test stage specified");
2029 }
2030 }
2031
2032 } // TransformFeedback
2033 } // vkt
2034