1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2015 The Khronos Group Inc.
6 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and/or associated documentation files (the
10 * "Materials"), to deal in the Materials without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sublicense, and/or sell copies of the Materials, and to
13 * permit persons to whom the Materials are furnished to do so, subject to
14 * the following conditions:
16 * The above copyright notice(s) and this permission notice shall be included
17 * in all copies or substantial portions of the Materials.
19 * The Materials are Confidential Information as defined by the
20 * Khronos Membership Agreement until designated non-confidential by Khronos,
21 * at which point this condition clause shall be removed.
23 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
26 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
27 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
28 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
29 * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
33 * \brief SSBO layout case.
34 *//*--------------------------------------------------------------------*/
36 #include "vktSSBOLayoutCase.hpp"
37 #include "gluShaderProgram.hpp"
38 #include "gluContextInfo.hpp"
39 #include "gluShaderUtil.hpp"
40 #include "gluVarType.hpp"
41 #include "gluVarTypeUtil.hpp"
42 #include "tcuTestLog.hpp"
43 #include "deRandom.hpp"
44 #include "deStringUtil.hpp"
48 #include "deSharedPtr.hpp"
53 #include "vkBuilderUtil.hpp"
54 #include "vkMemUtil.hpp"
55 #include "vkPrograms.hpp"
56 #include "vkQueryUtil.hpp"
58 #include "vkRefUtil.hpp"
59 #include "vkTypeUtil.hpp"
71 using glu::StructType;
72 using glu::StructMember;
77 LayoutFlagsFmt (deUint32 flags_) : flags(flags_) {}
80 std::ostream& operator<< (std::ostream& str, const LayoutFlagsFmt& fmt)
88 { LAYOUT_STD140, "std140" },
89 { LAYOUT_STD430, "std430" },
90 { LAYOUT_ROW_MAJOR, "row_major" },
91 { LAYOUT_COLUMN_MAJOR, "column_major" }
94 deUint32 remBits = fmt.flags;
95 for (int descNdx = 0; descNdx < DE_LENGTH_OF_ARRAY(bitDesc); descNdx++)
97 if (remBits & bitDesc[descNdx].bit)
99 if (remBits != fmt.flags)
101 str << bitDesc[descNdx].token;
102 remBits &= ~bitDesc[descNdx].bit;
105 DE_ASSERT(remBits == 0);
109 // BufferVar implementation.
111 BufferVar::BufferVar (const char* name, const VarType& type, deUint32 flags)
118 // BufferBlock implementation.
120 BufferBlock::BufferBlock (const char* blockName)
121 : m_blockName (blockName)
128 void BufferBlock::setArraySize (int arraySize)
130 DE_ASSERT(arraySize >= 0);
131 m_lastUnsizedArraySizes.resize(arraySize == 0 ? 1 : arraySize, 0);
132 m_arraySize = arraySize;
135 std::ostream& operator<< (std::ostream& stream, const BlockLayoutEntry& entry)
137 stream << entry.name << " { name = " << entry.name
138 << ", size = " << entry.size
139 << ", activeVarIndices = [";
141 for (vector<int>::const_iterator i = entry.activeVarIndices.begin(); i != entry.activeVarIndices.end(); i++)
143 if (i != entry.activeVarIndices.begin())
152 static bool isUnsizedArray (const BufferVarLayoutEntry& entry)
154 DE_ASSERT(entry.arraySize != 0 || entry.topLevelArraySize != 0);
155 return entry.arraySize == 0 || entry.topLevelArraySize == 0;
158 std::ostream& operator<< (std::ostream& stream, const BufferVarLayoutEntry& entry)
160 stream << entry.name << " { type = " << glu::getDataTypeName(entry.type)
161 << ", blockNdx = " << entry.blockNdx
162 << ", offset = " << entry.offset
163 << ", arraySize = " << entry.arraySize
164 << ", arrayStride = " << entry.arrayStride
165 << ", matrixStride = " << entry.matrixStride
166 << ", topLevelArraySize = " << entry.topLevelArraySize
167 << ", topLevelArrayStride = " << entry.topLevelArrayStride
168 << ", isRowMajor = " << (entry.isRowMajor ? "true" : "false")
173 // \todo [2012-01-24 pyry] Speed up lookups using hash.
175 int BufferLayout::getVariableIndex (const string& name) const
177 for (int ndx = 0; ndx < (int)bufferVars.size(); ndx++)
179 if (bufferVars[ndx].name == name)
185 int BufferLayout::getBlockIndex (const string& name) const
187 for (int ndx = 0; ndx < (int)blocks.size(); ndx++)
189 if (blocks[ndx].name == name)
195 // ShaderInterface implementation.
197 ShaderInterface::ShaderInterface (void)
201 ShaderInterface::~ShaderInterface (void)
203 for (std::vector<StructType*>::iterator i = m_structs.begin(); i != m_structs.end(); i++)
206 for (std::vector<BufferBlock*>::iterator i = m_bufferBlocks.begin(); i != m_bufferBlocks.end(); i++)
210 StructType& ShaderInterface::allocStruct (const char* name)
212 m_structs.reserve(m_structs.size()+1);
213 m_structs.push_back(new StructType(name));
214 return *m_structs.back();
217 struct StructNameEquals
221 StructNameEquals (const char* name_) : name(name_) {}
223 bool operator() (const StructType* type) const
225 return type->getTypeName() && name == type->getTypeName();
229 const StructType* ShaderInterface::findStruct (const char* name) const
231 std::vector<StructType*>::const_iterator pos = std::find_if(m_structs.begin(), m_structs.end(), StructNameEquals(name));
232 return pos != m_structs.end() ? *pos : DE_NULL;
235 void ShaderInterface::getNamedStructs (std::vector<const StructType*>& structs) const
237 for (std::vector<StructType*>::const_iterator i = m_structs.begin(); i != m_structs.end(); i++)
239 if ((*i)->getTypeName() != DE_NULL)
240 structs.push_back(*i);
244 BufferBlock& ShaderInterface::allocBlock (const char* name)
246 m_bufferBlocks.reserve(m_bufferBlocks.size()+1);
247 m_bufferBlocks.push_back(new BufferBlock(name));
248 return *m_bufferBlocks.back();
251 namespace // Utilities
253 // Layout computation.
255 int getDataTypeByteSize (glu::DataType type)
257 return glu::getDataTypeScalarSize(type)*(int)sizeof(deUint32);
260 int getDataTypeByteAlignment (glu::DataType type)
264 case glu::TYPE_FLOAT:
267 case glu::TYPE_BOOL: return 1*(int)sizeof(deUint32);
269 case glu::TYPE_FLOAT_VEC2:
270 case glu::TYPE_INT_VEC2:
271 case glu::TYPE_UINT_VEC2:
272 case glu::TYPE_BOOL_VEC2: return 2*(int)sizeof(deUint32);
274 case glu::TYPE_FLOAT_VEC3:
275 case glu::TYPE_INT_VEC3:
276 case glu::TYPE_UINT_VEC3:
277 case glu::TYPE_BOOL_VEC3: // Fall-through to vec4
279 case glu::TYPE_FLOAT_VEC4:
280 case glu::TYPE_INT_VEC4:
281 case glu::TYPE_UINT_VEC4:
282 case glu::TYPE_BOOL_VEC4: return 4*(int)sizeof(deUint32);
290 static inline int deRoundUp32 (int a, int b)
293 return d*b == a ? a : (d+1)*b;
296 int computeStd140BaseAlignment (const VarType& type, deUint32 layoutFlags)
298 const int vec4Alignment = (int)sizeof(deUint32)*4;
300 if (type.isBasicType())
302 glu::DataType basicType = type.getBasicType();
304 if (glu::isDataTypeMatrix(basicType))
306 const bool isRowMajor = !!(layoutFlags & LAYOUT_ROW_MAJOR);
307 const int vecSize = isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType)
308 : glu::getDataTypeMatrixNumRows(basicType);
309 const int vecAlign = deAlign32(getDataTypeByteAlignment(glu::getDataTypeFloatVec(vecSize)), vec4Alignment);
314 return getDataTypeByteAlignment(basicType);
316 else if (type.isArrayType())
318 int elemAlignment = computeStd140BaseAlignment(type.getElementType(), layoutFlags);
320 // Round up to alignment of vec4
321 return deAlign32(elemAlignment, vec4Alignment);
325 DE_ASSERT(type.isStructType());
327 int maxBaseAlignment = 0;
329 for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++)
330 maxBaseAlignment = de::max(maxBaseAlignment, computeStd140BaseAlignment(memberIter->getType(), layoutFlags));
332 return deAlign32(maxBaseAlignment, vec4Alignment);
336 int computeStd430BaseAlignment (const VarType& type, deUint32 layoutFlags)
338 // Otherwise identical to std140 except that alignment of structures and arrays
339 // are not rounded up to alignment of vec4.
341 if (type.isBasicType())
343 glu::DataType basicType = type.getBasicType();
345 if (glu::isDataTypeMatrix(basicType))
347 const bool isRowMajor = !!(layoutFlags & LAYOUT_ROW_MAJOR);
348 const int vecSize = isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType)
349 : glu::getDataTypeMatrixNumRows(basicType);
350 const int vecAlign = getDataTypeByteAlignment(glu::getDataTypeFloatVec(vecSize));
355 return getDataTypeByteAlignment(basicType);
357 else if (type.isArrayType())
359 return computeStd430BaseAlignment(type.getElementType(), layoutFlags);
363 DE_ASSERT(type.isStructType());
365 int maxBaseAlignment = 0;
367 for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++)
368 maxBaseAlignment = de::max(maxBaseAlignment, computeStd430BaseAlignment(memberIter->getType(), layoutFlags));
370 return maxBaseAlignment;
374 inline deUint32 mergeLayoutFlags (deUint32 prevFlags, deUint32 newFlags)
376 const deUint32 packingMask = LAYOUT_STD430|LAYOUT_STD140;
377 const deUint32 matrixMask = LAYOUT_ROW_MAJOR|LAYOUT_COLUMN_MAJOR;
379 deUint32 mergedFlags = 0;
381 mergedFlags |= ((newFlags & packingMask) ? newFlags : prevFlags) & packingMask;
382 mergedFlags |= ((newFlags & matrixMask) ? newFlags : prevFlags) & matrixMask;
387 //! Appends all child elements to layout, returns value that should be appended to offset.
388 int computeReferenceLayout (
389 BufferLayout& layout,
392 const std::string& curPrefix,
394 deUint32 layoutFlags)
396 // Reference layout uses std430 rules by default. std140 rules are
397 // choosen only for blocks that have std140 layout.
398 const bool isStd140 = (layoutFlags & LAYOUT_STD140) != 0;
399 const int baseAlignment = isStd140 ? computeStd140BaseAlignment(type, layoutFlags)
400 : computeStd430BaseAlignment(type, layoutFlags);
401 int curOffset = deAlign32(baseOffset, baseAlignment);
402 const int topLevelArraySize = 1; // Default values
403 const int topLevelArrayStride = 0;
405 if (type.isBasicType())
407 const glu::DataType basicType = type.getBasicType();
408 BufferVarLayoutEntry entry;
410 entry.name = curPrefix;
411 entry.type = basicType;
413 entry.arrayStride = 0;
414 entry.matrixStride = 0;
415 entry.topLevelArraySize = topLevelArraySize;
416 entry.topLevelArrayStride = topLevelArrayStride;
417 entry.blockNdx = curBlockNdx;
419 if (glu::isDataTypeMatrix(basicType))
421 // Array of vectors as specified in rules 5 & 7.
422 const bool isRowMajor = !!(layoutFlags & LAYOUT_ROW_MAJOR);
423 const int numVecs = isRowMajor ? glu::getDataTypeMatrixNumRows(basicType)
424 : glu::getDataTypeMatrixNumColumns(basicType);
426 entry.offset = curOffset;
427 entry.matrixStride = baseAlignment;
428 entry.isRowMajor = isRowMajor;
430 curOffset += numVecs*baseAlignment;
435 entry.offset = curOffset;
437 curOffset += getDataTypeByteSize(basicType);
440 layout.bufferVars.push_back(entry);
442 else if (type.isArrayType())
444 const VarType& elemType = type.getElementType();
446 if (elemType.isBasicType() && !glu::isDataTypeMatrix(elemType.getBasicType()))
448 // Array of scalars or vectors.
449 const glu::DataType elemBasicType = elemType.getBasicType();
450 const int stride = baseAlignment;
451 BufferVarLayoutEntry entry;
453 entry.name = curPrefix + "[0]"; // Array variables are always postfixed with [0]
454 entry.type = elemBasicType;
455 entry.blockNdx = curBlockNdx;
456 entry.offset = curOffset;
457 entry.arraySize = type.getArraySize();
458 entry.arrayStride = stride;
459 entry.matrixStride = 0;
460 entry.topLevelArraySize = topLevelArraySize;
461 entry.topLevelArrayStride = topLevelArrayStride;
463 curOffset += stride*type.getArraySize();
465 layout.bufferVars.push_back(entry);
467 else if (elemType.isBasicType() && glu::isDataTypeMatrix(elemType.getBasicType()))
469 // Array of matrices.
470 const glu::DataType elemBasicType = elemType.getBasicType();
471 const bool isRowMajor = !!(layoutFlags & LAYOUT_ROW_MAJOR);
472 const int numVecs = isRowMajor ? glu::getDataTypeMatrixNumRows(elemBasicType)
473 : glu::getDataTypeMatrixNumColumns(elemBasicType);
474 const int vecStride = baseAlignment;
475 BufferVarLayoutEntry entry;
477 entry.name = curPrefix + "[0]"; // Array variables are always postfixed with [0]
478 entry.type = elemBasicType;
479 entry.blockNdx = curBlockNdx;
480 entry.offset = curOffset;
481 entry.arraySize = type.getArraySize();
482 entry.arrayStride = vecStride*numVecs;
483 entry.matrixStride = vecStride;
484 entry.isRowMajor = isRowMajor;
485 entry.topLevelArraySize = topLevelArraySize;
486 entry.topLevelArrayStride = topLevelArrayStride;
488 curOffset += numVecs*vecStride*type.getArraySize();
490 layout.bufferVars.push_back(entry);
494 DE_ASSERT(elemType.isStructType() || elemType.isArrayType());
496 for (int elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++)
497 curOffset += computeReferenceLayout(layout, curBlockNdx, curOffset, curPrefix + "[" + de::toString(elemNdx) + "]", type.getElementType(), layoutFlags);
502 DE_ASSERT(type.isStructType());
504 for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++)
505 curOffset += computeReferenceLayout(layout, curBlockNdx, curOffset, curPrefix + "." + memberIter->getName(), memberIter->getType(), layoutFlags);
507 curOffset = deAlign32(curOffset, baseAlignment);
510 return curOffset-baseOffset;
513 //! Appends all child elements to layout, returns offset increment.
514 int computeReferenceLayout (BufferLayout& layout, int curBlockNdx, const std::string& blockPrefix, int baseOffset, const BufferVar& bufVar, deUint32 blockLayoutFlags)
516 const VarType& varType = bufVar.getType();
517 const deUint32 combinedFlags = mergeLayoutFlags(blockLayoutFlags, bufVar.getFlags());
519 if (varType.isArrayType())
521 // Top-level arrays need special care.
522 const int topLevelArraySize = varType.getArraySize() == VarType::UNSIZED_ARRAY ? 0 : varType.getArraySize();
523 const string prefix = blockPrefix + bufVar.getName() + "[0]";
524 const bool isStd140 = (blockLayoutFlags & LAYOUT_STD140) != 0;
525 const int vec4Align = (int)sizeof(deUint32)*4;
526 const int baseAlignment = isStd140 ? computeStd140BaseAlignment(varType, combinedFlags)
527 : computeStd430BaseAlignment(varType, combinedFlags);
528 int curOffset = deAlign32(baseOffset, baseAlignment);
529 const VarType& elemType = varType.getElementType();
531 if (elemType.isBasicType() && !glu::isDataTypeMatrix(elemType.getBasicType()))
533 // Array of scalars or vectors.
534 const glu::DataType elemBasicType = elemType.getBasicType();
535 const int elemBaseAlign = getDataTypeByteAlignment(elemBasicType);
536 const int stride = isStd140 ? deAlign32(elemBaseAlign, vec4Align) : elemBaseAlign;
537 BufferVarLayoutEntry entry;
540 entry.topLevelArraySize = 1;
541 entry.topLevelArrayStride = 0;
542 entry.type = elemBasicType;
543 entry.blockNdx = curBlockNdx;
544 entry.offset = curOffset;
545 entry.arraySize = topLevelArraySize;
546 entry.arrayStride = stride;
547 entry.matrixStride = 0;
549 layout.bufferVars.push_back(entry);
551 curOffset += stride*topLevelArraySize;
553 else if (elemType.isBasicType() && glu::isDataTypeMatrix(elemType.getBasicType()))
555 // Array of matrices.
556 const glu::DataType elemBasicType = elemType.getBasicType();
557 const bool isRowMajor = !!(combinedFlags & LAYOUT_ROW_MAJOR);
558 const int vecSize = isRowMajor ? glu::getDataTypeMatrixNumColumns(elemBasicType)
559 : glu::getDataTypeMatrixNumRows(elemBasicType);
560 const int numVecs = isRowMajor ? glu::getDataTypeMatrixNumRows(elemBasicType)
561 : glu::getDataTypeMatrixNumColumns(elemBasicType);
562 const glu::DataType vecType = glu::getDataTypeFloatVec(vecSize);
563 const int vecBaseAlign = getDataTypeByteAlignment(vecType);
564 const int stride = isStd140 ? deAlign32(vecBaseAlign, vec4Align) : vecBaseAlign;
565 BufferVarLayoutEntry entry;
568 entry.topLevelArraySize = 1;
569 entry.topLevelArrayStride = 0;
570 entry.type = elemBasicType;
571 entry.blockNdx = curBlockNdx;
572 entry.offset = curOffset;
573 entry.arraySize = topLevelArraySize;
574 entry.arrayStride = stride*numVecs;
575 entry.matrixStride = stride;
576 entry.isRowMajor = isRowMajor;
578 layout.bufferVars.push_back(entry);
580 curOffset += stride*numVecs*topLevelArraySize;
584 DE_ASSERT(elemType.isStructType() || elemType.isArrayType());
586 // Struct base alignment is not added multiple times as curOffset supplied to computeReferenceLayout
587 // was already aligned correctly. Thus computeReferenceLayout should not add any extra padding
588 // before struct. Padding after struct will be added as it should.
590 // Stride could be computed prior to creating child elements, but it would essentially require running
591 // the layout computation twice. Instead we fix stride to child elements afterwards.
593 const int firstChildNdx = (int)layout.bufferVars.size();
594 const int stride = computeReferenceLayout(layout, curBlockNdx, curOffset, prefix, varType.getElementType(), combinedFlags);
596 for (int childNdx = firstChildNdx; childNdx < (int)layout.bufferVars.size(); childNdx++)
598 layout.bufferVars[childNdx].topLevelArraySize = topLevelArraySize;
599 layout.bufferVars[childNdx].topLevelArrayStride = stride;
602 curOffset += stride*topLevelArraySize;
605 return curOffset-baseOffset;
608 return computeReferenceLayout(layout, curBlockNdx, baseOffset, blockPrefix + bufVar.getName(), varType, combinedFlags);
611 void computeReferenceLayout (BufferLayout& layout, const ShaderInterface& interface)
613 int numBlocks = interface.getNumBlocks();
615 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
617 const BufferBlock& block = interface.getBlock(blockNdx);
618 bool hasInstanceName = block.getInstanceName() != DE_NULL;
619 std::string blockPrefix = hasInstanceName ? (std::string(block.getBlockName()) + ".") : std::string("");
621 int activeBlockNdx = (int)layout.blocks.size();
622 int firstVarNdx = (int)layout.bufferVars.size();
624 for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++)
626 const BufferVar& bufVar = *varIter;
627 curOffset += computeReferenceLayout(layout, activeBlockNdx, blockPrefix, curOffset, bufVar, block.getFlags());
630 int varIndicesEnd = (int)layout.bufferVars.size();
631 int blockSize = curOffset;
632 int numInstances = block.isArray() ? block.getArraySize() : 1;
634 // Create block layout entries for each instance.
635 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
637 // Allocate entry for instance.
638 layout.blocks.push_back(BlockLayoutEntry());
639 BlockLayoutEntry& blockEntry = layout.blocks.back();
641 blockEntry.name = block.getBlockName();
642 blockEntry.size = blockSize;
644 // Compute active variable set for block.
645 for (int varNdx = firstVarNdx; varNdx < varIndicesEnd; varNdx++)
646 blockEntry.activeVarIndices.push_back(varNdx);
649 blockEntry.name += "[" + de::toString(instanceNdx) + "]";
656 void generateValue (const BufferVarLayoutEntry& entry, int unsizedArraySize, void* basePtr, de::Random& rnd)
658 const glu::DataType scalarType = glu::getDataTypeScalarType(entry.type);
659 const int scalarSize = glu::getDataTypeScalarSize(entry.type);
660 const int arraySize = entry.arraySize == 0 ? unsizedArraySize : entry.arraySize;
661 const int arrayStride = entry.arrayStride;
662 const int topLevelSize = entry.topLevelArraySize == 0 ? unsizedArraySize : entry.topLevelArraySize;
663 const int topLevelStride = entry.topLevelArrayStride;
664 const bool isMatrix = glu::isDataTypeMatrix(entry.type);
665 const int numVecs = isMatrix ? (entry.isRowMajor ? glu::getDataTypeMatrixNumRows(entry.type) : glu::getDataTypeMatrixNumColumns(entry.type)) : 1;
666 const int vecSize = scalarSize / numVecs;
667 const int compSize = sizeof(deUint32);
669 DE_ASSERT(scalarSize%numVecs == 0);
670 DE_ASSERT(topLevelSize >= 0);
671 DE_ASSERT(arraySize >= 0);
673 for (int topElemNdx = 0; topElemNdx < topLevelSize; topElemNdx++)
675 deUint8* const topElemPtr = (deUint8*)basePtr + entry.offset + topElemNdx*topLevelStride;
677 for (int elemNdx = 0; elemNdx < arraySize; elemNdx++)
679 deUint8* const elemPtr = topElemPtr + elemNdx*arrayStride;
681 for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
683 deUint8* const vecPtr = elemPtr + (isMatrix ? vecNdx*entry.matrixStride : 0);
685 for (int compNdx = 0; compNdx < vecSize; compNdx++)
687 deUint8* const compPtr = vecPtr + compSize*compNdx;
691 case glu::TYPE_FLOAT: *((float*)compPtr) = (float)rnd.getInt(-9, 9); break;
692 case glu::TYPE_INT: *((int*)compPtr) = rnd.getInt(-9, 9); break;
693 case glu::TYPE_UINT: *((deUint32*)compPtr) = (deUint32)rnd.getInt(0, 9); break;
694 // \note Random bit pattern is used for true values. Spec states that all non-zero values are
695 // interpreted as true but some implementations fail this.
696 case glu::TYPE_BOOL: *((deUint32*)compPtr) = rnd.getBool() ? rnd.getUint32()|1u : 0u; break;
706 void generateValues (const BufferLayout& layout, const vector<BlockDataPtr>& blockPointers, deUint32 seed)
708 de::Random rnd (seed);
709 const int numBlocks = (int)layout.blocks.size();
711 DE_ASSERT(numBlocks == (int)blockPointers.size());
713 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
715 const BlockLayoutEntry& blockLayout = layout.blocks[blockNdx];
716 const BlockDataPtr& blockPtr = blockPointers[blockNdx];
717 const int numEntries = (int)layout.blocks[blockNdx].activeVarIndices.size();
719 for (int entryNdx = 0; entryNdx < numEntries; entryNdx++)
721 const int varNdx = blockLayout.activeVarIndices[entryNdx];
722 const BufferVarLayoutEntry& varEntry = layout.bufferVars[varNdx];
724 generateValue(varEntry, blockPtr.lastUnsizedArraySize, blockPtr.ptr, rnd);
731 const char* getCompareFuncForType (glu::DataType type)
735 case glu::TYPE_FLOAT: return "bool compare_float (highp float a, highp float b) { return abs(a - b) < 0.05; }\n";
736 case glu::TYPE_FLOAT_VEC2: return "bool compare_vec2 (highp vec2 a, highp vec2 b) { return compare_float(a.x, b.x)&&compare_float(a.y, b.y); }\n";
737 case glu::TYPE_FLOAT_VEC3: return "bool compare_vec3 (highp vec3 a, highp vec3 b) { return compare_float(a.x, b.x)&&compare_float(a.y, b.y)&&compare_float(a.z, b.z); }\n";
738 case glu::TYPE_FLOAT_VEC4: return "bool compare_vec4 (highp vec4 a, highp vec4 b) { return compare_float(a.x, b.x)&&compare_float(a.y, b.y)&&compare_float(a.z, b.z)&&compare_float(a.w, b.w); }\n";
739 case glu::TYPE_FLOAT_MAT2: return "bool compare_mat2 (highp mat2 a, highp mat2 b) { return compare_vec2(a[0], b[0])&&compare_vec2(a[1], b[1]); }\n";
740 case glu::TYPE_FLOAT_MAT2X3: return "bool compare_mat2x3 (highp mat2x3 a, highp mat2x3 b){ return compare_vec3(a[0], b[0])&&compare_vec3(a[1], b[1]); }\n";
741 case glu::TYPE_FLOAT_MAT2X4: return "bool compare_mat2x4 (highp mat2x4 a, highp mat2x4 b){ return compare_vec4(a[0], b[0])&&compare_vec4(a[1], b[1]); }\n";
742 case glu::TYPE_FLOAT_MAT3X2: return "bool compare_mat3x2 (highp mat3x2 a, highp mat3x2 b){ return compare_vec2(a[0], b[0])&&compare_vec2(a[1], b[1])&&compare_vec2(a[2], b[2]); }\n";
743 case glu::TYPE_FLOAT_MAT3: return "bool compare_mat3 (highp mat3 a, highp mat3 b) { return compare_vec3(a[0], b[0])&&compare_vec3(a[1], b[1])&&compare_vec3(a[2], b[2]); }\n";
744 case glu::TYPE_FLOAT_MAT3X4: return "bool compare_mat3x4 (highp mat3x4 a, highp mat3x4 b){ return compare_vec4(a[0], b[0])&&compare_vec4(a[1], b[1])&&compare_vec4(a[2], b[2]); }\n";
745 case glu::TYPE_FLOAT_MAT4X2: return "bool compare_mat4x2 (highp mat4x2 a, highp mat4x2 b){ return compare_vec2(a[0], b[0])&&compare_vec2(a[1], b[1])&&compare_vec2(a[2], b[2])&&compare_vec2(a[3], b[3]); }\n";
746 case glu::TYPE_FLOAT_MAT4X3: return "bool compare_mat4x3 (highp mat4x3 a, highp mat4x3 b){ return compare_vec3(a[0], b[0])&&compare_vec3(a[1], b[1])&&compare_vec3(a[2], b[2])&&compare_vec3(a[3], b[3]); }\n";
747 case glu::TYPE_FLOAT_MAT4: return "bool compare_mat4 (highp mat4 a, highp mat4 b) { return compare_vec4(a[0], b[0])&&compare_vec4(a[1], b[1])&&compare_vec4(a[2], b[2])&&compare_vec4(a[3], b[3]); }\n";
748 case glu::TYPE_INT: return "bool compare_int (highp int a, highp int b) { return a == b; }\n";
749 case glu::TYPE_INT_VEC2: return "bool compare_ivec2 (highp ivec2 a, highp ivec2 b) { return a == b; }\n";
750 case glu::TYPE_INT_VEC3: return "bool compare_ivec3 (highp ivec3 a, highp ivec3 b) { return a == b; }\n";
751 case glu::TYPE_INT_VEC4: return "bool compare_ivec4 (highp ivec4 a, highp ivec4 b) { return a == b; }\n";
752 case glu::TYPE_UINT: return "bool compare_uint (highp uint a, highp uint b) { return a == b; }\n";
753 case glu::TYPE_UINT_VEC2: return "bool compare_uvec2 (highp uvec2 a, highp uvec2 b) { return a == b; }\n";
754 case glu::TYPE_UINT_VEC3: return "bool compare_uvec3 (highp uvec3 a, highp uvec3 b) { return a == b; }\n";
755 case glu::TYPE_UINT_VEC4: return "bool compare_uvec4 (highp uvec4 a, highp uvec4 b) { return a == b; }\n";
756 case glu::TYPE_BOOL: return "bool compare_bool (bool a, bool b) { return a == b; }\n";
757 case glu::TYPE_BOOL_VEC2: return "bool compare_bvec2 (bvec2 a, bvec2 b) { return a == b; }\n";
758 case glu::TYPE_BOOL_VEC3: return "bool compare_bvec3 (bvec3 a, bvec3 b) { return a == b; }\n";
759 case glu::TYPE_BOOL_VEC4: return "bool compare_bvec4 (bvec4 a, bvec4 b) { return a == b; }\n";
766 void getCompareDependencies (std::set<glu::DataType>& compareFuncs, glu::DataType basicType)
770 case glu::TYPE_FLOAT_VEC2:
771 case glu::TYPE_FLOAT_VEC3:
772 case glu::TYPE_FLOAT_VEC4:
773 compareFuncs.insert(glu::TYPE_FLOAT);
774 compareFuncs.insert(basicType);
777 case glu::TYPE_FLOAT_MAT2:
778 case glu::TYPE_FLOAT_MAT2X3:
779 case glu::TYPE_FLOAT_MAT2X4:
780 case glu::TYPE_FLOAT_MAT3X2:
781 case glu::TYPE_FLOAT_MAT3:
782 case glu::TYPE_FLOAT_MAT3X4:
783 case glu::TYPE_FLOAT_MAT4X2:
784 case glu::TYPE_FLOAT_MAT4X3:
785 case glu::TYPE_FLOAT_MAT4:
786 compareFuncs.insert(glu::TYPE_FLOAT);
787 compareFuncs.insert(glu::getDataTypeFloatVec(glu::getDataTypeMatrixNumRows(basicType)));
788 compareFuncs.insert(basicType);
792 compareFuncs.insert(basicType);
797 void collectUniqueBasicTypes (std::set<glu::DataType>& basicTypes, const VarType& type)
799 if (type.isStructType())
801 for (StructType::ConstIterator iter = type.getStructPtr()->begin(); iter != type.getStructPtr()->end(); ++iter)
802 collectUniqueBasicTypes(basicTypes, iter->getType());
804 else if (type.isArrayType())
805 collectUniqueBasicTypes(basicTypes, type.getElementType());
808 DE_ASSERT(type.isBasicType());
809 basicTypes.insert(type.getBasicType());
813 void collectUniqueBasicTypes (std::set<glu::DataType>& basicTypes, const BufferBlock& bufferBlock)
815 for (BufferBlock::const_iterator iter = bufferBlock.begin(); iter != bufferBlock.end(); ++iter)
816 collectUniqueBasicTypes(basicTypes, iter->getType());
819 void collectUniqueBasicTypes (std::set<glu::DataType>& basicTypes, const ShaderInterface& interface)
821 for (int ndx = 0; ndx < interface.getNumBlocks(); ++ndx)
822 collectUniqueBasicTypes(basicTypes, interface.getBlock(ndx));
825 void generateCompareFuncs (std::ostream& str, const ShaderInterface& interface)
827 std::set<glu::DataType> types;
828 std::set<glu::DataType> compareFuncs;
830 // Collect unique basic types
831 collectUniqueBasicTypes(types, interface);
833 // Set of compare functions required
834 for (std::set<glu::DataType>::const_iterator iter = types.begin(); iter != types.end(); ++iter)
836 getCompareDependencies(compareFuncs, *iter);
839 for (int type = 0; type < glu::TYPE_LAST; ++type)
841 if (compareFuncs.find(glu::DataType(type)) != compareFuncs.end())
842 str << getCompareFuncForType(glu::DataType(type));
849 Indent (int level_) : level(level_) {}
852 std::ostream& operator<< (std::ostream& str, const Indent& indent)
854 for (int i = 0; i < indent.level; i++)
859 void generateDeclaration (std::ostream& src, const BufferVar& bufferVar, int indentLevel)
861 // \todo [pyry] Qualifiers
863 if ((bufferVar.getFlags() & LAYOUT_MASK) != 0)
864 src << "layout(" << LayoutFlagsFmt(bufferVar.getFlags() & LAYOUT_MASK) << ") ";
866 src << glu::declare(bufferVar.getType(), bufferVar.getName(), indentLevel);
869 void generateDeclaration (std::ostream& src, const BufferBlock& block, int bindingPoint)
873 if ((block.getFlags() & LAYOUT_MASK) != 0)
874 src << LayoutFlagsFmt(block.getFlags() & LAYOUT_MASK) << ", ";
876 src << "binding = " << bindingPoint;
880 src << "buffer " << block.getBlockName();
883 for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++)
886 generateDeclaration(src, *varIter, 1 /* indent level */);
892 if (block.getInstanceName() != DE_NULL)
894 src << " " << block.getInstanceName();
896 src << "[" << block.getArraySize() << "]";
899 DE_ASSERT(!block.isArray());
904 void generateImmMatrixSrc (std::ostream& src, glu::DataType basicType, int matrixStride, bool isRowMajor, const void* valuePtr)
906 DE_ASSERT(glu::isDataTypeMatrix(basicType));
908 const int compSize = sizeof(deUint32);
909 const int numRows = glu::getDataTypeMatrixNumRows(basicType);
910 const int numCols = glu::getDataTypeMatrixNumColumns(basicType);
912 src << glu::getDataTypeName(basicType) << "(";
914 // Constructed in column-wise order.
915 for (int colNdx = 0; colNdx < numCols; colNdx++)
917 for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
919 const deUint8* compPtr = (const deUint8*)valuePtr + (isRowMajor ? rowNdx*matrixStride + colNdx*compSize
920 : colNdx*matrixStride + rowNdx*compSize);
922 if (colNdx > 0 || rowNdx > 0)
925 src << de::floatToString(*((const float*)compPtr), 1);
932 void generateImmScalarVectorSrc (std::ostream& src, glu::DataType basicType, const void* valuePtr)
934 DE_ASSERT(glu::isDataTypeFloatOrVec(basicType) ||
935 glu::isDataTypeIntOrIVec(basicType) ||
936 glu::isDataTypeUintOrUVec(basicType) ||
937 glu::isDataTypeBoolOrBVec(basicType));
939 const glu::DataType scalarType = glu::getDataTypeScalarType(basicType);
940 const int scalarSize = glu::getDataTypeScalarSize(basicType);
941 const int compSize = sizeof(deUint32);
944 src << glu::getDataTypeName(basicType) << "(";
946 for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
948 const deUint8* compPtr = (const deUint8*)valuePtr + scalarNdx*compSize;
955 case glu::TYPE_FLOAT: src << de::floatToString(*((const float*)compPtr), 1); break;
956 case glu::TYPE_INT: src << *((const int*)compPtr); break;
957 case glu::TYPE_UINT: src << *((const deUint32*)compPtr) << "u"; break;
958 case glu::TYPE_BOOL: src << (*((const deUint32*)compPtr) != 0u ? "true" : "false"); break;
968 string getAPIName (const BufferBlock& block, const BufferVar& var, const glu::TypeComponentVector& accessPath)
970 std::ostringstream name;
972 if (block.getInstanceName())
973 name << block.getBlockName() << ".";
975 name << var.getName();
977 for (glu::TypeComponentVector::const_iterator pathComp = accessPath.begin(); pathComp != accessPath.end(); pathComp++)
979 if (pathComp->type == glu::VarTypeComponent::STRUCT_MEMBER)
981 const VarType curType = glu::getVarType(var.getType(), accessPath.begin(), pathComp);
982 const StructType* structPtr = curType.getStructPtr();
984 name << "." << structPtr->getMember(pathComp->index).getName();
986 else if (pathComp->type == glu::VarTypeComponent::ARRAY_ELEMENT)
988 if (pathComp == accessPath.begin() || (pathComp+1) == accessPath.end())
989 name << "[0]"; // Top- / bottom-level array
991 name << "[" << pathComp->index << "]";
1000 string getShaderName (const BufferBlock& block, int instanceNdx, const BufferVar& var, const glu::TypeComponentVector& accessPath)
1002 std::ostringstream name;
1004 if (block.getInstanceName())
1006 name << block.getInstanceName();
1008 if (block.isArray())
1009 name << "[" << instanceNdx << "]";
1014 DE_ASSERT(instanceNdx == 0);
1016 name << var.getName();
1018 for (glu::TypeComponentVector::const_iterator pathComp = accessPath.begin(); pathComp != accessPath.end(); pathComp++)
1020 if (pathComp->type == glu::VarTypeComponent::STRUCT_MEMBER)
1022 const VarType curType = glu::getVarType(var.getType(), accessPath.begin(), pathComp);
1023 const StructType* structPtr = curType.getStructPtr();
1025 name << "." << structPtr->getMember(pathComp->index).getName();
1027 else if (pathComp->type == glu::VarTypeComponent::ARRAY_ELEMENT)
1028 name << "[" << pathComp->index << "]";
1036 int computeOffset (const BufferVarLayoutEntry& varLayout, const glu::TypeComponentVector& accessPath)
1038 const int topLevelNdx = (accessPath.size() > 1 && accessPath.front().type == glu::VarTypeComponent::ARRAY_ELEMENT) ? accessPath.front().index : 0;
1039 const int bottomLevelNdx = (!accessPath.empty() && accessPath.back().type == glu::VarTypeComponent::ARRAY_ELEMENT) ? accessPath.back().index : 0;
1041 return varLayout.offset + varLayout.topLevelArrayStride*topLevelNdx + varLayout.arrayStride*bottomLevelNdx;
1044 void generateCompareSrc (
1046 const char* resultVar,
1047 const BufferLayout& bufferLayout,
1048 const BufferBlock& block,
1050 const BlockDataPtr& blockPtr,
1051 const BufferVar& bufVar,
1052 const glu::SubTypeAccess& accessPath)
1054 const VarType curType = accessPath.getType();
1056 if (curType.isArrayType())
1058 const int arraySize = curType.getArraySize() == VarType::UNSIZED_ARRAY ? block.getLastUnsizedArraySize(instanceNdx) : curType.getArraySize();
1060 for (int elemNdx = 0; elemNdx < arraySize; elemNdx++)
1061 generateCompareSrc(src, resultVar, bufferLayout, block, instanceNdx, blockPtr, bufVar, accessPath.element(elemNdx));
1063 else if (curType.isStructType())
1065 const int numMembers = curType.getStructPtr()->getNumMembers();
1067 for (int memberNdx = 0; memberNdx < numMembers; memberNdx++)
1068 generateCompareSrc(src, resultVar, bufferLayout, block, instanceNdx, blockPtr, bufVar, accessPath.member(memberNdx));
1072 DE_ASSERT(curType.isBasicType());
1074 const string apiName = getAPIName(block, bufVar, accessPath.getPath());
1075 const int varNdx = bufferLayout.getVariableIndex(apiName);
1077 DE_ASSERT(varNdx >= 0);
1079 const BufferVarLayoutEntry& varLayout = bufferLayout.bufferVars[varNdx];
1080 const string shaderName = getShaderName(block, instanceNdx, bufVar, accessPath.getPath());
1081 const glu::DataType basicType = curType.getBasicType();
1082 const bool isMatrix = glu::isDataTypeMatrix(basicType);
1083 const char* typeName = glu::getDataTypeName(basicType);
1084 const void* valuePtr = (const deUint8*)blockPtr.ptr + computeOffset(varLayout, accessPath.getPath());
1086 src << "\t" << resultVar << " = " << resultVar << " && compare_" << typeName << "(" << shaderName << ", ";
1089 generateImmMatrixSrc(src, basicType, varLayout.matrixStride, varLayout.isRowMajor, valuePtr);
1091 generateImmScalarVectorSrc(src, basicType, valuePtr);
1098 void generateCompareSrc (std::ostream& src, const char* resultVar, const ShaderInterface& interface, const BufferLayout& layout, const vector<BlockDataPtr>& blockPointers)
1100 for (int declNdx = 0; declNdx < interface.getNumBlocks(); declNdx++)
1102 const BufferBlock& block = interface.getBlock(declNdx);
1103 const bool isArray = block.isArray();
1104 const int numInstances = isArray ? block.getArraySize() : 1;
1106 DE_ASSERT(!isArray || block.getInstanceName());
1108 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1110 const string instanceName = block.getBlockName() + (isArray ? "[" + de::toString(instanceNdx) + "]" : string(""));
1111 const int blockNdx = layout.getBlockIndex(instanceName);
1112 const BlockDataPtr& blockPtr = blockPointers[blockNdx];
1114 for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++)
1116 const BufferVar& bufVar = *varIter;
1118 if ((bufVar.getFlags() & ACCESS_READ) == 0)
1119 continue; // Don't read from that variable.
1121 generateCompareSrc(src, resultVar, layout, block, instanceNdx, blockPtr, bufVar, glu::SubTypeAccess(bufVar.getType()));
1127 // \todo [2013-10-14 pyry] Almost identical to generateCompareSrc - unify?
1129 void generateWriteSrc (
1131 const BufferLayout& bufferLayout,
1132 const BufferBlock& block,
1134 const BlockDataPtr& blockPtr,
1135 const BufferVar& bufVar,
1136 const glu::SubTypeAccess& accessPath)
1138 const VarType curType = accessPath.getType();
1140 if (curType.isArrayType())
1142 const int arraySize = curType.getArraySize() == VarType::UNSIZED_ARRAY ? block.getLastUnsizedArraySize(instanceNdx) : curType.getArraySize();
1144 for (int elemNdx = 0; elemNdx < arraySize; elemNdx++)
1145 generateWriteSrc(src, bufferLayout, block, instanceNdx, blockPtr, bufVar, accessPath.element(elemNdx));
1147 else if (curType.isStructType())
1149 const int numMembers = curType.getStructPtr()->getNumMembers();
1151 for (int memberNdx = 0; memberNdx < numMembers; memberNdx++)
1152 generateWriteSrc(src, bufferLayout, block, instanceNdx, blockPtr, bufVar, accessPath.member(memberNdx));
1156 DE_ASSERT(curType.isBasicType());
1158 const string apiName = getAPIName(block, bufVar, accessPath.getPath());
1159 const int varNdx = bufferLayout.getVariableIndex(apiName);
1161 DE_ASSERT(varNdx >= 0);
1163 const BufferVarLayoutEntry& varLayout = bufferLayout.bufferVars[varNdx];
1164 const string shaderName = getShaderName(block, instanceNdx, bufVar, accessPath.getPath());
1165 const glu::DataType basicType = curType.getBasicType();
1166 const bool isMatrix = glu::isDataTypeMatrix(basicType);
1167 const void* valuePtr = (const deUint8*)blockPtr.ptr + computeOffset(varLayout, accessPath.getPath());
1169 src << "\t" << shaderName << " = ";
1172 generateImmMatrixSrc(src, basicType, varLayout.matrixStride, varLayout.isRowMajor, valuePtr);
1174 generateImmScalarVectorSrc(src, basicType, valuePtr);
1181 void generateWriteSrc (std::ostream& src, const ShaderInterface& interface, const BufferLayout& layout, const vector<BlockDataPtr>& blockPointers)
1183 for (int declNdx = 0; declNdx < interface.getNumBlocks(); declNdx++)
1185 const BufferBlock& block = interface.getBlock(declNdx);
1186 const bool isArray = block.isArray();
1187 const int numInstances = isArray ? block.getArraySize() : 1;
1189 DE_ASSERT(!isArray || block.getInstanceName());
1191 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1193 const string instanceName = block.getBlockName() + (isArray ? "[" + de::toString(instanceNdx) + "]" : string(""));
1194 const int blockNdx = layout.getBlockIndex(instanceName);
1195 const BlockDataPtr& blockPtr = blockPointers[blockNdx];
1197 for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++)
1199 const BufferVar& bufVar = *varIter;
1201 if ((bufVar.getFlags() & ACCESS_WRITE) == 0)
1202 continue; // Don't write to that variable.
1204 generateWriteSrc(src, layout, block, instanceNdx, blockPtr, bufVar, glu::SubTypeAccess(bufVar.getType()));
1210 string generateComputeShader (const ShaderInterface& interface, const BufferLayout& layout, const vector<BlockDataPtr>& comparePtrs, const vector<BlockDataPtr>& writePtrs)
1212 std::ostringstream src;
1214 src << "#version 450\n";
1215 src << "layout(local_size_x = 1) in;\n";
1218 // Atomic counter for counting passed invocations.
1219 src << "layout(std140, binding = 0) buffer AcBlock { highp uint ac_numPassed; };\n\n";
1221 std::vector<const StructType*> namedStructs;
1222 interface.getNamedStructs(namedStructs);
1223 for (std::vector<const StructType*>::const_iterator structIter = namedStructs.begin(); structIter != namedStructs.end(); structIter++)
1224 src << glu::declare(*structIter) << ";\n";
1227 int bindingPoint = 1;
1229 for (int blockNdx = 0; blockNdx < interface.getNumBlocks(); blockNdx++)
1231 const BufferBlock& block = interface.getBlock(blockNdx);
1232 generateDeclaration(src, block, bindingPoint);
1234 bindingPoint += block.isArray() ? block.getArraySize() : 1;
1238 // Comparison utilities.
1240 generateCompareFuncs(src, interface);
1243 "void main (void)\n"
1245 " bool allOk = true;\n";
1248 generateCompareSrc(src, "allOk", interface, layout, comparePtrs);
1250 src << " if (allOk)\n"
1251 << " ac_numPassed++;\n"
1255 generateWriteSrc(src, interface, layout, writePtrs);
1262 void copyBufferVarData (const BufferVarLayoutEntry& dstEntry, const BlockDataPtr& dstBlockPtr, const BufferVarLayoutEntry& srcEntry, const BlockDataPtr& srcBlockPtr)
1264 DE_ASSERT(dstEntry.arraySize <= srcEntry.arraySize);
1265 DE_ASSERT(dstEntry.topLevelArraySize <= srcEntry.topLevelArraySize);
1266 DE_ASSERT(dstBlockPtr.lastUnsizedArraySize <= srcBlockPtr.lastUnsizedArraySize);
1267 DE_ASSERT(dstEntry.type == srcEntry.type);
1269 deUint8* const dstBasePtr = (deUint8*)dstBlockPtr.ptr + dstEntry.offset;
1270 const deUint8* const srcBasePtr = (const deUint8*)srcBlockPtr.ptr + srcEntry.offset;
1271 const int scalarSize = glu::getDataTypeScalarSize(dstEntry.type);
1272 const bool isMatrix = glu::isDataTypeMatrix(dstEntry.type);
1273 const int compSize = sizeof(deUint32);
1274 const int dstArraySize = dstEntry.arraySize == 0 ? dstBlockPtr.lastUnsizedArraySize : dstEntry.arraySize;
1275 const int dstArrayStride = dstEntry.arrayStride;
1276 const int dstTopLevelSize = dstEntry.topLevelArraySize == 0 ? dstBlockPtr.lastUnsizedArraySize : dstEntry.topLevelArraySize;
1277 const int dstTopLevelStride = dstEntry.topLevelArrayStride;
1278 const int srcArraySize = srcEntry.arraySize == 0 ? srcBlockPtr.lastUnsizedArraySize : srcEntry.arraySize;
1279 const int srcArrayStride = srcEntry.arrayStride;
1280 const int srcTopLevelSize = srcEntry.topLevelArraySize == 0 ? srcBlockPtr.lastUnsizedArraySize : srcEntry.topLevelArraySize;
1281 const int srcTopLevelStride = srcEntry.topLevelArrayStride;
1283 DE_ASSERT(dstArraySize <= srcArraySize && dstTopLevelSize <= srcTopLevelSize);
1284 DE_UNREF(srcArraySize && srcTopLevelSize);
1286 for (int topElemNdx = 0; topElemNdx < dstTopLevelSize; topElemNdx++)
1288 deUint8* const dstTopPtr = dstBasePtr + topElemNdx*dstTopLevelStride;
1289 const deUint8* const srcTopPtr = srcBasePtr + topElemNdx*srcTopLevelStride;
1291 for (int elementNdx = 0; elementNdx < dstArraySize; elementNdx++)
1293 deUint8* const dstElemPtr = dstTopPtr + elementNdx*dstArrayStride;
1294 const deUint8* const srcElemPtr = srcTopPtr + elementNdx*srcArrayStride;
1298 const int numRows = glu::getDataTypeMatrixNumRows(dstEntry.type);
1299 const int numCols = glu::getDataTypeMatrixNumColumns(dstEntry.type);
1301 for (int colNdx = 0; colNdx < numCols; colNdx++)
1303 for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
1305 deUint8* dstCompPtr = dstElemPtr + (dstEntry.isRowMajor ? rowNdx*dstEntry.matrixStride + colNdx*compSize
1306 : colNdx*dstEntry.matrixStride + rowNdx*compSize);
1307 const deUint8* srcCompPtr = srcElemPtr + (srcEntry.isRowMajor ? rowNdx*srcEntry.matrixStride + colNdx*compSize
1308 : colNdx*srcEntry.matrixStride + rowNdx*compSize);
1310 DE_ASSERT((deIntptr)(srcCompPtr + compSize) - (deIntptr)srcBlockPtr.ptr <= (deIntptr)srcBlockPtr.size);
1311 DE_ASSERT((deIntptr)(dstCompPtr + compSize) - (deIntptr)dstBlockPtr.ptr <= (deIntptr)dstBlockPtr.size);
1312 deMemcpy(dstCompPtr, srcCompPtr, compSize);
1318 DE_ASSERT((deIntptr)(srcElemPtr + scalarSize*compSize) - (deIntptr)srcBlockPtr.ptr <= (deIntptr)srcBlockPtr.size);
1319 DE_ASSERT((deIntptr)(dstElemPtr + scalarSize*compSize) - (deIntptr)dstBlockPtr.ptr <= (deIntptr)dstBlockPtr.size);
1320 deMemcpy(dstElemPtr, srcElemPtr, scalarSize*compSize);
1326 void copyData (const BufferLayout& dstLayout, const vector<BlockDataPtr>& dstBlockPointers, const BufferLayout& srcLayout, const vector<BlockDataPtr>& srcBlockPointers)
1328 // \note Src layout is used as reference in case of activeVarIndices happens to be incorrect in dstLayout blocks.
1329 int numBlocks = (int)srcLayout.blocks.size();
1331 for (int srcBlockNdx = 0; srcBlockNdx < numBlocks; srcBlockNdx++)
1333 const BlockLayoutEntry& srcBlock = srcLayout.blocks[srcBlockNdx];
1334 const BlockDataPtr& srcBlockPtr = srcBlockPointers[srcBlockNdx];
1335 int dstBlockNdx = dstLayout.getBlockIndex(srcBlock.name.c_str());
1337 if (dstBlockNdx >= 0)
1339 DE_ASSERT(de::inBounds(dstBlockNdx, 0, (int)dstBlockPointers.size()));
1341 const BlockDataPtr& dstBlockPtr = dstBlockPointers[dstBlockNdx];
1343 for (vector<int>::const_iterator srcVarNdxIter = srcBlock.activeVarIndices.begin(); srcVarNdxIter != srcBlock.activeVarIndices.end(); srcVarNdxIter++)
1345 const BufferVarLayoutEntry& srcEntry = srcLayout.bufferVars[*srcVarNdxIter];
1346 int dstVarNdx = dstLayout.getVariableIndex(srcEntry.name.c_str());
1349 copyBufferVarData(dstLayout.bufferVars[dstVarNdx], dstBlockPtr, srcEntry, srcBlockPtr);
1355 void copyNonWrittenData (
1356 const BufferLayout& layout,
1357 const BufferBlock& block,
1359 const BlockDataPtr& srcBlockPtr,
1360 const BlockDataPtr& dstBlockPtr,
1361 const BufferVar& bufVar,
1362 const glu::SubTypeAccess& accessPath)
1364 const VarType curType = accessPath.getType();
1366 if (curType.isArrayType())
1368 const int arraySize = curType.getArraySize() == VarType::UNSIZED_ARRAY ? block.getLastUnsizedArraySize(instanceNdx) : curType.getArraySize();
1370 for (int elemNdx = 0; elemNdx < arraySize; elemNdx++)
1371 copyNonWrittenData(layout, block, instanceNdx, srcBlockPtr, dstBlockPtr, bufVar, accessPath.element(elemNdx));
1373 else if (curType.isStructType())
1375 const int numMembers = curType.getStructPtr()->getNumMembers();
1377 for (int memberNdx = 0; memberNdx < numMembers; memberNdx++)
1378 copyNonWrittenData(layout, block, instanceNdx, srcBlockPtr, dstBlockPtr, bufVar, accessPath.member(memberNdx));
1382 DE_ASSERT(curType.isBasicType());
1384 const string apiName = getAPIName(block, bufVar, accessPath.getPath());
1385 const int varNdx = layout.getVariableIndex(apiName);
1387 DE_ASSERT(varNdx >= 0);
1389 const BufferVarLayoutEntry& varLayout = layout.bufferVars[varNdx];
1390 copyBufferVarData(varLayout, dstBlockPtr, varLayout, srcBlockPtr);
1395 void copyNonWrittenData (const ShaderInterface& interface, const BufferLayout& layout, const vector<BlockDataPtr>& srcPtrs, const vector<BlockDataPtr>& dstPtrs)
1397 for (int declNdx = 0; declNdx < interface.getNumBlocks(); declNdx++)
1399 const BufferBlock& block = interface.getBlock(declNdx);
1400 const bool isArray = block.isArray();
1401 const int numInstances = isArray ? block.getArraySize() : 1;
1403 DE_ASSERT(!isArray || block.getInstanceName());
1405 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1407 const string instanceName = block.getBlockName() + (isArray ? "[" + de::toString(instanceNdx) + "]" : string(""));
1408 const int blockNdx = layout.getBlockIndex(instanceName);
1409 const BlockDataPtr& srcBlockPtr = srcPtrs[blockNdx];
1410 const BlockDataPtr& dstBlockPtr = dstPtrs[blockNdx];
1412 for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++)
1414 const BufferVar& bufVar = *varIter;
1416 if (bufVar.getFlags() & ACCESS_WRITE)
1419 copyNonWrittenData(layout, block, instanceNdx, srcBlockPtr, dstBlockPtr, bufVar, glu::SubTypeAccess(bufVar.getType()));
1425 bool compareComponents (glu::DataType scalarType, const void* ref, const void* res, int numComps)
1427 if (scalarType == glu::TYPE_FLOAT)
1429 const float threshold = 0.05f; // Same as used in shaders - should be fine for values being used.
1431 for (int ndx = 0; ndx < numComps; ndx++)
1433 const float refVal = *((const float*)ref + ndx);
1434 const float resVal = *((const float*)res + ndx);
1436 if (deFloatAbs(resVal - refVal) >= threshold)
1440 else if (scalarType == glu::TYPE_BOOL)
1442 for (int ndx = 0; ndx < numComps; ndx++)
1444 const deUint32 refVal = *((const deUint32*)ref + ndx);
1445 const deUint32 resVal = *((const deUint32*)res + ndx);
1447 if ((refVal != 0) != (resVal != 0))
1453 DE_ASSERT(scalarType == glu::TYPE_INT || scalarType == glu::TYPE_UINT);
1455 for (int ndx = 0; ndx < numComps; ndx++)
1457 const deUint32 refVal = *((const deUint32*)ref + ndx);
1458 const deUint32 resVal = *((const deUint32*)res + ndx);
1460 if (refVal != resVal)
1468 bool compareBufferVarData (tcu::TestLog& log, const BufferVarLayoutEntry& refEntry, const BlockDataPtr& refBlockPtr, const BufferVarLayoutEntry& resEntry, const BlockDataPtr& resBlockPtr)
1470 DE_ASSERT(resEntry.arraySize <= refEntry.arraySize);
1471 DE_ASSERT(resEntry.topLevelArraySize <= refEntry.topLevelArraySize);
1472 DE_ASSERT(resBlockPtr.lastUnsizedArraySize <= refBlockPtr.lastUnsizedArraySize);
1473 DE_ASSERT(resEntry.type == refEntry.type);
1475 deUint8* const resBasePtr = (deUint8*)resBlockPtr.ptr + resEntry.offset;
1476 const deUint8* const refBasePtr = (const deUint8*)refBlockPtr.ptr + refEntry.offset;
1477 const glu::DataType scalarType = glu::getDataTypeScalarType(refEntry.type);
1478 const int scalarSize = glu::getDataTypeScalarSize(resEntry.type);
1479 const bool isMatrix = glu::isDataTypeMatrix(resEntry.type);
1480 const int compSize = sizeof(deUint32);
1481 const int maxPrints = 3;
1484 const int resArraySize = resEntry.arraySize == 0 ? resBlockPtr.lastUnsizedArraySize : resEntry.arraySize;
1485 const int resArrayStride = resEntry.arrayStride;
1486 const int resTopLevelSize = resEntry.topLevelArraySize == 0 ? resBlockPtr.lastUnsizedArraySize : resEntry.topLevelArraySize;
1487 const int resTopLevelStride = resEntry.topLevelArrayStride;
1488 const int refArraySize = refEntry.arraySize == 0 ? refBlockPtr.lastUnsizedArraySize : refEntry.arraySize;
1489 const int refArrayStride = refEntry.arrayStride;
1490 const int refTopLevelSize = refEntry.topLevelArraySize == 0 ? refBlockPtr.lastUnsizedArraySize : refEntry.topLevelArraySize;
1491 const int refTopLevelStride = refEntry.topLevelArrayStride;
1493 DE_ASSERT(resArraySize <= refArraySize && resTopLevelSize <= refTopLevelSize);
1494 DE_UNREF(refArraySize && refTopLevelSize);
1496 for (int topElemNdx = 0; topElemNdx < resTopLevelSize; topElemNdx++)
1498 deUint8* const resTopPtr = resBasePtr + topElemNdx*resTopLevelStride;
1499 const deUint8* const refTopPtr = refBasePtr + topElemNdx*refTopLevelStride;
1501 for (int elementNdx = 0; elementNdx < resArraySize; elementNdx++)
1503 deUint8* const resElemPtr = resTopPtr + elementNdx*resArrayStride;
1504 const deUint8* const refElemPtr = refTopPtr + elementNdx*refArrayStride;
1508 const int numRows = glu::getDataTypeMatrixNumRows(resEntry.type);
1509 const int numCols = glu::getDataTypeMatrixNumColumns(resEntry.type);
1512 for (int colNdx = 0; colNdx < numCols; colNdx++)
1514 for (int rowNdx = 0; rowNdx < numRows; rowNdx++)
1516 deUint8* resCompPtr = resElemPtr + (resEntry.isRowMajor ? rowNdx*resEntry.matrixStride + colNdx*compSize
1517 : colNdx*resEntry.matrixStride + rowNdx*compSize);
1518 const deUint8* refCompPtr = refElemPtr + (refEntry.isRowMajor ? rowNdx*refEntry.matrixStride + colNdx*compSize
1519 : colNdx*refEntry.matrixStride + rowNdx*compSize);
1521 DE_ASSERT((deIntptr)(refCompPtr + compSize) - (deIntptr)refBlockPtr.ptr <= (deIntptr)refBlockPtr.size);
1522 DE_ASSERT((deIntptr)(resCompPtr + compSize) - (deIntptr)resBlockPtr.ptr <= (deIntptr)resBlockPtr.size);
1524 isOk = isOk && compareComponents(scalarType, resCompPtr, refCompPtr, 1);
1531 if (numFailed < maxPrints)
1533 std::ostringstream expected, got;
1534 generateImmMatrixSrc(expected, refEntry.type, refEntry.matrixStride, refEntry.isRowMajor, refElemPtr);
1535 generateImmMatrixSrc(got, resEntry.type, resEntry.matrixStride, resEntry.isRowMajor, resElemPtr);
1536 log << TestLog::Message << "ERROR: mismatch in " << refEntry.name << ", top-level ndx " << topElemNdx << ", bottom-level ndx " << elementNdx << ":\n"
1537 << " expected " << expected.str() << "\n"
1538 << " got " << got.str()
1539 << TestLog::EndMessage;
1545 DE_ASSERT((deIntptr)(refElemPtr + scalarSize*compSize) - (deIntptr)refBlockPtr.ptr <= (deIntptr)refBlockPtr.size);
1546 DE_ASSERT((deIntptr)(resElemPtr + scalarSize*compSize) - (deIntptr)resBlockPtr.ptr <= (deIntptr)resBlockPtr.size);
1548 const bool isOk = compareComponents(scalarType, resElemPtr, refElemPtr, scalarSize);
1553 if (numFailed < maxPrints)
1555 std::ostringstream expected, got;
1556 generateImmScalarVectorSrc(expected, refEntry.type, refElemPtr);
1557 generateImmScalarVectorSrc(got, resEntry.type, resElemPtr);
1558 log << TestLog::Message << "ERROR: mismatch in " << refEntry.name << ", top-level ndx " << topElemNdx << ", bottom-level ndx " << elementNdx << ":\n"
1559 << " expected " << expected.str() << "\n"
1560 << " got " << got.str()
1561 << TestLog::EndMessage;
1568 if (numFailed >= maxPrints)
1569 log << TestLog::Message << "... (" << numFailed << " failures for " << refEntry.name << " in total)" << TestLog::EndMessage;
1571 return numFailed == 0;
1574 bool compareData (tcu::TestLog& log, const BufferLayout& refLayout, const vector<BlockDataPtr>& refBlockPointers, const BufferLayout& resLayout, const vector<BlockDataPtr>& resBlockPointers)
1576 const int numBlocks = (int)refLayout.blocks.size();
1579 for (int refBlockNdx = 0; refBlockNdx < numBlocks; refBlockNdx++)
1581 const BlockLayoutEntry& refBlock = refLayout.blocks[refBlockNdx];
1582 const BlockDataPtr& refBlockPtr = refBlockPointers[refBlockNdx];
1583 int resBlockNdx = resLayout.getBlockIndex(refBlock.name.c_str());
1585 if (resBlockNdx >= 0)
1587 DE_ASSERT(de::inBounds(resBlockNdx, 0, (int)resBlockPointers.size()));
1589 const BlockDataPtr& resBlockPtr = resBlockPointers[resBlockNdx];
1591 for (vector<int>::const_iterator refVarNdxIter = refBlock.activeVarIndices.begin(); refVarNdxIter != refBlock.activeVarIndices.end(); refVarNdxIter++)
1593 const BufferVarLayoutEntry& refEntry = refLayout.bufferVars[*refVarNdxIter];
1594 int resVarNdx = resLayout.getVariableIndex(refEntry.name.c_str());
1598 const BufferVarLayoutEntry& resEntry = resLayout.bufferVars[resVarNdx];
1599 allOk = compareBufferVarData(log, refEntry, refBlockPtr, resEntry, resBlockPtr) && allOk;
1608 string getBlockAPIName (const BufferBlock& block, int instanceNdx)
1610 DE_ASSERT(block.isArray() || instanceNdx == 0);
1611 return block.getBlockName() + (block.isArray() ? ("[" + de::toString(instanceNdx) + "]") : string());
1614 // \note Some implementations don't report block members in the order they are declared.
1615 // For checking whether size has to be adjusted by some top-level array actual size,
1616 // we only need to know a) whether there is a unsized top-level array, and b)
1617 // what is stride of that array.
1619 static bool hasUnsizedArray (const BufferLayout& layout, const BlockLayoutEntry& entry)
1621 for (vector<int>::const_iterator varNdx = entry.activeVarIndices.begin(); varNdx != entry.activeVarIndices.end(); ++varNdx)
1623 if (isUnsizedArray(layout.bufferVars[*varNdx]))
1630 static int getUnsizedArrayStride (const BufferLayout& layout, const BlockLayoutEntry& entry)
1632 for (vector<int>::const_iterator varNdx = entry.activeVarIndices.begin(); varNdx != entry.activeVarIndices.end(); ++varNdx)
1634 const BufferVarLayoutEntry& varEntry = layout.bufferVars[*varNdx];
1636 if (varEntry.arraySize == 0)
1637 return varEntry.arrayStride;
1638 else if (varEntry.topLevelArraySize == 0)
1639 return varEntry.topLevelArrayStride;
1645 vector<int> computeBufferSizes (const ShaderInterface& interface, const BufferLayout& layout)
1647 vector<int> sizes(layout.blocks.size());
1649 for (int declNdx = 0; declNdx < interface.getNumBlocks(); declNdx++)
1651 const BufferBlock& block = interface.getBlock(declNdx);
1652 const bool isArray = block.isArray();
1653 const int numInstances = isArray ? block.getArraySize() : 1;
1655 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
1657 const string apiName = getBlockAPIName(block, instanceNdx);
1658 const int blockNdx = layout.getBlockIndex(apiName);
1662 const BlockLayoutEntry& blockLayout = layout.blocks[blockNdx];
1663 const int baseSize = blockLayout.size;
1664 const bool isLastUnsized = hasUnsizedArray(layout, blockLayout);
1665 const int lastArraySize = isLastUnsized ? block.getLastUnsizedArraySize(instanceNdx) : 0;
1666 const int stride = isLastUnsized ? getUnsizedArrayStride(layout, blockLayout) : 0;
1668 sizes[blockNdx] = baseSize + lastArraySize*stride;
1676 BlockDataPtr getBlockDataPtr (const BufferLayout& layout, const BlockLayoutEntry& blockLayout, void* ptr, int bufferSize)
1678 const bool isLastUnsized = hasUnsizedArray(layout, blockLayout);
1679 const int baseSize = blockLayout.size;
1683 const int lastArrayStride = getUnsizedArrayStride(layout, blockLayout);
1684 const int lastArraySize = (bufferSize-baseSize) / (lastArrayStride ? lastArrayStride : 1);
1686 DE_ASSERT(baseSize + lastArraySize*lastArrayStride == bufferSize);
1688 return BlockDataPtr(ptr, bufferSize, lastArraySize);
1691 return BlockDataPtr(ptr, bufferSize, 0);
1699 Buffer (deUint32 buffer_, int size_) : buffer(buffer_), size(size_) {}
1700 Buffer (void) : buffer(0), size(0) {}
1703 struct BlockLocation
1709 BlockLocation (int index_, int offset_, int size_) : index(index_), offset(offset_), size(size_) {}
1710 BlockLocation (void) : index(0), offset(0), size(0) {}
1713 void initRefDataStorage (const ShaderInterface& interface, const BufferLayout& layout, RefDataStorage& storage)
1715 DE_ASSERT(storage.data.empty() && storage.pointers.empty());
1717 const vector<int> bufferSizes = computeBufferSizes(interface, layout);
1720 for (vector<int>::const_iterator sizeIter = bufferSizes.begin(); sizeIter != bufferSizes.end(); ++sizeIter)
1721 totalSize += *sizeIter;
1723 storage.data.resize(totalSize);
1725 // Pointers for each block.
1727 deUint8* basePtr = storage.data.empty() ? DE_NULL : &storage.data[0];
1730 DE_ASSERT(bufferSizes.size() == layout.blocks.size());
1731 DE_ASSERT(totalSize == 0 || basePtr);
1733 storage.pointers.resize(layout.blocks.size());
1735 for (int blockNdx = 0; blockNdx < (int)layout.blocks.size(); blockNdx++)
1737 const BlockLayoutEntry& blockLayout = layout.blocks[blockNdx];
1738 const int bufferSize = bufferSizes[blockNdx];
1740 storage.pointers[blockNdx] = getBlockDataPtr(layout, blockLayout, basePtr + curOffset, bufferSize);
1742 curOffset += bufferSize;
1748 vector<BlockDataPtr> blockLocationsToPtrs (const BufferLayout& layout, const vector<BlockLocation>& blockLocations, const vector<void*>& bufPtrs)
1750 vector<BlockDataPtr> blockPtrs(blockLocations.size());
1752 DE_ASSERT(layout.blocks.size() == blockLocations.size());
1754 for (int blockNdx = 0; blockNdx < (int)layout.blocks.size(); blockNdx++)
1756 const BlockLayoutEntry& blockLayout = layout.blocks[blockNdx];
1757 const BlockLocation& location = blockLocations[blockNdx];
1759 blockPtrs[blockNdx] = getBlockDataPtr(layout, blockLayout, (deUint8*)bufPtrs[location.index] + location.offset, location.size);
1765 } // anonymous (utilities)
1767 de::MovePtr<vk::Allocation> allocateAndBindMemory (Context& context, vk::VkBuffer buffer, vk::MemoryRequirement memReqs)
1769 const vk::DeviceInterface& vkd = context.getDeviceInterface();
1770 const vk::VkMemoryRequirements bufReqs = vk::getBufferMemoryRequirements(vkd, context.getDevice(), buffer);
1771 de::MovePtr<vk::Allocation> memory = context.getDefaultAllocator().allocate(bufReqs, memReqs);
1773 vkd.bindBufferMemory(context.getDevice(), buffer, memory->getMemory(), memory->getOffset());
1778 vk::Move<vk::VkBuffer> createBuffer (Context& context, vk::VkDeviceSize bufferSize, vk::VkBufferUsageFlags usageFlags)
1780 const vk::VkDevice vkDevice = context.getDevice();
1781 const vk::DeviceInterface& vk = context.getDeviceInterface();
1782 const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
1784 const vk::VkBufferCreateInfo bufferInfo =
1786 vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
1787 DE_NULL, // const void* pNext;
1788 0u, // VkBufferCreateFlags flags;
1789 bufferSize, // VkDeviceSize size;
1790 usageFlags, // VkBufferUsageFlags usage;
1791 vk::VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1792 1u, // deUint32 queueFamilyCount;
1793 &queueFamilyIndex // const deUint32* pQueueFamilyIndices;
1796 return vk::createBuffer(vk, vkDevice, &bufferInfo);
1799 // SSBOLayoutCaseInstance
1801 class SSBOLayoutCaseInstance : public TestInstance
1804 SSBOLayoutCaseInstance (Context& context,
1805 SSBOLayoutCase::BufferMode bufferMode,
1806 const ShaderInterface& interface,
1807 const BufferLayout& refLayout,
1808 const RefDataStorage& initialData,
1809 const RefDataStorage& writeData);
1810 virtual ~SSBOLayoutCaseInstance (void);
1811 virtual tcu::TestStatus iterate (void);
1814 SSBOLayoutCase::BufferMode m_bufferMode;
1815 const ShaderInterface& m_interface;
1816 const BufferLayout& m_refLayout;
1817 const RefDataStorage& m_initialData; // Initial data stored in buffer.
1818 const RefDataStorage& m_writeData; // Data written by compute shader.
1821 typedef de::SharedPtr<vk::Unique<vk::VkBuffer> > VkBufferSp;
1822 typedef de::SharedPtr<vk::Allocation> AllocationSp;
1824 std::vector<VkBufferSp> m_uniformBuffers;
1825 std::vector<AllocationSp> m_uniformAllocs;
1828 SSBOLayoutCaseInstance::SSBOLayoutCaseInstance (Context& context,
1829 SSBOLayoutCase::BufferMode bufferMode,
1830 const ShaderInterface& interface,
1831 const BufferLayout& refLayout,
1832 const RefDataStorage& initialData,
1833 const RefDataStorage& writeData)
1834 : TestInstance (context)
1835 , m_bufferMode (bufferMode)
1836 , m_interface (interface)
1837 , m_refLayout (refLayout)
1838 , m_initialData (initialData)
1839 , m_writeData (writeData)
1843 SSBOLayoutCaseInstance::~SSBOLayoutCaseInstance (void)
1847 tcu::TestStatus SSBOLayoutCaseInstance::iterate (void)
1849 // todo: add compute stage availability check
1850 const vk::DeviceInterface& vk = m_context.getDeviceInterface();
1851 const vk::VkDevice device = m_context.getDevice();
1852 const vk::VkQueue queue = m_context.getUniversalQueue();
1853 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
1855 // Create descriptor set
1856 const deUint32 acBufferSize = 1024;
1857 vk::Move<vk::VkBuffer> acBuffer (createBuffer(m_context, acBufferSize, vk:: VK_BUFFER_USAGE_STORAGE_BUFFER_BIT));
1858 de::UniquePtr<vk::Allocation> acBufferAlloc (allocateAndBindMemory(m_context, *acBuffer, vk::MemoryRequirement::HostVisible));
1860 deMemset(acBufferAlloc->getHostPtr(), 0, acBufferSize);
1861 flushMappedMemoryRange(vk, device, acBufferAlloc->getMemory(), acBufferAlloc->getOffset(), acBufferSize);
1863 vk::DescriptorSetLayoutBuilder setLayoutBuilder;
1864 vk::DescriptorPoolBuilder poolBuilder;
1867 .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT);
1869 const int numBlocks = (int)m_refLayout.blocks.size();
1870 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1873 .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT);
1877 .addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, (deUint32)(1 + numBlocks));
1879 const vk::Unique<vk::VkDescriptorSetLayout> descriptorSetLayout(setLayoutBuilder.build(vk, device));
1880 const vk::Unique<vk::VkDescriptorPool> descriptorPool(poolBuilder.build(vk, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
1882 const vk::VkDescriptorSetAllocateInfo allocInfo =
1884 vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
1888 &descriptorSetLayout.get(),
1891 const vk::Unique<vk::VkDescriptorSet> descriptorSet(allocateDescriptorSet(vk, device, &allocInfo));
1892 const vk::VkDescriptorBufferInfo descriptorInfo = makeDescriptorBufferInfo(*acBuffer, 0ull, acBufferSize);
1894 vk::DescriptorSetUpdateBuilder setUpdateBuilder;
1895 std::vector<vk::VkDescriptorBufferInfo> descriptors(numBlocks);
1898 .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorInfo);
1900 vector<BlockDataPtr> mappedBlockPtrs;
1902 // Upload base buffers
1904 const std::vector<int> bufferSizes = computeBufferSizes(m_interface, m_refLayout);
1905 std::vector<void*> mapPtrs;
1906 std::vector<BlockLocation> blockLocations (numBlocks);
1908 DE_ASSERT(bufferSizes.size() == m_refLayout.blocks.size());
1910 if (m_bufferMode == SSBOLayoutCase::BUFFERMODE_PER_BLOCK)
1912 mapPtrs.resize(numBlocks);
1913 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1915 const deUint32 bufferSize = bufferSizes[blockNdx];
1916 DE_ASSERT(bufferSize > 0);
1918 blockLocations[blockNdx] = BlockLocation(blockNdx, 0, bufferSize);
1920 vk::Move<vk::VkBuffer> buffer = createBuffer(m_context, bufferSize, vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
1921 de::MovePtr<vk::Allocation> alloc = allocateAndBindMemory(m_context, *buffer, vk::MemoryRequirement::HostVisible);
1923 descriptors[blockNdx] = makeDescriptorBufferInfo(*buffer, 0ull, bufferSize);
1925 mapPtrs[blockNdx] = alloc->getHostPtr();
1927 m_uniformBuffers.push_back(VkBufferSp(new vk::Unique<vk::VkBuffer>(buffer)));
1928 m_uniformAllocs.push_back(AllocationSp(alloc.release()));
1930 setUpdateBuilder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(blockNdx + 1),
1931 vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptors[blockNdx]);
1936 DE_ASSERT(m_bufferMode == SSBOLayoutCase::BUFFERMODE_SINGLE);
1938 vk::VkPhysicalDeviceProperties properties;
1939 m_context.getInstanceInterface().getPhysicalDeviceProperties(m_context.getPhysicalDevice(), &properties);
1940 const int bindingAlignment = (int)properties.limits.minStorageBufferOffsetAlignment;
1942 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1944 const int bufferSize = bufferSizes[blockNdx];
1945 DE_ASSERT(bufferSize > 0);
1947 if (bindingAlignment > 0)
1948 curOffset = deRoundUp32(curOffset, bindingAlignment);
1950 blockLocations[blockNdx] = BlockLocation(0, curOffset, bufferSize);
1951 curOffset += bufferSize;
1954 const int totalBufferSize = curOffset;
1955 vk::Move<vk::VkBuffer> buffer = createBuffer(m_context, totalBufferSize, vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
1956 de::MovePtr<vk::Allocation> alloc = allocateAndBindMemory(m_context, *buffer, vk::MemoryRequirement::HostVisible);
1958 mapPtrs.push_back(alloc->getHostPtr());
1960 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++)
1962 const deUint32 bufferSize = bufferSizes[blockNdx];
1963 const deUint32 offset = blockLocations[blockNdx].offset;
1965 descriptors[blockNdx] = makeDescriptorBufferInfo(*buffer, offset, bufferSize);
1967 setUpdateBuilder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(blockNdx + 1),
1968 vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptors[blockNdx]);
1971 m_uniformBuffers.push_back(VkBufferSp(new vk::Unique<vk::VkBuffer>(buffer)));
1972 m_uniformAllocs.push_back(AllocationSp(alloc.release()));
1975 // Copy the initial data to the storage buffers
1977 mappedBlockPtrs = blockLocationsToPtrs(m_refLayout, blockLocations, mapPtrs);
1978 copyData(m_refLayout, mappedBlockPtrs, m_refLayout, m_initialData.pointers);
1980 if (m_bufferMode == SSBOLayoutCase::BUFFERMODE_PER_BLOCK)
1982 DE_ASSERT(m_uniformAllocs.size() == bufferSizes.size());
1983 for (size_t allocNdx = 0; allocNdx < m_uniformAllocs.size(); allocNdx++)
1985 const int size = bufferSizes[allocNdx];
1986 vk::Allocation* alloc = m_uniformAllocs[allocNdx].get();
1987 flushMappedMemoryRange(vk, device, alloc->getMemory(), alloc->getOffset(), size);
1992 DE_ASSERT(m_bufferMode == SSBOLayoutCase::BUFFERMODE_SINGLE);
1993 DE_ASSERT(m_uniformAllocs.size() == 1);
1995 for (size_t bufferNdx = 0; bufferNdx < bufferSizes.size(); bufferNdx++)
1997 totalSize += bufferSizes[bufferNdx];
2000 DE_ASSERT(totalSize > 0);
2001 vk::Allocation* alloc = m_uniformAllocs[0].get();
2002 flushMappedMemoryRange(vk, device, alloc->getMemory(), alloc->getOffset(), totalSize);
2007 setUpdateBuilder.update(vk, device);
2009 const vk::VkPipelineLayoutCreateInfo pipelineLayoutParams =
2011 vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
2012 DE_NULL, // const void* pNext;
2013 (vk::VkPipelineLayoutCreateFlags)0,
2014 1u, // deUint32 descriptorSetCount;
2015 &*descriptorSetLayout, // const VkDescriptorSetLayout* pSetLayouts;
2016 0u, // deUint32 pushConstantRangeCount;
2017 DE_NULL, // const VkPushConstantRange* pPushConstantRanges;
2019 vk::Move<vk::VkPipelineLayout> pipelineLayout(createPipelineLayout(vk, device, &pipelineLayoutParams));
2021 vk::Move<vk::VkShaderModule> shaderModule (createShaderModule(vk, device, m_context.getBinaryCollection().get("compute"), 0));
2022 const vk::VkPipelineShaderStageCreateInfo pipelineShaderStageParams =
2024 vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,// VkStructureType sType;
2025 DE_NULL, // const void* pNext;
2026 (vk::VkPipelineShaderStageCreateFlags)0,
2027 vk::VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStage stage;
2028 *shaderModule, // VkShader shader;
2030 DE_NULL, // const VkSpecializationInfo* pSpecializationInfo;
2032 const vk::VkComputePipelineCreateInfo pipelineCreateInfo =
2034 vk::VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // VkStructureType sType;
2035 DE_NULL, // const void* pNext;
2036 0, // VkPipelineCreateFlags flags;
2037 pipelineShaderStageParams, // VkPipelineShaderStageCreateInfo stage;
2038 *pipelineLayout, // VkPipelineLayout layout;
2039 DE_NULL, // VkPipeline basePipelineHandle;
2040 0, // deInt32 basePipelineIndex;
2042 vk::Move<vk::VkPipeline> pipeline(createComputePipeline(vk, device, DE_NULL, &pipelineCreateInfo));
2044 const vk::VkCommandPoolCreateInfo cmdPoolParams =
2046 vk::VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, // VkStructureType sType;
2047 DE_NULL, // const void* pNext;
2048 vk::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, // VkCmdPoolCreateFlags flags;
2049 queueFamilyIndex, // deUint32 queueFamilyIndex;
2051 vk::Move<vk::VkCommandPool> cmdPool (createCommandPool(vk, device, &cmdPoolParams));
2053 const vk::VkCommandBufferAllocateInfo cmdBufParams =
2055 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType sType;
2056 DE_NULL, // const void* pNext;
2057 *cmdPool, // VkCmdPool pool;
2058 vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY, // VkCmdBufferLevel level;
2059 1u, // deUint32 bufferCount;
2061 vk::Move<vk::VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vk, device, &cmdBufParams));
2063 const vk::VkCommandBufferBeginInfo cmdBufBeginParams =
2065 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
2066 DE_NULL, // const void* pNext;
2067 0u, // VkCmdBufferOptimizeFlags flags;
2068 DE_NULL, // VkRenderPass renderPass;
2069 0u, // deUint32 subpass;
2070 DE_NULL, // VkFramebuffer framebuffer;
2072 (vk::VkQueryControlFlags)0,
2073 (vk::VkQueryPipelineStatisticFlags)0,
2075 VK_CHECK(vk.beginCommandBuffer(*cmdBuffer, &cmdBufBeginParams));
2077 vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
2078 vk.cmdBindDescriptorSets(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
2080 vk.cmdDispatch(*cmdBuffer, 1, 1, 1);
2082 VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
2084 const vk::VkFenceCreateInfo fenceParams =
2086 vk::VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // VkStructureType sType;
2087 DE_NULL, // const void* pNext;
2088 0u, // VkFenceCreateFlags flags;
2090 vk::Move<vk::VkFence> fence (createFence(vk, device, &fenceParams));
2092 const vk::VkSubmitInfo submitInfo =
2094 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
2097 (const vk::VkSemaphore*)DE_NULL,
2101 (const vk::VkSemaphore*)DE_NULL,
2104 VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfo, *fence));
2105 VK_CHECK(vk.waitForFences(device, 1u, &fence.get(), DE_TRUE, ~0ull));
2107 // Read back ac_numPassed data
2110 const int refCount = 1;
2113 resCount = *(const int*)((const deUint8*)acBufferAlloc->getHostPtr());
2115 counterOk = (refCount == resCount);
2118 m_context.getTestContext().getLog() << TestLog::Message << "Error: ac_numPassed = " << resCount << ", expected " << refCount << TestLog::EndMessage;
2123 const bool compareOk = compareData(m_context.getTestContext().getLog(), m_refLayout, m_writeData.pointers, m_refLayout, mappedBlockPtrs);
2125 if (compareOk && counterOk)
2126 return tcu::TestStatus::pass("Result comparison and counter values are OK");
2127 else if (!compareOk && counterOk)
2128 return tcu::TestStatus::fail("Result comparison failed");
2129 else if (compareOk && !counterOk)
2130 return tcu::TestStatus::fail("Counter value incorrect");
2132 return tcu::TestStatus::fail("Result comparison and counter values are incorrect");
2137 SSBOLayoutCase::SSBOLayoutCase (tcu::TestContext& testCtx, const char* name, const char* description, BufferMode bufferMode)
2138 : TestCase (testCtx, name, description)
2139 , m_bufferMode (bufferMode)
2143 SSBOLayoutCase::~SSBOLayoutCase (void)
2147 void SSBOLayoutCase::initPrograms (vk::SourceCollections& programCollection) const
2149 DE_ASSERT(!m_computeShaderSrc.empty());
2151 programCollection.glslSources.add("compute") << glu::ComputeSource(m_computeShaderSrc);
2154 TestInstance* SSBOLayoutCase::createInstance (Context& context) const
2156 return new SSBOLayoutCaseInstance(context, m_bufferMode, m_interface, m_refLayout, m_initialData, m_writeData);
2159 void SSBOLayoutCase::init (void)
2161 computeReferenceLayout (m_refLayout, m_interface);
2162 initRefDataStorage (m_interface, m_refLayout, m_initialData);
2163 initRefDataStorage (m_interface, m_refLayout, m_writeData);
2164 generateValues (m_refLayout, m_initialData.pointers, deStringHash(getName()) ^ 0xad2f7214);
2165 generateValues (m_refLayout, m_writeData.pointers, deStringHash(getName()) ^ 0x25ca4e7);
2166 copyNonWrittenData (m_interface, m_refLayout, m_initialData.pointers, m_writeData.pointers);
2168 m_computeShaderSrc = generateComputeShader(m_interface, m_refLayout, m_initialData.pointers, m_writeData.pointers);