1 /*------------------------------------------------------------------------ 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2015 The Khronos Group Inc. 6 * Copyright (c) 2015 Samsung Electronics Co., Ltd. 7 * Copyright (c) 2016 The Android Open Source Project 8 * 9 * Licensed under the Apache License, Version 2.0 (the "License"); 10 * you may not use this file except in compliance with the License. 11 * You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 * 21 *//*! 22 * \file 23 * \brief Uniform block case. 24 *//*--------------------------------------------------------------------*/ 25 26 #include "vktUniformBlockCase.hpp" 27 28 #include "vkPrograms.hpp" 29 30 #include "gluVarType.hpp" 31 #include "tcuTestLog.hpp" 32 #include "tcuSurface.hpp" 33 #include "deRandom.hpp" 34 #include "deStringUtil.hpp" 35 36 #include "tcuTextureUtil.hpp" 37 #include "deSharedPtr.hpp" 38 #include "deFloat16.h" 39 40 #include "vkMemUtil.hpp" 41 #include "vkQueryUtil.hpp" 42 #include "vkTypeUtil.hpp" 43 #include "vkRef.hpp" 44 #include "vkRefUtil.hpp" 45 #include "vkBuilderUtil.hpp" 46 #include "vkCmdUtil.hpp" 47 #include "vkObjUtil.hpp" 48 #include "vkImageUtil.hpp" 49 50 #include <map> 51 #include <set> 52 53 namespace vkt 54 { 55 namespace ubo 56 { 57 58 using namespace vk; 59 60 // VarType implementation. 61 62 VarType::VarType (void) 63 : m_type (TYPE_LAST) 64 , m_flags (0) 65 { 66 } 67 68 VarType::VarType (const VarType& other) 69 : m_type (TYPE_LAST) 70 , m_flags (0) 71 { 72 *this = other; 73 } 74 75 VarType::VarType (glu::DataType basicType, deUint32 flags) 76 : m_type (TYPE_BASIC) 77 , m_flags (flags) 78 { 79 m_data.basicType = basicType; 80 } 81 82 VarType::VarType (const VarType& elementType, int arraySize) 83 : m_type (TYPE_ARRAY) 84 , m_flags (0) 85 { 86 m_data.array.size = arraySize; 87 m_data.array.elementType = new VarType(elementType); 88 } 89 90 VarType::VarType (const StructType* structPtr, deUint32 flags) 91 : m_type (TYPE_STRUCT) 92 , m_flags (flags) 93 { 94 m_data.structPtr = structPtr; 95 } 96 97 VarType::~VarType (void) 98 { 99 if (m_type == TYPE_ARRAY) 100 delete m_data.array.elementType; 101 } 102 103 VarType& VarType::operator= (const VarType& other) 104 { 105 if (this == &other) 106 return *this; // Self-assignment. 107 108 VarType *oldElementType = m_type == TYPE_ARRAY ? m_data.array.elementType : DE_NULL; 109 110 m_type = other.m_type; 111 m_flags = other.m_flags; 112 m_data = Data(); 113 114 if (m_type == TYPE_ARRAY) 115 { 116 m_data.array.elementType = new VarType(*other.m_data.array.elementType); 117 m_data.array.size = other.m_data.array.size; 118 } 119 else 120 m_data = other.m_data; 121 122 delete oldElementType; 123 124 return *this; 125 } 126 127 // StructType implementation. 128 129 void StructType::addMember (const std::string& name, const VarType& type, deUint32 flags) 130 { 131 m_members.push_back(StructMember(name, type, flags)); 132 } 133 134 // Uniform implementation. 135 136 Uniform::Uniform (const std::string& name, const VarType& type, deUint32 flags) 137 : m_name (name) 138 , m_type (type) 139 , m_flags (flags) 140 { 141 } 142 143 // UniformBlock implementation. 144 145 UniformBlock::UniformBlock (const std::string& blockName) 146 : m_blockName (blockName) 147 , m_arraySize (0) 148 , m_flags (0) 149 { 150 } 151 152 std::ostream& operator<< (std::ostream& stream, const BlockLayoutEntry& entry) 153 { 154 stream << entry.name << " { name = " << entry.name 155 << ", size = " << entry.size 156 << ", activeUniformIndices = ["; 157 158 for (std::vector<int>::const_iterator i = entry.activeUniformIndices.begin(); i != entry.activeUniformIndices.end(); i++) 159 { 160 if (i != entry.activeUniformIndices.begin()) 161 stream << ", "; 162 stream << *i; 163 } 164 165 stream << "] }"; 166 return stream; 167 } 168 169 std::ostream& operator<< (std::ostream& stream, const UniformLayoutEntry& entry) 170 { 171 stream << entry.name << " { type = " << glu::getDataTypeName(entry.type) 172 << ", size = " << entry.size 173 << ", blockNdx = " << entry.blockNdx 174 << ", offset = " << entry.offset 175 << ", arrayStride = " << entry.arrayStride 176 << ", matrixStride = " << entry.matrixStride 177 << ", isRowMajor = " << (entry.isRowMajor ? "true" : "false") 178 << " }"; 179 return stream; 180 } 181 182 int UniformLayout::getUniformLayoutIndex (int blockNdx, const std::string& name) const 183 { 184 for (int ndx = 0; ndx < (int)uniforms.size(); ndx++) 185 { 186 if (blocks[uniforms[ndx].blockNdx].blockDeclarationNdx == blockNdx && 187 uniforms[ndx].name == name) 188 return ndx; 189 } 190 191 return -1; 192 } 193 194 int UniformLayout::getBlockLayoutIndex (int blockNdx, int instanceNdx) const 195 { 196 for (int ndx = 0; ndx < (int)blocks.size(); ndx++) 197 { 198 if (blocks[ndx].blockDeclarationNdx == blockNdx && 199 blocks[ndx].instanceNdx == instanceNdx) 200 return ndx; 201 } 202 203 return -1; 204 } 205 206 // ShaderInterface implementation. 207 208 ShaderInterface::ShaderInterface (void) 209 { 210 } 211 212 ShaderInterface::~ShaderInterface (void) 213 { 214 } 215 216 StructType& ShaderInterface::allocStruct (const std::string& name) 217 { 218 m_structs.push_back(StructTypeSP(new StructType(name))); 219 return *m_structs.back(); 220 } 221 222 struct StructNameEquals 223 { 224 std::string name; 225 226 StructNameEquals (const std::string& name_) : name(name_) {} 227 228 bool operator() (const StructTypeSP type) const 229 { 230 return type->hasTypeName() && name == type->getTypeName(); 231 } 232 }; 233 234 void ShaderInterface::getNamedStructs (std::vector<const StructType*>& structs) const 235 { 236 for (std::vector<StructTypeSP>::const_iterator i = m_structs.begin(); i != m_structs.end(); i++) 237 { 238 if ((*i)->hasTypeName()) 239 structs.push_back((*i).get()); 240 } 241 } 242 243 UniformBlock& ShaderInterface::allocBlock (const std::string& name) 244 { 245 m_uniformBlocks.push_back(UniformBlockSP(new UniformBlock(name))); 246 return *m_uniformBlocks.back(); 247 } 248 249 bool ShaderInterface::usesBlockLayout (UniformFlags layoutFlag) const 250 { 251 for (int i = 0, num_blocks = getNumUniformBlocks() ; i < num_blocks ; i++) 252 { 253 if (m_uniformBlocks[i]->getFlags() & layoutFlag) 254 return true; 255 } 256 return false; 257 } 258 259 namespace // Utilities 260 { 261 262 struct PrecisionFlagsFmt 263 { 264 deUint32 flags; 265 PrecisionFlagsFmt (deUint32 flags_) : flags(flags_) {} 266 }; 267 268 std::ostream& operator<< (std::ostream& str, const PrecisionFlagsFmt& fmt) 269 { 270 // Precision. 271 DE_ASSERT(dePop32(fmt.flags & (PRECISION_LOW|PRECISION_MEDIUM|PRECISION_HIGH)) <= 1); 272 str << (fmt.flags & PRECISION_LOW ? "lowp" : 273 fmt.flags & PRECISION_MEDIUM ? "mediump" : 274 fmt.flags & PRECISION_HIGH ? "highp" : ""); 275 return str; 276 } 277 278 struct LayoutFlagsFmt 279 { 280 deUint32 flags; 281 deUint32 offset; 282 LayoutFlagsFmt (deUint32 flags_, deUint32 offset_ = 0u) : flags(flags_), offset(offset_) {} 283 }; 284 285 std::ostream& operator<< (std::ostream& str, const LayoutFlagsFmt& fmt) 286 { 287 static const struct 288 { 289 deUint32 bit; 290 const char* token; 291 } bitDesc[] = 292 { 293 { LAYOUT_STD140, "std140" }, 294 { LAYOUT_STD430, "std430" }, 295 { LAYOUT_SCALAR, "scalar" }, 296 { LAYOUT_ROW_MAJOR, "row_major" }, 297 { LAYOUT_COLUMN_MAJOR, "column_major" }, 298 { LAYOUT_OFFSET, "offset" }, 299 }; 300 301 deUint32 remBits = fmt.flags; 302 for (int descNdx = 0; descNdx < DE_LENGTH_OF_ARRAY(bitDesc); descNdx++) 303 { 304 if (remBits & bitDesc[descNdx].bit) 305 { 306 if (remBits != fmt.flags) 307 str << ", "; 308 str << bitDesc[descNdx].token; 309 if (bitDesc[descNdx].bit == LAYOUT_OFFSET) 310 str << " = " << fmt.offset; 311 remBits &= ~bitDesc[descNdx].bit; 312 } 313 } 314 DE_ASSERT(remBits == 0); 315 return str; 316 } 317 318 // Layout computation. 319 320 int getDataTypeByteSize (glu::DataType type) 321 { 322 if (deInRange32(type, glu::TYPE_UINT8, glu::TYPE_UINT8_VEC4) || deInRange32(type, glu::TYPE_INT8, glu::TYPE_INT8_VEC4)) 323 { 324 return glu::getDataTypeScalarSize(type)*(int)sizeof(deUint8); 325 } 326 if (deInRange32(type, glu::TYPE_UINT16, glu::TYPE_UINT16_VEC4) || deInRange32(type, glu::TYPE_INT16, glu::TYPE_INT16_VEC4) || deInRange32(type, glu::TYPE_FLOAT16, glu::TYPE_FLOAT16_VEC4)) 327 { 328 return glu::getDataTypeScalarSize(type)*(int)sizeof(deUint16); 329 } 330 else 331 { 332 return glu::getDataTypeScalarSize(type)*(int)sizeof(deUint32); 333 } 334 } 335 336 int getDataTypeByteAlignment (glu::DataType type) 337 { 338 switch (type) 339 { 340 case glu::TYPE_FLOAT: 341 case glu::TYPE_INT: 342 case glu::TYPE_UINT: 343 case glu::TYPE_BOOL: return 1*(int)sizeof(deUint32); 344 345 case glu::TYPE_FLOAT_VEC2: 346 case glu::TYPE_INT_VEC2: 347 case glu::TYPE_UINT_VEC2: 348 case glu::TYPE_BOOL_VEC2: return 2*(int)sizeof(deUint32); 349 350 case glu::TYPE_FLOAT_VEC3: 351 case glu::TYPE_INT_VEC3: 352 case glu::TYPE_UINT_VEC3: 353 case glu::TYPE_BOOL_VEC3: // Fall-through to vec4 354 355 case glu::TYPE_FLOAT_VEC4: 356 case glu::TYPE_INT_VEC4: 357 case glu::TYPE_UINT_VEC4: 358 case glu::TYPE_BOOL_VEC4: return 4*(int)sizeof(deUint32); 359 360 case glu::TYPE_UINT8: 361 case glu::TYPE_INT8 : return 1*(int)sizeof(deUint8); 362 363 case glu::TYPE_UINT8_VEC2: 364 case glu::TYPE_INT8_VEC2: return 2*(int)sizeof(deUint8); 365 366 case glu::TYPE_UINT8_VEC3: 367 case glu::TYPE_INT8_VEC3: // Fall-through to vec4 368 369 case glu::TYPE_UINT8_VEC4: 370 case glu::TYPE_INT8_VEC4: return 4*(int)sizeof(deUint8); 371 372 case glu::TYPE_UINT16: 373 case glu::TYPE_INT16: 374 case glu::TYPE_FLOAT16: return 1*(int)sizeof(deUint16); 375 376 case glu::TYPE_UINT16_VEC2: 377 case glu::TYPE_INT16_VEC2: 378 case glu::TYPE_FLOAT16_VEC2: return 2*(int)sizeof(deUint16); 379 380 case glu::TYPE_UINT16_VEC3: 381 case glu::TYPE_INT16_VEC3: 382 case glu::TYPE_FLOAT16_VEC3: // Fall-through to vec4 383 384 case glu::TYPE_UINT16_VEC4: 385 case glu::TYPE_INT16_VEC4: 386 case glu::TYPE_FLOAT16_VEC4: return 4*(int)sizeof(deUint16); 387 388 default: 389 DE_ASSERT(false); 390 return 0; 391 } 392 } 393 394 deInt32 getminUniformBufferOffsetAlignment (Context &ctx) 395 { 396 VkPhysicalDeviceProperties properties; 397 ctx.getInstanceInterface().getPhysicalDeviceProperties(ctx.getPhysicalDevice(), &properties); 398 VkDeviceSize align = properties.limits.minUniformBufferOffsetAlignment; 399 DE_ASSERT(align == (VkDeviceSize)(deInt32)align); 400 return (deInt32)align; 401 } 402 403 static inline int deRoundUp32 (int a, int b) 404 { 405 int d = a/b; 406 return d*b == a ? a : (d+1)*b; 407 } 408 409 410 int computeStd140BaseAlignment (const VarType& type, deUint32 layoutFlags) 411 { 412 const int vec4Alignment = (int)sizeof(deUint32)*4; 413 414 if (type.isBasicType()) 415 { 416 glu::DataType basicType = type.getBasicType(); 417 418 if (glu::isDataTypeMatrix(basicType)) 419 { 420 const bool isRowMajor = !!(layoutFlags & LAYOUT_ROW_MAJOR); 421 const int vecSize = isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType) 422 : glu::getDataTypeMatrixNumRows(basicType); 423 const int vecAlign = deAlign32(getDataTypeByteAlignment(glu::getDataTypeFloatVec(vecSize)), vec4Alignment); 424 425 return vecAlign; 426 } 427 else 428 return getDataTypeByteAlignment(basicType); 429 } 430 else if (type.isArrayType()) 431 { 432 int elemAlignment = computeStd140BaseAlignment(type.getElementType(), layoutFlags); 433 434 // Round up to alignment of vec4 435 return deAlign32(elemAlignment, vec4Alignment); 436 } 437 else 438 { 439 DE_ASSERT(type.isStructType()); 440 441 int maxBaseAlignment = 0; 442 443 for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++) 444 maxBaseAlignment = de::max(maxBaseAlignment, computeStd140BaseAlignment(memberIter->getType(), layoutFlags)); 445 446 return deAlign32(maxBaseAlignment, vec4Alignment); 447 } 448 } 449 450 int computeStd430BaseAlignment (const VarType& type, deUint32 layoutFlags) 451 { 452 // Otherwise identical to std140 except that alignment of structures and arrays 453 // are not rounded up to alignment of vec4. 454 455 if (type.isBasicType()) 456 { 457 glu::DataType basicType = type.getBasicType(); 458 459 if (glu::isDataTypeMatrix(basicType)) 460 { 461 const bool isRowMajor = !!(layoutFlags & LAYOUT_ROW_MAJOR); 462 const int vecSize = isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType) 463 : glu::getDataTypeMatrixNumRows(basicType); 464 const int vecAlign = getDataTypeByteAlignment(glu::getDataTypeFloatVec(vecSize)); 465 return vecAlign; 466 } 467 else 468 return getDataTypeByteAlignment(basicType); 469 } 470 else if (type.isArrayType()) 471 { 472 return computeStd430BaseAlignment(type.getElementType(), layoutFlags); 473 } 474 else 475 { 476 DE_ASSERT(type.isStructType()); 477 478 int maxBaseAlignment = 0; 479 480 for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++) 481 maxBaseAlignment = de::max(maxBaseAlignment, computeStd430BaseAlignment(memberIter->getType(), layoutFlags)); 482 483 return maxBaseAlignment; 484 } 485 } 486 487 int computeRelaxedBlockBaseAlignment (const VarType& type, deUint32 layoutFlags) 488 { 489 if (type.isBasicType()) 490 { 491 glu::DataType basicType = type.getBasicType(); 492 493 if (glu::isDataTypeVector(basicType)) 494 return getDataTypeByteAlignment(glu::getDataTypeScalarType(basicType)); 495 496 if (glu::isDataTypeMatrix(basicType)) 497 { 498 const bool isRowMajor = !!(layoutFlags & LAYOUT_ROW_MAJOR); 499 const int vecSize = isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType) 500 : glu::getDataTypeMatrixNumRows(basicType); 501 const int vecAlign = getDataTypeByteAlignment(glu::getDataTypeFloatVec(vecSize)); 502 return vecAlign; 503 } 504 else 505 return getDataTypeByteAlignment(basicType); 506 } 507 else if (type.isArrayType()) 508 return computeStd430BaseAlignment(type.getElementType(), layoutFlags); 509 else 510 { 511 DE_ASSERT(type.isStructType()); 512 513 int maxBaseAlignment = 0; 514 for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++) 515 maxBaseAlignment = de::max(maxBaseAlignment, computeRelaxedBlockBaseAlignment(memberIter->getType(), layoutFlags)); 516 517 return maxBaseAlignment; 518 } 519 } 520 521 int computeScalarBlockAlignment (const VarType& type, deUint32 layoutFlags) 522 { 523 if (type.isBasicType()) 524 { 525 return getDataTypeByteAlignment(glu::getDataTypeScalarType(type.getBasicType())); 526 } 527 else if (type.isArrayType()) 528 return computeScalarBlockAlignment(type.getElementType(), layoutFlags); 529 else 530 { 531 DE_ASSERT(type.isStructType()); 532 533 int maxBaseAlignment = 0; 534 for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++) 535 maxBaseAlignment = de::max(maxBaseAlignment, computeScalarBlockAlignment(memberIter->getType(), layoutFlags)); 536 537 return maxBaseAlignment; 538 } 539 } 540 541 inline deUint32 mergeLayoutFlags (deUint32 prevFlags, deUint32 newFlags) 542 { 543 const deUint32 packingMask = LAYOUT_STD140|LAYOUT_STD430|LAYOUT_SCALAR; 544 const deUint32 matrixMask = LAYOUT_ROW_MAJOR|LAYOUT_COLUMN_MAJOR; 545 546 deUint32 mergedFlags = 0; 547 548 mergedFlags |= ((newFlags & packingMask) ? newFlags : prevFlags) & packingMask; 549 mergedFlags |= ((newFlags & matrixMask) ? newFlags : prevFlags) & matrixMask; 550 551 return mergedFlags; 552 } 553 554 //! Appends all child elements to layout, returns value that should be appended to offset. 555 int computeReferenceLayout ( 556 UniformLayout& layout, 557 int curBlockNdx, 558 int baseOffset, 559 const std::string& curPrefix, 560 const VarType& type, 561 deUint32 layoutFlags) 562 { 563 // HACK to make code match SSBO tests 564 const int LAYOUT_RELAXED = 0; 565 // Reference layout uses std140 rules by default. std430 rules are 566 // choosen only for blocks that have std140 layout. 567 const int baseAlignment = (layoutFlags & LAYOUT_SCALAR) != 0 ? computeScalarBlockAlignment(type, layoutFlags) : 568 (layoutFlags & LAYOUT_STD430) != 0 ? computeStd430BaseAlignment(type, layoutFlags) : 569 (layoutFlags & LAYOUT_RELAXED) != 0 ? computeRelaxedBlockBaseAlignment(type, layoutFlags) : 570 computeStd140BaseAlignment(type, layoutFlags); 571 int curOffset = deAlign32(baseOffset, baseAlignment); 572 const int topLevelArraySize = 1; // Default values 573 const int topLevelArrayStride = 0; 574 575 if (type.isBasicType()) 576 { 577 const glu::DataType basicType = type.getBasicType(); 578 UniformLayoutEntry entry; 579 580 entry.name = curPrefix; 581 entry.type = basicType; 582 entry.arraySize = 1; 583 entry.arrayStride = 0; 584 entry.matrixStride = 0; 585 entry.topLevelArraySize = topLevelArraySize; 586 entry.topLevelArrayStride = topLevelArrayStride; 587 entry.blockNdx = curBlockNdx; 588 589 if (glu::isDataTypeMatrix(basicType)) 590 { 591 // Array of vectors as specified in rules 5 & 7. 592 const bool isRowMajor = !!(layoutFlags & LAYOUT_ROW_MAJOR); 593 const int vecSize = isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType) 594 : glu::getDataTypeMatrixNumRows(basicType); 595 const glu::DataType vecType = glu::getDataTypeFloatVec(vecSize); 596 const int numVecs = isRowMajor ? glu::getDataTypeMatrixNumRows(basicType) 597 : glu::getDataTypeMatrixNumColumns(basicType); 598 const int vecStride = (layoutFlags & LAYOUT_SCALAR) ? getDataTypeByteSize(vecType) : baseAlignment; 599 600 entry.offset = curOffset; 601 entry.matrixStride = vecStride; 602 entry.isRowMajor = isRowMajor; 603 604 curOffset += numVecs*entry.matrixStride; 605 } 606 else 607 { 608 if (!(layoutFlags & LAYOUT_SCALAR) && (layoutFlags & LAYOUT_RELAXED) && 609 glu::isDataTypeVector(basicType) && (getDataTypeByteSize(basicType) <= 16 ? curOffset / 16 != (curOffset + getDataTypeByteSize(basicType) - 1) / 16 : curOffset % 16 != 0)) 610 curOffset = deIntRoundToPow2(curOffset, 16); 611 612 // Scalar or vector. 613 entry.offset = curOffset; 614 615 curOffset += getDataTypeByteSize(basicType); 616 } 617 618 layout.uniforms.push_back(entry); 619 } 620 else if (type.isArrayType()) 621 { 622 const VarType& elemType = type.getElementType(); 623 624 if (elemType.isBasicType() && !glu::isDataTypeMatrix(elemType.getBasicType())) 625 { 626 // Array of scalars or vectors. 627 const glu::DataType elemBasicType = elemType.getBasicType(); 628 const int stride = (layoutFlags & LAYOUT_SCALAR) ? getDataTypeByteSize(elemBasicType) : baseAlignment; 629 UniformLayoutEntry entry; 630 631 entry.name = curPrefix + "[0]"; // Array variables are always postfixed with [0] 632 entry.type = elemBasicType; 633 entry.blockNdx = curBlockNdx; 634 entry.offset = curOffset; 635 entry.arraySize = type.getArraySize(); 636 entry.arrayStride = stride; 637 entry.matrixStride = 0; 638 entry.topLevelArraySize = topLevelArraySize; 639 entry.topLevelArrayStride = topLevelArrayStride; 640 641 curOffset += stride*type.getArraySize(); 642 643 layout.uniforms.push_back(entry); 644 } 645 else if (elemType.isBasicType() && glu::isDataTypeMatrix(elemType.getBasicType())) 646 { 647 // Array of matrices. 648 const glu::DataType elemBasicType = elemType.getBasicType(); 649 const bool isRowMajor = !!(layoutFlags & LAYOUT_ROW_MAJOR); 650 const int vecSize = isRowMajor ? glu::getDataTypeMatrixNumColumns(elemBasicType) 651 : glu::getDataTypeMatrixNumRows(elemBasicType); 652 const glu::DataType vecType = glu::getDataTypeFloatVec(vecSize); 653 const int numVecs = isRowMajor ? glu::getDataTypeMatrixNumRows(elemBasicType) 654 : glu::getDataTypeMatrixNumColumns(elemBasicType); 655 const int vecStride = (layoutFlags & LAYOUT_SCALAR) ? getDataTypeByteSize(vecType) : baseAlignment; 656 UniformLayoutEntry entry; 657 658 entry.name = curPrefix + "[0]"; // Array variables are always postfixed with [0] 659 entry.type = elemBasicType; 660 entry.blockNdx = curBlockNdx; 661 entry.offset = curOffset; 662 entry.arraySize = type.getArraySize(); 663 entry.arrayStride = vecStride*numVecs; 664 entry.matrixStride = vecStride; 665 entry.isRowMajor = isRowMajor; 666 entry.topLevelArraySize = topLevelArraySize; 667 entry.topLevelArrayStride = topLevelArrayStride; 668 669 curOffset += entry.arrayStride*type.getArraySize(); 670 671 layout.uniforms.push_back(entry); 672 } 673 else 674 { 675 DE_ASSERT(elemType.isStructType() || elemType.isArrayType()); 676 677 for (int elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++) 678 curOffset += computeReferenceLayout(layout, curBlockNdx, curOffset, curPrefix + "[" + de::toString(elemNdx) + "]", type.getElementType(), layoutFlags); 679 } 680 } 681 else 682 { 683 DE_ASSERT(type.isStructType()); 684 685 for (StructType::ConstIterator memberIter = type.getStructPtr()->begin(); memberIter != type.getStructPtr()->end(); memberIter++) 686 curOffset += computeReferenceLayout(layout, curBlockNdx, curOffset, curPrefix + "." + memberIter->getName(), memberIter->getType(), layoutFlags); 687 688 if (!(layoutFlags & LAYOUT_SCALAR)) 689 curOffset = deAlign32(curOffset, baseAlignment); 690 } 691 692 return curOffset-baseOffset; 693 } 694 695 void computeReferenceLayout (UniformLayout& layout, const ShaderInterface& interface) 696 { 697 int numUniformBlocks = interface.getNumUniformBlocks(); 698 699 for (int blockNdx = 0; blockNdx < numUniformBlocks; blockNdx++) 700 { 701 const UniformBlock& block = interface.getUniformBlock(blockNdx); 702 bool hasInstanceName = block.hasInstanceName(); 703 std::string blockPrefix = hasInstanceName ? (block.getBlockName() + ".") : ""; 704 int curOffset = 0; 705 int activeBlockNdx = (int)layout.blocks.size(); 706 int firstUniformNdx = (int)layout.uniforms.size(); 707 708 for (UniformBlock::ConstIterator uniformIter = block.begin(); uniformIter != block.end(); uniformIter++) 709 { 710 const Uniform& uniform = *uniformIter; 711 curOffset += computeReferenceLayout(layout, activeBlockNdx, curOffset, blockPrefix + uniform.getName(), uniform.getType(), mergeLayoutFlags(block.getFlags(), uniform.getFlags())); 712 } 713 714 int uniformIndicesEnd = (int)layout.uniforms.size(); 715 int blockSize = curOffset; 716 int numInstances = block.isArray() ? block.getArraySize() : 1; 717 718 // Create block layout entries for each instance. 719 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++) 720 { 721 // Allocate entry for instance. 722 layout.blocks.push_back(BlockLayoutEntry()); 723 BlockLayoutEntry& blockEntry = layout.blocks.back(); 724 725 blockEntry.name = block.getBlockName(); 726 blockEntry.size = blockSize; 727 blockEntry.bindingNdx = blockNdx; 728 blockEntry.blockDeclarationNdx = blockNdx; 729 blockEntry.instanceNdx = instanceNdx; 730 731 // Compute active uniform set for block. 732 for (int uniformNdx = firstUniformNdx; uniformNdx < uniformIndicesEnd; uniformNdx++) 733 blockEntry.activeUniformIndices.push_back(uniformNdx); 734 735 if (block.isArray()) 736 blockEntry.name += "[" + de::toString(instanceNdx) + "]"; 737 } 738 } 739 } 740 741 // Value generator. 742 743 void generateValue (const UniformLayoutEntry& entry, void* basePtr, de::Random& rnd) 744 { 745 glu::DataType scalarType = glu::getDataTypeScalarType(entry.type); 746 int scalarSize = glu::getDataTypeScalarSize(entry.type); 747 bool isMatrix = glu::isDataTypeMatrix(entry.type); 748 int numVecs = isMatrix ? (entry.isRowMajor ? glu::getDataTypeMatrixNumRows(entry.type) : glu::getDataTypeMatrixNumColumns(entry.type)) : 1; 749 int vecSize = scalarSize / numVecs; 750 bool isArray = entry.size > 1; 751 const size_t compSize = getDataTypeByteSize(scalarType); 752 753 DE_ASSERT(scalarSize%numVecs == 0); 754 755 for (int elemNdx = 0; elemNdx < entry.size; elemNdx++) 756 { 757 deUint8* elemPtr = (deUint8*)basePtr + entry.offset + (isArray ? elemNdx*entry.arrayStride : 0); 758 759 for (int vecNdx = 0; vecNdx < numVecs; vecNdx++) 760 { 761 deUint8* vecPtr = elemPtr + (isMatrix ? vecNdx*entry.matrixStride : 0); 762 763 for (int compNdx = 0; compNdx < vecSize; compNdx++) 764 { 765 deUint8* compPtr = vecPtr + compSize*compNdx; 766 767 switch (scalarType) 768 { 769 case glu::TYPE_FLOAT: *((float*)compPtr) = (float)rnd.getInt(-9, 9); break; 770 case glu::TYPE_INT: *((int*)compPtr) = rnd.getInt(-9, 9); break; 771 case glu::TYPE_UINT: *((deUint32*)compPtr) = (deUint32)rnd.getInt(0, 9); break; 772 case glu::TYPE_INT8: *((deInt8*)compPtr) = (deInt8)rnd.getInt(-9, 9); break; 773 case glu::TYPE_UINT8: *((deUint8*)compPtr) = (deUint8)rnd.getInt(0, 9); break; 774 case glu::TYPE_INT16: *((deInt16*)compPtr) = (deInt16)rnd.getInt(-9, 9); break; 775 case glu::TYPE_UINT16: *((deUint16*)compPtr) = (deUint16)rnd.getInt(0, 9); break; 776 case glu::TYPE_FLOAT16: *((deFloat16*)compPtr) = deFloat32To16((float)rnd.getInt(-9, 9)); break; 777 // \note Random bit pattern is used for true values. Spec states that all non-zero values are 778 // interpreted as true but some implementations fail this. 779 case glu::TYPE_BOOL: *((deUint32*)compPtr) = rnd.getBool() ? rnd.getUint32()|1u : 0u; break; 780 default: 781 DE_ASSERT(false); 782 } 783 } 784 } 785 } 786 } 787 788 void generateValues (const UniformLayout& layout, const std::map<int, void*>& blockPointers, deUint32 seed) 789 { 790 de::Random rnd (seed); 791 int numBlocks = (int)layout.blocks.size(); 792 793 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 794 { 795 void* basePtr = blockPointers.find(blockNdx)->second; 796 int numEntries = (int)layout.blocks[blockNdx].activeUniformIndices.size(); 797 798 for (int entryNdx = 0; entryNdx < numEntries; entryNdx++) 799 { 800 const UniformLayoutEntry& entry = layout.uniforms[layout.blocks[blockNdx].activeUniformIndices[entryNdx]]; 801 generateValue(entry, basePtr, rnd); 802 } 803 } 804 } 805 806 // Shader generator. 807 808 const char* getCompareFuncForType (glu::DataType type) 809 { 810 switch (type) 811 { 812 case glu::TYPE_FLOAT: return "mediump float compare_float (highp float a, highp float b) { return abs(a - b) < 0.05 ? 1.0 : 0.0; }\n"; 813 case glu::TYPE_FLOAT_VEC2: return "mediump float compare_vec2 (highp vec2 a, highp vec2 b) { return compare_float(a.x, b.x)*compare_float(a.y, b.y); }\n"; 814 case glu::TYPE_FLOAT_VEC3: return "mediump float 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"; 815 case glu::TYPE_FLOAT_VEC4: return "mediump float 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"; 816 case glu::TYPE_FLOAT_MAT2: return "mediump float compare_mat2 (highp mat2 a, highp mat2 b) { return compare_vec2(a[0], b[0])*compare_vec2(a[1], b[1]); }\n"; 817 case glu::TYPE_FLOAT_MAT2X3: return "mediump float compare_mat2x3 (highp mat2x3 a, highp mat2x3 b){ return compare_vec3(a[0], b[0])*compare_vec3(a[1], b[1]); }\n"; 818 case glu::TYPE_FLOAT_MAT2X4: return "mediump float compare_mat2x4 (highp mat2x4 a, highp mat2x4 b){ return compare_vec4(a[0], b[0])*compare_vec4(a[1], b[1]); }\n"; 819 case glu::TYPE_FLOAT_MAT3X2: return "mediump float 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"; 820 case glu::TYPE_FLOAT_MAT3: return "mediump float 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"; 821 case glu::TYPE_FLOAT_MAT3X4: return "mediump float 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"; 822 case glu::TYPE_FLOAT_MAT4X2: return "mediump float 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"; 823 case glu::TYPE_FLOAT_MAT4X3: return "mediump float 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"; 824 case glu::TYPE_FLOAT_MAT4: return "mediump float 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"; 825 case glu::TYPE_INT: return "mediump float compare_int (highp int a, highp int b) { return a == b ? 1.0 : 0.0; }\n"; 826 case glu::TYPE_INT_VEC2: return "mediump float compare_ivec2 (highp ivec2 a, highp ivec2 b) { return a == b ? 1.0 : 0.0; }\n"; 827 case glu::TYPE_INT_VEC3: return "mediump float compare_ivec3 (highp ivec3 a, highp ivec3 b) { return a == b ? 1.0 : 0.0; }\n"; 828 case glu::TYPE_INT_VEC4: return "mediump float compare_ivec4 (highp ivec4 a, highp ivec4 b) { return a == b ? 1.0 : 0.0; }\n"; 829 case glu::TYPE_UINT: return "mediump float compare_uint (highp uint a, highp uint b) { return a == b ? 1.0 : 0.0; }\n"; 830 case glu::TYPE_UINT_VEC2: return "mediump float compare_uvec2 (highp uvec2 a, highp uvec2 b) { return a == b ? 1.0 : 0.0; }\n"; 831 case glu::TYPE_UINT_VEC3: return "mediump float compare_uvec3 (highp uvec3 a, highp uvec3 b) { return a == b ? 1.0 : 0.0; }\n"; 832 case glu::TYPE_UINT_VEC4: return "mediump float compare_uvec4 (highp uvec4 a, highp uvec4 b) { return a == b ? 1.0 : 0.0; }\n"; 833 case glu::TYPE_BOOL: return "mediump float compare_bool (bool a, bool b) { return a == b ? 1.0 : 0.0; }\n"; 834 case glu::TYPE_BOOL_VEC2: return "mediump float compare_bvec2 (bvec2 a, bvec2 b) { return a == b ? 1.0 : 0.0; }\n"; 835 case glu::TYPE_BOOL_VEC3: return "mediump float compare_bvec3 (bvec3 a, bvec3 b) { return a == b ? 1.0 : 0.0; }\n"; 836 case glu::TYPE_BOOL_VEC4: return "mediump float compare_bvec4 (bvec4 a, bvec4 b) { return a == b ? 1.0 : 0.0; }\n"; 837 case glu::TYPE_FLOAT16: return "mediump float compare_float16_t(highp float a, highp float b) { return abs(a - b) < 0.05 ? 1.0 : 0.0; }\n"; 838 case glu::TYPE_FLOAT16_VEC2: return "mediump float compare_f16vec2 (highp vec2 a, highp vec2 b) { return compare_float(a.x, b.x)*compare_float(a.y, b.y); }\n"; 839 case glu::TYPE_FLOAT16_VEC3: return "mediump float compare_f16vec3 (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"; 840 case glu::TYPE_FLOAT16_VEC4: return "mediump float compare_f16vec4 (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"; 841 case glu::TYPE_INT8: return "mediump float compare_int8_t (highp int a, highp int b) { return a == b ? 1.0 : 0.0; }\n"; 842 case glu::TYPE_INT8_VEC2: return "mediump float compare_i8vec2 (highp ivec2 a, highp ivec2 b) { return a == b ? 1.0 : 0.0; }\n"; 843 case glu::TYPE_INT8_VEC3: return "mediump float compare_i8vec3 (highp ivec3 a, highp ivec3 b) { return a == b ? 1.0 : 0.0; }\n"; 844 case glu::TYPE_INT8_VEC4: return "mediump float compare_i8vec4 (highp ivec4 a, highp ivec4 b) { return a == b ? 1.0 : 0.0; }\n"; 845 case glu::TYPE_UINT8: return "mediump float compare_uint8_t (highp uint a, highp uint b) { return a == b ? 1.0 : 0.0; }\n"; 846 case glu::TYPE_UINT8_VEC2: return "mediump float compare_u8vec2 (highp uvec2 a, highp uvec2 b) { return a == b ? 1.0 : 0.0; }\n"; 847 case glu::TYPE_UINT8_VEC3: return "mediump float compare_u8vec3 (highp uvec3 a, highp uvec3 b) { return a == b ? 1.0 : 0.0; }\n"; 848 case glu::TYPE_UINT8_VEC4: return "mediump float compare_u8vec4 (highp uvec4 a, highp uvec4 b) { return a == b ? 1.0 : 0.0; }\n"; 849 case glu::TYPE_INT16: return "mediump float compare_int16_t (highp int a, highp int b) { return a == b ? 1.0 : 0.0; }\n"; 850 case glu::TYPE_INT16_VEC2: return "mediump float compare_i16vec2 (highp ivec2 a, highp ivec2 b) { return a == b ? 1.0 : 0.0; }\n"; 851 case glu::TYPE_INT16_VEC3: return "mediump float compare_i16vec3 (highp ivec3 a, highp ivec3 b) { return a == b ? 1.0 : 0.0; }\n"; 852 case glu::TYPE_INT16_VEC4: return "mediump float compare_i16vec4 (highp ivec4 a, highp ivec4 b) { return a == b ? 1.0 : 0.0; }\n"; 853 case glu::TYPE_UINT16: return "mediump float compare_uint16_t (highp uint a, highp uint b) { return a == b ? 1.0 : 0.0; }\n"; 854 case glu::TYPE_UINT16_VEC2: return "mediump float compare_u16vec2 (highp uvec2 a, highp uvec2 b) { return a == b ? 1.0 : 0.0; }\n"; 855 case glu::TYPE_UINT16_VEC3: return "mediump float compare_u16vec3 (highp uvec3 a, highp uvec3 b) { return a == b ? 1.0 : 0.0; }\n"; 856 case glu::TYPE_UINT16_VEC4: return "mediump float compare_u16vec4 (highp uvec4 a, highp uvec4 b) { return a == b ? 1.0 : 0.0; }\n"; 857 default: 858 DE_ASSERT(false); 859 return DE_NULL; 860 } 861 } 862 863 void getCompareDependencies (std::set<glu::DataType>& compareFuncs, glu::DataType basicType) 864 { 865 switch (basicType) 866 { 867 case glu::TYPE_FLOAT_VEC2: 868 case glu::TYPE_FLOAT_VEC3: 869 case glu::TYPE_FLOAT_VEC4: 870 case glu::TYPE_FLOAT16_VEC2: 871 case glu::TYPE_FLOAT16_VEC3: 872 case glu::TYPE_FLOAT16_VEC4: 873 compareFuncs.insert(glu::TYPE_FLOAT); 874 compareFuncs.insert(basicType); 875 break; 876 877 case glu::TYPE_FLOAT_MAT2: 878 case glu::TYPE_FLOAT_MAT2X3: 879 case glu::TYPE_FLOAT_MAT2X4: 880 case glu::TYPE_FLOAT_MAT3X2: 881 case glu::TYPE_FLOAT_MAT3: 882 case glu::TYPE_FLOAT_MAT3X4: 883 case glu::TYPE_FLOAT_MAT4X2: 884 case glu::TYPE_FLOAT_MAT4X3: 885 case glu::TYPE_FLOAT_MAT4: 886 compareFuncs.insert(glu::TYPE_FLOAT); 887 compareFuncs.insert(glu::getDataTypeFloatVec(glu::getDataTypeMatrixNumRows(basicType))); 888 compareFuncs.insert(basicType); 889 break; 890 891 default: 892 compareFuncs.insert(basicType); 893 break; 894 } 895 } 896 897 void collectUniqueBasicTypes (std::set<glu::DataType>& basicTypes, const VarType& type) 898 { 899 if (type.isStructType()) 900 { 901 for (StructType::ConstIterator iter = type.getStruct().begin(); iter != type.getStruct().end(); ++iter) 902 collectUniqueBasicTypes(basicTypes, iter->getType()); 903 } 904 else if (type.isArrayType()) 905 collectUniqueBasicTypes(basicTypes, type.getElementType()); 906 else 907 { 908 DE_ASSERT(type.isBasicType()); 909 basicTypes.insert(type.getBasicType()); 910 } 911 } 912 913 void collectUniqueBasicTypes (std::set<glu::DataType>& basicTypes, const UniformBlock& uniformBlock) 914 { 915 for (UniformBlock::ConstIterator iter = uniformBlock.begin(); iter != uniformBlock.end(); ++iter) 916 collectUniqueBasicTypes(basicTypes, iter->getType()); 917 } 918 919 void collectUniqueBasicTypes (std::set<glu::DataType>& basicTypes, const ShaderInterface& interface) 920 { 921 for (int ndx = 0; ndx < interface.getNumUniformBlocks(); ++ndx) 922 collectUniqueBasicTypes(basicTypes, interface.getUniformBlock(ndx)); 923 } 924 925 void generateCompareFuncs (std::ostream& str, const ShaderInterface& interface) 926 { 927 std::set<glu::DataType> types; 928 std::set<glu::DataType> compareFuncs; 929 930 // Collect unique basic types 931 collectUniqueBasicTypes(types, interface); 932 933 // Set of compare functions required 934 for (std::set<glu::DataType>::const_iterator iter = types.begin(); iter != types.end(); ++iter) 935 { 936 getCompareDependencies(compareFuncs, *iter); 937 } 938 939 for (int type = 0; type < glu::TYPE_LAST; ++type) 940 { 941 if (compareFuncs.find(glu::DataType(type)) != compareFuncs.end()) 942 str << getCompareFuncForType(glu::DataType(type)); 943 } 944 } 945 946 bool uses16BitStorage (const ShaderInterface& interface) 947 { 948 // If any of blocks has LAYOUT_16BIT_STORAGE flag 949 for (int ndx = 0; ndx < interface.getNumUniformBlocks(); ++ndx) 950 { 951 if (interface.getUniformBlock(ndx).getFlags() & LAYOUT_16BIT_STORAGE) 952 return true; 953 } 954 return false; 955 } 956 957 bool uses8BitStorage (const ShaderInterface& interface) 958 { 959 // If any of blocks has LAYOUT_8BIT_STORAGE flag 960 for (int ndx = 0; ndx < interface.getNumUniformBlocks(); ++ndx) 961 { 962 if (interface.getUniformBlock(ndx).getFlags() & LAYOUT_8BIT_STORAGE) 963 return true; 964 } 965 return false; 966 } 967 968 bool usesScalarOrStd430Layout (const ShaderInterface& interface) 969 { 970 // If any of blocks has LAYOUT_SCALAR or LAYOUT_STD430 flags 971 for (int ndx = 0; ndx < interface.getNumUniformBlocks(); ++ndx) 972 { 973 if (interface.getUniformBlock(ndx).getFlags() & (LAYOUT_SCALAR | LAYOUT_STD430)) 974 return true; 975 } 976 return false; 977 } 978 979 struct Indent 980 { 981 int level; 982 Indent (int level_) : level(level_) {} 983 }; 984 985 std::ostream& operator<< (std::ostream& str, const Indent& indent) 986 { 987 for (int i = 0; i < indent.level; i++) 988 str << "\t"; 989 return str; 990 } 991 992 void generateDeclaration (std::ostringstream& src, const VarType& type, const std::string& name, int indentLevel, deUint32 unusedHints, deUint32 flagsMask, deUint32 offset); 993 void generateDeclaration (std::ostringstream& src, const Uniform& uniform, int indentLevel, deUint32 offset); 994 void generateDeclaration (std::ostringstream& src, const StructType& structType, int indentLevel); 995 996 void generateLocalDeclaration (std::ostringstream& src, const StructType& structType, int indentLevel); 997 void generateFullDeclaration (std::ostringstream& src, const StructType& structType, int indentLevel); 998 999 void generateDeclaration (std::ostringstream& src, const StructType& structType, int indentLevel) 1000 { 1001 DE_ASSERT(structType.hasTypeName()); 1002 generateFullDeclaration(src, structType, indentLevel); 1003 src << ";\n"; 1004 } 1005 1006 void generateFullDeclaration (std::ostringstream& src, const StructType& structType, int indentLevel) 1007 { 1008 src << "struct"; 1009 if (structType.hasTypeName()) 1010 src << " " << structType.getTypeName(); 1011 src << "\n" << Indent(indentLevel) << "{\n"; 1012 1013 for (StructType::ConstIterator memberIter = structType.begin(); memberIter != structType.end(); memberIter++) 1014 { 1015 src << Indent(indentLevel + 1); 1016 generateDeclaration(src, memberIter->getType(), memberIter->getName(), indentLevel + 1, memberIter->getFlags() & UNUSED_BOTH, ~LAYOUT_OFFSET, 0u); 1017 } 1018 1019 src << Indent(indentLevel) << "}"; 1020 } 1021 1022 void generateLocalDeclaration (std::ostringstream& src, const StructType& structType, int /* indentLevel */) 1023 { 1024 src << structType.getTypeName(); 1025 } 1026 1027 void generateLayoutAndPrecisionDeclaration (std::ostringstream& src, deUint32 flags, deUint32 offset) 1028 { 1029 if ((flags & LAYOUT_MASK) != 0) 1030 src << "layout(" << LayoutFlagsFmt(flags & LAYOUT_MASK, offset) << ") "; 1031 1032 if ((flags & PRECISION_MASK) != 0) 1033 src << PrecisionFlagsFmt(flags & PRECISION_MASK) << " "; 1034 } 1035 1036 void generateDeclaration (std::ostringstream& src, const VarType& type, const std::string& name, int indentLevel, deUint32 unusedHints, deUint32 flagsMask, deUint32 offset) 1037 { 1038 generateLayoutAndPrecisionDeclaration(src, type.getFlags() & flagsMask, offset); 1039 1040 if (type.isBasicType()) 1041 src << glu::getDataTypeName(type.getBasicType()) << " " << name; 1042 else if (type.isArrayType()) 1043 { 1044 std::vector<int> arraySizes; 1045 const VarType* curType = &type; 1046 while (curType->isArrayType()) 1047 { 1048 arraySizes.push_back(curType->getArraySize()); 1049 curType = &curType->getElementType(); 1050 } 1051 1052 generateLayoutAndPrecisionDeclaration(src, curType->getFlags() & flagsMask, offset); 1053 1054 if (curType->isBasicType()) 1055 src << glu::getDataTypeName(curType->getBasicType()); 1056 else 1057 { 1058 DE_ASSERT(curType->isStructType()); 1059 generateLocalDeclaration(src, curType->getStruct(), indentLevel+1); 1060 } 1061 1062 src << " " << name; 1063 1064 for (std::vector<int>::const_iterator sizeIter = arraySizes.begin(); sizeIter != arraySizes.end(); sizeIter++) 1065 src << "[" << *sizeIter << "]"; 1066 } 1067 else 1068 { 1069 generateLocalDeclaration(src, type.getStruct(), indentLevel+1); 1070 src << " " << name; 1071 } 1072 1073 src << ";"; 1074 1075 // Print out unused hints. 1076 if (unusedHints != 0) 1077 src << " // unused in " << (unusedHints == UNUSED_BOTH ? "both shaders" : 1078 unusedHints == UNUSED_VERTEX ? "vertex shader" : 1079 unusedHints == UNUSED_FRAGMENT ? "fragment shader" : "???"); 1080 1081 src << "\n"; 1082 } 1083 1084 void generateDeclaration (std::ostringstream& src, const Uniform& uniform, int indentLevel, deUint32 offset) 1085 { 1086 if ((uniform.getFlags() & LAYOUT_MASK) != 0) 1087 src << "layout(" << LayoutFlagsFmt(uniform.getFlags() & LAYOUT_MASK) << ") "; 1088 1089 generateDeclaration(src, uniform.getType(), uniform.getName(), indentLevel, uniform.getFlags() & UNUSED_BOTH, ~0u, offset); 1090 } 1091 1092 deUint32 getBlockMemberOffset (int blockNdx, const UniformBlock& block, const Uniform& uniform, const UniformLayout& layout) 1093 { 1094 std::ostringstream name; 1095 const VarType* curType = &uniform.getType(); 1096 1097 if (block.getInstanceName().length() != 0) 1098 name << block.getBlockName() << "."; // \note UniformLayoutEntry uses block name rather than instance name 1099 1100 name << uniform.getName(); 1101 1102 while (!curType->isBasicType()) 1103 { 1104 if (curType->isArrayType()) 1105 { 1106 name << "[0]"; 1107 curType = &curType->getElementType(); 1108 } 1109 1110 if (curType->isStructType()) 1111 { 1112 const StructType::ConstIterator firstMember = curType->getStruct().begin(); 1113 name << "." << firstMember->getName(); 1114 curType = &firstMember->getType(); 1115 } 1116 } 1117 1118 const int uniformNdx = layout.getUniformLayoutIndex(blockNdx, name.str()); 1119 DE_ASSERT(uniformNdx >= 0); 1120 1121 return layout.uniforms[uniformNdx].offset; 1122 } 1123 1124 template<typename T> 1125 void semiShuffle (std::vector<T>& v) 1126 { 1127 const std::vector<T> src = v; 1128 int i = -1; 1129 int n = static_cast<int>(src.size()); 1130 1131 v.clear(); 1132 1133 while (n) 1134 { 1135 i += n; 1136 v.push_back(src[i]); 1137 n = (n > 0 ? 1 - n : -1 - n); 1138 } 1139 } 1140 1141 template<typename T> 1142 //! \note Stores pointers to original elements 1143 class Traverser 1144 { 1145 public: 1146 template<typename Iter> 1147 Traverser (const Iter beg, const Iter end, const bool shuffled) 1148 { 1149 for (Iter it = beg; it != end; ++it) 1150 m_elements.push_back(&(*it)); 1151 1152 if (shuffled) 1153 semiShuffle(m_elements); 1154 1155 m_next = m_elements.begin(); 1156 } 1157 1158 T* next (void) 1159 { 1160 if (m_next != m_elements.end()) 1161 return *m_next++; 1162 else 1163 return DE_NULL; 1164 } 1165 1166 private: 1167 typename std::vector<T*> m_elements; 1168 typename std::vector<T*>::const_iterator m_next; 1169 }; 1170 1171 glu::DataType getPromoteType(glu::DataType type) 1172 { 1173 switch (type) 1174 { 1175 case glu::TYPE_UINT8: return glu::TYPE_UINT; 1176 case glu::TYPE_UINT8_VEC2: return glu::TYPE_UINT_VEC2; 1177 case glu::TYPE_UINT8_VEC3: return glu::TYPE_UINT_VEC3; 1178 case glu::TYPE_UINT8_VEC4: return glu::TYPE_UINT_VEC4; 1179 case glu::TYPE_INT8: return glu::TYPE_INT; 1180 case glu::TYPE_INT8_VEC2: return glu::TYPE_INT_VEC2; 1181 case glu::TYPE_INT8_VEC3: return glu::TYPE_INT_VEC3; 1182 case glu::TYPE_INT8_VEC4: return glu::TYPE_INT_VEC4; 1183 case glu::TYPE_UINT16: return glu::TYPE_UINT; 1184 case glu::TYPE_UINT16_VEC2: return glu::TYPE_UINT_VEC2; 1185 case glu::TYPE_UINT16_VEC3: return glu::TYPE_UINT_VEC3; 1186 case glu::TYPE_UINT16_VEC4: return glu::TYPE_UINT_VEC4; 1187 case glu::TYPE_INT16: return glu::TYPE_INT; 1188 case glu::TYPE_INT16_VEC2: return glu::TYPE_INT_VEC2; 1189 case glu::TYPE_INT16_VEC3: return glu::TYPE_INT_VEC3; 1190 case glu::TYPE_INT16_VEC4: return glu::TYPE_INT_VEC4; 1191 case glu::TYPE_FLOAT16: return glu::TYPE_FLOAT; 1192 case glu::TYPE_FLOAT16_VEC2: return glu::TYPE_FLOAT_VEC2; 1193 case glu::TYPE_FLOAT16_VEC3: return glu::TYPE_FLOAT_VEC3; 1194 case glu::TYPE_FLOAT16_VEC4: return glu::TYPE_FLOAT_VEC4; 1195 default: return type; 1196 } 1197 } 1198 1199 void generateDeclaration (std::ostringstream& src, int blockNdx, const UniformBlock& block, const UniformLayout& layout, bool shuffleUniformMembers) 1200 { 1201 src << "layout(set = 0, binding = " << blockNdx; 1202 if ((block.getFlags() & LAYOUT_MASK) != 0) 1203 src << ", " << LayoutFlagsFmt(block.getFlags() & LAYOUT_MASK); 1204 src << ") "; 1205 1206 src << "uniform " << block.getBlockName(); 1207 src << "\n{\n"; 1208 1209 Traverser<const Uniform> uniforms(block.begin(), block.end(), shuffleUniformMembers); 1210 1211 while (const Uniform* pUniform = uniforms.next()) 1212 { 1213 src << Indent(1); 1214 generateDeclaration(src, *pUniform, 1 /* indent level */, getBlockMemberOffset(blockNdx, block, *pUniform, layout)); 1215 } 1216 1217 src << "}"; 1218 1219 if (block.hasInstanceName()) 1220 { 1221 src << " " << block.getInstanceName(); 1222 if (block.isArray()) 1223 src << "[" << block.getArraySize() << "]"; 1224 } 1225 else 1226 DE_ASSERT(!block.isArray()); 1227 1228 src << ";\n"; 1229 } 1230 1231 void generateValueSrc (std::ostringstream& src, const UniformLayoutEntry& entry, const void* basePtr, int elementNdx) 1232 { 1233 glu::DataType scalarType = glu::getDataTypeScalarType(entry.type); 1234 int scalarSize = glu::getDataTypeScalarSize(entry.type); 1235 bool isArray = entry.size > 1; 1236 const deUint8* elemPtr = (const deUint8*)basePtr + entry.offset + (isArray ? elementNdx * entry.arrayStride : 0); 1237 const size_t compSize = getDataTypeByteSize(scalarType); 1238 1239 if (scalarSize > 1) 1240 src << glu::getDataTypeName(getPromoteType(entry.type)) << "("; 1241 1242 if (glu::isDataTypeMatrix(entry.type)) 1243 { 1244 int numRows = glu::getDataTypeMatrixNumRows(entry.type); 1245 int numCols = glu::getDataTypeMatrixNumColumns(entry.type); 1246 1247 DE_ASSERT(scalarType == glu::TYPE_FLOAT); 1248 1249 // Constructed in column-wise order. 1250 for (int colNdx = 0; colNdx < numCols; colNdx++) 1251 { 1252 for (int rowNdx = 0; rowNdx < numRows; rowNdx++) 1253 { 1254 const deUint8* compPtr = elemPtr + (entry.isRowMajor ? (rowNdx * entry.matrixStride + colNdx * compSize) 1255 : (colNdx * entry.matrixStride + rowNdx * compSize)); 1256 1257 if (colNdx > 0 || rowNdx > 0) 1258 src << ", "; 1259 1260 src << de::floatToString(*((const float*)compPtr), 1); 1261 } 1262 } 1263 } 1264 else 1265 { 1266 for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++) 1267 { 1268 const deUint8* compPtr = elemPtr + scalarNdx * compSize; 1269 1270 if (scalarNdx > 0) 1271 src << ", "; 1272 1273 switch (scalarType) 1274 { 1275 case glu::TYPE_FLOAT16: src << de::floatToString(deFloat16To32(*((const deFloat16*)compPtr)), 1); break; 1276 case glu::TYPE_FLOAT: src << de::floatToString(*((const float*)compPtr), 1); break; 1277 case glu::TYPE_INT8: src << (deUint32)*((const deInt8*)compPtr); break; 1278 case glu::TYPE_INT16: src << *((const deInt16*)compPtr); break; 1279 case glu::TYPE_INT: src << *((const int*)compPtr); break; 1280 case glu::TYPE_UINT8: src << (deUint32)*((const deUint8*)compPtr) << "u"; break; 1281 case glu::TYPE_UINT16: src << *((const deUint16*)compPtr) << "u"; break; 1282 case glu::TYPE_UINT: src << *((const deUint32*)compPtr) << "u"; break; 1283 case glu::TYPE_BOOL: src << (*((const deUint32*)compPtr) != 0u ? "true" : "false"); break; 1284 default: 1285 DE_ASSERT(false); 1286 } 1287 } 1288 } 1289 1290 if (scalarSize > 1) 1291 src << ")"; 1292 } 1293 1294 bool isMatrix (glu::DataType elementType) 1295 { 1296 return (elementType >= glu::TYPE_FLOAT_MAT2) && (elementType <= glu::TYPE_FLOAT_MAT4); 1297 } 1298 1299 void writeMatrixTypeSrc (int columnCount, 1300 int rowCount, 1301 std::string compare, 1302 std::string compareType, 1303 std::ostringstream& src, 1304 const std::string& srcName, 1305 const void* basePtr, 1306 const UniformLayoutEntry& entry, 1307 bool vector) 1308 { 1309 if (vector) // generateTestSrcMatrixPerVec 1310 { 1311 for (int colNdex = 0; colNdex < columnCount; colNdex++) 1312 { 1313 src << "\tresult *= " << compare + compareType << "(" << srcName << "[" << colNdex << "], "; 1314 1315 if (glu::isDataTypeMatrix(entry.type)) 1316 { 1317 int scalarSize = glu::getDataTypeScalarSize(entry.type); 1318 const deUint8* elemPtr = (const deUint8*)basePtr + entry.offset; 1319 const int compSize = sizeof(deUint32); 1320 1321 if (scalarSize > 1) 1322 src << compareType << "("; 1323 for (int rowNdex = 0; rowNdex < rowCount; rowNdex++) 1324 { 1325 const deUint8* compPtr = elemPtr + (entry.isRowMajor ? (rowNdex * entry.matrixStride + colNdex * compSize) 1326 : (colNdex * entry.matrixStride + rowNdex * compSize)); 1327 src << de::floatToString(*((const float*)compPtr), 1); 1328 1329 if (rowNdex < rowCount-1) 1330 src << ", "; 1331 } 1332 src << "));\n"; 1333 } 1334 else 1335 { 1336 generateValueSrc(src, entry, basePtr, 0); 1337 src << "[" << colNdex << "]);\n"; 1338 } 1339 } 1340 } 1341 else // generateTestSrcMatrixPerElement 1342 { 1343 for (int colNdex = 0; colNdex < columnCount; colNdex++) 1344 { 1345 for (int rowNdex = 0; rowNdex < rowCount; rowNdex++) 1346 { 1347 src << "\tresult *= " << compare + compareType << "(" << srcName << "[" << colNdex << "][" << rowNdex << "], "; 1348 if (glu::isDataTypeMatrix(entry.type)) 1349 { 1350 const deUint8* elemPtr = (const deUint8*)basePtr + entry.offset; 1351 const int compSize = sizeof(deUint32); 1352 const deUint8* compPtr = elemPtr + (entry.isRowMajor ? (rowNdex * entry.matrixStride + colNdex * compSize) 1353 : (colNdex * entry.matrixStride + rowNdex * compSize)); 1354 1355 src << de::floatToString(*((const float*)compPtr), 1) << ");\n"; 1356 } 1357 else 1358 { 1359 generateValueSrc(src, entry, basePtr, 0); 1360 src << "[" << colNdex << "][" << rowNdex << "]);\n"; 1361 } 1362 } 1363 } 1364 } 1365 } 1366 1367 void generateTestSrcMatrixPerVec (glu::DataType elementType, 1368 std::ostringstream& src, 1369 const std::string& srcName, 1370 const void* basePtr, 1371 const UniformLayoutEntry& entry, 1372 bool vector) 1373 { 1374 std::string compare = "compare_"; 1375 switch (elementType) 1376 { 1377 case glu::TYPE_FLOAT_MAT2: 1378 writeMatrixTypeSrc(2, 2, compare, "vec2", src, srcName, basePtr, entry, vector); 1379 break; 1380 1381 case glu::TYPE_FLOAT_MAT2X3: 1382 writeMatrixTypeSrc(2, 3, compare, "vec3", src, srcName, basePtr, entry, vector); 1383 break; 1384 1385 case glu::TYPE_FLOAT_MAT2X4: 1386 writeMatrixTypeSrc(2, 4, compare, "vec4", src, srcName, basePtr, entry, vector); 1387 break; 1388 1389 case glu::TYPE_FLOAT_MAT3X4: 1390 writeMatrixTypeSrc(3, 4, compare, "vec4", src, srcName, basePtr, entry, vector); 1391 break; 1392 1393 case glu::TYPE_FLOAT_MAT4: 1394 writeMatrixTypeSrc(4, 4, compare, "vec4", src, srcName, basePtr, entry, vector); 1395 break; 1396 1397 case glu::TYPE_FLOAT_MAT4X2: 1398 writeMatrixTypeSrc(4, 2, compare, "vec2", src, srcName, basePtr, entry, vector); 1399 break; 1400 1401 case glu::TYPE_FLOAT_MAT4X3: 1402 writeMatrixTypeSrc(4, 3, compare, "vec3", src, srcName, basePtr, entry, vector); 1403 break; 1404 1405 default: 1406 break; 1407 } 1408 } 1409 1410 void generateTestSrcMatrixPerElement (glu::DataType elementType, 1411 std::ostringstream& src, 1412 const std::string& srcName, 1413 const void* basePtr, 1414 const UniformLayoutEntry& entry, 1415 bool vector) 1416 { 1417 std::string compare = "compare_"; 1418 std::string compareType = "float"; 1419 switch (elementType) 1420 { 1421 case glu::TYPE_FLOAT_MAT2: 1422 writeMatrixTypeSrc(2, 2, compare, compareType, src, srcName, basePtr, entry, vector); 1423 break; 1424 1425 case glu::TYPE_FLOAT_MAT2X3: 1426 writeMatrixTypeSrc(2, 3, compare, compareType, src, srcName, basePtr, entry, vector); 1427 break; 1428 1429 case glu::TYPE_FLOAT_MAT2X4: 1430 writeMatrixTypeSrc(2, 4, compare, compareType, src, srcName, basePtr, entry, vector); 1431 break; 1432 1433 case glu::TYPE_FLOAT_MAT3X4: 1434 writeMatrixTypeSrc(3, 4, compare, compareType, src, srcName, basePtr, entry, vector); 1435 break; 1436 1437 case glu::TYPE_FLOAT_MAT4: 1438 writeMatrixTypeSrc(4, 4, compare, compareType, src, srcName, basePtr, entry, vector); 1439 break; 1440 1441 case glu::TYPE_FLOAT_MAT4X2: 1442 writeMatrixTypeSrc(4, 2, compare, compareType, src, srcName, basePtr, entry, vector); 1443 break; 1444 1445 case glu::TYPE_FLOAT_MAT4X3: 1446 writeMatrixTypeSrc(4, 3, compare, compareType, src, srcName, basePtr, entry, vector); 1447 break; 1448 1449 default: 1450 break; 1451 } 1452 } 1453 1454 void generateSingleCompare (std::ostringstream& src, 1455 glu::DataType elementType, 1456 const std::string& srcName, 1457 const void* basePtr, 1458 const UniformLayoutEntry& entry, 1459 MatrixLoadFlags matrixLoadFlag) 1460 { 1461 if (matrixLoadFlag == LOAD_FULL_MATRIX) 1462 { 1463 const char* typeName = glu::getDataTypeName(elementType); 1464 const char* castName = ""; 1465 glu::DataType promoteType = getPromoteType(elementType); 1466 if (elementType != promoteType) 1467 { 1468 castName = glu::getDataTypeName(promoteType); 1469 } 1470 1471 src << "\tresult *= compare_" << typeName << "(" << castName << "(" << srcName << "), "; 1472 generateValueSrc(src, entry, basePtr, 0); 1473 src << ");\n"; 1474 } 1475 else 1476 { 1477 if (isMatrix(elementType)) 1478 { 1479 generateTestSrcMatrixPerVec (elementType, src, srcName, basePtr, entry, true); 1480 generateTestSrcMatrixPerElement (elementType, src, srcName, basePtr, entry, false); 1481 } 1482 } 1483 } 1484 1485 void generateCompareSrc (std::ostringstream& src, 1486 const char* resultVar, 1487 const VarType& type, 1488 const std::string& srcName, 1489 const std::string& apiName, 1490 const UniformLayout& layout, 1491 int blockNdx, 1492 const void* basePtr, 1493 deUint32 unusedMask, 1494 MatrixLoadFlags matrixLoadFlag) 1495 { 1496 if (type.isBasicType() || (type.isArrayType() && type.getElementType().isBasicType())) 1497 { 1498 // Basic type or array of basic types. 1499 bool isArray = type.isArrayType(); 1500 glu::DataType elementType = isArray ? type.getElementType().getBasicType() : type.getBasicType(); 1501 const char* typeName = glu::getDataTypeName(elementType); 1502 std::string fullApiName = std::string(apiName) + (isArray ? "[0]" : ""); // Arrays are always postfixed with [0] 1503 int uniformNdx = layout.getUniformLayoutIndex(blockNdx, fullApiName); 1504 const UniformLayoutEntry& entry = layout.uniforms[uniformNdx]; 1505 1506 const char* castName = ""; 1507 glu::DataType promoteType = getPromoteType(elementType); 1508 if (elementType != promoteType) 1509 { 1510 castName = glu::getDataTypeName(promoteType); 1511 } 1512 1513 if (isArray) 1514 { 1515 for (int elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++) 1516 { 1517 src << "\tresult *= compare_" << typeName << "(" << castName << "(" << srcName << "[" << elemNdx << "]), "; 1518 generateValueSrc(src, entry, basePtr, elemNdx); 1519 src << ");\n"; 1520 } 1521 } 1522 else 1523 { 1524 generateSingleCompare(src, elementType, srcName, basePtr, entry, matrixLoadFlag); 1525 } 1526 } 1527 else if (type.isArrayType()) 1528 { 1529 const VarType& elementType = type.getElementType(); 1530 1531 for (int elementNdx = 0; elementNdx < type.getArraySize(); elementNdx++) 1532 { 1533 std::string op = std::string("[") + de::toString(elementNdx) + "]"; 1534 std::string elementSrcName = std::string(srcName) + op; 1535 std::string elementApiName = std::string(apiName) + op; 1536 generateCompareSrc(src, resultVar, elementType, elementSrcName, elementApiName, layout, blockNdx, basePtr, unusedMask, LOAD_FULL_MATRIX); 1537 } 1538 } 1539 else 1540 { 1541 DE_ASSERT(type.isStructType()); 1542 1543 for (StructType::ConstIterator memberIter = type.getStruct().begin(); memberIter != type.getStruct().end(); memberIter++) 1544 { 1545 if (memberIter->getFlags() & unusedMask) 1546 continue; // Skip member. 1547 1548 std::string op = std::string(".") + memberIter->getName(); 1549 std::string memberSrcName = std::string(srcName) + op; 1550 std::string memberApiName = std::string(apiName) + op; 1551 generateCompareSrc(src, resultVar, memberIter->getType(), memberSrcName, memberApiName, layout, blockNdx, basePtr, unusedMask, LOAD_FULL_MATRIX); 1552 } 1553 } 1554 } 1555 1556 void generateCompareSrc (std::ostringstream& src, 1557 const char* resultVar, 1558 const ShaderInterface& interface, 1559 const UniformLayout& layout, 1560 const std::map<int, 1561 void*>& blockPointers, 1562 bool isVertex, 1563 MatrixLoadFlags matrixLoadFlag) 1564 { 1565 deUint32 unusedMask = isVertex ? UNUSED_VERTEX : UNUSED_FRAGMENT; 1566 1567 for (int blockNdx = 0; blockNdx < interface.getNumUniformBlocks(); blockNdx++) 1568 { 1569 const UniformBlock& block = interface.getUniformBlock(blockNdx); 1570 1571 if ((block.getFlags() & (isVertex ? DECLARE_VERTEX : DECLARE_FRAGMENT)) == 0) 1572 continue; // Skip. 1573 1574 bool hasInstanceName = block.hasInstanceName(); 1575 bool isArray = block.isArray(); 1576 int numInstances = isArray ? block.getArraySize() : 1; 1577 std::string apiPrefix = hasInstanceName ? block.getBlockName() + "." : std::string(""); 1578 1579 DE_ASSERT(!isArray || hasInstanceName); 1580 1581 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++) 1582 { 1583 std::string instancePostfix = isArray ? std::string("[") + de::toString(instanceNdx) + "]" : std::string(""); 1584 std::string blockInstanceName = block.getBlockName() + instancePostfix; 1585 std::string srcPrefix = hasInstanceName ? block.getInstanceName() + instancePostfix + "." : std::string(""); 1586 int blockLayoutNdx = layout.getBlockLayoutIndex(blockNdx, instanceNdx); 1587 void* basePtr = blockPointers.find(blockLayoutNdx)->second; 1588 1589 for (UniformBlock::ConstIterator uniformIter = block.begin(); uniformIter != block.end(); uniformIter++) 1590 { 1591 const Uniform& uniform = *uniformIter; 1592 1593 if (uniform.getFlags() & unusedMask) 1594 continue; // Don't read from that uniform. 1595 1596 std::string srcName = srcPrefix + uniform.getName(); 1597 std::string apiName = apiPrefix + uniform.getName(); 1598 generateCompareSrc(src, resultVar, uniform.getType(), srcName, apiName, layout, blockNdx, basePtr, unusedMask, matrixLoadFlag); 1599 } 1600 } 1601 } 1602 } 1603 1604 std::string generateVertexShader (const ShaderInterface& interface, const UniformLayout& layout, const std::map<int, void*>& blockPointers, MatrixLoadFlags matrixLoadFlag, bool shuffleUniformMembers) 1605 { 1606 std::ostringstream src; 1607 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"; 1608 src << "#extension GL_EXT_shader_16bit_storage : enable\n"; 1609 src << "#extension GL_EXT_shader_8bit_storage : enable\n"; 1610 src << "#extension GL_EXT_scalar_block_layout : enable\n"; 1611 1612 src << "layout(location = 0) in highp vec4 a_position;\n"; 1613 src << "layout(location = 0) out mediump float v_vtxResult;\n"; 1614 src << "\n"; 1615 1616 std::vector<const StructType*> namedStructs; 1617 interface.getNamedStructs(namedStructs); 1618 for (std::vector<const StructType*>::const_iterator structIter = namedStructs.begin(); structIter != namedStructs.end(); structIter++) 1619 generateDeclaration(src, **structIter, 0); 1620 1621 for (int blockNdx = 0; blockNdx < interface.getNumUniformBlocks(); blockNdx++) 1622 { 1623 const UniformBlock& block = interface.getUniformBlock(blockNdx); 1624 if (block.getFlags() & DECLARE_VERTEX) 1625 generateDeclaration(src, blockNdx, block, layout, shuffleUniformMembers); 1626 } 1627 1628 // Comparison utilities. 1629 src << "\n"; 1630 generateCompareFuncs(src, interface); 1631 1632 src << "\n" 1633 "void main (void)\n" 1634 "{\n" 1635 " gl_Position = a_position;\n" 1636 " mediump float result = 1.0;\n"; 1637 1638 // Value compare. 1639 generateCompareSrc(src, "result", interface, layout, blockPointers, true, matrixLoadFlag); 1640 1641 src << " v_vtxResult = result;\n" 1642 "}\n"; 1643 1644 return src.str(); 1645 } 1646 1647 std::string generateFragmentShader (const ShaderInterface& interface, const UniformLayout& layout, const std::map<int, void*>& blockPointers, MatrixLoadFlags matrixLoadFlag, bool shuffleUniformMembers) 1648 { 1649 std::ostringstream src; 1650 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"; 1651 src << "#extension GL_EXT_shader_16bit_storage : enable\n"; 1652 src << "#extension GL_EXT_shader_8bit_storage : enable\n"; 1653 src << "#extension GL_EXT_scalar_block_layout : enable\n"; 1654 1655 src << "layout(location = 0) in mediump float v_vtxResult;\n"; 1656 src << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n"; 1657 src << "\n"; 1658 1659 std::vector<const StructType*> namedStructs; 1660 interface.getNamedStructs(namedStructs); 1661 for (std::vector<const StructType*>::const_iterator structIter = namedStructs.begin(); structIter != namedStructs.end(); structIter++) 1662 generateDeclaration(src, **structIter, 0); 1663 1664 for (int blockNdx = 0; blockNdx < interface.getNumUniformBlocks(); blockNdx++) 1665 { 1666 const UniformBlock& block = interface.getUniformBlock(blockNdx); 1667 if (block.getFlags() & DECLARE_FRAGMENT) 1668 generateDeclaration(src, blockNdx, block, layout, shuffleUniformMembers); 1669 } 1670 1671 // Comparison utilities. 1672 src << "\n"; 1673 generateCompareFuncs(src, interface); 1674 1675 src << "\n" 1676 "void main (void)\n" 1677 "{\n" 1678 " mediump float result = 1.0;\n"; 1679 1680 // Value compare. 1681 generateCompareSrc(src, "result", interface, layout, blockPointers, false, matrixLoadFlag); 1682 1683 src << " dEQP_FragColor = vec4(1.0, v_vtxResult, result, 1.0);\n" 1684 "}\n"; 1685 1686 return src.str(); 1687 } 1688 1689 Move<VkBuffer> createBuffer (Context& context, VkDeviceSize bufferSize, vk::VkBufferUsageFlags usageFlags) 1690 { 1691 const VkDevice vkDevice = context.getDevice(); 1692 const DeviceInterface& vk = context.getDeviceInterface(); 1693 const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); 1694 1695 const VkBufferCreateInfo bufferInfo = 1696 { 1697 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType; 1698 DE_NULL, // const void* pNext; 1699 0u, // VkBufferCreateFlags flags; 1700 bufferSize, // VkDeviceSize size; 1701 usageFlags, // VkBufferUsageFlags usage; 1702 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; 1703 1u, // deUint32 queueFamilyIndexCount; 1704 &queueFamilyIndex // const deUint32* pQueueFamilyIndices; 1705 }; 1706 1707 return vk::createBuffer(vk, vkDevice, &bufferInfo); 1708 } 1709 1710 Move<vk::VkImage> createImage2D (Context& context, deUint32 width, deUint32 height, vk::VkFormat format, vk::VkImageTiling tiling, vk::VkImageUsageFlags usageFlags) 1711 { 1712 const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); 1713 const vk::VkImageCreateInfo params = 1714 { 1715 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType 1716 DE_NULL, // const void* pNext 1717 0u, // VkImageCreateFlags flags 1718 vk::VK_IMAGE_TYPE_2D, // VkImageType imageType 1719 format, // VkFormat format 1720 { width, height, 1u }, // VkExtent3D extent 1721 1u, // deUint32 mipLevels 1722 1u, // deUint32 arrayLayers 1723 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples 1724 tiling, // VkImageTiling tiling 1725 usageFlags, // VkImageUsageFlags usage 1726 vk::VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode 1727 1u, // deUint32 queueFamilyIndexCount 1728 &queueFamilyIndex, // const deUint32* pQueueFamilyIndices 1729 vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout 1730 }; 1731 1732 return vk::createImage(context.getDeviceInterface(), context.getDevice(), ¶ms); 1733 } 1734 1735 de::MovePtr<vk::Allocation> allocateAndBindMemory (Context& context, vk::VkBuffer buffer, vk::MemoryRequirement memReqs) 1736 { 1737 const vk::DeviceInterface& vkd = context.getDeviceInterface(); 1738 const vk::VkMemoryRequirements bufReqs = vk::getBufferMemoryRequirements(vkd, context.getDevice(), buffer); 1739 de::MovePtr<vk::Allocation> memory = context.getDefaultAllocator().allocate(bufReqs, memReqs); 1740 1741 vkd.bindBufferMemory(context.getDevice(), buffer, memory->getMemory(), memory->getOffset()); 1742 1743 return memory; 1744 } 1745 1746 de::MovePtr<vk::Allocation> allocateAndBindMemory (Context& context, vk::VkImage image, vk::MemoryRequirement memReqs) 1747 { 1748 const vk::DeviceInterface& vkd = context.getDeviceInterface(); 1749 const vk::VkMemoryRequirements imgReqs = vk::getImageMemoryRequirements(vkd, context.getDevice(), image); 1750 de::MovePtr<vk::Allocation> memory = context.getDefaultAllocator().allocate(imgReqs, memReqs); 1751 1752 vkd.bindImageMemory(context.getDevice(), image, memory->getMemory(), memory->getOffset()); 1753 1754 return memory; 1755 } 1756 1757 Move<vk::VkImageView> createAttachmentView (Context& context, vk::VkImage image, vk::VkFormat format) 1758 { 1759 const vk::VkImageViewCreateInfo params = 1760 { 1761 vk::VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // sType 1762 DE_NULL, // pNext 1763 0u, // flags 1764 image, // image 1765 vk::VK_IMAGE_VIEW_TYPE_2D, // viewType 1766 format, // format 1767 vk::makeComponentMappingRGBA(), // components 1768 { vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u,1u }, // subresourceRange 1769 }; 1770 1771 return vk::createImageView(context.getDeviceInterface(), context.getDevice(), ¶ms); 1772 } 1773 1774 Move<vk::VkPipelineLayout> createPipelineLayout (Context& context, vk::VkDescriptorSetLayout descriptorSetLayout) 1775 { 1776 const vk::VkPipelineLayoutCreateInfo params = 1777 { 1778 vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // sType 1779 DE_NULL, // pNext 1780 0u, // flags 1781 1u, // setLayoutCount 1782 &descriptorSetLayout, // pSetLayouts 1783 0u, // pushConstantRangeCount 1784 DE_NULL, // pPushConstantRanges 1785 }; 1786 1787 return vk::createPipelineLayout(context.getDeviceInterface(), context.getDevice(), ¶ms); 1788 } 1789 1790 Move<vk::VkCommandPool> createCmdPool (Context& context) 1791 { 1792 const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); 1793 1794 return vk::createCommandPool(context.getDeviceInterface(), context.getDevice(), vk::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex); 1795 } 1796 1797 Move<vk::VkCommandBuffer> createCmdBuffer (Context& context, vk::VkCommandPool cmdPool) 1798 { 1799 return vk::allocateCommandBuffer(context.getDeviceInterface(), context.getDevice(), cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY); 1800 } 1801 1802 // UniformBlockCaseInstance 1803 1804 class UniformBlockCaseInstance : public vkt::TestInstance 1805 { 1806 public: 1807 UniformBlockCaseInstance (Context& context, 1808 UniformBlockCase::BufferMode bufferMode, 1809 const UniformLayout& layout, 1810 const std::map<int, void*>& blockPointers); 1811 virtual ~UniformBlockCaseInstance (void); 1812 virtual tcu::TestStatus iterate (void); 1813 1814 private: 1815 enum 1816 { 1817 RENDER_WIDTH = 100, 1818 RENDER_HEIGHT = 100, 1819 }; 1820 1821 vk::Move<VkRenderPass> createRenderPass (vk::VkFormat format) const; 1822 vk::Move<VkFramebuffer> createFramebuffer (vk::VkRenderPass renderPass, vk::VkImageView colorImageView) const; 1823 vk::Move<VkDescriptorSetLayout> createDescriptorSetLayout (void) const; 1824 vk::Move<VkDescriptorPool> createDescriptorPool (void) const; 1825 vk::Move<VkPipeline> createPipeline (vk::VkShaderModule vtxShaderModule, vk::VkShaderModule fragShaderModule, vk::VkPipelineLayout pipelineLayout, vk::VkRenderPass renderPass) const; 1826 1827 vk::VkDescriptorBufferInfo addUniformData (deUint32 size, const void* dataPtr); 1828 1829 UniformBlockCase::BufferMode m_bufferMode; 1830 const UniformLayout& m_layout; 1831 const std::map<int, void*>& m_blockPointers; 1832 1833 typedef de::SharedPtr<vk::Unique<vk::VkBuffer> > VkBufferSp; 1834 typedef de::SharedPtr<vk::Allocation> AllocationSp; 1835 1836 std::vector<VkBufferSp> m_uniformBuffers; 1837 std::vector<AllocationSp> m_uniformAllocs; 1838 }; 1839 1840 UniformBlockCaseInstance::UniformBlockCaseInstance (Context& ctx, 1841 UniformBlockCase::BufferMode bufferMode, 1842 const UniformLayout& layout, 1843 const std::map<int, void*>& blockPointers) 1844 : vkt::TestInstance (ctx) 1845 , m_bufferMode (bufferMode) 1846 , m_layout (layout) 1847 , m_blockPointers (blockPointers) 1848 { 1849 } 1850 1851 UniformBlockCaseInstance::~UniformBlockCaseInstance (void) 1852 { 1853 } 1854 1855 tcu::TestStatus UniformBlockCaseInstance::iterate (void) 1856 { 1857 const vk::DeviceInterface& vk = m_context.getDeviceInterface(); 1858 const vk::VkDevice device = m_context.getDevice(); 1859 const vk::VkQueue queue = m_context.getUniversalQueue(); 1860 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); 1861 1862 const float positions[] = 1863 { 1864 -1.0f, -1.0f, 0.0f, 1.0f, 1865 -1.0f, +1.0f, 0.0f, 1.0f, 1866 +1.0f, -1.0f, 0.0f, 1.0f, 1867 +1.0f, +1.0f, 0.0f, 1.0f 1868 }; 1869 1870 const deUint32 indices[] = { 0, 1, 2, 2, 1, 3 }; 1871 1872 vk::Unique<VkBuffer> positionsBuffer (createBuffer(m_context, sizeof(positions), vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)); 1873 de::UniquePtr<Allocation> positionsAlloc (allocateAndBindMemory(m_context, *positionsBuffer, MemoryRequirement::HostVisible)); 1874 vk::Unique<VkBuffer> indicesBuffer (createBuffer(m_context, sizeof(indices), vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT|vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)); 1875 de::UniquePtr<Allocation> indicesAlloc (allocateAndBindMemory(m_context, *indicesBuffer, MemoryRequirement::HostVisible)); 1876 1877 int minUniformBufferOffsetAlignment = getminUniformBufferOffsetAlignment(m_context); 1878 1879 // Upload attrbiutes data 1880 { 1881 deMemcpy(positionsAlloc->getHostPtr(), positions, sizeof(positions)); 1882 flushAlloc(vk, device, *positionsAlloc); 1883 1884 deMemcpy(indicesAlloc->getHostPtr(), indices, sizeof(indices)); 1885 flushAlloc(vk, device, *indicesAlloc); 1886 } 1887 1888 vk::Unique<VkImage> colorImage (createImage2D(m_context, 1889 RENDER_WIDTH, 1890 RENDER_HEIGHT, 1891 vk::VK_FORMAT_R8G8B8A8_UNORM, 1892 vk::VK_IMAGE_TILING_OPTIMAL, 1893 vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT|vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT)); 1894 de::UniquePtr<Allocation> colorImageAlloc (allocateAndBindMemory(m_context, *colorImage, MemoryRequirement::Any)); 1895 vk::Unique<VkImageView> colorImageView (createAttachmentView(m_context, *colorImage, vk::VK_FORMAT_R8G8B8A8_UNORM)); 1896 1897 vk::Unique<VkDescriptorSetLayout> descriptorSetLayout (createDescriptorSetLayout()); 1898 vk::Unique<VkDescriptorPool> descriptorPool (createDescriptorPool()); 1899 1900 const VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = 1901 { 1902 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType; 1903 DE_NULL, // const void* pNext; 1904 *descriptorPool, // VkDescriptorPool descriptorPool; 1905 1u, // deUint32 setLayoutCount; 1906 &descriptorSetLayout.get() // const VkDescriptorSetLayout* pSetLayouts; 1907 }; 1908 1909 vk::Unique<VkDescriptorSet> descriptorSet(vk::allocateDescriptorSet(vk, device, &descriptorSetAllocateInfo)); 1910 int numBlocks = (int)m_layout.blocks.size(); 1911 std::vector<vk::VkDescriptorBufferInfo> descriptors(numBlocks); 1912 1913 // Upload uniform data 1914 { 1915 vk::DescriptorSetUpdateBuilder descriptorSetUpdateBuilder; 1916 1917 if (m_bufferMode == UniformBlockCase::BUFFERMODE_PER_BLOCK) 1918 { 1919 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 1920 { 1921 const BlockLayoutEntry& block = m_layout.blocks[blockNdx]; 1922 const void* srcPtr = m_blockPointers.find(blockNdx)->second; 1923 1924 descriptors[blockNdx] = addUniformData(block.size, srcPtr); 1925 descriptorSetUpdateBuilder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::bindingArrayElement(block.bindingNdx, block.instanceNdx), 1926 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descriptors[blockNdx]); 1927 } 1928 } 1929 else 1930 { 1931 int currentOffset = 0; 1932 std::map<int, int> offsets; 1933 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 1934 { 1935 if (minUniformBufferOffsetAlignment > 0) 1936 currentOffset = deAlign32(currentOffset, minUniformBufferOffsetAlignment); 1937 offsets[blockNdx] = currentOffset; 1938 currentOffset += m_layout.blocks[blockNdx].size; 1939 } 1940 1941 deUint32 totalSize = currentOffset; 1942 1943 // Make a copy of the data that satisfies the device's min uniform buffer alignment 1944 std::vector<deUint8> data; 1945 data.resize(totalSize); 1946 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 1947 { 1948 deMemcpy(&data[offsets[blockNdx]], m_blockPointers.find(blockNdx)->second, m_layout.blocks[blockNdx].size); 1949 } 1950 1951 vk::VkBuffer buffer = addUniformData(totalSize, &data[0]).buffer; 1952 1953 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 1954 { 1955 const BlockLayoutEntry& block = m_layout.blocks[blockNdx]; 1956 deUint32 size = block.size; 1957 1958 const VkDescriptorBufferInfo descriptor = 1959 { 1960 buffer, // VkBuffer buffer; 1961 (deUint32)offsets[blockNdx], // VkDeviceSize offset; 1962 size, // VkDeviceSize range; 1963 }; 1964 1965 descriptors[blockNdx] = descriptor; 1966 descriptorSetUpdateBuilder.writeSingle(*descriptorSet, 1967 vk::DescriptorSetUpdateBuilder::Location::bindingArrayElement(block.bindingNdx, block.instanceNdx), 1968 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1969 &descriptors[blockNdx]); 1970 } 1971 } 1972 1973 descriptorSetUpdateBuilder.update(vk, device); 1974 } 1975 1976 vk::Unique<VkRenderPass> renderPass (createRenderPass(vk::VK_FORMAT_R8G8B8A8_UNORM)); 1977 vk::Unique<VkFramebuffer> framebuffer (createFramebuffer(*renderPass, *colorImageView)); 1978 vk::Unique<VkPipelineLayout> pipelineLayout (createPipelineLayout(m_context, *descriptorSetLayout)); 1979 1980 vk::Unique<VkShaderModule> vtxShaderModule (vk::createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0)); 1981 vk::Unique<VkShaderModule> fragShaderModule (vk::createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0)); 1982 vk::Unique<VkPipeline> pipeline (createPipeline(*vtxShaderModule, *fragShaderModule, *pipelineLayout, *renderPass)); 1983 vk::Unique<VkCommandPool> cmdPool (createCmdPool(m_context)); 1984 vk::Unique<VkCommandBuffer> cmdBuffer (createCmdBuffer(m_context, *cmdPool)); 1985 vk::Unique<VkBuffer> readImageBuffer (createBuffer(m_context, (vk::VkDeviceSize)(RENDER_WIDTH * RENDER_HEIGHT * 4), vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT)); 1986 de::UniquePtr<Allocation> readImageAlloc (allocateAndBindMemory(m_context, *readImageBuffer, vk::MemoryRequirement::HostVisible)); 1987 1988 // Record command buffer 1989 const vk::VkCommandBufferBeginInfo beginInfo = 1990 { 1991 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType; 1992 DE_NULL, // const void* pNext; 1993 0u, // VkCommandBufferUsageFlags flags; 1994 (const vk::VkCommandBufferInheritanceInfo*)DE_NULL, 1995 }; 1996 VK_CHECK(vk.beginCommandBuffer(*cmdBuffer, &beginInfo)); 1997 1998 // Add barrier for initializing image state 1999 { 2000 const vk::VkImageMemoryBarrier initializeBarrier = 2001 { 2002 vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType; 2003 DE_NULL, // const void* pNext 2004 0, // VVkAccessFlags srcAccessMask; 2005 vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags dstAccessMask; 2006 vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout; 2007 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout newLayout; 2008 queueFamilyIndex, // deUint32 srcQueueFamilyIndex; 2009 queueFamilyIndex, // deUint32 dstQueueFamilyIndex; 2010 *colorImage, // VkImage image; 2011 { 2012 vk::VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask; 2013 0u, // deUint32 baseMipLevel; 2014 1u, // deUint32 mipLevels; 2015 0u, // deUint32 baseArraySlice; 2016 1u, // deUint32 arraySize; 2017 } // VkImageSubresourceRange subresourceRange 2018 }; 2019 2020 vk.cmdPipelineBarrier(*cmdBuffer, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, vk::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, (vk::VkDependencyFlags)0, 2021 0, (const vk::VkMemoryBarrier*)DE_NULL, 2022 0, (const vk::VkBufferMemoryBarrier*)DE_NULL, 2023 1, &initializeBarrier); 2024 } 2025 2026 beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(0, 0, RENDER_WIDTH, RENDER_HEIGHT), tcu::Vec4(0.125f, 0.25f, 0.75f, 1.0f)); 2027 2028 vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline); 2029 vk.cmdBindDescriptorSets(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u, DE_NULL); 2030 2031 const vk::VkDeviceSize offsets[] = { 0u }; 2032 vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &*positionsBuffer, offsets); 2033 vk.cmdBindIndexBuffer(*cmdBuffer, *indicesBuffer, (vk::VkDeviceSize)0, vk::VK_INDEX_TYPE_UINT32); 2034 2035 vk.cmdDrawIndexed(*cmdBuffer, DE_LENGTH_OF_ARRAY(indices), 1u, 0u, 0u, 0u); 2036 endRenderPass(vk, *cmdBuffer); 2037 2038 copyImageToBuffer(vk, *cmdBuffer, *colorImage, *readImageBuffer, tcu::IVec2(RENDER_WIDTH, RENDER_HEIGHT)); 2039 2040 endCommandBuffer(vk, *cmdBuffer); 2041 2042 // Submit the command buffer 2043 submitCommandsAndWait(vk, device, queue, cmdBuffer.get()); 2044 2045 // Read back the results 2046 tcu::Surface surface(RENDER_WIDTH, RENDER_HEIGHT); 2047 { 2048 const tcu::TextureFormat textureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8); 2049 const tcu::ConstPixelBufferAccess imgAccess(textureFormat, RENDER_WIDTH, RENDER_HEIGHT, 1, readImageAlloc->getHostPtr()); 2050 invalidateAlloc(vk, device, *readImageAlloc); 2051 2052 tcu::copy(surface.getAccess(), imgAccess); 2053 } 2054 2055 // Check if the result image is all white 2056 tcu::RGBA white(tcu::RGBA::white()); 2057 int numFailedPixels = 0; 2058 2059 for (int y = 0; y < surface.getHeight(); y++) 2060 { 2061 for (int x = 0; x < surface.getWidth(); x++) 2062 { 2063 if (surface.getPixel(x, y) != white) 2064 numFailedPixels += 1; 2065 } 2066 } 2067 2068 if (numFailedPixels > 0) 2069 { 2070 tcu::TestLog& log = m_context.getTestContext().getLog(); 2071 log << tcu::TestLog::Image("Image", "Rendered image", surface); 2072 log << tcu::TestLog::Message << "Image comparison failed, got " << numFailedPixels << " non-white pixels" << tcu::TestLog::EndMessage; 2073 2074 for (size_t blockNdx = 0; blockNdx < m_layout.blocks.size(); blockNdx++) 2075 { 2076 const BlockLayoutEntry& block = m_layout.blocks[blockNdx]; 2077 log << tcu::TestLog::Message << "Block index: " << blockNdx << " infos: " << block << tcu::TestLog::EndMessage; 2078 } 2079 2080 for (size_t uniformNdx = 0; uniformNdx < m_layout.uniforms.size(); uniformNdx++) 2081 { 2082 log << tcu::TestLog::Message << "Uniform index: " << uniformNdx << " infos: " << m_layout.uniforms[uniformNdx] << tcu::TestLog::EndMessage; 2083 } 2084 2085 return tcu::TestStatus::fail("Detected non-white pixels"); 2086 } 2087 else 2088 return tcu::TestStatus::pass("Full white image ok"); 2089 } 2090 2091 vk::VkDescriptorBufferInfo UniformBlockCaseInstance::addUniformData (deUint32 size, const void* dataPtr) 2092 { 2093 const VkDevice vkDevice = m_context.getDevice(); 2094 const DeviceInterface& vk = m_context.getDeviceInterface(); 2095 2096 Move<VkBuffer> buffer = createBuffer(m_context, size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); 2097 de::MovePtr<Allocation> alloc = allocateAndBindMemory(m_context, *buffer, vk::MemoryRequirement::HostVisible); 2098 2099 deMemcpy(alloc->getHostPtr(), dataPtr, size); 2100 flushAlloc(vk, vkDevice, *alloc); 2101 2102 const VkDescriptorBufferInfo descriptor = 2103 { 2104 *buffer, // VkBuffer buffer; 2105 0u, // VkDeviceSize offset; 2106 size, // VkDeviceSize range; 2107 2108 }; 2109 2110 m_uniformBuffers.push_back(VkBufferSp(new vk::Unique<vk::VkBuffer>(buffer))); 2111 m_uniformAllocs.push_back(AllocationSp(alloc.release())); 2112 2113 return descriptor; 2114 } 2115 2116 vk::Move<VkRenderPass> UniformBlockCaseInstance::createRenderPass (vk::VkFormat format) const 2117 { 2118 const VkDevice vkDevice = m_context.getDevice(); 2119 const DeviceInterface& vk = m_context.getDeviceInterface(); 2120 2121 return vk::makeRenderPass(vk, vkDevice, format); 2122 } 2123 2124 vk::Move<VkFramebuffer> UniformBlockCaseInstance::createFramebuffer (vk::VkRenderPass renderPass, vk::VkImageView colorImageView) const 2125 { 2126 const VkDevice vkDevice = m_context.getDevice(); 2127 const DeviceInterface& vk = m_context.getDeviceInterface(); 2128 2129 const VkFramebufferCreateInfo framebufferParams = 2130 { 2131 VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType; 2132 DE_NULL, // const void* pNext; 2133 0u, // VkFramebufferCreateFlags flags; 2134 renderPass, // VkRenderPass renderPass; 2135 1u, // deUint32 attachmentCount; 2136 &colorImageView, // const VkImageView* pAttachments; 2137 RENDER_WIDTH, // deUint32 width; 2138 RENDER_HEIGHT, // deUint32 height; 2139 1u // deUint32 layers; 2140 }; 2141 2142 return vk::createFramebuffer(vk, vkDevice, &framebufferParams); 2143 } 2144 2145 vk::Move<VkDescriptorSetLayout> UniformBlockCaseInstance::createDescriptorSetLayout (void) const 2146 { 2147 int numBlocks = (int)m_layout.blocks.size(); 2148 int lastBindingNdx = -1; 2149 std::vector<int> lengths; 2150 2151 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 2152 { 2153 const BlockLayoutEntry& block = m_layout.blocks[blockNdx]; 2154 2155 if (block.bindingNdx == lastBindingNdx) 2156 { 2157 lengths.back()++; 2158 } 2159 else 2160 { 2161 lengths.push_back(1); 2162 lastBindingNdx = block.bindingNdx; 2163 } 2164 } 2165 2166 vk::DescriptorSetLayoutBuilder layoutBuilder; 2167 for (size_t i = 0; i < lengths.size(); i++) 2168 { 2169 if (lengths[i] > 0) 2170 { 2171 layoutBuilder.addArrayBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, lengths[i], vk::VK_SHADER_STAGE_ALL); 2172 } 2173 else 2174 { 2175 layoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_SHADER_STAGE_ALL); 2176 } 2177 } 2178 2179 return layoutBuilder.build(m_context.getDeviceInterface(), m_context.getDevice()); 2180 } 2181 2182 vk::Move<VkDescriptorPool> UniformBlockCaseInstance::createDescriptorPool (void) const 2183 { 2184 vk::DescriptorPoolBuilder poolBuilder; 2185 2186 return poolBuilder 2187 .addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, (int)m_layout.blocks.size()) 2188 .build(m_context.getDeviceInterface(), m_context.getDevice(), VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); 2189 } 2190 2191 vk::Move<VkPipeline> UniformBlockCaseInstance::createPipeline (vk::VkShaderModule vtxShaderModule, vk::VkShaderModule fragShaderModule, vk::VkPipelineLayout pipelineLayout, vk::VkRenderPass renderPass) const 2192 { 2193 const VkDevice vkDevice = m_context.getDevice(); 2194 const DeviceInterface& vk = m_context.getDeviceInterface(); 2195 2196 const std::vector<VkViewport> viewports (1, makeViewport(tcu::UVec2(RENDER_WIDTH, RENDER_HEIGHT))); 2197 const std::vector<VkRect2D> scissors (1, makeRect2D(tcu::UVec2(RENDER_WIDTH, RENDER_HEIGHT))); 2198 2199 return vk::makeGraphicsPipeline(vk, // const DeviceInterface& vk 2200 vkDevice, // const VkDevice device 2201 pipelineLayout, // const VkPipelineLayout pipelineLayout 2202 vtxShaderModule, // const VkShaderModule vertexShaderModule 2203 DE_NULL, // const VkShaderModule tessellationControlShaderModule 2204 DE_NULL, // const VkShaderModule tessellationEvalShaderModule 2205 DE_NULL, // const VkShaderModule geometryShaderModule 2206 fragShaderModule, // const VkShaderModule fragmentShaderModule 2207 renderPass, // const VkRenderPass renderPass 2208 viewports, // const std::vector<VkViewport>& viewports 2209 scissors); // const std::vector<VkRect2D>& scissors 2210 } 2211 2212 } // anonymous (utilities) 2213 2214 // UniformBlockCase. 2215 2216 UniformBlockCase::UniformBlockCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, BufferMode bufferMode, MatrixLoadFlags matrixLoadFlag, bool shuffleUniformMembers) 2217 : TestCase (testCtx, name, description) 2218 , m_bufferMode (bufferMode) 2219 , m_matrixLoadFlag (matrixLoadFlag) 2220 , m_shuffleUniformMembers (shuffleUniformMembers) 2221 { 2222 } 2223 2224 UniformBlockCase::~UniformBlockCase (void) 2225 { 2226 } 2227 2228 void UniformBlockCase::initPrograms (vk::SourceCollections& programCollection) const 2229 { 2230 DE_ASSERT(!m_vertShaderSource.empty()); 2231 DE_ASSERT(!m_fragShaderSource.empty()); 2232 2233 vk::ShaderBuildOptions::Flags flags = vk::ShaderBuildOptions::Flags(0); 2234 // TODO(dneto): If these tests ever use LAYOUT_RELAXED, then add support 2235 // here as well. 2236 if (usesBlockLayout(UniformFlags(LAYOUT_SCALAR | LAYOUT_STD430))) 2237 { 2238 flags = vk::ShaderBuildOptions::FLAG_ALLOW_SCALAR_OFFSETS; 2239 } 2240 2241 programCollection.glslSources.add("vert") << glu::VertexSource(m_vertShaderSource) 2242 << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::getBaselineSpirvVersion(programCollection.usedVulkanVersion), flags); 2243 2244 programCollection.glslSources.add("frag") << glu::FragmentSource(m_fragShaderSource) 2245 << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::getBaselineSpirvVersion(programCollection.usedVulkanVersion), flags); 2246 } 2247 2248 TestInstance* UniformBlockCase::createInstance (Context& context) const 2249 { 2250 if (!context.get16BitStorageFeatures().uniformAndStorageBuffer16BitAccess && uses16BitStorage(m_interface)) 2251 TCU_THROW(NotSupportedError, "uniformAndStorageBuffer16BitAccess not supported"); 2252 if (!context.get8BitStorageFeatures().uniformAndStorageBuffer8BitAccess && uses8BitStorage(m_interface)) 2253 TCU_THROW(NotSupportedError, "uniformAndStorageBuffer8BitAccess not supported"); 2254 if (!context.getScalarBlockLayoutFeatures().scalarBlockLayout && usesScalarOrStd430Layout(m_interface)) 2255 TCU_THROW(NotSupportedError, "scalarBlockLayout not supported"); 2256 2257 return new UniformBlockCaseInstance(context, m_bufferMode, m_uniformLayout, m_blockPointers); 2258 } 2259 2260 void UniformBlockCase::init (void) 2261 { 2262 const int vec4Alignment = (int)sizeof(deUint32)*4; 2263 2264 // Compute reference layout. 2265 computeReferenceLayout(m_uniformLayout, m_interface); 2266 2267 // Assign storage for reference values. 2268 { 2269 int totalSize = 0; 2270 for (std::vector<BlockLayoutEntry>::const_iterator blockIter = m_uniformLayout.blocks.begin(); blockIter != m_uniformLayout.blocks.end(); blockIter++) 2271 { 2272 // Include enough space for alignment of individual blocks 2273 totalSize += deRoundUp32(blockIter->size, vec4Alignment); 2274 } 2275 m_data.resize(totalSize); 2276 2277 // Pointers for each block. 2278 int curOffset = 0; 2279 for (int blockNdx = 0; blockNdx < (int)m_uniformLayout.blocks.size(); blockNdx++) 2280 { 2281 m_blockPointers[blockNdx] = &m_data[0] + curOffset; 2282 2283 // Ensure each new block starts fully aligned to avoid unaligned host accesses 2284 curOffset += deRoundUp32(m_uniformLayout.blocks[blockNdx].size, vec4Alignment); 2285 } 2286 } 2287 2288 // Generate values. 2289 generateValues(m_uniformLayout, m_blockPointers, 1 /* seed */); 2290 2291 // Generate shaders. 2292 m_vertShaderSource = generateVertexShader(m_interface, m_uniformLayout, m_blockPointers, m_matrixLoadFlag, m_shuffleUniformMembers); 2293 m_fragShaderSource = generateFragmentShader(m_interface, m_uniformLayout, m_blockPointers, m_matrixLoadFlag, m_shuffleUniformMembers); 2294 } 2295 2296 } // ubo 2297 } // vkt 2298