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; 67 LayoutFlagsFmt (deUint32 flags_) : flags(flags_) {} 68 }; 69 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 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 110 BufferBlock::BufferBlock (const char* blockName) 111 : m_blockName (blockName) 112 , m_arraySize (-1) 113 , m_flags (0) 114 { 115 setArraySize(0); 116 } 117 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 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 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 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 165 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 175 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 187 ShaderInterface::ShaderInterface (void) 188 { 189 } 190 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 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 211 StructNameEquals (const char* name_) : name(name_) {} 212 213 bool operator() (const StructType* type) const 214 { 215 return type->getTypeName() && name == type->getTypeName(); 216 } 217 }; 218 219 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 225 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 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 245 int getDataTypeByteSize (glu::DataType type) 246 { 247 return glu::getDataTypeScalarSize(type)*(int)sizeof(deUint32); 248 } 249 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 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 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 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 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. 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. 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 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 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 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 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 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 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 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 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 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; 839 Indent (int level_) : level(level_) {} 840 }; 841 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 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 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 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 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 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 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 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 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 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 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 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 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 450\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 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 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 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 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 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 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 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 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 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 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 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 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 1685 Buffer (deUint32 buffer_, int size_) : buffer(buffer_), size(size_) {} 1686 Buffer (void) : buffer(0), size(0) {} 1687 }; 1688 1689 struct BlockLocation 1690 { 1691 int index; 1692 int offset; 1693 int size; 1694 1695 BlockLocation (int index_, int offset_, int size_) : index(index_), offset(offset_), size(size_) {} 1696 BlockLocation (void) : index(0), offset(0), size(0) {} 1697 }; 1698 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 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 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 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 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 1829 SSBOLayoutCaseInstance::~SSBOLayoutCaseInstance (void) 1830 { 1831 } 1832 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 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 2146 SSBOLayoutCase::~SSBOLayoutCase (void) 2147 { 2148 } 2149 2150 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 2157 TestInstance* SSBOLayoutCase::createInstance (Context& context) const 2158 { 2159 return new SSBOLayoutCaseInstance(context, m_bufferMode, m_interface, m_refLayout, m_initialData, m_writeData); 2160 } 2161 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