1/*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 3.1 Module 3 * ------------------------------------------------- 4 * 5 * Copyright 2014 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief SSBO layout case. 22 *//*--------------------------------------------------------------------*/ 23 24#include "es31fSSBOLayoutCase.hpp" 25#include "gluRenderContext.hpp" 26#include "gluShaderProgram.hpp" 27#include "gluPixelTransfer.hpp" 28#include "gluContextInfo.hpp" 29#include "gluRenderContext.hpp" 30#include "gluProgramInterfaceQuery.hpp" 31#include "gluObjectWrapper.hpp" 32#include "gluVarTypeUtil.hpp" 33#include "glwFunctions.hpp" 34#include "glwEnums.hpp" 35#include "tcuTestLog.hpp" 36#include "tcuSurface.hpp" 37#include "tcuRenderTarget.hpp" 38#include "deRandom.hpp" 39#include "deStringUtil.hpp" 40#include "deMemory.h" 41#include "deString.h" 42#include "deMath.h" 43 44#include <algorithm> 45#include <map> 46 47using tcu::TestLog; 48using std::string; 49using std::vector; 50using std::map; 51 52namespace deqp 53{ 54namespace gles31 55{ 56 57using glu::VarType; 58using glu::StructType; 59using glu::StructMember; 60 61namespace bb 62{ 63 64struct LayoutFlagsFmt 65{ 66 deUint32 flags; 67 LayoutFlagsFmt (deUint32 flags_) : flags(flags_) {} 68}; 69 70std::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_SHARED, "shared" }, 79 { LAYOUT_PACKED, "packed" }, 80 { LAYOUT_STD140, "std140" }, 81 { LAYOUT_STD430, "std430" }, 82 { LAYOUT_ROW_MAJOR, "row_major" }, 83 { LAYOUT_COLUMN_MAJOR, "column_major" } 84 }; 85 86 deUint32 remBits = fmt.flags; 87 for (int descNdx = 0; descNdx < DE_LENGTH_OF_ARRAY(bitDesc); descNdx++) 88 { 89 if (remBits & bitDesc[descNdx].bit) 90 { 91 if (remBits != fmt.flags) 92 str << ", "; 93 str << bitDesc[descNdx].token; 94 remBits &= ~bitDesc[descNdx].bit; 95 } 96 } 97 DE_ASSERT(remBits == 0); 98 return str; 99} 100 101// BufferVar implementation. 102 103BufferVar::BufferVar (const char* name, const VarType& type, deUint32 flags) 104 : m_name (name) 105 , m_type (type) 106 , m_flags (flags) 107{ 108} 109 110// BufferBlock implementation. 111 112BufferBlock::BufferBlock (const char* blockName) 113 : m_blockName (blockName) 114 , m_arraySize (-1) 115 , m_flags (0) 116{ 117 setArraySize(0); 118} 119 120void BufferBlock::setArraySize (int arraySize) 121{ 122 DE_ASSERT(arraySize >= 0); 123 m_lastUnsizedArraySizes.resize(arraySize == 0 ? 1 : arraySize, 0); 124 m_arraySize = arraySize; 125} 126 127struct BlockLayoutEntry 128{ 129 BlockLayoutEntry (void) 130 : size(0) 131 { 132 } 133 134 std::string name; 135 int size; 136 std::vector<int> activeVarIndices; 137}; 138 139std::ostream& operator<< (std::ostream& stream, const BlockLayoutEntry& entry) 140{ 141 stream << entry.name << " { name = " << entry.name 142 << ", size = " << entry.size 143 << ", activeVarIndices = ["; 144 145 for (vector<int>::const_iterator i = entry.activeVarIndices.begin(); i != entry.activeVarIndices.end(); i++) 146 { 147 if (i != entry.activeVarIndices.begin()) 148 stream << ", "; 149 stream << *i; 150 } 151 152 stream << "] }"; 153 return stream; 154} 155 156struct BufferVarLayoutEntry 157{ 158 BufferVarLayoutEntry (void) 159 : type (glu::TYPE_LAST) 160 , blockNdx (-1) 161 , offset (-1) 162 , arraySize (-1) 163 , arrayStride (-1) 164 , matrixStride (-1) 165 , topLevelArraySize (-1) 166 , topLevelArrayStride (-1) 167 , isRowMajor (false) 168 { 169 } 170 171 std::string name; 172 glu::DataType type; 173 int blockNdx; 174 int offset; 175 int arraySize; 176 int arrayStride; 177 int matrixStride; 178 int topLevelArraySize; 179 int topLevelArrayStride; 180 bool isRowMajor; 181}; 182 183static bool isUnsizedArray (const BufferVarLayoutEntry& entry) 184{ 185 DE_ASSERT(entry.arraySize != 0 || entry.topLevelArraySize != 0); 186 return entry.arraySize == 0 || entry.topLevelArraySize == 0; 187} 188 189std::ostream& operator<< (std::ostream& stream, const BufferVarLayoutEntry& entry) 190{ 191 stream << entry.name << " { type = " << glu::getDataTypeName(entry.type) 192 << ", blockNdx = " << entry.blockNdx 193 << ", offset = " << entry.offset 194 << ", arraySize = " << entry.arraySize 195 << ", arrayStride = " << entry.arrayStride 196 << ", matrixStride = " << entry.matrixStride 197 << ", topLevelArraySize = " << entry.topLevelArraySize 198 << ", topLevelArrayStride = " << entry.topLevelArrayStride 199 << ", isRowMajor = " << (entry.isRowMajor ? "true" : "false") 200 << " }"; 201 return stream; 202} 203 204class BufferLayout 205{ 206public: 207 std::vector<BlockLayoutEntry> blocks; 208 std::vector<BufferVarLayoutEntry> bufferVars; 209 210 int getVariableIndex (const string& name) const; 211 int getBlockIndex (const string& name) const; 212}; 213 214// \todo [2012-01-24 pyry] Speed up lookups using hash. 215 216int BufferLayout::getVariableIndex (const string& name) const 217{ 218 for (int ndx = 0; ndx < (int)bufferVars.size(); ndx++) 219 { 220 if (bufferVars[ndx].name == name) 221 return ndx; 222 } 223 return -1; 224} 225 226int BufferLayout::getBlockIndex (const string& name) const 227{ 228 for (int ndx = 0; ndx < (int)blocks.size(); ndx++) 229 { 230 if (blocks[ndx].name == name) 231 return ndx; 232 } 233 return -1; 234} 235 236// ShaderInterface implementation. 237 238ShaderInterface::ShaderInterface (void) 239{ 240} 241 242ShaderInterface::~ShaderInterface (void) 243{ 244 for (std::vector<StructType*>::iterator i = m_structs.begin(); i != m_structs.end(); i++) 245 delete *i; 246 247 for (std::vector<BufferBlock*>::iterator i = m_bufferBlocks.begin(); i != m_bufferBlocks.end(); i++) 248 delete *i; 249} 250 251StructType& ShaderInterface::allocStruct (const char* name) 252{ 253 m_structs.reserve(m_structs.size()+1); 254 m_structs.push_back(new StructType(name)); 255 return *m_structs.back(); 256} 257 258struct StructNameEquals 259{ 260 std::string name; 261 262 StructNameEquals (const char* name_) : name(name_) {} 263 264 bool operator() (const StructType* type) const 265 { 266 return type->getTypeName() && name == type->getTypeName(); 267 } 268}; 269 270const StructType* ShaderInterface::findStruct (const char* name) const 271{ 272 std::vector<StructType*>::const_iterator pos = std::find_if(m_structs.begin(), m_structs.end(), StructNameEquals(name)); 273 return pos != m_structs.end() ? *pos : DE_NULL; 274} 275 276void ShaderInterface::getNamedStructs (std::vector<const StructType*>& structs) const 277{ 278 for (std::vector<StructType*>::const_iterator i = m_structs.begin(); i != m_structs.end(); i++) 279 { 280 if ((*i)->getTypeName() != DE_NULL) 281 structs.push_back(*i); 282 } 283} 284 285BufferBlock& ShaderInterface::allocBlock (const char* name) 286{ 287 m_bufferBlocks.reserve(m_bufferBlocks.size()+1); 288 m_bufferBlocks.push_back(new BufferBlock(name)); 289 return *m_bufferBlocks.back(); 290} 291 292// BlockDataPtr 293 294struct BlockDataPtr 295{ 296 void* ptr; 297 int size; //!< Redundant, for debugging purposes. 298 int lastUnsizedArraySize; 299 300 BlockDataPtr (void* ptr_, int size_, int lastUnsizedArraySize_) 301 : ptr (ptr_) 302 , size (size_) 303 , lastUnsizedArraySize (lastUnsizedArraySize_) 304 { 305 } 306 307 BlockDataPtr (void) 308 : ptr (DE_NULL) 309 , size (0) 310 , lastUnsizedArraySize (0) 311 { 312 } 313}; 314 315namespace // Utilities 316{ 317 318int findBlockIndex (const BufferLayout& layout, const string& name) 319{ 320 for (int ndx = 0; ndx < (int)layout.blocks.size(); ndx++) 321 { 322 if (layout.blocks[ndx].name == name) 323 return ndx; 324 } 325 return -1; 326} 327 328// Layout computation. 329 330int getDataTypeByteSize (glu::DataType type) 331{ 332 return glu::getDataTypeScalarSize(type)*(int)sizeof(deUint32); 333} 334 335int getDataTypeByteAlignment (glu::DataType type) 336{ 337 switch (type) 338 { 339 case glu::TYPE_FLOAT: 340 case glu::TYPE_INT: 341 case glu::TYPE_UINT: 342 case glu::TYPE_BOOL: return 1*(int)sizeof(deUint32); 343 344 case glu::TYPE_FLOAT_VEC2: 345 case glu::TYPE_INT_VEC2: 346 case glu::TYPE_UINT_VEC2: 347 case glu::TYPE_BOOL_VEC2: return 2*(int)sizeof(deUint32); 348 349 case glu::TYPE_FLOAT_VEC3: 350 case glu::TYPE_INT_VEC3: 351 case glu::TYPE_UINT_VEC3: 352 case glu::TYPE_BOOL_VEC3: // Fall-through to vec4 353 354 case glu::TYPE_FLOAT_VEC4: 355 case glu::TYPE_INT_VEC4: 356 case glu::TYPE_UINT_VEC4: 357 case glu::TYPE_BOOL_VEC4: return 4*(int)sizeof(deUint32); 358 359 default: 360 DE_ASSERT(false); 361 return 0; 362 } 363} 364 365static inline int deRoundUp32 (int a, int b) 366{ 367 int d = a/b; 368 return d*b == a ? a : (d+1)*b; 369} 370 371int computeStd140BaseAlignment (const VarType& type, deUint32 layoutFlags) 372{ 373 const int vec4Alignment = (int)sizeof(deUint32)*4; 374 375 if (type.isBasicType()) 376 { 377 glu::DataType basicType = type.getBasicType(); 378 379 if (glu::isDataTypeMatrix(basicType)) 380 { 381 const bool isRowMajor = !!(layoutFlags & LAYOUT_ROW_MAJOR); 382 const int vecSize = isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType) 383 : glu::getDataTypeMatrixNumRows(basicType); 384 const int vecAlign = deAlign32(getDataTypeByteAlignment(glu::getDataTypeFloatVec(vecSize)), vec4Alignment); 385 386 return vecAlign; 387 } 388 else 389 return getDataTypeByteAlignment(basicType); 390 } 391 else if (type.isArrayType()) 392 { 393 int elemAlignment = computeStd140BaseAlignment(type.getElementType(), layoutFlags); 394 395 // Round up to alignment of vec4 396 return deAlign32(elemAlignment, vec4Alignment); 397 } 398 else 399 { 400 DE_ASSERT(type.isStructType()); 401 402 int maxBaseAlignment = 0; 403 404 for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++) 405 maxBaseAlignment = de::max(maxBaseAlignment, computeStd140BaseAlignment(memberIter->getType(), layoutFlags)); 406 407 return deAlign32(maxBaseAlignment, vec4Alignment); 408 } 409} 410 411int computeStd430BaseAlignment (const VarType& type, deUint32 layoutFlags) 412{ 413 // Otherwise identical to std140 except that alignment of structures and arrays 414 // are not rounded up to alignment of vec4. 415 416 if (type.isBasicType()) 417 { 418 glu::DataType basicType = type.getBasicType(); 419 420 if (glu::isDataTypeMatrix(basicType)) 421 { 422 const bool isRowMajor = !!(layoutFlags & LAYOUT_ROW_MAJOR); 423 const int vecSize = isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType) 424 : glu::getDataTypeMatrixNumRows(basicType); 425 const int vecAlign = getDataTypeByteAlignment(glu::getDataTypeFloatVec(vecSize)); 426 427 return vecAlign; 428 } 429 else 430 return getDataTypeByteAlignment(basicType); 431 } 432 else if (type.isArrayType()) 433 { 434 return computeStd430BaseAlignment(type.getElementType(), layoutFlags); 435 } 436 else 437 { 438 DE_ASSERT(type.isStructType()); 439 440 int maxBaseAlignment = 0; 441 442 for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++) 443 maxBaseAlignment = de::max(maxBaseAlignment, computeStd430BaseAlignment(memberIter->getType(), layoutFlags)); 444 445 return maxBaseAlignment; 446 } 447} 448 449inline deUint32 mergeLayoutFlags (deUint32 prevFlags, deUint32 newFlags) 450{ 451 const deUint32 packingMask = LAYOUT_PACKED|LAYOUT_SHARED|LAYOUT_STD140|LAYOUT_STD430; 452 const deUint32 matrixMask = LAYOUT_ROW_MAJOR|LAYOUT_COLUMN_MAJOR; 453 454 deUint32 mergedFlags = 0; 455 456 mergedFlags |= ((newFlags & packingMask) ? newFlags : prevFlags) & packingMask; 457 mergedFlags |= ((newFlags & matrixMask) ? newFlags : prevFlags) & matrixMask; 458 459 return mergedFlags; 460} 461 462//! Appends all child elements to layout, returns value that should be appended to offset. 463int computeReferenceLayout ( 464 BufferLayout& layout, 465 int curBlockNdx, 466 int baseOffset, 467 const std::string& curPrefix, 468 const VarType& type, 469 deUint32 layoutFlags) 470{ 471 // Reference layout uses std430 rules by default. std140 rules are 472 // choosen only for blocks that have std140 layout. 473 const bool isStd140 = (layoutFlags & LAYOUT_STD140) != 0; 474 const int baseAlignment = isStd140 ? computeStd140BaseAlignment(type, layoutFlags) 475 : computeStd430BaseAlignment(type, layoutFlags); 476 int curOffset = deAlign32(baseOffset, baseAlignment); 477 const int topLevelArraySize = 1; // Default values 478 const int topLevelArrayStride = 0; 479 480 if (type.isBasicType()) 481 { 482 const glu::DataType basicType = type.getBasicType(); 483 BufferVarLayoutEntry entry; 484 485 entry.name = curPrefix; 486 entry.type = basicType; 487 entry.arraySize = 1; 488 entry.arrayStride = 0; 489 entry.matrixStride = 0; 490 entry.topLevelArraySize = topLevelArraySize; 491 entry.topLevelArrayStride = topLevelArrayStride; 492 entry.blockNdx = curBlockNdx; 493 494 if (glu::isDataTypeMatrix(basicType)) 495 { 496 // Array of vectors as specified in rules 5 & 7. 497 const bool isRowMajor = !!(layoutFlags & LAYOUT_ROW_MAJOR); 498 const int numVecs = isRowMajor ? glu::getDataTypeMatrixNumRows(basicType) 499 : glu::getDataTypeMatrixNumColumns(basicType); 500 501 entry.offset = curOffset; 502 entry.matrixStride = baseAlignment; 503 entry.isRowMajor = isRowMajor; 504 505 curOffset += numVecs*baseAlignment; 506 } 507 else 508 { 509 // Scalar or vector. 510 entry.offset = curOffset; 511 512 curOffset += getDataTypeByteSize(basicType); 513 } 514 515 layout.bufferVars.push_back(entry); 516 } 517 else if (type.isArrayType()) 518 { 519 const VarType& elemType = type.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 stride = baseAlignment; 526 BufferVarLayoutEntry entry; 527 528 entry.name = curPrefix + "[0]"; // Array variables are always postfixed with [0] 529 entry.type = elemBasicType; 530 entry.blockNdx = curBlockNdx; 531 entry.offset = curOffset; 532 entry.arraySize = type.getArraySize(); 533 entry.arrayStride = stride; 534 entry.matrixStride = 0; 535 entry.topLevelArraySize = topLevelArraySize; 536 entry.topLevelArrayStride = topLevelArrayStride; 537 538 curOffset += stride*type.getArraySize(); 539 540 layout.bufferVars.push_back(entry); 541 } 542 else if (elemType.isBasicType() && glu::isDataTypeMatrix(elemType.getBasicType())) 543 { 544 // Array of matrices. 545 const glu::DataType elemBasicType = elemType.getBasicType(); 546 const bool isRowMajor = !!(layoutFlags & LAYOUT_ROW_MAJOR); 547 const int numVecs = isRowMajor ? glu::getDataTypeMatrixNumRows(elemBasicType) 548 : glu::getDataTypeMatrixNumColumns(elemBasicType); 549 const int vecStride = baseAlignment; 550 BufferVarLayoutEntry entry; 551 552 entry.name = curPrefix + "[0]"; // Array variables are always postfixed with [0] 553 entry.type = elemBasicType; 554 entry.blockNdx = curBlockNdx; 555 entry.offset = curOffset; 556 entry.arraySize = type.getArraySize(); 557 entry.arrayStride = vecStride*numVecs; 558 entry.matrixStride = vecStride; 559 entry.isRowMajor = isRowMajor; 560 entry.topLevelArraySize = topLevelArraySize; 561 entry.topLevelArrayStride = topLevelArrayStride; 562 563 curOffset += numVecs*vecStride*type.getArraySize(); 564 565 layout.bufferVars.push_back(entry); 566 } 567 else 568 { 569 DE_ASSERT(elemType.isStructType() || elemType.isArrayType()); 570 571 for (int elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++) 572 curOffset += computeReferenceLayout(layout, curBlockNdx, curOffset, curPrefix + "[" + de::toString(elemNdx) + "]", type.getElementType(), layoutFlags); 573 } 574 } 575 else 576 { 577 DE_ASSERT(type.isStructType()); 578 579 for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++) 580 curOffset += computeReferenceLayout(layout, curBlockNdx, curOffset, curPrefix + "." + memberIter->getName(), memberIter->getType(), layoutFlags); 581 582 curOffset = deAlign32(curOffset, baseAlignment); 583 } 584 585 return curOffset-baseOffset; 586} 587 588//! Appends all child elements to layout, returns offset increment. 589int computeReferenceLayout (BufferLayout& layout, int curBlockNdx, const std::string& blockPrefix, int baseOffset, const BufferVar& bufVar, deUint32 blockLayoutFlags) 590{ 591 const VarType& varType = bufVar.getType(); 592 const deUint32 combinedFlags = mergeLayoutFlags(blockLayoutFlags, bufVar.getFlags()); 593 594 if (varType.isArrayType()) 595 { 596 // Top-level arrays need special care. 597 const int topLevelArraySize = varType.getArraySize() == VarType::UNSIZED_ARRAY ? 0 : varType.getArraySize(); 598 const string prefix = blockPrefix + bufVar.getName() + "[0]"; 599 const bool isStd140 = (blockLayoutFlags & LAYOUT_STD140) != 0; 600 const int vec4Align = (int)sizeof(deUint32)*4; 601 const int baseAlignment = isStd140 ? computeStd140BaseAlignment(varType, combinedFlags) 602 : computeStd430BaseAlignment(varType, combinedFlags); 603 int curOffset = deAlign32(baseOffset, baseAlignment); 604 const VarType& elemType = varType.getElementType(); 605 606 if (elemType.isBasicType() && !glu::isDataTypeMatrix(elemType.getBasicType())) 607 { 608 // Array of scalars or vectors. 609 const glu::DataType elemBasicType = elemType.getBasicType(); 610 const int elemBaseAlign = getDataTypeByteAlignment(elemBasicType); 611 const int stride = isStd140 ? deAlign32(elemBaseAlign, vec4Align) : elemBaseAlign; 612 BufferVarLayoutEntry entry; 613 614 entry.name = prefix; 615 entry.topLevelArraySize = 1; 616 entry.topLevelArrayStride = 0; 617 entry.type = elemBasicType; 618 entry.blockNdx = curBlockNdx; 619 entry.offset = curOffset; 620 entry.arraySize = topLevelArraySize; 621 entry.arrayStride = stride; 622 entry.matrixStride = 0; 623 624 layout.bufferVars.push_back(entry); 625 626 curOffset += stride*topLevelArraySize; 627 } 628 else if (elemType.isBasicType() && glu::isDataTypeMatrix(elemType.getBasicType())) 629 { 630 // Array of matrices. 631 const glu::DataType elemBasicType = elemType.getBasicType(); 632 const bool isRowMajor = !!(combinedFlags & LAYOUT_ROW_MAJOR); 633 const int vecSize = isRowMajor ? glu::getDataTypeMatrixNumColumns(elemBasicType) 634 : glu::getDataTypeMatrixNumRows(elemBasicType); 635 const int numVecs = isRowMajor ? glu::getDataTypeMatrixNumRows(elemBasicType) 636 : glu::getDataTypeMatrixNumColumns(elemBasicType); 637 const glu::DataType vecType = glu::getDataTypeFloatVec(vecSize); 638 const int vecBaseAlign = getDataTypeByteAlignment(vecType); 639 const int stride = isStd140 ? deAlign32(vecBaseAlign, vec4Align) : vecBaseAlign; 640 BufferVarLayoutEntry entry; 641 642 entry.name = prefix; 643 entry.topLevelArraySize = 1; 644 entry.topLevelArrayStride = 0; 645 entry.type = elemBasicType; 646 entry.blockNdx = curBlockNdx; 647 entry.offset = curOffset; 648 entry.arraySize = topLevelArraySize; 649 entry.arrayStride = stride*numVecs; 650 entry.matrixStride = stride; 651 entry.isRowMajor = isRowMajor; 652 653 layout.bufferVars.push_back(entry); 654 655 curOffset += stride*numVecs*topLevelArraySize; 656 } 657 else 658 { 659 DE_ASSERT(elemType.isStructType() || elemType.isArrayType()); 660 661 // Struct base alignment is not added multiple times as curOffset supplied to computeReferenceLayout 662 // was already aligned correctly. Thus computeReferenceLayout should not add any extra padding 663 // before struct. Padding after struct will be added as it should. 664 // 665 // Stride could be computed prior to creating child elements, but it would essentially require running 666 // the layout computation twice. Instead we fix stride to child elements afterwards. 667 668 const int firstChildNdx = (int)layout.bufferVars.size(); 669 const int stride = computeReferenceLayout(layout, curBlockNdx, curOffset, prefix, varType.getElementType(), combinedFlags); 670 671 for (int childNdx = firstChildNdx; childNdx < (int)layout.bufferVars.size(); childNdx++) 672 { 673 layout.bufferVars[childNdx].topLevelArraySize = topLevelArraySize; 674 layout.bufferVars[childNdx].topLevelArrayStride = stride; 675 } 676 677 curOffset += stride*topLevelArraySize; 678 } 679 680 return curOffset-baseOffset; 681 } 682 else 683 return computeReferenceLayout(layout, curBlockNdx, baseOffset, blockPrefix + bufVar.getName(), varType, combinedFlags); 684} 685 686void computeReferenceLayout (BufferLayout& layout, const ShaderInterface& interface) 687{ 688 int numBlocks = interface.getNumBlocks(); 689 690 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 691 { 692 const BufferBlock& block = interface.getBlock(blockNdx); 693 bool hasInstanceName = block.getInstanceName() != DE_NULL; 694 std::string blockPrefix = hasInstanceName ? (std::string(block.getBlockName()) + ".") : std::string(""); 695 int curOffset = 0; 696 int activeBlockNdx = (int)layout.blocks.size(); 697 int firstVarNdx = (int)layout.bufferVars.size(); 698 699 for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++) 700 { 701 const BufferVar& bufVar = *varIter; 702 curOffset += computeReferenceLayout(layout, activeBlockNdx, blockPrefix, curOffset, bufVar, block.getFlags()); 703 } 704 705 int varIndicesEnd = (int)layout.bufferVars.size(); 706 int blockSize = curOffset; 707 int numInstances = block.isArray() ? block.getArraySize() : 1; 708 709 // Create block layout entries for each instance. 710 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++) 711 { 712 // Allocate entry for instance. 713 layout.blocks.push_back(BlockLayoutEntry()); 714 BlockLayoutEntry& blockEntry = layout.blocks.back(); 715 716 blockEntry.name = block.getBlockName(); 717 blockEntry.size = blockSize; 718 719 // Compute active variable set for block. 720 for (int varNdx = firstVarNdx; varNdx < varIndicesEnd; varNdx++) 721 blockEntry.activeVarIndices.push_back(varNdx); 722 723 if (block.isArray()) 724 blockEntry.name += "[" + de::toString(instanceNdx) + "]"; 725 } 726 } 727} 728 729// Value generator. 730 731void generateValue (const BufferVarLayoutEntry& entry, int unsizedArraySize, void* basePtr, de::Random& rnd) 732{ 733 const glu::DataType scalarType = glu::getDataTypeScalarType(entry.type); 734 const int scalarSize = glu::getDataTypeScalarSize(entry.type); 735 const int arraySize = entry.arraySize == 0 ? unsizedArraySize : entry.arraySize; 736 const int arrayStride = entry.arrayStride; 737 const int topLevelSize = entry.topLevelArraySize == 0 ? unsizedArraySize : entry.topLevelArraySize; 738 const int topLevelStride = entry.topLevelArrayStride; 739 const bool isMatrix = glu::isDataTypeMatrix(entry.type); 740 const int numVecs = isMatrix ? (entry.isRowMajor ? glu::getDataTypeMatrixNumRows(entry.type) : glu::getDataTypeMatrixNumColumns(entry.type)) : 1; 741 const int vecSize = scalarSize / numVecs; 742 const int compSize = sizeof(deUint32); 743 744 DE_ASSERT(scalarSize%numVecs == 0); 745 DE_ASSERT(topLevelSize >= 0); 746 DE_ASSERT(arraySize >= 0); 747 748 for (int topElemNdx = 0; topElemNdx < topLevelSize; topElemNdx++) 749 { 750 deUint8* const topElemPtr = (deUint8*)basePtr + entry.offset + topElemNdx*topLevelStride; 751 752 for (int elemNdx = 0; elemNdx < arraySize; elemNdx++) 753 { 754 deUint8* const elemPtr = topElemPtr + elemNdx*arrayStride; 755 756 for (int vecNdx = 0; vecNdx < numVecs; vecNdx++) 757 { 758 deUint8* const vecPtr = elemPtr + (isMatrix ? vecNdx*entry.matrixStride : 0); 759 760 for (int compNdx = 0; compNdx < vecSize; compNdx++) 761 { 762 deUint8* const compPtr = vecPtr + compSize*compNdx; 763 764 switch (scalarType) 765 { 766 case glu::TYPE_FLOAT: *((float*)compPtr) = (float)rnd.getInt(-9, 9); break; 767 case glu::TYPE_INT: *((int*)compPtr) = rnd.getInt(-9, 9); break; 768 case glu::TYPE_UINT: *((deUint32*)compPtr) = (deUint32)rnd.getInt(0, 9); break; 769 // \note Random bit pattern is used for true values. Spec states that all non-zero values are 770 // interpreted as true but some implementations fail this. 771 case glu::TYPE_BOOL: *((deUint32*)compPtr) = rnd.getBool() ? rnd.getUint32()|1u : 0u; break; 772 default: 773 DE_ASSERT(false); 774 } 775 } 776 } 777 } 778 } 779} 780 781void generateValues (const BufferLayout& layout, const vector<BlockDataPtr>& blockPointers, deUint32 seed) 782{ 783 de::Random rnd (seed); 784 const int numBlocks = (int)layout.blocks.size(); 785 786 DE_ASSERT(numBlocks == (int)blockPointers.size()); 787 788 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 789 { 790 const BlockLayoutEntry& blockLayout = layout.blocks[blockNdx]; 791 const BlockDataPtr& blockPtr = blockPointers[blockNdx]; 792 const int numEntries = (int)layout.blocks[blockNdx].activeVarIndices.size(); 793 794 for (int entryNdx = 0; entryNdx < numEntries; entryNdx++) 795 { 796 const int varNdx = blockLayout.activeVarIndices[entryNdx]; 797 const BufferVarLayoutEntry& varEntry = layout.bufferVars[varNdx]; 798 799 generateValue(varEntry, blockPtr.lastUnsizedArraySize, blockPtr.ptr, rnd); 800 } 801 } 802} 803 804// Shader generator. 805 806const char* getCompareFuncForType (glu::DataType type) 807{ 808 switch (type) 809 { 810 case glu::TYPE_FLOAT: return "bool compare_float (highp float a, highp float b) { return abs(a - b) < 0.05; }\n"; 811 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"; 812 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"; 813 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"; 814 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"; 815 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"; 816 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"; 817 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"; 818 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"; 819 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"; 820 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"; 821 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"; 822 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"; 823 case glu::TYPE_INT: return "bool compare_int (highp int a, highp int b) { return a == b; }\n"; 824 case glu::TYPE_INT_VEC2: return "bool compare_ivec2 (highp ivec2 a, highp ivec2 b) { return a == b; }\n"; 825 case glu::TYPE_INT_VEC3: return "bool compare_ivec3 (highp ivec3 a, highp ivec3 b) { return a == b; }\n"; 826 case glu::TYPE_INT_VEC4: return "bool compare_ivec4 (highp ivec4 a, highp ivec4 b) { return a == b; }\n"; 827 case glu::TYPE_UINT: return "bool compare_uint (highp uint a, highp uint b) { return a == b; }\n"; 828 case glu::TYPE_UINT_VEC2: return "bool compare_uvec2 (highp uvec2 a, highp uvec2 b) { return a == b; }\n"; 829 case glu::TYPE_UINT_VEC3: return "bool compare_uvec3 (highp uvec3 a, highp uvec3 b) { return a == b; }\n"; 830 case glu::TYPE_UINT_VEC4: return "bool compare_uvec4 (highp uvec4 a, highp uvec4 b) { return a == b; }\n"; 831 case glu::TYPE_BOOL: return "bool compare_bool (bool a, bool b) { return a == b; }\n"; 832 case glu::TYPE_BOOL_VEC2: return "bool compare_bvec2 (bvec2 a, bvec2 b) { return a == b; }\n"; 833 case glu::TYPE_BOOL_VEC3: return "bool compare_bvec3 (bvec3 a, bvec3 b) { return a == b; }\n"; 834 case glu::TYPE_BOOL_VEC4: return "bool compare_bvec4 (bvec4 a, bvec4 b) { return a == b; }\n"; 835 default: 836 DE_ASSERT(false); 837 return DE_NULL; 838 } 839} 840 841void getCompareDependencies (std::set<glu::DataType>& compareFuncs, glu::DataType basicType) 842{ 843 switch (basicType) 844 { 845 case glu::TYPE_FLOAT_VEC2: 846 case glu::TYPE_FLOAT_VEC3: 847 case glu::TYPE_FLOAT_VEC4: 848 compareFuncs.insert(glu::TYPE_FLOAT); 849 compareFuncs.insert(basicType); 850 break; 851 852 case glu::TYPE_FLOAT_MAT2: 853 case glu::TYPE_FLOAT_MAT2X3: 854 case glu::TYPE_FLOAT_MAT2X4: 855 case glu::TYPE_FLOAT_MAT3X2: 856 case glu::TYPE_FLOAT_MAT3: 857 case glu::TYPE_FLOAT_MAT3X4: 858 case glu::TYPE_FLOAT_MAT4X2: 859 case glu::TYPE_FLOAT_MAT4X3: 860 case glu::TYPE_FLOAT_MAT4: 861 compareFuncs.insert(glu::TYPE_FLOAT); 862 compareFuncs.insert(glu::getDataTypeFloatVec(glu::getDataTypeMatrixNumRows(basicType))); 863 compareFuncs.insert(basicType); 864 break; 865 866 default: 867 compareFuncs.insert(basicType); 868 break; 869 } 870} 871 872void collectUniqueBasicTypes (std::set<glu::DataType>& basicTypes, const VarType& type) 873{ 874 if (type.isStructType()) 875 { 876 for (StructType::ConstIterator iter = type.getStructPtr()->begin(); iter != type.getStructPtr()->end(); ++iter) 877 collectUniqueBasicTypes(basicTypes, iter->getType()); 878 } 879 else if (type.isArrayType()) 880 collectUniqueBasicTypes(basicTypes, type.getElementType()); 881 else 882 { 883 DE_ASSERT(type.isBasicType()); 884 basicTypes.insert(type.getBasicType()); 885 } 886} 887 888void collectUniqueBasicTypes (std::set<glu::DataType>& basicTypes, const BufferBlock& bufferBlock) 889{ 890 for (BufferBlock::const_iterator iter = bufferBlock.begin(); iter != bufferBlock.end(); ++iter) 891 collectUniqueBasicTypes(basicTypes, iter->getType()); 892} 893 894void collectUniqueBasicTypes (std::set<glu::DataType>& basicTypes, const ShaderInterface& interface) 895{ 896 for (int ndx = 0; ndx < interface.getNumBlocks(); ++ndx) 897 collectUniqueBasicTypes(basicTypes, interface.getBlock(ndx)); 898} 899 900void generateCompareFuncs (std::ostream& str, const ShaderInterface& interface) 901{ 902 std::set<glu::DataType> types; 903 std::set<glu::DataType> compareFuncs; 904 905 // Collect unique basic types 906 collectUniqueBasicTypes(types, interface); 907 908 // Set of compare functions required 909 for (std::set<glu::DataType>::const_iterator iter = types.begin(); iter != types.end(); ++iter) 910 { 911 getCompareDependencies(compareFuncs, *iter); 912 } 913 914 for (int type = 0; type < glu::TYPE_LAST; ++type) 915 { 916 if (compareFuncs.find(glu::DataType(type)) != compareFuncs.end()) 917 str << getCompareFuncForType(glu::DataType(type)); 918 } 919} 920 921struct Indent 922{ 923 int level; 924 Indent (int level_) : level(level_) {} 925}; 926 927std::ostream& operator<< (std::ostream& str, const Indent& indent) 928{ 929 for (int i = 0; i < indent.level; i++) 930 str << "\t"; 931 return str; 932} 933 934void generateDeclaration (std::ostream& src, const BufferVar& bufferVar, int indentLevel) 935{ 936 // \todo [pyry] Qualifiers 937 938 if ((bufferVar.getFlags() & LAYOUT_MASK) != 0) 939 src << "layout(" << LayoutFlagsFmt(bufferVar.getFlags() & LAYOUT_MASK) << ") "; 940 941 src << glu::declare(bufferVar.getType(), bufferVar.getName(), indentLevel); 942} 943 944void generateDeclaration (std::ostream& src, const BufferBlock& block, int bindingPoint) 945{ 946 src << "layout("; 947 948 if ((block.getFlags() & LAYOUT_MASK) != 0) 949 src << LayoutFlagsFmt(block.getFlags() & LAYOUT_MASK) << ", "; 950 951 src << "binding = " << bindingPoint; 952 953 src << ") "; 954 955 src << "buffer " << block.getBlockName(); 956 src << "\n{\n"; 957 958 for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++) 959 { 960 src << Indent(1); 961 generateDeclaration(src, *varIter, 1 /* indent level */); 962 src << ";\n"; 963 } 964 965 src << "}"; 966 967 if (block.getInstanceName() != DE_NULL) 968 { 969 src << " " << block.getInstanceName(); 970 if (block.isArray()) 971 src << "[" << block.getArraySize() << "]"; 972 } 973 else 974 DE_ASSERT(!block.isArray()); 975 976 src << ";\n"; 977} 978 979void generateImmMatrixSrc (std::ostream& src, glu::DataType basicType, int matrixStride, bool isRowMajor, const void* valuePtr) 980{ 981 DE_ASSERT(glu::isDataTypeMatrix(basicType)); 982 983 const int compSize = sizeof(deUint32); 984 const int numRows = glu::getDataTypeMatrixNumRows(basicType); 985 const int numCols = glu::getDataTypeMatrixNumColumns(basicType); 986 987 src << glu::getDataTypeName(basicType) << "("; 988 989 // Constructed in column-wise order. 990 for (int colNdx = 0; colNdx < numCols; colNdx++) 991 { 992 for (int rowNdx = 0; rowNdx < numRows; rowNdx++) 993 { 994 const deUint8* compPtr = (const deUint8*)valuePtr + (isRowMajor ? rowNdx*matrixStride + colNdx*compSize 995 : colNdx*matrixStride + rowNdx*compSize); 996 997 if (colNdx > 0 || rowNdx > 0) 998 src << ", "; 999 1000 src << de::floatToString(*((const float*)compPtr), 1); 1001 } 1002 } 1003 1004 src << ")"; 1005} 1006 1007void generateImmScalarVectorSrc (std::ostream& src, glu::DataType basicType, const void* valuePtr) 1008{ 1009 DE_ASSERT(glu::isDataTypeFloatOrVec(basicType) || 1010 glu::isDataTypeIntOrIVec(basicType) || 1011 glu::isDataTypeUintOrUVec(basicType) || 1012 glu::isDataTypeBoolOrBVec(basicType)); 1013 1014 const glu::DataType scalarType = glu::getDataTypeScalarType(basicType); 1015 const int scalarSize = glu::getDataTypeScalarSize(basicType); 1016 const int compSize = sizeof(deUint32); 1017 1018 if (scalarSize > 1) 1019 src << glu::getDataTypeName(basicType) << "("; 1020 1021 for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++) 1022 { 1023 const deUint8* compPtr = (const deUint8*)valuePtr + scalarNdx*compSize; 1024 1025 if (scalarNdx > 0) 1026 src << ", "; 1027 1028 switch (scalarType) 1029 { 1030 case glu::TYPE_FLOAT: src << de::floatToString(*((const float*)compPtr), 1); break; 1031 case glu::TYPE_INT: src << *((const int*)compPtr); break; 1032 case glu::TYPE_UINT: src << *((const deUint32*)compPtr) << "u"; break; 1033 case glu::TYPE_BOOL: src << (*((const deUint32*)compPtr) != 0u ? "true" : "false"); break; 1034 default: 1035 DE_ASSERT(false); 1036 } 1037 } 1038 1039 if (scalarSize > 1) 1040 src << ")"; 1041} 1042 1043string getAPIName (const BufferBlock& block, const BufferVar& var, const glu::TypeComponentVector& accessPath) 1044{ 1045 std::ostringstream name; 1046 1047 if (block.getInstanceName()) 1048 name << block.getBlockName() << "."; 1049 1050 name << var.getName(); 1051 1052 for (glu::TypeComponentVector::const_iterator pathComp = accessPath.begin(); pathComp != accessPath.end(); pathComp++) 1053 { 1054 if (pathComp->type == glu::VarTypeComponent::STRUCT_MEMBER) 1055 { 1056 const VarType curType = glu::getVarType(var.getType(), accessPath.begin(), pathComp); 1057 const StructType* structPtr = curType.getStructPtr(); 1058 1059 name << "." << structPtr->getMember(pathComp->index).getName(); 1060 } 1061 else if (pathComp->type == glu::VarTypeComponent::ARRAY_ELEMENT) 1062 { 1063 if (pathComp == accessPath.begin() || (pathComp+1) == accessPath.end()) 1064 name << "[0]"; // Top- / bottom-level array 1065 else 1066 name << "[" << pathComp->index << "]"; 1067 } 1068 else 1069 DE_ASSERT(false); 1070 } 1071 1072 return name.str(); 1073} 1074 1075string getShaderName (const BufferBlock& block, int instanceNdx, const BufferVar& var, const glu::TypeComponentVector& accessPath) 1076{ 1077 std::ostringstream name; 1078 1079 if (block.getInstanceName()) 1080 { 1081 name << block.getInstanceName(); 1082 1083 if (block.isArray()) 1084 name << "[" << instanceNdx << "]"; 1085 1086 name << "."; 1087 } 1088 else 1089 DE_ASSERT(instanceNdx == 0); 1090 1091 name << var.getName(); 1092 1093 for (glu::TypeComponentVector::const_iterator pathComp = accessPath.begin(); pathComp != accessPath.end(); pathComp++) 1094 { 1095 if (pathComp->type == glu::VarTypeComponent::STRUCT_MEMBER) 1096 { 1097 const VarType curType = glu::getVarType(var.getType(), accessPath.begin(), pathComp); 1098 const StructType* structPtr = curType.getStructPtr(); 1099 1100 name << "." << structPtr->getMember(pathComp->index).getName(); 1101 } 1102 else if (pathComp->type == glu::VarTypeComponent::ARRAY_ELEMENT) 1103 name << "[" << pathComp->index << "]"; 1104 else 1105 DE_ASSERT(false); 1106 } 1107 1108 return name.str(); 1109} 1110 1111int computeOffset (const BufferVarLayoutEntry& varLayout, const glu::TypeComponentVector& accessPath) 1112{ 1113 const int topLevelNdx = (accessPath.size() > 1 && accessPath.front().type == glu::VarTypeComponent::ARRAY_ELEMENT) ? accessPath.front().index : 0; 1114 const int bottomLevelNdx = (!accessPath.empty() && accessPath.back().type == glu::VarTypeComponent::ARRAY_ELEMENT) ? accessPath.back().index : 0; 1115 1116 return varLayout.offset + varLayout.topLevelArrayStride*topLevelNdx + varLayout.arrayStride*bottomLevelNdx; 1117} 1118 1119void generateCompareSrc ( 1120 std::ostream& src, 1121 const char* resultVar, 1122 const BufferLayout& bufferLayout, 1123 const BufferBlock& block, 1124 int instanceNdx, 1125 const BlockDataPtr& blockPtr, 1126 const BufferVar& bufVar, 1127 const glu::SubTypeAccess& accessPath) 1128{ 1129 const VarType curType = accessPath.getType(); 1130 1131 if (curType.isArrayType()) 1132 { 1133 const int arraySize = curType.getArraySize() == VarType::UNSIZED_ARRAY ? block.getLastUnsizedArraySize(instanceNdx) : curType.getArraySize(); 1134 1135 for (int elemNdx = 0; elemNdx < arraySize; elemNdx++) 1136 generateCompareSrc(src, resultVar, bufferLayout, block, instanceNdx, blockPtr, bufVar, accessPath.element(elemNdx)); 1137 } 1138 else if (curType.isStructType()) 1139 { 1140 const int numMembers = curType.getStructPtr()->getNumMembers(); 1141 1142 for (int memberNdx = 0; memberNdx < numMembers; memberNdx++) 1143 generateCompareSrc(src, resultVar, bufferLayout, block, instanceNdx, blockPtr, bufVar, accessPath.member(memberNdx)); 1144 } 1145 else 1146 { 1147 DE_ASSERT(curType.isBasicType()); 1148 1149 const string apiName = getAPIName(block, bufVar, accessPath.getPath()); 1150 const int varNdx = bufferLayout.getVariableIndex(apiName); 1151 1152 DE_ASSERT(varNdx >= 0); 1153 { 1154 const BufferVarLayoutEntry& varLayout = bufferLayout.bufferVars[varNdx]; 1155 const string shaderName = getShaderName(block, instanceNdx, bufVar, accessPath.getPath()); 1156 const glu::DataType basicType = curType.getBasicType(); 1157 const bool isMatrix = glu::isDataTypeMatrix(basicType); 1158 const char* typeName = glu::getDataTypeName(basicType); 1159 const void* valuePtr = (const deUint8*)blockPtr.ptr + computeOffset(varLayout, accessPath.getPath()); 1160 1161 src << "\t" << resultVar << " = " << resultVar << " && compare_" << typeName << "(" << shaderName << ", "; 1162 1163 if (isMatrix) 1164 generateImmMatrixSrc(src, basicType, varLayout.matrixStride, varLayout.isRowMajor, valuePtr); 1165 else 1166 generateImmScalarVectorSrc(src, basicType, valuePtr); 1167 1168 src << ");\n"; 1169 } 1170 } 1171} 1172 1173void generateCompareSrc (std::ostream& src, const char* resultVar, const ShaderInterface& interface, const BufferLayout& layout, const vector<BlockDataPtr>& blockPointers) 1174{ 1175 for (int declNdx = 0; declNdx < interface.getNumBlocks(); declNdx++) 1176 { 1177 const BufferBlock& block = interface.getBlock(declNdx); 1178 const bool isArray = block.isArray(); 1179 const int numInstances = isArray ? block.getArraySize() : 1; 1180 1181 DE_ASSERT(!isArray || block.getInstanceName()); 1182 1183 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++) 1184 { 1185 const string instanceName = block.getBlockName() + (isArray ? "[" + de::toString(instanceNdx) + "]" : string("")); 1186 const int blockNdx = layout.getBlockIndex(instanceName); 1187 const BlockDataPtr& blockPtr = blockPointers[blockNdx]; 1188 1189 for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++) 1190 { 1191 const BufferVar& bufVar = *varIter; 1192 1193 if ((bufVar.getFlags() & ACCESS_READ) == 0) 1194 continue; // Don't read from that variable. 1195 1196 generateCompareSrc(src, resultVar, layout, block, instanceNdx, blockPtr, bufVar, glu::SubTypeAccess(bufVar.getType())); 1197 } 1198 } 1199 } 1200} 1201 1202// \todo [2013-10-14 pyry] Almost identical to generateCompareSrc - unify? 1203 1204void generateWriteSrc ( 1205 std::ostream& src, 1206 const BufferLayout& bufferLayout, 1207 const BufferBlock& block, 1208 int instanceNdx, 1209 const BlockDataPtr& blockPtr, 1210 const BufferVar& bufVar, 1211 const glu::SubTypeAccess& accessPath) 1212{ 1213 const VarType curType = accessPath.getType(); 1214 1215 if (curType.isArrayType()) 1216 { 1217 const int arraySize = curType.getArraySize() == VarType::UNSIZED_ARRAY ? block.getLastUnsizedArraySize(instanceNdx) : curType.getArraySize(); 1218 1219 for (int elemNdx = 0; elemNdx < arraySize; elemNdx++) 1220 generateWriteSrc(src, bufferLayout, block, instanceNdx, blockPtr, bufVar, accessPath.element(elemNdx)); 1221 } 1222 else if (curType.isStructType()) 1223 { 1224 const int numMembers = curType.getStructPtr()->getNumMembers(); 1225 1226 for (int memberNdx = 0; memberNdx < numMembers; memberNdx++) 1227 generateWriteSrc(src, bufferLayout, block, instanceNdx, blockPtr, bufVar, accessPath.member(memberNdx)); 1228 } 1229 else 1230 { 1231 DE_ASSERT(curType.isBasicType()); 1232 1233 const string apiName = getAPIName(block, bufVar, accessPath.getPath()); 1234 const int varNdx = bufferLayout.getVariableIndex(apiName); 1235 1236 DE_ASSERT(varNdx >= 0); 1237 { 1238 const BufferVarLayoutEntry& varLayout = bufferLayout.bufferVars[varNdx]; 1239 const string shaderName = getShaderName(block, instanceNdx, bufVar, accessPath.getPath()); 1240 const glu::DataType basicType = curType.getBasicType(); 1241 const bool isMatrix = glu::isDataTypeMatrix(basicType); 1242 const void* valuePtr = (const deUint8*)blockPtr.ptr + computeOffset(varLayout, accessPath.getPath()); 1243 1244 src << "\t" << shaderName << " = "; 1245 1246 if (isMatrix) 1247 generateImmMatrixSrc(src, basicType, varLayout.matrixStride, varLayout.isRowMajor, valuePtr); 1248 else 1249 generateImmScalarVectorSrc(src, basicType, valuePtr); 1250 1251 src << ";\n"; 1252 } 1253 } 1254} 1255 1256void generateWriteSrc (std::ostream& src, const ShaderInterface& interface, const BufferLayout& layout, const vector<BlockDataPtr>& blockPointers) 1257{ 1258 for (int declNdx = 0; declNdx < interface.getNumBlocks(); declNdx++) 1259 { 1260 const BufferBlock& block = interface.getBlock(declNdx); 1261 const bool isArray = block.isArray(); 1262 const int numInstances = isArray ? block.getArraySize() : 1; 1263 1264 DE_ASSERT(!isArray || block.getInstanceName()); 1265 1266 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++) 1267 { 1268 const string instanceName = block.getBlockName() + (isArray ? "[" + de::toString(instanceNdx) + "]" : string("")); 1269 const int blockNdx = layout.getBlockIndex(instanceName); 1270 const BlockDataPtr& blockPtr = blockPointers[blockNdx]; 1271 1272 for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++) 1273 { 1274 const BufferVar& bufVar = *varIter; 1275 1276 if ((bufVar.getFlags() & ACCESS_WRITE) == 0) 1277 continue; // Don't write to that variable. 1278 1279 generateWriteSrc(src, layout, block, instanceNdx, blockPtr, bufVar, glu::SubTypeAccess(bufVar.getType())); 1280 } 1281 } 1282 } 1283} 1284 1285string generateComputeShader (glu::GLSLVersion glslVersion, const ShaderInterface& interface, const BufferLayout& layout, const vector<BlockDataPtr>& comparePtrs, const vector<BlockDataPtr>& writePtrs) 1286{ 1287 std::ostringstream src; 1288 1289 DE_ASSERT(glslVersion == glu::GLSL_VERSION_310_ES || glslVersion == glu::GLSL_VERSION_430); 1290 1291 src << glu::getGLSLVersionDeclaration(glslVersion) << "\n"; 1292 src << "layout(local_size_x = 1) in;\n"; 1293 src << "\n"; 1294 1295 std::vector<const StructType*> namedStructs; 1296 interface.getNamedStructs(namedStructs); 1297 for (std::vector<const StructType*>::const_iterator structIter = namedStructs.begin(); structIter != namedStructs.end(); structIter++) 1298 src << glu::declare(*structIter) << ";\n"; 1299 1300 { 1301 int bindingPoint = 0; 1302 1303 for (int blockNdx = 0; blockNdx < interface.getNumBlocks(); blockNdx++) 1304 { 1305 const BufferBlock& block = interface.getBlock(blockNdx); 1306 generateDeclaration(src, block, bindingPoint); 1307 1308 bindingPoint += block.isArray() ? block.getArraySize() : 1; 1309 } 1310 } 1311 1312 // Atomic counter for counting passed invocations. 1313 src << "\nlayout(binding = 0) uniform atomic_uint ac_numPassed;\n"; 1314 1315 // Comparison utilities. 1316 src << "\n"; 1317 generateCompareFuncs(src, interface); 1318 1319 src << "\n" 1320 "void main (void)\n" 1321 "{\n" 1322 " bool allOk = true;\n"; 1323 1324 // Value compare. 1325 generateCompareSrc(src, "allOk", interface, layout, comparePtrs); 1326 1327 src << " if (allOk)\n" 1328 << " atomicCounterIncrement(ac_numPassed);\n" 1329 << "\n"; 1330 1331 // Value write. 1332 generateWriteSrc(src, interface, layout, writePtrs); 1333 1334 src << "}\n"; 1335 1336 return src.str(); 1337} 1338 1339void getGLBufferLayout (const glw::Functions& gl, BufferLayout& layout, deUint32 program) 1340{ 1341 int numActiveBufferVars = 0; 1342 int numActiveBlocks = 0; 1343 1344 gl.getProgramInterfaceiv(program, GL_BUFFER_VARIABLE, GL_ACTIVE_RESOURCES, &numActiveBufferVars); 1345 gl.getProgramInterfaceiv(program, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &numActiveBlocks); 1346 1347 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to get number of buffer variables and buffer blocks"); 1348 1349 // Block entries. 1350 layout.blocks.resize(numActiveBlocks); 1351 for (int blockNdx = 0; blockNdx < numActiveBlocks; blockNdx++) 1352 { 1353 BlockLayoutEntry& entry = layout.blocks[blockNdx]; 1354 const deUint32 queryParams[] = { GL_BUFFER_DATA_SIZE, GL_NUM_ACTIVE_VARIABLES, GL_NAME_LENGTH }; 1355 int returnValues[] = { 0, 0, 0 }; 1356 1357 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(queryParams) == DE_LENGTH_OF_ARRAY(returnValues)); 1358 1359 { 1360 int returnLength = 0; 1361 gl.getProgramResourceiv(program, GL_SHADER_STORAGE_BLOCK, (deUint32)blockNdx, DE_LENGTH_OF_ARRAY(queryParams), &queryParams[0], DE_LENGTH_OF_ARRAY(returnValues), &returnLength, &returnValues[0]); 1362 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceiv(GL_SHADER_STORAGE_BLOCK) failed"); 1363 1364 if (returnLength != DE_LENGTH_OF_ARRAY(returnValues)) 1365 throw tcu::TestError("glGetProgramResourceiv(GL_SHADER_STORAGE_BLOCK) returned wrong number of values"); 1366 } 1367 1368 entry.size = returnValues[0]; 1369 1370 // Query active variables 1371 if (returnValues[1] > 0) 1372 { 1373 const int numBlockVars = returnValues[1]; 1374 const deUint32 queryArg = GL_ACTIVE_VARIABLES; 1375 int retLength = 0; 1376 1377 entry.activeVarIndices.resize(numBlockVars); 1378 gl.getProgramResourceiv(program, GL_SHADER_STORAGE_BLOCK, (deUint32)blockNdx, 1, &queryArg, numBlockVars, &retLength, &entry.activeVarIndices[0]); 1379 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceiv(GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_VARIABLES) failed"); 1380 1381 if (retLength != numBlockVars) 1382 throw tcu::TestError("glGetProgramResourceiv(GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_VARIABLES) returned wrong number of values"); 1383 } 1384 1385 // Query name 1386 if (returnValues[2] > 0) 1387 { 1388 const int nameLen = returnValues[2]; 1389 int retLen = 0; 1390 vector<char> name (nameLen); 1391 1392 gl.getProgramResourceName(program, GL_SHADER_STORAGE_BLOCK, (deUint32)blockNdx, (glw::GLsizei)name.size(), &retLen, &name[0]); 1393 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceName(GL_SHADER_STORAGE_BLOCK) failed"); 1394 1395 if (retLen+1 != nameLen) 1396 throw tcu::TestError("glGetProgramResourceName(GL_SHADER_STORAGE_BLOCK) returned invalid name. Number of characters written is inconsistent with NAME_LENGTH property."); 1397 if (name[nameLen-1] != 0) 1398 throw tcu::TestError("glGetProgramResourceName(GL_SHADER_STORAGE_BLOCK) returned invalid name. Expected null terminator at index " + de::toString(nameLen-1)); 1399 1400 entry.name = &name[0]; 1401 } 1402 else 1403 throw tcu::TestError("glGetProgramResourceiv() returned invalid GL_NAME_LENGTH"); 1404 } 1405 1406 layout.bufferVars.resize(numActiveBufferVars); 1407 for (int bufVarNdx = 0; bufVarNdx < numActiveBufferVars; bufVarNdx++) 1408 { 1409 BufferVarLayoutEntry& entry = layout.bufferVars[bufVarNdx]; 1410 const deUint32 queryParams[] = 1411 { 1412 GL_BLOCK_INDEX, // 0 1413 GL_TYPE, // 1 1414 GL_OFFSET, // 2 1415 GL_ARRAY_SIZE, // 3 1416 GL_ARRAY_STRIDE, // 4 1417 GL_MATRIX_STRIDE, // 5 1418 GL_TOP_LEVEL_ARRAY_SIZE, // 6 1419 GL_TOP_LEVEL_ARRAY_STRIDE, // 7 1420 GL_IS_ROW_MAJOR, // 8 1421 GL_NAME_LENGTH // 9 1422 }; 1423 int returnValues[DE_LENGTH_OF_ARRAY(queryParams)]; 1424 1425 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(queryParams) == DE_LENGTH_OF_ARRAY(returnValues)); 1426 1427 { 1428 int returnLength = 0; 1429 gl.getProgramResourceiv(program, GL_BUFFER_VARIABLE, (deUint32)bufVarNdx, DE_LENGTH_OF_ARRAY(queryParams), &queryParams[0], DE_LENGTH_OF_ARRAY(returnValues), &returnLength, &returnValues[0]); 1430 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceiv(GL_BUFFER_VARIABLE) failed"); 1431 1432 if (returnLength != DE_LENGTH_OF_ARRAY(returnValues)) 1433 throw tcu::TestError("glGetProgramResourceiv(GL_BUFFER_VARIABLE) returned wrong number of values"); 1434 } 1435 1436 // Map values 1437 entry.blockNdx = returnValues[0]; 1438 entry.type = glu::getDataTypeFromGLType(returnValues[1]); 1439 entry.offset = returnValues[2]; 1440 entry.arraySize = returnValues[3]; 1441 entry.arrayStride = returnValues[4]; 1442 entry.matrixStride = returnValues[5]; 1443 entry.topLevelArraySize = returnValues[6]; 1444 entry.topLevelArrayStride = returnValues[7]; 1445 entry.isRowMajor = returnValues[8] != 0; 1446 1447 // Query name 1448 DE_ASSERT(queryParams[9] == GL_NAME_LENGTH); 1449 if (returnValues[9] > 0) 1450 { 1451 const int nameLen = returnValues[9]; 1452 int retLen = 0; 1453 vector<char> name (nameLen); 1454 1455 gl.getProgramResourceName(program, GL_BUFFER_VARIABLE, (deUint32)bufVarNdx, (glw::GLsizei)name.size(), &retLen, &name[0]); 1456 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceName(GL_BUFFER_VARIABLE) failed"); 1457 1458 if (retLen+1 != nameLen) 1459 throw tcu::TestError("glGetProgramResourceName(GL_BUFFER_VARIABLE) returned invalid name. Number of characters written is inconsistent with NAME_LENGTH property."); 1460 if (name[nameLen-1] != 0) 1461 throw tcu::TestError("glGetProgramResourceName(GL_BUFFER_VARIABLE) returned invalid name. Expected null terminator at index " + de::toString(nameLen-1)); 1462 1463 entry.name = &name[0]; 1464 } 1465 else 1466 throw tcu::TestError("glGetProgramResourceiv() returned invalid GL_NAME_LENGTH"); 1467 } 1468} 1469 1470void copyBufferVarData (const BufferVarLayoutEntry& dstEntry, const BlockDataPtr& dstBlockPtr, const BufferVarLayoutEntry& srcEntry, const BlockDataPtr& srcBlockPtr) 1471{ 1472 DE_ASSERT(dstEntry.arraySize <= srcEntry.arraySize); 1473 DE_ASSERT(dstEntry.topLevelArraySize <= srcEntry.topLevelArraySize); 1474 DE_ASSERT(dstBlockPtr.lastUnsizedArraySize <= srcBlockPtr.lastUnsizedArraySize); 1475 DE_ASSERT(dstEntry.type == srcEntry.type); 1476 1477 deUint8* const dstBasePtr = (deUint8*)dstBlockPtr.ptr + dstEntry.offset; 1478 const deUint8* const srcBasePtr = (const deUint8*)srcBlockPtr.ptr + srcEntry.offset; 1479 const int scalarSize = glu::getDataTypeScalarSize(dstEntry.type); 1480 const bool isMatrix = glu::isDataTypeMatrix(dstEntry.type); 1481 const int compSize = sizeof(deUint32); 1482 const int dstArraySize = dstEntry.arraySize == 0 ? dstBlockPtr.lastUnsizedArraySize : dstEntry.arraySize; 1483 const int dstArrayStride = dstEntry.arrayStride; 1484 const int dstTopLevelSize = dstEntry.topLevelArraySize == 0 ? dstBlockPtr.lastUnsizedArraySize : dstEntry.topLevelArraySize; 1485 const int dstTopLevelStride = dstEntry.topLevelArrayStride; 1486 const int srcArraySize = srcEntry.arraySize == 0 ? srcBlockPtr.lastUnsizedArraySize : srcEntry.arraySize; 1487 const int srcArrayStride = srcEntry.arrayStride; 1488 const int srcTopLevelSize = srcEntry.topLevelArraySize == 0 ? srcBlockPtr.lastUnsizedArraySize : srcEntry.topLevelArraySize; 1489 const int srcTopLevelStride = srcEntry.topLevelArrayStride; 1490 1491 DE_ASSERT(dstArraySize <= srcArraySize && dstTopLevelSize <= srcTopLevelSize); 1492 DE_UNREF(srcArraySize && srcTopLevelSize); 1493 1494 for (int topElemNdx = 0; topElemNdx < dstTopLevelSize; topElemNdx++) 1495 { 1496 deUint8* const dstTopPtr = dstBasePtr + topElemNdx*dstTopLevelStride; 1497 const deUint8* const srcTopPtr = srcBasePtr + topElemNdx*srcTopLevelStride; 1498 1499 for (int elementNdx = 0; elementNdx < dstArraySize; elementNdx++) 1500 { 1501 deUint8* const dstElemPtr = dstTopPtr + elementNdx*dstArrayStride; 1502 const deUint8* const srcElemPtr = srcTopPtr + elementNdx*srcArrayStride; 1503 1504 if (isMatrix) 1505 { 1506 const int numRows = glu::getDataTypeMatrixNumRows(dstEntry.type); 1507 const int numCols = glu::getDataTypeMatrixNumColumns(dstEntry.type); 1508 1509 for (int colNdx = 0; colNdx < numCols; colNdx++) 1510 { 1511 for (int rowNdx = 0; rowNdx < numRows; rowNdx++) 1512 { 1513 deUint8* dstCompPtr = dstElemPtr + (dstEntry.isRowMajor ? rowNdx*dstEntry.matrixStride + colNdx*compSize 1514 : colNdx*dstEntry.matrixStride + rowNdx*compSize); 1515 const deUint8* srcCompPtr = srcElemPtr + (srcEntry.isRowMajor ? rowNdx*srcEntry.matrixStride + colNdx*compSize 1516 : colNdx*srcEntry.matrixStride + rowNdx*compSize); 1517 1518 DE_ASSERT((deIntptr)(srcCompPtr + compSize) - (deIntptr)srcBlockPtr.ptr <= (deIntptr)srcBlockPtr.size); 1519 DE_ASSERT((deIntptr)(dstCompPtr + compSize) - (deIntptr)dstBlockPtr.ptr <= (deIntptr)dstBlockPtr.size); 1520 deMemcpy(dstCompPtr, srcCompPtr, compSize); 1521 } 1522 } 1523 } 1524 else 1525 { 1526 DE_ASSERT((deIntptr)(srcElemPtr + scalarSize*compSize) - (deIntptr)srcBlockPtr.ptr <= (deIntptr)srcBlockPtr.size); 1527 DE_ASSERT((deIntptr)(dstElemPtr + scalarSize*compSize) - (deIntptr)dstBlockPtr.ptr <= (deIntptr)dstBlockPtr.size); 1528 deMemcpy(dstElemPtr, srcElemPtr, scalarSize*compSize); 1529 } 1530 } 1531 } 1532} 1533 1534void copyData (const BufferLayout& dstLayout, const vector<BlockDataPtr>& dstBlockPointers, const BufferLayout& srcLayout, const vector<BlockDataPtr>& srcBlockPointers) 1535{ 1536 // \note Src layout is used as reference in case of activeVarIndices happens to be incorrect in dstLayout blocks. 1537 int numBlocks = (int)srcLayout.blocks.size(); 1538 1539 for (int srcBlockNdx = 0; srcBlockNdx < numBlocks; srcBlockNdx++) 1540 { 1541 const BlockLayoutEntry& srcBlock = srcLayout.blocks[srcBlockNdx]; 1542 const BlockDataPtr& srcBlockPtr = srcBlockPointers[srcBlockNdx]; 1543 int dstBlockNdx = dstLayout.getBlockIndex(srcBlock.name.c_str()); 1544 1545 if (dstBlockNdx >= 0) 1546 { 1547 DE_ASSERT(de::inBounds(dstBlockNdx, 0, (int)dstBlockPointers.size())); 1548 1549 const BlockDataPtr& dstBlockPtr = dstBlockPointers[dstBlockNdx]; 1550 1551 for (vector<int>::const_iterator srcVarNdxIter = srcBlock.activeVarIndices.begin(); srcVarNdxIter != srcBlock.activeVarIndices.end(); srcVarNdxIter++) 1552 { 1553 const BufferVarLayoutEntry& srcEntry = srcLayout.bufferVars[*srcVarNdxIter]; 1554 int dstVarNdx = dstLayout.getVariableIndex(srcEntry.name.c_str()); 1555 1556 if (dstVarNdx >= 0) 1557 copyBufferVarData(dstLayout.bufferVars[dstVarNdx], dstBlockPtr, srcEntry, srcBlockPtr); 1558 } 1559 } 1560 } 1561} 1562 1563void copyNonWrittenData ( 1564 const BufferLayout& layout, 1565 const BufferBlock& block, 1566 int instanceNdx, 1567 const BlockDataPtr& srcBlockPtr, 1568 const BlockDataPtr& dstBlockPtr, 1569 const BufferVar& bufVar, 1570 const glu::SubTypeAccess& accessPath) 1571{ 1572 const VarType curType = accessPath.getType(); 1573 1574 if (curType.isArrayType()) 1575 { 1576 const int arraySize = curType.getArraySize() == VarType::UNSIZED_ARRAY ? block.getLastUnsizedArraySize(instanceNdx) : curType.getArraySize(); 1577 1578 for (int elemNdx = 0; elemNdx < arraySize; elemNdx++) 1579 copyNonWrittenData(layout, block, instanceNdx, srcBlockPtr, dstBlockPtr, bufVar, accessPath.element(elemNdx)); 1580 } 1581 else if (curType.isStructType()) 1582 { 1583 const int numMembers = curType.getStructPtr()->getNumMembers(); 1584 1585 for (int memberNdx = 0; memberNdx < numMembers; memberNdx++) 1586 copyNonWrittenData(layout, block, instanceNdx, srcBlockPtr, dstBlockPtr, bufVar, accessPath.member(memberNdx)); 1587 } 1588 else 1589 { 1590 DE_ASSERT(curType.isBasicType()); 1591 1592 const string apiName = getAPIName(block, bufVar, accessPath.getPath()); 1593 const int varNdx = layout.getVariableIndex(apiName); 1594 1595 DE_ASSERT(varNdx >= 0); 1596 { 1597 const BufferVarLayoutEntry& varLayout = layout.bufferVars[varNdx]; 1598 copyBufferVarData(varLayout, dstBlockPtr, varLayout, srcBlockPtr); 1599 } 1600 } 1601} 1602 1603void copyNonWrittenData (const ShaderInterface& interface, const BufferLayout& layout, const vector<BlockDataPtr>& srcPtrs, const vector<BlockDataPtr>& dstPtrs) 1604{ 1605 for (int declNdx = 0; declNdx < interface.getNumBlocks(); declNdx++) 1606 { 1607 const BufferBlock& block = interface.getBlock(declNdx); 1608 const bool isArray = block.isArray(); 1609 const int numInstances = isArray ? block.getArraySize() : 1; 1610 1611 DE_ASSERT(!isArray || block.getInstanceName()); 1612 1613 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++) 1614 { 1615 const string instanceName = block.getBlockName() + (isArray ? "[" + de::toString(instanceNdx) + "]" : string("")); 1616 const int blockNdx = layout.getBlockIndex(instanceName); 1617 const BlockDataPtr& srcBlockPtr = srcPtrs[blockNdx]; 1618 const BlockDataPtr& dstBlockPtr = dstPtrs[blockNdx]; 1619 1620 for (BufferBlock::const_iterator varIter = block.begin(); varIter != block.end(); varIter++) 1621 { 1622 const BufferVar& bufVar = *varIter; 1623 1624 if (bufVar.getFlags() & ACCESS_WRITE) 1625 continue; 1626 1627 copyNonWrittenData(layout, block, instanceNdx, srcBlockPtr, dstBlockPtr, bufVar, glu::SubTypeAccess(bufVar.getType())); 1628 } 1629 } 1630 } 1631} 1632 1633bool compareComponents (glu::DataType scalarType, const void* ref, const void* res, int numComps) 1634{ 1635 if (scalarType == glu::TYPE_FLOAT) 1636 { 1637 const float threshold = 0.05f; // Same as used in shaders - should be fine for values being used. 1638 1639 for (int ndx = 0; ndx < numComps; ndx++) 1640 { 1641 const float refVal = *((const float*)ref + ndx); 1642 const float resVal = *((const float*)res + ndx); 1643 1644 if (!(deFloatAbs(resVal - refVal) <= threshold)) 1645 return false; 1646 } 1647 } 1648 else if (scalarType == glu::TYPE_BOOL) 1649 { 1650 for (int ndx = 0; ndx < numComps; ndx++) 1651 { 1652 const deUint32 refVal = *((const deUint32*)ref + ndx); 1653 const deUint32 resVal = *((const deUint32*)res + ndx); 1654 1655 if ((refVal != 0) != (resVal != 0)) 1656 return false; 1657 } 1658 } 1659 else 1660 { 1661 DE_ASSERT(scalarType == glu::TYPE_INT || scalarType == glu::TYPE_UINT); 1662 1663 for (int ndx = 0; ndx < numComps; ndx++) 1664 { 1665 const deUint32 refVal = *((const deUint32*)ref + ndx); 1666 const deUint32 resVal = *((const deUint32*)res + ndx); 1667 1668 if (refVal != resVal) 1669 return false; 1670 } 1671 } 1672 1673 return true; 1674} 1675 1676bool compareBufferVarData (tcu::TestLog& log, const BufferVarLayoutEntry& refEntry, const BlockDataPtr& refBlockPtr, const BufferVarLayoutEntry& resEntry, const BlockDataPtr& resBlockPtr) 1677{ 1678 DE_ASSERT(resEntry.arraySize <= refEntry.arraySize); 1679 DE_ASSERT(resEntry.topLevelArraySize <= refEntry.topLevelArraySize); 1680 DE_ASSERT(resBlockPtr.lastUnsizedArraySize <= refBlockPtr.lastUnsizedArraySize); 1681 DE_ASSERT(resEntry.type == refEntry.type); 1682 1683 deUint8* const resBasePtr = (deUint8*)resBlockPtr.ptr + resEntry.offset; 1684 const deUint8* const refBasePtr = (const deUint8*)refBlockPtr.ptr + refEntry.offset; 1685 const glu::DataType scalarType = glu::getDataTypeScalarType(refEntry.type); 1686 const int scalarSize = glu::getDataTypeScalarSize(resEntry.type); 1687 const bool isMatrix = glu::isDataTypeMatrix(resEntry.type); 1688 const int compSize = sizeof(deUint32); 1689 const int maxPrints = 3; 1690 int numFailed = 0; 1691 1692 const int resArraySize = resEntry.arraySize == 0 ? resBlockPtr.lastUnsizedArraySize : resEntry.arraySize; 1693 const int resArrayStride = resEntry.arrayStride; 1694 const int resTopLevelSize = resEntry.topLevelArraySize == 0 ? resBlockPtr.lastUnsizedArraySize : resEntry.topLevelArraySize; 1695 const int resTopLevelStride = resEntry.topLevelArrayStride; 1696 const int refArraySize = refEntry.arraySize == 0 ? refBlockPtr.lastUnsizedArraySize : refEntry.arraySize; 1697 const int refArrayStride = refEntry.arrayStride; 1698 const int refTopLevelSize = refEntry.topLevelArraySize == 0 ? refBlockPtr.lastUnsizedArraySize : refEntry.topLevelArraySize; 1699 const int refTopLevelStride = refEntry.topLevelArrayStride; 1700 1701 DE_ASSERT(resArraySize <= refArraySize && resTopLevelSize <= refTopLevelSize); 1702 DE_UNREF(refArraySize && refTopLevelSize); 1703 1704 for (int topElemNdx = 0; topElemNdx < resTopLevelSize; topElemNdx++) 1705 { 1706 deUint8* const resTopPtr = resBasePtr + topElemNdx*resTopLevelStride; 1707 const deUint8* const refTopPtr = refBasePtr + topElemNdx*refTopLevelStride; 1708 1709 for (int elementNdx = 0; elementNdx < resArraySize; elementNdx++) 1710 { 1711 deUint8* const resElemPtr = resTopPtr + elementNdx*resArrayStride; 1712 const deUint8* const refElemPtr = refTopPtr + elementNdx*refArrayStride; 1713 1714 if (isMatrix) 1715 { 1716 const int numRows = glu::getDataTypeMatrixNumRows(resEntry.type); 1717 const int numCols = glu::getDataTypeMatrixNumColumns(resEntry.type); 1718 bool isOk = true; 1719 1720 for (int colNdx = 0; colNdx < numCols; colNdx++) 1721 { 1722 for (int rowNdx = 0; rowNdx < numRows; rowNdx++) 1723 { 1724 deUint8* resCompPtr = resElemPtr + (resEntry.isRowMajor ? rowNdx*resEntry.matrixStride + colNdx*compSize 1725 : colNdx*resEntry.matrixStride + rowNdx*compSize); 1726 const deUint8* refCompPtr = refElemPtr + (refEntry.isRowMajor ? rowNdx*refEntry.matrixStride + colNdx*compSize 1727 : colNdx*refEntry.matrixStride + rowNdx*compSize); 1728 1729 DE_ASSERT((deIntptr)(refCompPtr + compSize) - (deIntptr)refBlockPtr.ptr <= (deIntptr)refBlockPtr.size); 1730 DE_ASSERT((deIntptr)(resCompPtr + compSize) - (deIntptr)resBlockPtr.ptr <= (deIntptr)resBlockPtr.size); 1731 1732 isOk = isOk && compareComponents(scalarType, resCompPtr, refCompPtr, 1); 1733 } 1734 } 1735 1736 if (!isOk) 1737 { 1738 numFailed += 1; 1739 if (numFailed < maxPrints) 1740 { 1741 std::ostringstream expected, got; 1742 generateImmMatrixSrc(expected, refEntry.type, refEntry.matrixStride, refEntry.isRowMajor, refElemPtr); 1743 generateImmMatrixSrc(got, resEntry.type, resEntry.matrixStride, resEntry.isRowMajor, resElemPtr); 1744 log << TestLog::Message << "ERROR: mismatch in " << refEntry.name << ", top-level ndx " << topElemNdx << ", bottom-level ndx " << elementNdx << ":\n" 1745 << " expected " << expected.str() << "\n" 1746 << " got " << got.str() 1747 << TestLog::EndMessage; 1748 } 1749 } 1750 } 1751 else 1752 { 1753 DE_ASSERT((deIntptr)(refElemPtr + scalarSize*compSize) - (deIntptr)refBlockPtr.ptr <= (deIntptr)refBlockPtr.size); 1754 DE_ASSERT((deIntptr)(resElemPtr + scalarSize*compSize) - (deIntptr)resBlockPtr.ptr <= (deIntptr)resBlockPtr.size); 1755 1756 const bool isOk = compareComponents(scalarType, resElemPtr, refElemPtr, scalarSize); 1757 1758 if (!isOk) 1759 { 1760 numFailed += 1; 1761 if (numFailed < maxPrints) 1762 { 1763 std::ostringstream expected, got; 1764 generateImmScalarVectorSrc(expected, refEntry.type, refElemPtr); 1765 generateImmScalarVectorSrc(got, resEntry.type, resElemPtr); 1766 log << TestLog::Message << "ERROR: mismatch in " << refEntry.name << ", top-level ndx " << topElemNdx << ", bottom-level ndx " << elementNdx << ":\n" 1767 << " expected " << expected.str() << "\n" 1768 << " got " << got.str() 1769 << TestLog::EndMessage; 1770 } 1771 } 1772 } 1773 } 1774 } 1775 1776 if (numFailed >= maxPrints) 1777 log << TestLog::Message << "... (" << numFailed << " failures for " << refEntry.name << " in total)" << TestLog::EndMessage; 1778 1779 return numFailed == 0; 1780} 1781 1782bool compareData (tcu::TestLog& log, const BufferLayout& refLayout, const vector<BlockDataPtr>& refBlockPointers, const BufferLayout& resLayout, const vector<BlockDataPtr>& resBlockPointers) 1783{ 1784 const int numBlocks = (int)refLayout.blocks.size(); 1785 bool allOk = true; 1786 1787 for (int refBlockNdx = 0; refBlockNdx < numBlocks; refBlockNdx++) 1788 { 1789 const BlockLayoutEntry& refBlock = refLayout.blocks[refBlockNdx]; 1790 const BlockDataPtr& refBlockPtr = refBlockPointers[refBlockNdx]; 1791 int resBlockNdx = resLayout.getBlockIndex(refBlock.name.c_str()); 1792 1793 if (resBlockNdx >= 0) 1794 { 1795 DE_ASSERT(de::inBounds(resBlockNdx, 0, (int)resBlockPointers.size())); 1796 1797 const BlockDataPtr& resBlockPtr = resBlockPointers[resBlockNdx]; 1798 1799 for (vector<int>::const_iterator refVarNdxIter = refBlock.activeVarIndices.begin(); refVarNdxIter != refBlock.activeVarIndices.end(); refVarNdxIter++) 1800 { 1801 const BufferVarLayoutEntry& refEntry = refLayout.bufferVars[*refVarNdxIter]; 1802 int resVarNdx = resLayout.getVariableIndex(refEntry.name.c_str()); 1803 1804 if (resVarNdx >= 0) 1805 { 1806 const BufferVarLayoutEntry& resEntry = resLayout.bufferVars[resVarNdx]; 1807 allOk = compareBufferVarData(log, refEntry, refBlockPtr, resEntry, resBlockPtr) && allOk; 1808 } 1809 } 1810 } 1811 } 1812 1813 return allOk; 1814} 1815 1816string getBlockAPIName (const BufferBlock& block, int instanceNdx) 1817{ 1818 DE_ASSERT(block.isArray() || instanceNdx == 0); 1819 return block.getBlockName() + (block.isArray() ? ("[" + de::toString(instanceNdx) + "]") : string()); 1820} 1821 1822// \note Some implementations don't report block members in the order they are declared. 1823// For checking whether size has to be adjusted by some top-level array actual size, 1824// we only need to know a) whether there is a unsized top-level array, and b) 1825// what is stride of that array. 1826 1827static bool hasUnsizedArray (const BufferLayout& layout, const BlockLayoutEntry& entry) 1828{ 1829 for (vector<int>::const_iterator varNdx = entry.activeVarIndices.begin(); varNdx != entry.activeVarIndices.end(); ++varNdx) 1830 { 1831 if (isUnsizedArray(layout.bufferVars[*varNdx])) 1832 return true; 1833 } 1834 1835 return false; 1836} 1837 1838static int getUnsizedArrayStride (const BufferLayout& layout, const BlockLayoutEntry& entry) 1839{ 1840 for (vector<int>::const_iterator varNdx = entry.activeVarIndices.begin(); varNdx != entry.activeVarIndices.end(); ++varNdx) 1841 { 1842 const BufferVarLayoutEntry& varEntry = layout.bufferVars[*varNdx]; 1843 1844 if (varEntry.arraySize == 0) 1845 return varEntry.arrayStride; 1846 else if (varEntry.topLevelArraySize == 0) 1847 return varEntry.topLevelArrayStride; 1848 } 1849 1850 return 0; 1851} 1852 1853vector<int> computeBufferSizes (const ShaderInterface& interface, const BufferLayout& layout) 1854{ 1855 vector<int> sizes(layout.blocks.size()); 1856 1857 for (int declNdx = 0; declNdx < interface.getNumBlocks(); declNdx++) 1858 { 1859 const BufferBlock& block = interface.getBlock(declNdx); 1860 const bool isArray = block.isArray(); 1861 const int numInstances = isArray ? block.getArraySize() : 1; 1862 1863 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++) 1864 { 1865 const string apiName = getBlockAPIName(block, instanceNdx); 1866 const int blockNdx = layout.getBlockIndex(apiName); 1867 1868 if (blockNdx >= 0) 1869 { 1870 const BlockLayoutEntry& blockLayout = layout.blocks[blockNdx]; 1871 const int baseSize = blockLayout.size; 1872 const bool isLastUnsized = hasUnsizedArray(layout, blockLayout); 1873 const int lastArraySize = isLastUnsized ? block.getLastUnsizedArraySize(instanceNdx) : 0; 1874 const int stride = isLastUnsized ? getUnsizedArrayStride(layout, blockLayout) : 0; 1875 1876 sizes[blockNdx] = baseSize + lastArraySize*stride; 1877 } 1878 } 1879 } 1880 1881 return sizes; 1882} 1883 1884BlockDataPtr getBlockDataPtr (const BufferLayout& layout, const BlockLayoutEntry& blockLayout, void* ptr, int bufferSize) 1885{ 1886 const bool isLastUnsized = hasUnsizedArray(layout, blockLayout); 1887 const int baseSize = blockLayout.size; 1888 1889 if (isLastUnsized) 1890 { 1891 const int lastArrayStride = getUnsizedArrayStride(layout, blockLayout); 1892 const int lastArraySize = (bufferSize-baseSize) / (lastArrayStride ? lastArrayStride : 1); 1893 1894 DE_ASSERT(baseSize + lastArraySize*lastArrayStride == bufferSize); 1895 1896 return BlockDataPtr(ptr, bufferSize, lastArraySize); 1897 } 1898 else 1899 return BlockDataPtr(ptr, bufferSize, 0); 1900} 1901 1902struct RefDataStorage 1903{ 1904 vector<deUint8> data; 1905 vector<BlockDataPtr> pointers; 1906}; 1907 1908struct Buffer 1909{ 1910 deUint32 buffer; 1911 int size; 1912 1913 Buffer (deUint32 buffer_, int size_) : buffer(buffer_), size(size_) {} 1914 Buffer (void) : buffer(0), size(0) {} 1915}; 1916 1917struct BlockLocation 1918{ 1919 int index; 1920 int offset; 1921 int size; 1922 1923 BlockLocation (int index_, int offset_, int size_) : index(index_), offset(offset_), size(size_) {} 1924 BlockLocation (void) : index(0), offset(0), size(0) {} 1925}; 1926 1927void initRefDataStorage (const ShaderInterface& interface, const BufferLayout& layout, RefDataStorage& storage) 1928{ 1929 DE_ASSERT(storage.data.empty() && storage.pointers.empty()); 1930 1931 const vector<int> bufferSizes = computeBufferSizes(interface, layout); 1932 int totalSize = 0; 1933 1934 for (vector<int>::const_iterator sizeIter = bufferSizes.begin(); sizeIter != bufferSizes.end(); ++sizeIter) 1935 totalSize += *sizeIter; 1936 1937 storage.data.resize(totalSize); 1938 1939 // Pointers for each block. 1940 { 1941 deUint8* basePtr = storage.data.empty() ? DE_NULL : &storage.data[0]; 1942 int curOffset = 0; 1943 1944 DE_ASSERT(bufferSizes.size() == layout.blocks.size()); 1945 DE_ASSERT(totalSize == 0 || basePtr); 1946 1947 storage.pointers.resize(layout.blocks.size()); 1948 1949 for (int blockNdx = 0; blockNdx < (int)layout.blocks.size(); blockNdx++) 1950 { 1951 const BlockLayoutEntry& blockLayout = layout.blocks[blockNdx]; 1952 const int bufferSize = bufferSizes[blockNdx]; 1953 1954 storage.pointers[blockNdx] = getBlockDataPtr(layout, blockLayout, basePtr + curOffset, bufferSize); 1955 1956 curOffset += bufferSize; 1957 } 1958 } 1959} 1960 1961vector<BlockDataPtr> blockLocationsToPtrs (const BufferLayout& layout, const vector<BlockLocation>& blockLocations, const vector<void*>& bufPtrs) 1962{ 1963 vector<BlockDataPtr> blockPtrs(blockLocations.size()); 1964 1965 DE_ASSERT(layout.blocks.size() == blockLocations.size()); 1966 1967 for (int blockNdx = 0; blockNdx < (int)layout.blocks.size(); blockNdx++) 1968 { 1969 const BlockLayoutEntry& blockLayout = layout.blocks[blockNdx]; 1970 const BlockLocation& location = blockLocations[blockNdx]; 1971 1972 blockPtrs[blockNdx] = getBlockDataPtr(layout, blockLayout, (deUint8*)bufPtrs[location.index] + location.offset, location.size); 1973 } 1974 1975 return blockPtrs; 1976} 1977 1978vector<void*> mapBuffers (const glw::Functions& gl, const vector<Buffer>& buffers, deUint32 access) 1979{ 1980 vector<void*> mapPtrs(buffers.size(), DE_NULL); 1981 1982 try 1983 { 1984 for (int ndx = 0; ndx < (int)buffers.size(); ndx++) 1985 { 1986 if (buffers[ndx].size > 0) 1987 { 1988 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, buffers[ndx].buffer); 1989 mapPtrs[ndx] = gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, buffers[ndx].size, access); 1990 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to map buffer"); 1991 TCU_CHECK(mapPtrs[ndx]); 1992 } 1993 else 1994 mapPtrs[ndx] = DE_NULL; 1995 } 1996 1997 return mapPtrs; 1998 } 1999 catch (...) 2000 { 2001 for (int ndx = 0; ndx < (int)buffers.size(); ndx++) 2002 { 2003 if (mapPtrs[ndx]) 2004 { 2005 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, buffers[ndx].buffer); 2006 gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER); 2007 } 2008 } 2009 2010 throw; 2011 } 2012} 2013 2014void unmapBuffers (const glw::Functions& gl, const vector<Buffer>& buffers) 2015{ 2016 for (int ndx = 0; ndx < (int)buffers.size(); ndx++) 2017 { 2018 if (buffers[ndx].size > 0) 2019 { 2020 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, buffers[ndx].buffer); 2021 gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER); 2022 } 2023 } 2024 2025 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to unmap buffer"); 2026} 2027 2028} // anonymous (utilities) 2029 2030class BufferManager 2031{ 2032public: 2033 BufferManager (const glu::RenderContext& renderCtx); 2034 ~BufferManager (void); 2035 2036 deUint32 allocBuffer (void); 2037 2038private: 2039 BufferManager (const BufferManager& other); 2040 BufferManager& operator= (const BufferManager& other); 2041 2042 const glu::RenderContext& m_renderCtx; 2043 std::vector<deUint32> m_buffers; 2044}; 2045 2046BufferManager::BufferManager (const glu::RenderContext& renderCtx) 2047 : m_renderCtx(renderCtx) 2048{ 2049} 2050 2051BufferManager::~BufferManager (void) 2052{ 2053 if (!m_buffers.empty()) 2054 m_renderCtx.getFunctions().deleteBuffers((glw::GLsizei)m_buffers.size(), &m_buffers[0]); 2055} 2056 2057deUint32 BufferManager::allocBuffer (void) 2058{ 2059 deUint32 buf = 0; 2060 2061 m_buffers.reserve(m_buffers.size()+1); 2062 m_renderCtx.getFunctions().genBuffers(1, &buf); 2063 GLU_EXPECT_NO_ERROR(m_renderCtx.getFunctions().getError(), "Failed to allocate buffer"); 2064 m_buffers.push_back(buf); 2065 2066 return buf; 2067} 2068 2069} // bb 2070 2071using namespace bb; 2072 2073// SSBOLayoutCase. 2074 2075SSBOLayoutCase::SSBOLayoutCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* description, glu::GLSLVersion glslVersion, BufferMode bufferMode) 2076 : TestCase (testCtx, name, description) 2077 , m_renderCtx (renderCtx) 2078 , m_glslVersion (glslVersion) 2079 , m_bufferMode (bufferMode) 2080{ 2081 DE_ASSERT(glslVersion == glu::GLSL_VERSION_310_ES || glslVersion == glu::GLSL_VERSION_430); 2082} 2083 2084SSBOLayoutCase::~SSBOLayoutCase (void) 2085{ 2086} 2087 2088SSBOLayoutCase::IterateResult SSBOLayoutCase::iterate (void) 2089{ 2090 TestLog& log = m_testCtx.getLog(); 2091 const glw::Functions& gl = m_renderCtx.getFunctions(); 2092 2093 BufferLayout refLayout; // std140 / std430 layout. 2094 BufferLayout glLayout; // Layout reported by GL. 2095 RefDataStorage initialData; // Initial data stored in buffer. 2096 RefDataStorage writeData; // Data written by compute shader. 2097 2098 BufferManager bufferManager (m_renderCtx); 2099 vector<Buffer> buffers; // Buffers allocated for storage 2100 vector<BlockLocation> blockLocations; // Block locations in storage (index, offset) 2101 2102 // Initialize result to pass. 2103 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 2104 2105 computeReferenceLayout (refLayout, m_interface); 2106 initRefDataStorage (m_interface, refLayout, initialData); 2107 initRefDataStorage (m_interface, refLayout, writeData); 2108 generateValues (refLayout, initialData.pointers, deStringHash(getName()) ^ 0xad2f7214); 2109 generateValues (refLayout, writeData.pointers, deStringHash(getName()) ^ 0x25ca4e7); 2110 copyNonWrittenData (m_interface, refLayout, initialData.pointers, writeData.pointers); 2111 2112 const glu::ShaderProgram program(m_renderCtx, glu::ProgramSources() << glu::ComputeSource(generateComputeShader(m_glslVersion, m_interface, refLayout, initialData.pointers, writeData.pointers))); 2113 log << program; 2114 2115 if (!program.isOk()) 2116 { 2117 // Compile failed. 2118 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compile failed"); 2119 return STOP; 2120 } 2121 2122 // Query layout from GL. 2123 getGLBufferLayout(gl, glLayout, program.getProgram()); 2124 2125 // Print layout to log. 2126 { 2127 tcu::ScopedLogSection section(log, "ActiveBufferBlocks", "Active Buffer Blocks"); 2128 for (int blockNdx = 0; blockNdx < (int)glLayout.blocks.size(); blockNdx++) 2129 log << TestLog::Message << blockNdx << ": " << glLayout.blocks[blockNdx] << TestLog::EndMessage; 2130 } 2131 2132 { 2133 tcu::ScopedLogSection section(log, "ActiveBufferVars", "Active Buffer Variables"); 2134 for (int varNdx = 0; varNdx < (int)glLayout.bufferVars.size(); varNdx++) 2135 log << TestLog::Message << varNdx << ": " << glLayout.bufferVars[varNdx] << TestLog::EndMessage; 2136 } 2137 2138 // Verify layouts. 2139 { 2140 if (!checkLayoutIndices(glLayout) || !checkLayoutBounds(glLayout) || !compareTypes(refLayout, glLayout)) 2141 { 2142 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid layout"); 2143 return STOP; // It is not safe to use the given layout. 2144 } 2145 2146 if (!compareStdBlocks(refLayout, glLayout)) 2147 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid std140 or std430 layout"); 2148 2149 if (!compareSharedBlocks(refLayout, glLayout)) 2150 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid shared layout"); 2151 2152 if (!checkIndexQueries(program.getProgram(), glLayout)) 2153 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Inconsintent block index query results"); 2154 } 2155 2156 // Allocate GL buffers & compute placement. 2157 { 2158 const int numBlocks = (int)glLayout.blocks.size(); 2159 const vector<int> bufferSizes = computeBufferSizes(m_interface, glLayout); 2160 2161 DE_ASSERT(bufferSizes.size() == glLayout.blocks.size()); 2162 2163 blockLocations.resize(numBlocks); 2164 2165 if (m_bufferMode == BUFFERMODE_PER_BLOCK) 2166 { 2167 buffers.resize(numBlocks); 2168 2169 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 2170 { 2171 const int bufferSize = bufferSizes[blockNdx]; 2172 2173 buffers[blockNdx].size = bufferSize; 2174 blockLocations[blockNdx] = BlockLocation(blockNdx, 0, bufferSize); 2175 } 2176 } 2177 else 2178 { 2179 DE_ASSERT(m_bufferMode == BUFFERMODE_SINGLE); 2180 2181 int bindingAlignment = 0; 2182 int totalSize = 0; 2183 2184 gl.getIntegerv(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &bindingAlignment); 2185 2186 { 2187 int curOffset = 0; 2188 DE_ASSERT(bufferSizes.size() == glLayout.blocks.size()); 2189 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 2190 { 2191 const int bufferSize = bufferSizes[blockNdx]; 2192 2193 if (bindingAlignment > 0) 2194 curOffset = deRoundUp32(curOffset, bindingAlignment); 2195 2196 blockLocations[blockNdx] = BlockLocation(0, curOffset, bufferSize); 2197 curOffset += bufferSize; 2198 } 2199 totalSize = curOffset; 2200 } 2201 2202 buffers.resize(1); 2203 buffers[0].size = totalSize; 2204 } 2205 2206 for (int bufNdx = 0; bufNdx < (int)buffers.size(); bufNdx++) 2207 { 2208 const int bufferSize = buffers[bufNdx].size; 2209 const deUint32 buffer = bufferManager.allocBuffer(); 2210 2211 gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, buffer); 2212 gl.bufferData(GL_SHADER_STORAGE_BUFFER, bufferSize, DE_NULL, GL_STATIC_DRAW); 2213 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to allocate buffer"); 2214 2215 buffers[bufNdx].buffer = buffer; 2216 } 2217 } 2218 2219 { 2220 const vector<void*> mapPtrs = mapBuffers(gl, buffers, GL_MAP_WRITE_BIT); 2221 const vector<BlockDataPtr> mappedBlockPtrs = blockLocationsToPtrs(glLayout, blockLocations, mapPtrs); 2222 2223 copyData(glLayout, mappedBlockPtrs, refLayout, initialData.pointers); 2224 2225 unmapBuffers(gl, buffers); 2226 } 2227 2228 { 2229 int bindingPoint = 0; 2230 2231 for (int blockDeclNdx = 0; blockDeclNdx < m_interface.getNumBlocks(); blockDeclNdx++) 2232 { 2233 const BufferBlock& block = m_interface.getBlock(blockDeclNdx); 2234 const int numInst = block.isArray() ? block.getArraySize() : 1; 2235 2236 for (int instNdx = 0; instNdx < numInst; instNdx++) 2237 { 2238 const string instName = getBlockAPIName(block, instNdx); 2239 const int layoutNdx = findBlockIndex(glLayout, instName); 2240 2241 if (layoutNdx >= 0) 2242 { 2243 const BlockLocation& blockLoc = blockLocations[layoutNdx]; 2244 2245 if (blockLoc.size > 0) 2246 gl.bindBufferRange(GL_SHADER_STORAGE_BUFFER, bindingPoint, buffers[blockLoc.index].buffer, blockLoc.offset, blockLoc.size); 2247 } 2248 2249 bindingPoint += 1; 2250 } 2251 } 2252 } 2253 2254 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to bind buffers"); 2255 2256 { 2257 const bool execOk = execute(program.getProgram()); 2258 2259 if (execOk) 2260 { 2261 const vector<void*> mapPtrs = mapBuffers(gl, buffers, GL_MAP_READ_BIT); 2262 const vector<BlockDataPtr> mappedBlockPtrs = blockLocationsToPtrs(glLayout, blockLocations, mapPtrs); 2263 2264 const bool compareOk = compareData(m_testCtx.getLog(), refLayout, writeData.pointers, glLayout, mappedBlockPtrs); 2265 2266 unmapBuffers(gl, buffers); 2267 2268 if (!compareOk) 2269 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Result comparison failed"); 2270 } 2271 else 2272 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader execution failed"); 2273 } 2274 2275 return STOP; 2276} 2277 2278bool SSBOLayoutCase::compareStdBlocks (const BufferLayout& refLayout, const BufferLayout& cmpLayout) const 2279{ 2280 TestLog& log = m_testCtx.getLog(); 2281 bool isOk = true; 2282 int numBlocks = m_interface.getNumBlocks(); 2283 2284 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 2285 { 2286 const BufferBlock& block = m_interface.getBlock(blockNdx); 2287 bool isArray = block.isArray(); 2288 std::string instanceName = string(block.getBlockName()) + (isArray ? "[0]" : ""); 2289 int refBlockNdx = refLayout.getBlockIndex(instanceName.c_str()); 2290 int cmpBlockNdx = cmpLayout.getBlockIndex(instanceName.c_str()); 2291 2292 if ((block.getFlags() & (LAYOUT_STD140|LAYOUT_STD430)) == 0) 2293 continue; // Not std* layout. 2294 2295 DE_ASSERT(refBlockNdx >= 0); 2296 2297 if (cmpBlockNdx < 0) 2298 { 2299 // Not found. 2300 log << TestLog::Message << "Error: Buffer block '" << instanceName << "' not found" << TestLog::EndMessage; 2301 isOk = false; 2302 continue; 2303 } 2304 2305 const BlockLayoutEntry& refBlockLayout = refLayout.blocks[refBlockNdx]; 2306 const BlockLayoutEntry& cmpBlockLayout = cmpLayout.blocks[cmpBlockNdx]; 2307 2308 // \todo [2012-01-24 pyry] Verify that activeVarIndices is correct. 2309 // \todo [2012-01-24 pyry] Verify all instances. 2310 if (refBlockLayout.activeVarIndices.size() != cmpBlockLayout.activeVarIndices.size()) 2311 { 2312 log << TestLog::Message << "Error: Number of active variables differ in block '" << instanceName 2313 << "' (expected " << refBlockLayout.activeVarIndices.size() 2314 << ", got " << cmpBlockLayout.activeVarIndices.size() 2315 << ")" << TestLog::EndMessage; 2316 isOk = false; 2317 } 2318 2319 for (vector<int>::const_iterator ndxIter = refBlockLayout.activeVarIndices.begin(); ndxIter != refBlockLayout.activeVarIndices.end(); ndxIter++) 2320 { 2321 const BufferVarLayoutEntry& refEntry = refLayout.bufferVars[*ndxIter]; 2322 int cmpEntryNdx = cmpLayout.getVariableIndex(refEntry.name.c_str()); 2323 2324 if (cmpEntryNdx < 0) 2325 { 2326 log << TestLog::Message << "Error: Buffer variable '" << refEntry.name << "' not found" << TestLog::EndMessage; 2327 isOk = false; 2328 continue; 2329 } 2330 2331 const BufferVarLayoutEntry& cmpEntry = cmpLayout.bufferVars[cmpEntryNdx]; 2332 2333 if (refEntry.type != cmpEntry.type || 2334 refEntry.arraySize != cmpEntry.arraySize || 2335 refEntry.offset != cmpEntry.offset || 2336 refEntry.arrayStride != cmpEntry.arrayStride || 2337 refEntry.matrixStride != cmpEntry.matrixStride || 2338 refEntry.topLevelArraySize != cmpEntry.topLevelArraySize || 2339 refEntry.topLevelArrayStride != cmpEntry.topLevelArrayStride || 2340 refEntry.isRowMajor != cmpEntry.isRowMajor) 2341 { 2342 log << TestLog::Message << "Error: Layout mismatch in '" << refEntry.name << "':\n" 2343 << " expected: " << refEntry << "\n" 2344 << " got: " << cmpEntry 2345 << TestLog::EndMessage; 2346 isOk = false; 2347 } 2348 } 2349 } 2350 2351 return isOk; 2352} 2353 2354bool SSBOLayoutCase::compareSharedBlocks (const BufferLayout& refLayout, const BufferLayout& cmpLayout) const 2355{ 2356 TestLog& log = m_testCtx.getLog(); 2357 bool isOk = true; 2358 int numBlocks = m_interface.getNumBlocks(); 2359 2360 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 2361 { 2362 const BufferBlock& block = m_interface.getBlock(blockNdx); 2363 bool isArray = block.isArray(); 2364 std::string instanceName = string(block.getBlockName()) + (isArray ? "[0]" : ""); 2365 int refBlockNdx = refLayout.getBlockIndex(instanceName.c_str()); 2366 int cmpBlockNdx = cmpLayout.getBlockIndex(instanceName.c_str()); 2367 2368 if ((block.getFlags() & LAYOUT_SHARED) == 0) 2369 continue; // Not shared layout. 2370 2371 DE_ASSERT(refBlockNdx >= 0); 2372 2373 if (cmpBlockNdx < 0) 2374 { 2375 // Not found, should it? 2376 log << TestLog::Message << "Error: Buffer block '" << instanceName << "' not found" << TestLog::EndMessage; 2377 isOk = false; 2378 continue; 2379 } 2380 2381 const BlockLayoutEntry& refBlockLayout = refLayout.blocks[refBlockNdx]; 2382 const BlockLayoutEntry& cmpBlockLayout = cmpLayout.blocks[cmpBlockNdx]; 2383 2384 if (refBlockLayout.activeVarIndices.size() != cmpBlockLayout.activeVarIndices.size()) 2385 { 2386 log << TestLog::Message << "Error: Number of active variables differ in block '" << instanceName 2387 << "' (expected " << refBlockLayout.activeVarIndices.size() 2388 << ", got " << cmpBlockLayout.activeVarIndices.size() 2389 << ")" << TestLog::EndMessage; 2390 isOk = false; 2391 } 2392 2393 for (vector<int>::const_iterator ndxIter = refBlockLayout.activeVarIndices.begin(); ndxIter != refBlockLayout.activeVarIndices.end(); ndxIter++) 2394 { 2395 const BufferVarLayoutEntry& refEntry = refLayout.bufferVars[*ndxIter]; 2396 int cmpEntryNdx = cmpLayout.getVariableIndex(refEntry.name.c_str()); 2397 2398 if (cmpEntryNdx < 0) 2399 { 2400 log << TestLog::Message << "Error: Buffer variable '" << refEntry.name << "' not found" << TestLog::EndMessage; 2401 isOk = false; 2402 continue; 2403 } 2404 2405 const BufferVarLayoutEntry& cmpEntry = cmpLayout.bufferVars[cmpEntryNdx]; 2406 2407 if (refEntry.type != cmpEntry.type || 2408 refEntry.arraySize != cmpEntry.arraySize || 2409 refEntry.topLevelArraySize != cmpEntry.topLevelArraySize || 2410 refEntry.isRowMajor != cmpEntry.isRowMajor) 2411 { 2412 log << TestLog::Message << "Error: Type / array size mismatch in '" << refEntry.name << "':\n" 2413 << " expected: " << refEntry << "\n" 2414 << " got: " << cmpEntry 2415 << TestLog::EndMessage; 2416 isOk = false; 2417 } 2418 } 2419 } 2420 2421 return isOk; 2422} 2423 2424bool SSBOLayoutCase::compareTypes (const BufferLayout& refLayout, const BufferLayout& cmpLayout) const 2425{ 2426 TestLog& log = m_testCtx.getLog(); 2427 bool isOk = true; 2428 int numBlocks = m_interface.getNumBlocks(); 2429 2430 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 2431 { 2432 const BufferBlock& block = m_interface.getBlock(blockNdx); 2433 bool isArray = block.isArray(); 2434 int numInstances = isArray ? block.getArraySize() : 1; 2435 2436 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++) 2437 { 2438 std::ostringstream instanceName; 2439 2440 instanceName << block.getBlockName(); 2441 if (isArray) 2442 instanceName << "[" << instanceNdx << "]"; 2443 2444 int cmpBlockNdx = cmpLayout.getBlockIndex(instanceName.str().c_str()); 2445 2446 if (cmpBlockNdx < 0) 2447 continue; 2448 2449 const BlockLayoutEntry& cmpBlockLayout = cmpLayout.blocks[cmpBlockNdx]; 2450 2451 for (vector<int>::const_iterator ndxIter = cmpBlockLayout.activeVarIndices.begin(); ndxIter != cmpBlockLayout.activeVarIndices.end(); ndxIter++) 2452 { 2453 const BufferVarLayoutEntry& cmpEntry = cmpLayout.bufferVars[*ndxIter]; 2454 int refEntryNdx = refLayout.getVariableIndex(cmpEntry.name.c_str()); 2455 2456 if (refEntryNdx < 0) 2457 { 2458 log << TestLog::Message << "Error: Buffer variable '" << cmpEntry.name << "' not found in reference layout" << TestLog::EndMessage; 2459 isOk = false; 2460 continue; 2461 } 2462 2463 const BufferVarLayoutEntry& refEntry = refLayout.bufferVars[refEntryNdx]; 2464 2465 if (refEntry.type != cmpEntry.type) 2466 { 2467 log << TestLog::Message << "Error: Buffer variable type mismatch in '" << refEntry.name << "':\n" 2468 << " expected: " << glu::getDataTypeName(refEntry.type) << "\n" 2469 << " got: " << glu::getDataTypeName(cmpEntry.type) 2470 << TestLog::EndMessage; 2471 isOk = false; 2472 } 2473 2474 if (refEntry.arraySize < cmpEntry.arraySize) 2475 { 2476 log << TestLog::Message << "Error: Invalid array size in '" << refEntry.name << "': expected <= " << refEntry.arraySize << TestLog::EndMessage; 2477 isOk = false; 2478 } 2479 2480 if (refEntry.topLevelArraySize < cmpEntry.topLevelArraySize) 2481 { 2482 log << TestLog::Message << "Error: Invalid top-level array size in '" << refEntry.name << "': expected <= " << refEntry.topLevelArraySize << TestLog::EndMessage; 2483 isOk = false; 2484 } 2485 } 2486 } 2487 } 2488 2489 return isOk; 2490} 2491 2492bool SSBOLayoutCase::checkLayoutIndices (const BufferLayout& layout) const 2493{ 2494 TestLog& log = m_testCtx.getLog(); 2495 int numVars = (int)layout.bufferVars.size(); 2496 int numBlocks = (int)layout.blocks.size(); 2497 bool isOk = true; 2498 2499 // Check variable block indices. 2500 for (int varNdx = 0; varNdx < numVars; varNdx++) 2501 { 2502 const BufferVarLayoutEntry& bufVar = layout.bufferVars[varNdx]; 2503 2504 if (bufVar.blockNdx < 0 || !deInBounds32(bufVar.blockNdx, 0, numBlocks)) 2505 { 2506 log << TestLog::Message << "Error: Invalid block index in buffer variable '" << bufVar.name << "'" << TestLog::EndMessage; 2507 isOk = false; 2508 } 2509 } 2510 2511 // Check active variables. 2512 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 2513 { 2514 const BlockLayoutEntry& block = layout.blocks[blockNdx]; 2515 2516 for (vector<int>::const_iterator varNdxIter = block.activeVarIndices.begin(); varNdxIter != block.activeVarIndices.end(); varNdxIter++) 2517 { 2518 if (!deInBounds32(*varNdxIter, 0, numVars)) 2519 { 2520 log << TestLog::Message << "Error: Invalid active variable index " << *varNdxIter << " in block '" << block.name << "'" << TestLog::EndMessage; 2521 isOk = false; 2522 } 2523 } 2524 } 2525 2526 return isOk; 2527} 2528 2529bool SSBOLayoutCase::checkLayoutBounds (const BufferLayout& layout) const 2530{ 2531 TestLog& log = m_testCtx.getLog(); 2532 const int numVars = (int)layout.bufferVars.size(); 2533 bool isOk = true; 2534 2535 for (int varNdx = 0; varNdx < numVars; varNdx++) 2536 { 2537 const BufferVarLayoutEntry& var = layout.bufferVars[varNdx]; 2538 2539 if (var.blockNdx < 0 || isUnsizedArray(var)) 2540 continue; 2541 2542 const BlockLayoutEntry& block = layout.blocks[var.blockNdx]; 2543 const bool isMatrix = glu::isDataTypeMatrix(var.type); 2544 const int numVecs = isMatrix ? (var.isRowMajor ? glu::getDataTypeMatrixNumRows(var.type) : glu::getDataTypeMatrixNumColumns(var.type)) : 1; 2545 const int numComps = isMatrix ? (var.isRowMajor ? glu::getDataTypeMatrixNumColumns(var.type) : glu::getDataTypeMatrixNumRows(var.type)) : glu::getDataTypeScalarSize(var.type); 2546 const int numElements = var.arraySize; 2547 const int topLevelSize = var.topLevelArraySize; 2548 const int arrayStride = var.arrayStride; 2549 const int topLevelStride = var.topLevelArrayStride; 2550 const int compSize = sizeof(deUint32); 2551 const int vecSize = numComps*compSize; 2552 2553 int minOffset = 0; 2554 int maxOffset = 0; 2555 2556 // For negative strides. 2557 minOffset = de::min(minOffset, (numVecs-1)*var.matrixStride); 2558 minOffset = de::min(minOffset, (numElements-1)*arrayStride); 2559 minOffset = de::min(minOffset, (topLevelSize-1)*topLevelStride + (numElements-1)*arrayStride + (numVecs-1)*var.matrixStride); 2560 2561 maxOffset = de::max(maxOffset, vecSize); 2562 maxOffset = de::max(maxOffset, (numVecs-1)*var.matrixStride + vecSize); 2563 maxOffset = de::max(maxOffset, (numElements-1)*arrayStride + vecSize); 2564 maxOffset = de::max(maxOffset, (topLevelSize-1)*topLevelStride + (numElements-1)*arrayStride + vecSize); 2565 maxOffset = de::max(maxOffset, (topLevelSize-1)*topLevelStride + (numElements-1)*arrayStride + (numVecs-1)*var.matrixStride + vecSize); 2566 2567 if (var.offset+minOffset < 0 || var.offset+maxOffset > block.size) 2568 { 2569 log << TestLog::Message << "Error: Variable '" << var.name << "' out of block bounds" << TestLog::EndMessage; 2570 isOk = false; 2571 } 2572 } 2573 2574 return isOk; 2575} 2576 2577bool SSBOLayoutCase::checkIndexQueries (deUint32 program, const BufferLayout& layout) const 2578{ 2579 tcu::TestLog& log = m_testCtx.getLog(); 2580 const glw::Functions& gl = m_renderCtx.getFunctions(); 2581 bool allOk = true; 2582 2583 // \note Spec mandates that buffer blocks are assigned consecutive locations from 0. 2584 // BlockLayoutEntries are stored in that order in UniformLayout. 2585 for (int blockNdx = 0; blockNdx < (int)layout.blocks.size(); blockNdx++) 2586 { 2587 const BlockLayoutEntry& block = layout.blocks[blockNdx]; 2588 const int queriedNdx = gl.getProgramResourceIndex(program, GL_SHADER_STORAGE_BLOCK, block.name.c_str()); 2589 2590 if (queriedNdx != blockNdx) 2591 { 2592 log << TestLog::Message << "ERROR: glGetProgramResourceIndex(" << block.name << ") returned " << queriedNdx << ", expected " << blockNdx << "!" << TestLog::EndMessage; 2593 allOk = false; 2594 } 2595 2596 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformBlockIndex()"); 2597 } 2598 2599 return allOk; 2600} 2601 2602bool SSBOLayoutCase::execute (deUint32 program) 2603{ 2604 const glw::Functions& gl = m_renderCtx.getFunctions(); 2605 const deUint32 numPassedLoc = gl.getProgramResourceIndex(program, GL_UNIFORM, "ac_numPassed"); 2606 const glu::InterfaceVariableInfo acVarInfo = numPassedLoc != GL_INVALID_INDEX ? glu::getProgramInterfaceVariableInfo(gl, program, GL_UNIFORM, numPassedLoc) 2607 : glu::InterfaceVariableInfo(); 2608 const glu::InterfaceBlockInfo acBufferInfo = acVarInfo.atomicCounterBufferIndex != GL_INVALID_INDEX ? glu::getProgramInterfaceBlockInfo(gl, program, GL_ATOMIC_COUNTER_BUFFER, acVarInfo.atomicCounterBufferIndex) 2609 : glu::InterfaceBlockInfo(); 2610 const glu::Buffer acBuffer (m_renderCtx); 2611 bool isOk = true; 2612 2613 if (numPassedLoc == GL_INVALID_INDEX) 2614 throw tcu::TestError("No location for ac_numPassed found"); 2615 2616 if (acBufferInfo.index == GL_INVALID_INDEX) 2617 throw tcu::TestError("ac_numPassed buffer index is GL_INVALID_INDEX"); 2618 2619 if (acBufferInfo.dataSize == 0) 2620 throw tcu::TestError("ac_numPassed buffer size = 0"); 2621 2622 // Initialize atomic counter buffer. 2623 { 2624 vector<deUint8> emptyData(acBufferInfo.dataSize, 0); 2625 2626 gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, *acBuffer); 2627 gl.bufferData(GL_ATOMIC_COUNTER_BUFFER, (glw::GLsizeiptr)emptyData.size(), &emptyData[0], GL_STATIC_READ); 2628 gl.bindBufferBase(GL_ATOMIC_COUNTER_BUFFER, acBufferInfo.index, *acBuffer); 2629 GLU_EXPECT_NO_ERROR(gl.getError(), "Setting up buffer for ac_numPassed failed"); 2630 } 2631 2632 gl.useProgram(program); 2633 gl.dispatchCompute(1, 1, 1); 2634 GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute() failed"); 2635 2636 // Read back ac_numPassed data. 2637 { 2638 const void* mapPtr = gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, acBufferInfo.dataSize, GL_MAP_READ_BIT); 2639 const int refCount = 1; 2640 int resCount = 0; 2641 2642 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER) failed"); 2643 TCU_CHECK(mapPtr); 2644 2645 resCount = *(const int*)((const deUint8*)mapPtr + acVarInfo.offset); 2646 2647 gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER); 2648 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER) failed"); 2649 2650 if (refCount != resCount) 2651 { 2652 m_testCtx.getLog() << TestLog::Message << "ERROR: ac_numPassed = " << resCount << ", expected " << refCount << TestLog::EndMessage; 2653 isOk = false; 2654 } 2655 } 2656 2657 GLU_EXPECT_NO_ERROR(gl.getError(), "Shader execution failed"); 2658 2659 return isOk; 2660} 2661 2662} // gles31 2663} // deqp 2664