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