1 /*------------------------------------------------------------------------- 2 * OpenGL Conformance Test Suite 3 * ----------------------------- 4 * 5 * Copyright (c) 2016 Google Inc. 6 * Copyright (c) 2016 The Khronos Group Inc. 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 * 20 */ /*! 21 * \file 22 * \brief Uniform block case. 23 */ /*-------------------------------------------------------------------*/ 24 25 #include "glcUniformBlockCase.hpp" 26 #include "deMemory.h" 27 #include "deRandom.hpp" 28 #include "deString.h" 29 #include "deStringUtil.hpp" 30 #include "gluContextInfo.hpp" 31 #include "gluDrawUtil.hpp" 32 #include "gluPixelTransfer.hpp" 33 #include "gluRenderContext.hpp" 34 #include "glwEnums.hpp" 35 #include "glwFunctions.hpp" 36 #include "tcuRenderTarget.hpp" 37 #include "tcuSurface.hpp" 38 #include "tcuTestLog.hpp" 39 40 #include <algorithm> 41 #include <map> 42 43 using tcu::TestLog; 44 using std::string; 45 using std::vector; 46 using std::map; 47 48 namespace deqp 49 { 50 namespace ub 51 { 52 53 struct PrecisionFlagsFmt 54 { 55 deUint32 flags; 56 57 PrecisionFlagsFmt(deUint32 flags_) : flags(flags_) 58 { 59 } 60 }; 61 62 std::ostream& operator<<(std::ostream& str, const PrecisionFlagsFmt& fmt) 63 { 64 // Precision. 65 DE_ASSERT(dePop32(fmt.flags & (PRECISION_LOW | PRECISION_MEDIUM | PRECISION_HIGH)) <= 1); 66 str << (fmt.flags & PRECISION_LOW ? 67 "lowp" : 68 fmt.flags & PRECISION_MEDIUM ? "mediump" : fmt.flags & PRECISION_HIGH ? "highp" : ""); 69 return str; 70 } 71 72 struct LayoutFlagsFmt 73 { 74 deUint32 flags; 75 LayoutFlagsFmt(deUint32 flags_) : flags(flags_) 76 { 77 } 78 }; 79 80 std::ostream& operator<<(std::ostream& str, const LayoutFlagsFmt& fmt) 81 { 82 static const struct 83 { 84 deUint32 bit; 85 const char* token; 86 } bitDesc[] = { { LAYOUT_SHARED, "shared" }, 87 { LAYOUT_PACKED, "packed" }, 88 { LAYOUT_STD140, "std140" }, 89 { LAYOUT_ROW_MAJOR, "row_major" }, 90 { LAYOUT_COLUMN_MAJOR, "column_major" } }; 91 92 deUint32 remBits = fmt.flags; 93 for (int descNdx = 0; descNdx < DE_LENGTH_OF_ARRAY(bitDesc); descNdx++) 94 { 95 if (remBits & bitDesc[descNdx].bit) 96 { 97 if (remBits != fmt.flags) 98 str << ", "; 99 str << bitDesc[descNdx].token; 100 remBits &= ~bitDesc[descNdx].bit; 101 } 102 } 103 DE_ASSERT(remBits == 0); 104 return str; 105 } 106 107 // VarType implementation. 108 109 VarType::VarType(void) : m_type(TYPE_LAST), m_flags(0) 110 { 111 } 112 113 VarType::VarType(const VarType& other) : m_type(TYPE_LAST), m_flags(0) 114 { 115 *this = other; 116 } 117 118 VarType::VarType(glu::DataType basicType, deUint32 flags) : m_type(TYPE_BASIC), m_flags(flags) 119 { 120 m_data.basicType = basicType; 121 } 122 123 VarType::VarType(const VarType& elementType, int arraySize) : m_type(TYPE_ARRAY), m_flags(0) 124 { 125 m_data.array.size = arraySize; 126 m_data.array.elementType = new VarType(elementType); 127 } 128 129 VarType::VarType(const StructType* structPtr) : m_type(TYPE_STRUCT), m_flags(0) 130 { 131 m_data.structPtr = structPtr; 132 } 133 134 VarType::~VarType(void) 135 { 136 if (m_type == TYPE_ARRAY) 137 delete m_data.array.elementType; 138 } 139 140 VarType& VarType::operator=(const VarType& other) 141 { 142 if (this == &other) 143 return *this; // Self-assignment. 144 145 if (m_type == TYPE_ARRAY) 146 delete m_data.array.elementType; 147 148 m_type = other.m_type; 149 m_flags = other.m_flags; 150 m_data = Data(); 151 152 if (m_type == TYPE_ARRAY) 153 { 154 m_data.array.elementType = new VarType(*other.m_data.array.elementType); 155 m_data.array.size = other.m_data.array.size; 156 } 157 else 158 m_data = other.m_data; 159 160 return *this; 161 } 162 163 // StructType implementation. 164 165 void StructType::addMember(const char* name, const VarType& type, deUint32 flags) 166 { 167 m_members.push_back(StructMember(name, type, flags)); 168 } 169 170 // Uniform implementation. 171 172 Uniform::Uniform(const char* name, const VarType& type, deUint32 flags) : m_name(name), m_type(type), m_flags(flags) 173 { 174 } 175 176 // UniformBlock implementation. 177 178 UniformBlock::UniformBlock(const char* blockName) : m_blockName(blockName), m_arraySize(0), m_flags(0) 179 { 180 } 181 182 struct BlockLayoutEntry 183 { 184 BlockLayoutEntry(void) : size(0) 185 { 186 } 187 188 std::string name; 189 int size; 190 std::vector<int> activeUniformIndices; 191 }; 192 193 std::ostream& operator<<(std::ostream& stream, const BlockLayoutEntry& entry) 194 { 195 stream << entry.name << " { name = " << entry.name << ", size = " << entry.size << ", activeUniformIndices = ["; 196 197 for (vector<int>::const_iterator i = entry.activeUniformIndices.begin(); i != entry.activeUniformIndices.end(); i++) 198 { 199 if (i != entry.activeUniformIndices.begin()) 200 stream << ", "; 201 stream << *i; 202 } 203 204 stream << "] }"; 205 return stream; 206 } 207 208 struct UniformLayoutEntry 209 { 210 UniformLayoutEntry(void) 211 : type(glu::TYPE_LAST), size(0), blockNdx(-1), offset(-1), arrayStride(-1), matrixStride(-1), isRowMajor(false) 212 { 213 } 214 215 std::string name; 216 glu::DataType type; 217 int size; 218 int blockNdx; 219 int offset; 220 int arrayStride; 221 int matrixStride; 222 bool isRowMajor; 223 }; 224 225 std::ostream& operator<<(std::ostream& stream, const UniformLayoutEntry& entry) 226 { 227 stream << entry.name << " { type = " << glu::getDataTypeName(entry.type) << ", size = " << entry.size 228 << ", blockNdx = " << entry.blockNdx << ", offset = " << entry.offset 229 << ", arrayStride = " << entry.arrayStride << ", matrixStride = " << entry.matrixStride 230 << ", isRowMajor = " << (entry.isRowMajor ? "true" : "false") << " }"; 231 return stream; 232 } 233 234 class UniformLayout 235 { 236 public: 237 std::vector<BlockLayoutEntry> blocks; 238 std::vector<UniformLayoutEntry> uniforms; 239 240 int getUniformIndex(const char* name) const; 241 int getBlockIndex(const char* name) const; 242 }; 243 244 // \todo [2012-01-24 pyry] Speed up lookups using hash. 245 246 int UniformLayout::getUniformIndex(const char* name) const 247 { 248 for (int ndx = 0; ndx < (int)uniforms.size(); ndx++) 249 { 250 if (uniforms[ndx].name == name) 251 return ndx; 252 } 253 return -1; 254 } 255 256 int UniformLayout::getBlockIndex(const char* name) const 257 { 258 for (int ndx = 0; ndx < (int)blocks.size(); ndx++) 259 { 260 if (blocks[ndx].name == name) 261 return ndx; 262 } 263 return -1; 264 } 265 266 // ShaderInterface implementation. 267 268 ShaderInterface::ShaderInterface(void) 269 { 270 } 271 272 ShaderInterface::~ShaderInterface(void) 273 { 274 for (std::vector<StructType*>::iterator i = m_structs.begin(); i != m_structs.end(); i++) 275 delete *i; 276 277 for (std::vector<UniformBlock*>::iterator i = m_uniformBlocks.begin(); i != m_uniformBlocks.end(); i++) 278 delete *i; 279 } 280 281 StructType& ShaderInterface::allocStruct(const char* name) 282 { 283 m_structs.reserve(m_structs.size() + 1); 284 m_structs.push_back(new StructType(name)); 285 return *m_structs.back(); 286 } 287 288 struct StructNameEquals 289 { 290 std::string name; 291 292 StructNameEquals(const char* name_) : name(name_) 293 { 294 } 295 296 bool operator()(const StructType* type) const 297 { 298 return type->getTypeName() && name == type->getTypeName(); 299 } 300 }; 301 302 const StructType* ShaderInterface::findStruct(const char* name) const 303 { 304 std::vector<StructType*>::const_iterator pos = 305 std::find_if(m_structs.begin(), m_structs.end(), StructNameEquals(name)); 306 return pos != m_structs.end() ? *pos : DE_NULL; 307 } 308 309 void ShaderInterface::getNamedStructs(std::vector<const StructType*>& structs) const 310 { 311 for (std::vector<StructType*>::const_iterator i = m_structs.begin(); i != m_structs.end(); i++) 312 { 313 if ((*i)->getTypeName() != DE_NULL) 314 structs.push_back(*i); 315 } 316 } 317 318 UniformBlock& ShaderInterface::allocBlock(const char* name) 319 { 320 m_uniformBlocks.reserve(m_uniformBlocks.size() + 1); 321 m_uniformBlocks.push_back(new UniformBlock(name)); 322 return *m_uniformBlocks.back(); 323 } 324 325 namespace // Utilities 326 { 327 328 // Layout computation. 329 330 int getDataTypeByteSize(glu::DataType type) 331 { 332 return static_cast<int>(glu::getDataTypeScalarSize(type) * sizeof(deUint32)); 333 } 334 335 int 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: 343 return static_cast<int>(1 * 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: 349 return static_cast<int>(2 * sizeof(deUint32)); 350 351 case glu::TYPE_FLOAT_VEC3: 352 case glu::TYPE_INT_VEC3: 353 case glu::TYPE_UINT_VEC3: 354 case glu::TYPE_BOOL_VEC3: // Fall-through to vec4 355 356 case glu::TYPE_FLOAT_VEC4: 357 case glu::TYPE_INT_VEC4: 358 case glu::TYPE_UINT_VEC4: 359 case glu::TYPE_BOOL_VEC4: 360 return static_cast<int>(4 * sizeof(deUint32)); 361 362 default: 363 DE_ASSERT(false); 364 return 0; 365 } 366 } 367 368 int getDataTypeArrayStride(glu::DataType type) 369 { 370 DE_ASSERT(!glu::isDataTypeMatrix(type)); 371 372 int baseStride = getDataTypeByteSize(type); 373 int vec4Alignment = static_cast<int>(sizeof(deUint32) * 4); 374 375 DE_ASSERT(baseStride <= vec4Alignment); 376 return de::max(baseStride, vec4Alignment); // Really? See rule 4. 377 } 378 379 static inline int deRoundUp32(int a, int b) 380 { 381 int d = a / b; 382 return d * b == a ? a : (d + 1) * b; 383 } 384 385 int computeStd140BaseAlignment(const VarType& type) 386 { 387 const int vec4Alignment = static_cast<int>(sizeof(deUint32) * 4); 388 389 if (type.isBasicType()) 390 { 391 glu::DataType basicType = type.getBasicType(); 392 393 if (glu::isDataTypeMatrix(basicType)) 394 { 395 bool isRowMajor = !!(type.getFlags() & LAYOUT_ROW_MAJOR); 396 int vecSize = 397 isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType) : glu::getDataTypeMatrixNumRows(basicType); 398 399 return getDataTypeArrayStride(glu::getDataTypeFloatVec(vecSize)); 400 } 401 else 402 return getDataTypeByteAlignment(basicType); 403 } 404 else if (type.isArrayType()) 405 { 406 int elemAlignment = computeStd140BaseAlignment(type.getElementType()); 407 408 // Round up to alignment of vec4 409 return deRoundUp32(elemAlignment, vec4Alignment); 410 } 411 else 412 { 413 DE_ASSERT(type.isStructType()); 414 415 int maxBaseAlignment = 0; 416 417 for (StructType::ConstIterator memberIter = type.getStruct().begin(); memberIter != type.getStruct().end(); 418 memberIter++) 419 maxBaseAlignment = de::max(maxBaseAlignment, computeStd140BaseAlignment(memberIter->getType())); 420 421 return deRoundUp32(maxBaseAlignment, vec4Alignment); 422 } 423 } 424 425 inline deUint32 mergeLayoutFlags(deUint32 prevFlags, deUint32 newFlags) 426 { 427 const deUint32 packingMask = LAYOUT_PACKED | LAYOUT_SHARED | LAYOUT_STD140; 428 const deUint32 matrixMask = LAYOUT_ROW_MAJOR | LAYOUT_COLUMN_MAJOR; 429 430 deUint32 mergedFlags = 0; 431 432 mergedFlags |= ((newFlags & packingMask) ? newFlags : prevFlags) & packingMask; 433 mergedFlags |= ((newFlags & matrixMask) ? newFlags : prevFlags) & matrixMask; 434 435 return mergedFlags; 436 } 437 438 void computeStd140Layout(UniformLayout& layout, int& curOffset, int curBlockNdx, const std::string& curPrefix, 439 const VarType& type, deUint32 layoutFlags) 440 { 441 int baseAlignment = computeStd140BaseAlignment(type); 442 443 curOffset = deAlign32(curOffset, baseAlignment); 444 445 if (type.isBasicType()) 446 { 447 glu::DataType basicType = type.getBasicType(); 448 UniformLayoutEntry entry; 449 450 entry.name = curPrefix; 451 entry.type = basicType; 452 entry.size = 1; 453 entry.arrayStride = 0; 454 entry.matrixStride = 0; 455 entry.blockNdx = curBlockNdx; 456 457 if (glu::isDataTypeMatrix(basicType)) 458 { 459 // Array of vectors as specified in rules 5 & 7. 460 bool isRowMajor = !!(layoutFlags & LAYOUT_ROW_MAJOR); 461 int vecSize = 462 isRowMajor ? glu::getDataTypeMatrixNumColumns(basicType) : glu::getDataTypeMatrixNumRows(basicType); 463 int numVecs = 464 isRowMajor ? glu::getDataTypeMatrixNumRows(basicType) : glu::getDataTypeMatrixNumColumns(basicType); 465 int stride = getDataTypeArrayStride(glu::getDataTypeFloatVec(vecSize)); 466 467 entry.offset = curOffset; 468 entry.matrixStride = stride; 469 entry.isRowMajor = isRowMajor; 470 471 curOffset += numVecs * stride; 472 } 473 else 474 { 475 // Scalar or vector. 476 entry.offset = curOffset; 477 478 curOffset += getDataTypeByteSize(basicType); 479 } 480 481 layout.uniforms.push_back(entry); 482 } 483 else if (type.isArrayType()) 484 { 485 const VarType& elemType = type.getElementType(); 486 487 if (elemType.isBasicType() && !glu::isDataTypeMatrix(elemType.getBasicType())) 488 { 489 // Array of scalars or vectors. 490 glu::DataType elemBasicType = elemType.getBasicType(); 491 UniformLayoutEntry entry; 492 int stride = getDataTypeArrayStride(elemBasicType); 493 494 entry.name = curPrefix + "[0]"; // Array uniforms are always postfixed with [0] 495 entry.type = elemBasicType; 496 entry.blockNdx = curBlockNdx; 497 entry.offset = curOffset; 498 entry.size = type.getArraySize(); 499 entry.arrayStride = stride; 500 entry.matrixStride = 0; 501 502 curOffset += stride * type.getArraySize(); 503 504 layout.uniforms.push_back(entry); 505 } 506 else if (elemType.isBasicType() && glu::isDataTypeMatrix(elemType.getBasicType())) 507 { 508 // Array of matrices. 509 glu::DataType elemBasicType = elemType.getBasicType(); 510 bool isRowMajor = !!(layoutFlags & LAYOUT_ROW_MAJOR); 511 int vecSize = isRowMajor ? glu::getDataTypeMatrixNumColumns(elemBasicType) : 512 glu::getDataTypeMatrixNumRows(elemBasicType); 513 int numVecs = isRowMajor ? glu::getDataTypeMatrixNumRows(elemBasicType) : 514 glu::getDataTypeMatrixNumColumns(elemBasicType); 515 int stride = getDataTypeArrayStride(glu::getDataTypeFloatVec(vecSize)); 516 UniformLayoutEntry entry; 517 518 entry.name = curPrefix + "[0]"; // Array uniforms are always postfixed with [0] 519 entry.type = elemBasicType; 520 entry.blockNdx = curBlockNdx; 521 entry.offset = curOffset; 522 entry.size = type.getArraySize(); 523 entry.arrayStride = stride * numVecs; 524 entry.matrixStride = stride; 525 entry.isRowMajor = isRowMajor; 526 527 curOffset += numVecs * type.getArraySize() * stride; 528 529 layout.uniforms.push_back(entry); 530 } 531 else 532 { 533 DE_ASSERT(elemType.isStructType() || elemType.isArrayType()); 534 535 for (int elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++) 536 computeStd140Layout(layout, curOffset, curBlockNdx, curPrefix + "[" + de::toString(elemNdx) + "]", 537 type.getElementType(), layoutFlags); 538 } 539 } 540 else 541 { 542 DE_ASSERT(type.isStructType()); 543 544 for (StructType::ConstIterator memberIter = type.getStruct().begin(); memberIter != type.getStruct().end(); 545 memberIter++) 546 computeStd140Layout(layout, curOffset, curBlockNdx, curPrefix + "." + memberIter->getName(), 547 memberIter->getType(), layoutFlags); 548 549 curOffset = deAlign32(curOffset, baseAlignment); 550 } 551 } 552 553 void computeStd140Layout(UniformLayout& layout, const ShaderInterface& interface) 554 { 555 // \todo [2012-01-23 pyry] Uniforms in default block. 556 557 int numUniformBlocks = interface.getNumUniformBlocks(); 558 559 for (int blockNdx = 0; blockNdx < numUniformBlocks; blockNdx++) 560 { 561 const UniformBlock& block = interface.getUniformBlock(blockNdx); 562 bool hasInstanceName = block.getInstanceName() != DE_NULL; 563 std::string blockPrefix = hasInstanceName ? (std::string(block.getBlockName()) + ".") : std::string(""); 564 int curOffset = 0; 565 int activeBlockNdx = (int)layout.blocks.size(); 566 int firstUniformNdx = (int)layout.uniforms.size(); 567 568 for (UniformBlock::ConstIterator uniformIter = block.begin(); uniformIter != block.end(); uniformIter++) 569 { 570 const Uniform& uniform = *uniformIter; 571 computeStd140Layout(layout, curOffset, activeBlockNdx, blockPrefix + uniform.getName(), uniform.getType(), 572 mergeLayoutFlags(block.getFlags(), uniform.getFlags())); 573 } 574 575 int uniformIndicesEnd = (int)layout.uniforms.size(); 576 int blockSize = curOffset; 577 int numInstances = block.isArray() ? block.getArraySize() : 1; 578 579 // Create block layout entries for each instance. 580 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++) 581 { 582 // Allocate entry for instance. 583 layout.blocks.push_back(BlockLayoutEntry()); 584 BlockLayoutEntry& blockEntry = layout.blocks.back(); 585 586 blockEntry.name = block.getBlockName(); 587 blockEntry.size = blockSize; 588 589 // Compute active uniform set for block. 590 for (int uniformNdx = firstUniformNdx; uniformNdx < uniformIndicesEnd; uniformNdx++) 591 blockEntry.activeUniformIndices.push_back(uniformNdx); 592 593 if (block.isArray()) 594 blockEntry.name += "[" + de::toString(instanceNdx) + "]"; 595 } 596 } 597 } 598 599 // Value generator. 600 601 void generateValue(const UniformLayoutEntry& entry, void* basePtr, de::Random& rnd) 602 { 603 glu::DataType scalarType = glu::getDataTypeScalarType(entry.type); 604 int scalarSize = glu::getDataTypeScalarSize(entry.type); 605 bool isMatrix = glu::isDataTypeMatrix(entry.type); 606 int numVecs = isMatrix ? (entry.isRowMajor ? glu::getDataTypeMatrixNumRows(entry.type) : 607 glu::getDataTypeMatrixNumColumns(entry.type)) : 608 1; 609 int vecSize = scalarSize / numVecs; 610 bool isArray = entry.size > 1; 611 const int compSize = sizeof(deUint32); 612 613 DE_ASSERT(scalarSize % numVecs == 0); 614 615 for (int elemNdx = 0; elemNdx < entry.size; elemNdx++) 616 { 617 deUint8* elemPtr = (deUint8*)basePtr + entry.offset + (isArray ? elemNdx * entry.arrayStride : 0); 618 619 for (int vecNdx = 0; vecNdx < numVecs; vecNdx++) 620 { 621 deUint8* vecPtr = elemPtr + (isMatrix ? vecNdx * entry.matrixStride : 0); 622 623 for (int compNdx = 0; compNdx < vecSize; compNdx++) 624 { 625 deUint8* compPtr = vecPtr + compSize * compNdx; 626 627 switch (scalarType) 628 { 629 case glu::TYPE_FLOAT: 630 *((float*)compPtr) = (float)rnd.getInt(-9, 9); 631 break; 632 case glu::TYPE_INT: 633 *((int*)compPtr) = rnd.getInt(-9, 9); 634 break; 635 case glu::TYPE_UINT: 636 *((deUint32*)compPtr) = (deUint32)rnd.getInt(0, 9); 637 break; 638 // \note Random bit pattern is used for true values. Spec states that all non-zero values are 639 // interpreted as true but some implementations fail this. 640 case glu::TYPE_BOOL: 641 *((deUint32*)compPtr) = rnd.getBool() ? rnd.getUint32() | 1u : 0u; 642 break; 643 default: 644 DE_ASSERT(false); 645 } 646 } 647 } 648 } 649 } 650 651 void generateValues(const UniformLayout& layout, const std::map<int, void*>& blockPointers, deUint32 seed) 652 { 653 de::Random rnd(seed); 654 int numBlocks = (int)layout.blocks.size(); 655 656 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 657 { 658 void* basePtr = blockPointers.find(blockNdx)->second; 659 int numEntries = (int)layout.blocks[blockNdx].activeUniformIndices.size(); 660 661 for (int entryNdx = 0; entryNdx < numEntries; entryNdx++) 662 { 663 const UniformLayoutEntry& entry = layout.uniforms[layout.blocks[blockNdx].activeUniformIndices[entryNdx]]; 664 generateValue(entry, basePtr, rnd); 665 } 666 } 667 } 668 669 // Shader generator. 670 671 static const char* s_compareFuncs = 672 "mediump float compare_float (highp float a, highp float b) { return abs(a - b) < 0.05 ? 1.0 : 0.0; }\n" 673 "mediump float compare_vec2 (highp vec2 a, highp vec2 b) { return compare_float(a.x, " 674 "b.x)*compare_float(a.y, b.y); }\n" 675 "mediump float compare_vec3 (highp vec3 a, highp vec3 b) { return compare_float(a.x, " 676 "b.x)*compare_float(a.y, b.y)*compare_float(a.z, b.z); }\n" 677 "mediump float compare_vec4 (highp vec4 a, highp vec4 b) { return compare_float(a.x, " 678 "b.x)*compare_float(a.y, b.y)*compare_float(a.z, b.z)*compare_float(a.w, b.w); }\n" 679 "mediump float compare_mat2 (highp mat2 a, highp mat2 b) { return compare_vec2(a[0], " 680 "b[0])*compare_vec2(a[1], b[1]); }\n" 681 "mediump float compare_mat2x3 (highp mat2x3 a, highp mat2x3 b){ return compare_vec3(a[0], " 682 "b[0])*compare_vec3(a[1], b[1]); }\n" 683 "mediump float compare_mat2x4 (highp mat2x4 a, highp mat2x4 b){ return compare_vec4(a[0], " 684 "b[0])*compare_vec4(a[1], b[1]); }\n" 685 "mediump float compare_mat3x2 (highp mat3x2 a, highp mat3x2 b){ return compare_vec2(a[0], " 686 "b[0])*compare_vec2(a[1], b[1])*compare_vec2(a[2], b[2]); }\n" 687 "mediump float compare_mat3 (highp mat3 a, highp mat3 b) { return compare_vec3(a[0], " 688 "b[0])*compare_vec3(a[1], b[1])*compare_vec3(a[2], b[2]); }\n" 689 "mediump float compare_mat3x4 (highp mat3x4 a, highp mat3x4 b){ return compare_vec4(a[0], " 690 "b[0])*compare_vec4(a[1], b[1])*compare_vec4(a[2], b[2]); }\n" 691 "mediump float compare_mat4x2 (highp mat4x2 a, highp mat4x2 b){ return compare_vec2(a[0], " 692 "b[0])*compare_vec2(a[1], b[1])*compare_vec2(a[2], b[2])*compare_vec2(a[3], b[3]); }\n" 693 "mediump float compare_mat4x3 (highp mat4x3 a, highp mat4x3 b){ return compare_vec3(a[0], " 694 "b[0])*compare_vec3(a[1], b[1])*compare_vec3(a[2], b[2])*compare_vec3(a[3], b[3]); }\n" 695 "mediump float compare_mat4 (highp mat4 a, highp mat4 b) { return compare_vec4(a[0], " 696 "b[0])*compare_vec4(a[1], b[1])*compare_vec4(a[2], b[2])*compare_vec4(a[3], b[3]); }\n" 697 "mediump float compare_int (highp int a, highp int b) { return a == b ? 1.0 : 0.0; }\n" 698 "mediump float compare_ivec2 (highp ivec2 a, highp ivec2 b) { return a == b ? 1.0 : 0.0; }\n" 699 "mediump float compare_ivec3 (highp ivec3 a, highp ivec3 b) { return a == b ? 1.0 : 0.0; }\n" 700 "mediump float compare_ivec4 (highp ivec4 a, highp ivec4 b) { return a == b ? 1.0 : 0.0; }\n" 701 "mediump float compare_uint (highp uint a, highp uint b) { return a == b ? 1.0 : 0.0; }\n" 702 "mediump float compare_uvec2 (highp uvec2 a, highp uvec2 b) { return a == b ? 1.0 : 0.0; }\n" 703 "mediump float compare_uvec3 (highp uvec3 a, highp uvec3 b) { return a == b ? 1.0 : 0.0; }\n" 704 "mediump float compare_uvec4 (highp uvec4 a, highp uvec4 b) { return a == b ? 1.0 : 0.0; }\n" 705 "mediump float compare_bool (bool a, bool b) { return a == b ? 1.0 : 0.0; }\n" 706 "mediump float compare_bvec2 (bvec2 a, bvec2 b) { return a == b ? 1.0 : 0.0; }\n" 707 "mediump float compare_bvec3 (bvec3 a, bvec3 b) { return a == b ? 1.0 : 0.0; }\n" 708 "mediump float compare_bvec4 (bvec4 a, bvec4 b) { return a == b ? 1.0 : 0.0; }\n"; 709 710 struct Indent 711 { 712 int level; 713 714 Indent(int level_) : level(level_) 715 { 716 } 717 }; 718 719 std::ostream& operator<<(std::ostream& str, const Indent& indent) 720 { 721 for (int i = 0; i < indent.level; i++) 722 str << "\t"; 723 return str; 724 } 725 726 void generateDeclaration(std::ostringstream& src, const VarType& type, const char* name, int indentLevel, 727 deUint32 unusedHints); 728 void generateDeclaration(std::ostringstream& src, const Uniform& uniform, int indentLevel); 729 void generateDeclaration(std::ostringstream& src, const StructType& structType, int indentLevel); 730 731 void generateLocalDeclaration(std::ostringstream& src, const StructType& structType, int indentLevel); 732 void generateFullDeclaration(std::ostringstream& src, const StructType& structType, int indentLevel); 733 734 void generateDeclaration(std::ostringstream& src, const StructType& structType, int indentLevel) 735 { 736 DE_ASSERT(structType.getTypeName() != DE_NULL); 737 generateFullDeclaration(src, structType, indentLevel); 738 src << ";\n"; 739 } 740 741 void generateFullDeclaration(std::ostringstream& src, const StructType& structType, int indentLevel) 742 { 743 src << "struct"; 744 if (structType.getTypeName()) 745 src << " " << structType.getTypeName(); 746 src << "\n" << Indent(indentLevel) << "{\n"; 747 748 for (StructType::ConstIterator memberIter = structType.begin(); memberIter != structType.end(); memberIter++) 749 { 750 src << Indent(indentLevel + 1); 751 generateDeclaration(src, memberIter->getType(), memberIter->getName(), indentLevel + 1, 752 memberIter->getFlags() & UNUSED_BOTH); 753 } 754 755 src << Indent(indentLevel) << "}"; 756 } 757 758 void generateLocalDeclaration(std::ostringstream& src, const StructType& structType, int indentLevel) 759 { 760 if (structType.getTypeName() == DE_NULL) 761 generateFullDeclaration(src, structType, indentLevel); 762 else 763 src << structType.getTypeName(); 764 } 765 766 void generateDeclaration(std::ostringstream& src, const VarType& type, const char* name, int indentLevel, 767 deUint32 unusedHints) 768 { 769 deUint32 flags = type.getFlags(); 770 771 if ((flags & LAYOUT_MASK) != 0) 772 src << "layout(" << LayoutFlagsFmt(flags & LAYOUT_MASK) << ") "; 773 774 if ((flags & PRECISION_MASK) != 0) 775 src << PrecisionFlagsFmt(flags & PRECISION_MASK) << " "; 776 777 if (type.isBasicType()) 778 src << glu::getDataTypeName(type.getBasicType()) << " " << name; 779 else if (type.isArrayType()) 780 { 781 std::vector<int> arraySizes; 782 const VarType* curType = &type; 783 while (curType->isArrayType()) 784 { 785 arraySizes.push_back(curType->getArraySize()); 786 curType = &curType->getElementType(); 787 } 788 789 if (curType->isBasicType()) 790 { 791 if ((curType->getFlags() & PRECISION_MASK) != 0) 792 src << PrecisionFlagsFmt(curType->getFlags() & PRECISION_MASK) << " "; 793 src << glu::getDataTypeName(curType->getBasicType()); 794 } 795 else 796 { 797 DE_ASSERT(curType->isStructType()); 798 generateLocalDeclaration(src, curType->getStruct(), indentLevel + 1); 799 } 800 801 src << " " << name; 802 803 for (std::vector<int>::const_reverse_iterator sizeIter = arraySizes.rbegin(); sizeIter != arraySizes.rend(); 804 sizeIter++) 805 src << "[" << *sizeIter << "]"; 806 } 807 else 808 { 809 generateLocalDeclaration(src, type.getStruct(), indentLevel + 1); 810 src << " " << name; 811 } 812 813 src << ";"; 814 815 // Print out unused hints. 816 if (unusedHints != 0) 817 src << " // unused in " 818 << (unusedHints == UNUSED_BOTH ? 819 "both shaders" : 820 unusedHints == UNUSED_VERTEX ? "vertex shader" : 821 unusedHints == UNUSED_FRAGMENT ? "fragment shader" : "???"); 822 823 src << "\n"; 824 } 825 826 void generateDeclaration(std::ostringstream& src, const Uniform& uniform, int indentLevel) 827 { 828 if ((uniform.getFlags() & LAYOUT_MASK) != 0) 829 src << "layout(" << LayoutFlagsFmt(uniform.getFlags() & LAYOUT_MASK) << ") "; 830 831 generateDeclaration(src, uniform.getType(), uniform.getName(), indentLevel, uniform.getFlags() & UNUSED_BOTH); 832 } 833 834 void generateDeclaration(std::ostringstream& src, const UniformBlock& block) 835 { 836 if ((block.getFlags() & LAYOUT_MASK) != 0) 837 src << "layout(" << LayoutFlagsFmt(block.getFlags() & LAYOUT_MASK) << ") "; 838 839 src << "uniform " << block.getBlockName(); 840 src << "\n{\n"; 841 842 for (UniformBlock::ConstIterator uniformIter = block.begin(); uniformIter != block.end(); uniformIter++) 843 { 844 src << Indent(1); 845 generateDeclaration(src, *uniformIter, 1 /* indent level */); 846 } 847 848 src << "}"; 849 850 if (block.getInstanceName() != DE_NULL) 851 { 852 src << " " << block.getInstanceName(); 853 if (block.isArray()) 854 src << "[" << block.getArraySize() << "]"; 855 } 856 else 857 DE_ASSERT(!block.isArray()); 858 859 src << ";\n"; 860 } 861 862 void generateValueSrc(std::ostringstream& src, const UniformLayoutEntry& entry, const void* basePtr, int elementNdx) 863 { 864 glu::DataType scalarType = glu::getDataTypeScalarType(entry.type); 865 int scalarSize = glu::getDataTypeScalarSize(entry.type); 866 bool isArray = entry.size > 1; 867 const deUint8* elemPtr = (const deUint8*)basePtr + entry.offset + (isArray ? elementNdx * entry.arrayStride : 0); 868 const int compSize = sizeof(deUint32); 869 870 if (scalarSize > 1) 871 src << glu::getDataTypeName(entry.type) << "("; 872 873 if (glu::isDataTypeMatrix(entry.type)) 874 { 875 int numRows = glu::getDataTypeMatrixNumRows(entry.type); 876 int numCols = glu::getDataTypeMatrixNumColumns(entry.type); 877 878 DE_ASSERT(scalarType == glu::TYPE_FLOAT); 879 880 // Constructed in column-wise order. 881 for (int colNdx = 0; colNdx < numCols; colNdx++) 882 { 883 for (int rowNdx = 0; rowNdx < numRows; rowNdx++) 884 { 885 const deUint8* compPtr = elemPtr + (entry.isRowMajor ? rowNdx * entry.matrixStride + colNdx * compSize : 886 colNdx * entry.matrixStride + rowNdx * compSize); 887 888 if (colNdx > 0 || rowNdx > 0) 889 src << ", "; 890 891 src << de::floatToString(*((const float*)compPtr), 1); 892 } 893 } 894 } 895 else 896 { 897 for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++) 898 { 899 const deUint8* compPtr = elemPtr + scalarNdx * compSize; 900 901 if (scalarNdx > 0) 902 src << ", "; 903 904 switch (scalarType) 905 { 906 case glu::TYPE_FLOAT: 907 src << de::floatToString(*((const float*)compPtr), 1); 908 break; 909 case glu::TYPE_INT: 910 src << *((const int*)compPtr); 911 break; 912 case glu::TYPE_UINT: 913 src << *((const deUint32*)compPtr) << "u"; 914 break; 915 case glu::TYPE_BOOL: 916 src << (*((const deUint32*)compPtr) != 0u ? "true" : "false"); 917 break; 918 default: 919 DE_ASSERT(false); 920 } 921 } 922 } 923 924 if (scalarSize > 1) 925 src << ")"; 926 } 927 928 void generateCompareSrc(std::ostringstream& src, const char* resultVar, const VarType& type, const char* srcName, 929 const char* apiName, const UniformLayout& layout, const void* basePtr, deUint32 unusedMask) 930 { 931 if (type.isBasicType() || (type.isArrayType() && type.getElementType().isBasicType())) 932 { 933 // Basic type or array of basic types. 934 bool isArray = type.isArrayType(); 935 glu::DataType elementType = isArray ? type.getElementType().getBasicType() : type.getBasicType(); 936 const char* typeName = glu::getDataTypeName(elementType); 937 std::string fullApiName = string(apiName) + (isArray ? "[0]" : ""); // Arrays are always postfixed with [0] 938 int uniformNdx = layout.getUniformIndex(fullApiName.c_str()); 939 const UniformLayoutEntry& entry = layout.uniforms[uniformNdx]; 940 941 if (isArray) 942 { 943 for (int elemNdx = 0; elemNdx < type.getArraySize(); elemNdx++) 944 { 945 src << "\tresult *= compare_" << typeName << "(" << srcName << "[" << elemNdx << "], "; 946 generateValueSrc(src, entry, basePtr, elemNdx); 947 src << ");\n"; 948 } 949 } 950 else 951 { 952 src << "\tresult *= compare_" << typeName << "(" << srcName << ", "; 953 generateValueSrc(src, entry, basePtr, 0); 954 src << ");\n"; 955 } 956 } 957 else if (type.isArrayType()) 958 { 959 const VarType& elementType = type.getElementType(); 960 DE_ASSERT(!elementType.isArrayType()); 961 962 for (int elementNdx = 0; elementNdx < type.getArraySize(); elementNdx++) 963 { 964 std::string op = string("[") + de::toString(elementNdx) + "]"; 965 generateCompareSrc(src, resultVar, elementType, (string(srcName) + op).c_str(), 966 (string(apiName) + op).c_str(), layout, basePtr, unusedMask); 967 } 968 } 969 else 970 { 971 DE_ASSERT(type.isStructType()); 972 973 for (StructType::ConstIterator memberIter = type.getStruct().begin(); memberIter != type.getStruct().end(); 974 memberIter++) 975 { 976 if (memberIter->getFlags() & unusedMask) 977 continue; // Skip member. 978 979 string op = string(".") + memberIter->getName(); 980 generateCompareSrc(src, resultVar, memberIter->getType(), (string(srcName) + op).c_str(), 981 (string(apiName) + op).c_str(), layout, basePtr, unusedMask); 982 } 983 } 984 } 985 986 void generateCompareSrc(std::ostringstream& src, const char* resultVar, const ShaderInterface& interface, 987 const UniformLayout& layout, const std::map<int, void*>& blockPointers, bool isVertex) 988 { 989 deUint32 unusedMask = isVertex ? UNUSED_VERTEX : UNUSED_FRAGMENT; 990 991 for (int blockNdx = 0; blockNdx < interface.getNumUniformBlocks(); blockNdx++) 992 { 993 const UniformBlock& block = interface.getUniformBlock(blockNdx); 994 995 if ((block.getFlags() & (isVertex ? DECLARE_VERTEX : DECLARE_FRAGMENT)) == 0) 996 continue; // Skip. 997 998 bool hasInstanceName = block.getInstanceName() != DE_NULL; 999 bool isArray = block.isArray(); 1000 int numInstances = isArray ? block.getArraySize() : 1; 1001 std::string apiPrefix = hasInstanceName ? string(block.getBlockName()) + "." : string(""); 1002 1003 DE_ASSERT(!isArray || hasInstanceName); 1004 1005 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++) 1006 { 1007 std::string instancePostfix = isArray ? string("[") + de::toString(instanceNdx) + "]" : string(""); 1008 std::string blockInstanceName = block.getBlockName() + instancePostfix; 1009 std::string srcPrefix = 1010 hasInstanceName ? string(block.getInstanceName()) + instancePostfix + "." : string(""); 1011 int activeBlockNdx = layout.getBlockIndex(blockInstanceName.c_str()); 1012 void* basePtr = blockPointers.find(activeBlockNdx)->second; 1013 1014 for (UniformBlock::ConstIterator uniformIter = block.begin(); uniformIter != block.end(); uniformIter++) 1015 { 1016 const Uniform& uniform = *uniformIter; 1017 1018 if (uniform.getFlags() & unusedMask) 1019 continue; // Don't read from that uniform. 1020 1021 generateCompareSrc(src, resultVar, uniform.getType(), (srcPrefix + uniform.getName()).c_str(), 1022 (apiPrefix + uniform.getName()).c_str(), layout, basePtr, unusedMask); 1023 } 1024 } 1025 } 1026 } 1027 1028 void generateVertexShader(std::ostringstream& src, glu::GLSLVersion glslVersion, const ShaderInterface& interface, 1029 const UniformLayout& layout, const std::map<int, void*>& blockPointers) 1030 { 1031 DE_ASSERT(glslVersion == glu::GLSL_VERSION_300_ES || glslVersion == glu::GLSL_VERSION_310_ES || 1032 de::inRange<int>(glslVersion, glu::GLSL_VERSION_330, glu::GLSL_VERSION_430)); 1033 1034 src << glu::getGLSLVersionDeclaration(glslVersion) << "\n"; 1035 src << "in highp vec4 a_position;\n"; 1036 src << "out mediump float v_vtxResult;\n"; 1037 src << "\n"; 1038 1039 std::vector<const StructType*> namedStructs; 1040 interface.getNamedStructs(namedStructs); 1041 for (std::vector<const StructType*>::const_iterator structIter = namedStructs.begin(); 1042 structIter != namedStructs.end(); structIter++) 1043 generateDeclaration(src, **structIter, 0); 1044 1045 for (int blockNdx = 0; blockNdx < interface.getNumUniformBlocks(); blockNdx++) 1046 { 1047 const UniformBlock& block = interface.getUniformBlock(blockNdx); 1048 if (block.getFlags() & DECLARE_VERTEX) 1049 generateDeclaration(src, block); 1050 } 1051 1052 // Comparison utilities. 1053 src << "\n" << s_compareFuncs; 1054 1055 src << "\n" 1056 "void main (void)\n" 1057 "{\n" 1058 " gl_Position = a_position;\n" 1059 " mediump float result = 1.0;\n"; 1060 1061 // Value compare. 1062 generateCompareSrc(src, "result", interface, layout, blockPointers, true); 1063 1064 src << " v_vtxResult = result;\n" 1065 "}\n"; 1066 } 1067 1068 void generateFragmentShader(std::ostringstream& src, glu::GLSLVersion glslVersion, const ShaderInterface& interface, 1069 const UniformLayout& layout, const std::map<int, void*>& blockPointers) 1070 { 1071 DE_ASSERT(glslVersion == glu::GLSL_VERSION_300_ES || glslVersion == glu::GLSL_VERSION_310_ES || 1072 de::inRange<int>(glslVersion, glu::GLSL_VERSION_330, glu::GLSL_VERSION_430)); 1073 1074 src << glu::getGLSLVersionDeclaration(glslVersion) << "\n"; 1075 src << "in mediump float v_vtxResult;\n"; 1076 src << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n"; 1077 src << "\n"; 1078 1079 std::vector<const StructType*> namedStructs; 1080 interface.getNamedStructs(namedStructs); 1081 for (std::vector<const StructType*>::const_iterator structIter = namedStructs.begin(); 1082 structIter != namedStructs.end(); structIter++) 1083 generateDeclaration(src, **structIter, 0); 1084 1085 for (int blockNdx = 0; blockNdx < interface.getNumUniformBlocks(); blockNdx++) 1086 { 1087 const UniformBlock& block = interface.getUniformBlock(blockNdx); 1088 if (block.getFlags() & DECLARE_FRAGMENT) 1089 generateDeclaration(src, block); 1090 } 1091 1092 // Comparison utilities. 1093 src << "\n" << s_compareFuncs; 1094 1095 src << "\n" 1096 "void main (void)\n" 1097 "{\n" 1098 " mediump float result = 1.0;\n"; 1099 1100 // Value compare. 1101 generateCompareSrc(src, "result", interface, layout, blockPointers, false); 1102 1103 src << " dEQP_FragColor = vec4(1.0, v_vtxResult, result, 1.0);\n" 1104 "}\n"; 1105 } 1106 1107 void getGLUniformLayout(const glw::Functions& gl, UniformLayout& layout, deUint32 program) 1108 { 1109 int numActiveUniforms = 0; 1110 int numActiveBlocks = 0; 1111 1112 gl.getProgramiv(program, GL_ACTIVE_UNIFORMS, &numActiveUniforms); 1113 gl.getProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &numActiveBlocks); 1114 1115 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to get number of uniforms and uniform blocks"); 1116 1117 // Block entries. 1118 layout.blocks.resize(numActiveBlocks); 1119 for (int blockNdx = 0; blockNdx < numActiveBlocks; blockNdx++) 1120 { 1121 BlockLayoutEntry& entry = layout.blocks[blockNdx]; 1122 int size; 1123 int nameLen; 1124 int numBlockUniforms; 1125 1126 gl.getActiveUniformBlockiv(program, (deUint32)blockNdx, GL_UNIFORM_BLOCK_DATA_SIZE, &size); 1127 gl.getActiveUniformBlockiv(program, (deUint32)blockNdx, GL_UNIFORM_BLOCK_NAME_LENGTH, &nameLen); 1128 gl.getActiveUniformBlockiv(program, (deUint32)blockNdx, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &numBlockUniforms); 1129 1130 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform block query failed"); 1131 1132 // \note Some implementations incorrectly return 0 as name length even though the length should include null terminator. 1133 std::vector<char> nameBuf(nameLen > 0 ? nameLen : 1); 1134 gl.getActiveUniformBlockName(program, (deUint32)blockNdx, (glw::GLsizei)nameBuf.size(), DE_NULL, &nameBuf[0]); 1135 1136 entry.name = std::string(&nameBuf[0]); 1137 entry.size = size; 1138 entry.activeUniformIndices.resize(numBlockUniforms); 1139 1140 if (numBlockUniforms > 0) 1141 gl.getActiveUniformBlockiv(program, (deUint32)blockNdx, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, 1142 &entry.activeUniformIndices[0]); 1143 1144 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform block query failed"); 1145 } 1146 1147 if (numActiveUniforms > 0) 1148 { 1149 // Uniform entries. 1150 std::vector<deUint32> uniformIndices(numActiveUniforms); 1151 for (int i = 0; i < numActiveUniforms; i++) 1152 uniformIndices[i] = (deUint32)i; 1153 1154 std::vector<int> types(numActiveUniforms); 1155 std::vector<int> sizes(numActiveUniforms); 1156 std::vector<int> nameLengths(numActiveUniforms); 1157 std::vector<int> blockIndices(numActiveUniforms); 1158 std::vector<int> offsets(numActiveUniforms); 1159 std::vector<int> arrayStrides(numActiveUniforms); 1160 std::vector<int> matrixStrides(numActiveUniforms); 1161 std::vector<int> rowMajorFlags(numActiveUniforms); 1162 1163 // Execute queries. 1164 gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0], GL_UNIFORM_TYPE, 1165 &types[0]); 1166 gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0], GL_UNIFORM_SIZE, 1167 &sizes[0]); 1168 gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0], GL_UNIFORM_NAME_LENGTH, 1169 &nameLengths[0]); 1170 gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0], GL_UNIFORM_BLOCK_INDEX, 1171 &blockIndices[0]); 1172 gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0], GL_UNIFORM_OFFSET, 1173 &offsets[0]); 1174 gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0], 1175 GL_UNIFORM_ARRAY_STRIDE, &arrayStrides[0]); 1176 gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0], 1177 GL_UNIFORM_MATRIX_STRIDE, &matrixStrides[0]); 1178 gl.getActiveUniformsiv(program, (glw::GLsizei)uniformIndices.size(), &uniformIndices[0], 1179 GL_UNIFORM_IS_ROW_MAJOR, &rowMajorFlags[0]); 1180 1181 GLU_EXPECT_NO_ERROR(gl.getError(), "Active uniform query failed"); 1182 1183 // Translate to LayoutEntries 1184 layout.uniforms.resize(numActiveUniforms); 1185 for (int uniformNdx = 0; uniformNdx < numActiveUniforms; uniformNdx++) 1186 { 1187 UniformLayoutEntry& entry = layout.uniforms[uniformNdx]; 1188 std::vector<char> nameBuf(nameLengths[uniformNdx]); 1189 glw::GLsizei nameLen = 0; 1190 int size = 0; 1191 deUint32 type = GL_NONE; 1192 1193 gl.getActiveUniform(program, (deUint32)uniformNdx, (glw::GLsizei)nameBuf.size(), &nameLen, &size, &type, 1194 &nameBuf[0]); 1195 1196 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform name query failed"); 1197 1198 // \note glGetActiveUniform() returns length without \0 and glGetActiveUniformsiv() with \0 1199 if (nameLen + 1 != nameLengths[uniformNdx] || size != sizes[uniformNdx] || 1200 type != (deUint32)types[uniformNdx]) 1201 TCU_FAIL("Values returned by glGetActiveUniform() don't match with values queried with " 1202 "glGetActiveUniformsiv()."); 1203 1204 entry.name = std::string(&nameBuf[0]); 1205 entry.type = glu::getDataTypeFromGLType(types[uniformNdx]); 1206 entry.size = sizes[uniformNdx]; 1207 entry.blockNdx = blockIndices[uniformNdx]; 1208 entry.offset = offsets[uniformNdx]; 1209 entry.arrayStride = arrayStrides[uniformNdx]; 1210 entry.matrixStride = matrixStrides[uniformNdx]; 1211 entry.isRowMajor = rowMajorFlags[uniformNdx] != GL_FALSE; 1212 } 1213 } 1214 } 1215 1216 void copyUniformData(const UniformLayoutEntry& dstEntry, void* dstBlockPtr, const UniformLayoutEntry& srcEntry, 1217 const void* srcBlockPtr) 1218 { 1219 deUint8* dstBasePtr = (deUint8*)dstBlockPtr + dstEntry.offset; 1220 const deUint8* srcBasePtr = (const deUint8*)srcBlockPtr + srcEntry.offset; 1221 1222 DE_ASSERT(dstEntry.size <= srcEntry.size); 1223 DE_ASSERT(dstEntry.type == srcEntry.type); 1224 1225 int scalarSize = glu::getDataTypeScalarSize(dstEntry.type); 1226 bool isMatrix = glu::isDataTypeMatrix(dstEntry.type); 1227 const int compSize = sizeof(deUint32); 1228 1229 for (int elementNdx = 0; elementNdx < dstEntry.size; elementNdx++) 1230 { 1231 deUint8* dstElemPtr = dstBasePtr + elementNdx * dstEntry.arrayStride; 1232 const deUint8* srcElemPtr = srcBasePtr + elementNdx * srcEntry.arrayStride; 1233 1234 if (isMatrix) 1235 { 1236 int numRows = glu::getDataTypeMatrixNumRows(dstEntry.type); 1237 int numCols = glu::getDataTypeMatrixNumColumns(dstEntry.type); 1238 1239 for (int colNdx = 0; colNdx < numCols; colNdx++) 1240 { 1241 for (int rowNdx = 0; rowNdx < numRows; rowNdx++) 1242 { 1243 deUint8* dstCompPtr = 1244 dstElemPtr + (dstEntry.isRowMajor ? rowNdx * dstEntry.matrixStride + colNdx * compSize : 1245 colNdx * dstEntry.matrixStride + rowNdx * compSize); 1246 const deUint8* srcCompPtr = 1247 srcElemPtr + (srcEntry.isRowMajor ? rowNdx * srcEntry.matrixStride + colNdx * compSize : 1248 colNdx * srcEntry.matrixStride + rowNdx * compSize); 1249 deMemcpy(dstCompPtr, srcCompPtr, compSize); 1250 } 1251 } 1252 } 1253 else 1254 deMemcpy(dstElemPtr, srcElemPtr, scalarSize * compSize); 1255 } 1256 } 1257 1258 void copyUniformData(const UniformLayout& dstLayout, const std::map<int, void*>& dstBlockPointers, 1259 const UniformLayout& srcLayout, const std::map<int, void*>& srcBlockPointers) 1260 { 1261 // \note Src layout is used as reference in case of activeUniforms happens to be incorrect in dstLayout blocks. 1262 int numBlocks = (int)srcLayout.blocks.size(); 1263 1264 for (int srcBlockNdx = 0; srcBlockNdx < numBlocks; srcBlockNdx++) 1265 { 1266 const BlockLayoutEntry& srcBlock = srcLayout.blocks[srcBlockNdx]; 1267 const void* srcBlockPtr = srcBlockPointers.find(srcBlockNdx)->second; 1268 int dstBlockNdx = dstLayout.getBlockIndex(srcBlock.name.c_str()); 1269 void* dstBlockPtr = dstBlockNdx >= 0 ? dstBlockPointers.find(dstBlockNdx)->second : DE_NULL; 1270 1271 if (dstBlockNdx < 0) 1272 continue; 1273 1274 for (vector<int>::const_iterator srcUniformNdxIter = srcBlock.activeUniformIndices.begin(); 1275 srcUniformNdxIter != srcBlock.activeUniformIndices.end(); srcUniformNdxIter++) 1276 { 1277 const UniformLayoutEntry& srcEntry = srcLayout.uniforms[*srcUniformNdxIter]; 1278 int dstUniformNdx = dstLayout.getUniformIndex(srcEntry.name.c_str()); 1279 1280 if (dstUniformNdx < 0) 1281 continue; 1282 1283 copyUniformData(dstLayout.uniforms[dstUniformNdx], dstBlockPtr, srcEntry, srcBlockPtr); 1284 } 1285 } 1286 } 1287 1288 } // anonymous (utilities) 1289 1290 class UniformBufferManager 1291 { 1292 public: 1293 UniformBufferManager(const glu::RenderContext& renderCtx); 1294 ~UniformBufferManager(void); 1295 1296 deUint32 allocBuffer(void); 1297 1298 private: 1299 UniformBufferManager(const UniformBufferManager& other); 1300 UniformBufferManager& operator=(const UniformBufferManager& other); 1301 1302 const glu::RenderContext& m_renderCtx; 1303 std::vector<deUint32> m_buffers; 1304 }; 1305 1306 UniformBufferManager::UniformBufferManager(const glu::RenderContext& renderCtx) : m_renderCtx(renderCtx) 1307 { 1308 } 1309 1310 UniformBufferManager::~UniformBufferManager(void) 1311 { 1312 if (!m_buffers.empty()) 1313 m_renderCtx.getFunctions().deleteBuffers((glw::GLsizei)m_buffers.size(), &m_buffers[0]); 1314 } 1315 1316 deUint32 UniformBufferManager::allocBuffer(void) 1317 { 1318 deUint32 buf = 0; 1319 1320 m_buffers.reserve(m_buffers.size() + 1); 1321 m_renderCtx.getFunctions().genBuffers(1, &buf); 1322 GLU_EXPECT_NO_ERROR(m_renderCtx.getFunctions().getError(), "Failed to allocate uniform buffer"); 1323 m_buffers.push_back(buf); 1324 1325 return buf; 1326 } 1327 1328 } // ub 1329 1330 using namespace ub; 1331 1332 // UniformBlockCase. 1333 1334 UniformBlockCase::UniformBlockCase(Context& context, const char* name, const char* description, 1335 glu::GLSLVersion glslVersion, BufferMode bufferMode) 1336 : TestCase(context, name, description), m_glslVersion(glslVersion), m_bufferMode(bufferMode) 1337 { 1338 // \todo [2013-05-25 pyry] Support other versions as well. 1339 DE_ASSERT(glslVersion == glu::GLSL_VERSION_300_ES || glslVersion == glu::GLSL_VERSION_330); 1340 } 1341 1342 UniformBlockCase::~UniformBlockCase(void) 1343 { 1344 } 1345 1346 UniformBlockCase::IterateResult UniformBlockCase::iterate(void) 1347 { 1348 TestLog& log = m_testCtx.getLog(); 1349 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1350 UniformLayout refLayout; //!< std140 layout. 1351 vector<deUint8> data; //!< Data. 1352 map<int, void*> blockPointers; //!< Reference block pointers. 1353 1354 // Initialize result to pass. 1355 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1356 1357 // Compute reference layout. 1358 computeStd140Layout(refLayout, m_interface); 1359 1360 // Assign storage for reference values. 1361 { 1362 int totalSize = 0; 1363 for (vector<BlockLayoutEntry>::const_iterator blockIter = refLayout.blocks.begin(); 1364 blockIter != refLayout.blocks.end(); blockIter++) 1365 totalSize += blockIter->size; 1366 data.resize(totalSize); 1367 1368 // Pointers for each block. 1369 int curOffset = 0; 1370 for (int blockNdx = 0; blockNdx < (int)refLayout.blocks.size(); blockNdx++) 1371 { 1372 blockPointers[blockNdx] = &data[0] + curOffset; 1373 curOffset += refLayout.blocks[blockNdx].size; 1374 } 1375 } 1376 1377 // Generate values. 1378 generateValues(refLayout, blockPointers, 1 /* seed */); 1379 1380 // Generate shaders and build program. 1381 std::ostringstream vtxSrc; 1382 std::ostringstream fragSrc; 1383 1384 generateVertexShader(vtxSrc, m_glslVersion, m_interface, refLayout, blockPointers); 1385 generateFragmentShader(fragSrc, m_glslVersion, m_interface, refLayout, blockPointers); 1386 1387 glu::ShaderProgram program(m_context.getRenderContext(), 1388 glu::makeVtxFragSources(vtxSrc.str().c_str(), fragSrc.str().c_str())); 1389 log << program; 1390 1391 if (!program.isOk()) 1392 { 1393 // Compile failed. 1394 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Compile failed"); 1395 return STOP; 1396 } 1397 1398 // Query layout from GL. 1399 UniformLayout glLayout; 1400 getGLUniformLayout(gl, glLayout, program.getProgram()); 1401 1402 // Print layout to log. 1403 log << TestLog::Section("ActiveUniformBlocks", "Active Uniform Blocks"); 1404 for (int blockNdx = 0; blockNdx < (int)glLayout.blocks.size(); blockNdx++) 1405 log << TestLog::Message << blockNdx << ": " << glLayout.blocks[blockNdx] << TestLog::EndMessage; 1406 log << TestLog::EndSection; 1407 1408 log << TestLog::Section("ActiveUniforms", "Active Uniforms"); 1409 for (int uniformNdx = 0; uniformNdx < (int)glLayout.uniforms.size(); uniformNdx++) 1410 log << TestLog::Message << uniformNdx << ": " << glLayout.uniforms[uniformNdx] << TestLog::EndMessage; 1411 log << TestLog::EndSection; 1412 1413 // Check that we can even try rendering with given layout. 1414 if (!checkLayoutIndices(glLayout) || !checkLayoutBounds(glLayout) || !compareTypes(refLayout, glLayout)) 1415 { 1416 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid layout"); 1417 return STOP; // It is not safe to use the given layout. 1418 } 1419 1420 // Verify all std140 blocks. 1421 if (!compareStd140Blocks(refLayout, glLayout)) 1422 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid std140 layout"); 1423 1424 // Verify all shared blocks - all uniforms should be active, and certain properties match. 1425 if (!compareSharedBlocks(refLayout, glLayout)) 1426 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid shared layout"); 1427 1428 // Check consistency with index queries 1429 if (!checkIndexQueries(program.getProgram(), glLayout)) 1430 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Inconsintent block index query results"); 1431 1432 // Use program. 1433 gl.useProgram(program.getProgram()); 1434 1435 // Assign binding points to all active uniform blocks. 1436 for (int blockNdx = 0; blockNdx < (int)glLayout.blocks.size(); blockNdx++) 1437 { 1438 deUint32 binding = (deUint32)blockNdx; // \todo [2012-01-25 pyry] Randomize order? 1439 gl.uniformBlockBinding(program.getProgram(), (deUint32)blockNdx, binding); 1440 } 1441 1442 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set uniform block bindings"); 1443 1444 // Allocate buffers, write data and bind to targets. 1445 UniformBufferManager bufferManager(m_context.getRenderContext()); 1446 if (m_bufferMode == BUFFERMODE_PER_BLOCK) 1447 { 1448 int numBlocks = (int)glLayout.blocks.size(); 1449 vector<vector<deUint8> > glData(numBlocks); 1450 map<int, void*> glBlockPointers; 1451 1452 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 1453 { 1454 glData[blockNdx].resize(glLayout.blocks[blockNdx].size); 1455 glBlockPointers[blockNdx] = &glData[blockNdx][0]; 1456 } 1457 1458 copyUniformData(glLayout, glBlockPointers, refLayout, blockPointers); 1459 1460 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 1461 { 1462 deUint32 buffer = bufferManager.allocBuffer(); 1463 deUint32 binding = (deUint32)blockNdx; 1464 1465 gl.bindBuffer(GL_UNIFORM_BUFFER, buffer); 1466 gl.bufferData(GL_UNIFORM_BUFFER, (glw::GLsizeiptr)glData[blockNdx].size(), &glData[blockNdx][0], 1467 GL_STATIC_DRAW); 1468 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to upload uniform buffer data"); 1469 1470 gl.bindBufferBase(GL_UNIFORM_BUFFER, binding, buffer); 1471 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase(GL_UNIFORM_BUFFER) failed"); 1472 } 1473 } 1474 else 1475 { 1476 DE_ASSERT(m_bufferMode == BUFFERMODE_SINGLE); 1477 1478 int totalSize = 0; 1479 int curOffset = 0; 1480 int numBlocks = (int)glLayout.blocks.size(); 1481 int bindingAlignment = m_context.getContextInfo().getInt(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT); 1482 map<int, int> glBlockOffsets; 1483 1484 // Compute total size and offsets. 1485 curOffset = 0; 1486 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 1487 { 1488 if (bindingAlignment > 0) 1489 curOffset = deRoundUp32(curOffset, bindingAlignment); 1490 glBlockOffsets[blockNdx] = curOffset; 1491 curOffset += glLayout.blocks[blockNdx].size; 1492 } 1493 totalSize = curOffset; 1494 1495 // Assign block pointers. 1496 vector<deUint8> glData(totalSize); 1497 map<int, void*> glBlockPointers; 1498 1499 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 1500 glBlockPointers[blockNdx] = &glData[glBlockOffsets[blockNdx]]; 1501 1502 // Copy to gl format. 1503 copyUniformData(glLayout, glBlockPointers, refLayout, blockPointers); 1504 1505 // Allocate buffer and upload data. 1506 deUint32 buffer = bufferManager.allocBuffer(); 1507 gl.bindBuffer(GL_UNIFORM_BUFFER, buffer); 1508 if (!glData.empty()) 1509 gl.bufferData(GL_UNIFORM_BUFFER, (glw::GLsizeiptr)glData.size(), &glData[0], GL_STATIC_DRAW); 1510 1511 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to upload uniform buffer data"); 1512 1513 // Bind ranges to binding points. 1514 curOffset = 0; 1515 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 1516 { 1517 deUint32 binding = (deUint32)blockNdx; 1518 gl.bindBufferRange(GL_UNIFORM_BUFFER, binding, buffer, (glw::GLintptr)glBlockOffsets[blockNdx], 1519 (glw::GLsizeiptr)glLayout.blocks[blockNdx].size); 1520 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferRange(GL_UNIFORM_BUFFER) failed"); 1521 curOffset += glLayout.blocks[blockNdx].size; 1522 } 1523 } 1524 1525 bool renderOk = render(program); 1526 if (!renderOk) 1527 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image compare failed"); 1528 1529 return STOP; 1530 } 1531 1532 bool UniformBlockCase::compareStd140Blocks(const UniformLayout& refLayout, const UniformLayout& cmpLayout) const 1533 { 1534 TestLog& log = m_testCtx.getLog(); 1535 bool isOk = true; 1536 int numBlocks = m_interface.getNumUniformBlocks(); 1537 1538 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 1539 { 1540 const UniformBlock& block = m_interface.getUniformBlock(blockNdx); 1541 bool isArray = block.isArray(); 1542 std::string instanceName = string(block.getBlockName()) + (isArray ? "[0]" : ""); 1543 int refBlockNdx = refLayout.getBlockIndex(instanceName.c_str()); 1544 int cmpBlockNdx = cmpLayout.getBlockIndex(instanceName.c_str()); 1545 bool isUsed = (block.getFlags() & (DECLARE_VERTEX | DECLARE_FRAGMENT)) != 0; 1546 1547 if ((block.getFlags() & LAYOUT_STD140) == 0) 1548 continue; // Not std140 layout. 1549 1550 DE_ASSERT(refBlockNdx >= 0); 1551 1552 if (cmpBlockNdx < 0) 1553 { 1554 // Not found, should it? 1555 if (isUsed) 1556 { 1557 log << TestLog::Message << "Error: Uniform block '" << instanceName << "' not found" 1558 << TestLog::EndMessage; 1559 isOk = false; 1560 } 1561 1562 continue; // Skip block. 1563 } 1564 1565 const BlockLayoutEntry& refBlockLayout = refLayout.blocks[refBlockNdx]; 1566 const BlockLayoutEntry& cmpBlockLayout = cmpLayout.blocks[cmpBlockNdx]; 1567 1568 // \todo [2012-01-24 pyry] Verify that activeUniformIndices is correct. 1569 // \todo [2012-01-24 pyry] Verify all instances. 1570 if (refBlockLayout.activeUniformIndices.size() != cmpBlockLayout.activeUniformIndices.size()) 1571 { 1572 log << TestLog::Message << "Error: Number of active uniforms differ in block '" << instanceName 1573 << "' (expected " << refBlockLayout.activeUniformIndices.size() << ", got " 1574 << cmpBlockLayout.activeUniformIndices.size() << ")" << TestLog::EndMessage; 1575 isOk = false; 1576 } 1577 1578 for (vector<int>::const_iterator ndxIter = refBlockLayout.activeUniformIndices.begin(); 1579 ndxIter != refBlockLayout.activeUniformIndices.end(); ndxIter++) 1580 { 1581 const UniformLayoutEntry& refEntry = refLayout.uniforms[*ndxIter]; 1582 int cmpEntryNdx = cmpLayout.getUniformIndex(refEntry.name.c_str()); 1583 1584 if (cmpEntryNdx < 0) 1585 { 1586 log << TestLog::Message << "Error: Uniform '" << refEntry.name << "' not found" << TestLog::EndMessage; 1587 isOk = false; 1588 continue; 1589 } 1590 1591 const UniformLayoutEntry& cmpEntry = cmpLayout.uniforms[cmpEntryNdx]; 1592 1593 if (refEntry.type != cmpEntry.type || refEntry.size != cmpEntry.size || 1594 refEntry.offset != cmpEntry.offset || refEntry.arrayStride != cmpEntry.arrayStride || 1595 refEntry.matrixStride != cmpEntry.matrixStride || refEntry.isRowMajor != cmpEntry.isRowMajor) 1596 { 1597 log << TestLog::Message << "Error: Layout mismatch in '" << refEntry.name << "':\n" 1598 << " expected: type = " << glu::getDataTypeName(refEntry.type) << ", size = " << refEntry.size 1599 << ", offset = " << refEntry.offset << ", array stride = " << refEntry.arrayStride 1600 << ", matrix stride = " << refEntry.matrixStride 1601 << ", row major = " << (refEntry.isRowMajor ? "true" : "false") << "\n" 1602 << " got: type = " << glu::getDataTypeName(cmpEntry.type) << ", size = " << cmpEntry.size 1603 << ", offset = " << cmpEntry.offset << ", array stride = " << cmpEntry.arrayStride 1604 << ", matrix stride = " << cmpEntry.matrixStride 1605 << ", row major = " << (cmpEntry.isRowMajor ? "true" : "false") << TestLog::EndMessage; 1606 isOk = false; 1607 } 1608 } 1609 } 1610 1611 return isOk; 1612 } 1613 1614 bool UniformBlockCase::compareSharedBlocks(const UniformLayout& refLayout, const UniformLayout& cmpLayout) const 1615 { 1616 TestLog& log = m_testCtx.getLog(); 1617 bool isOk = true; 1618 int numBlocks = m_interface.getNumUniformBlocks(); 1619 1620 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 1621 { 1622 const UniformBlock& block = m_interface.getUniformBlock(blockNdx); 1623 bool isArray = block.isArray(); 1624 std::string instanceName = string(block.getBlockName()) + (isArray ? "[0]" : ""); 1625 int refBlockNdx = refLayout.getBlockIndex(instanceName.c_str()); 1626 int cmpBlockNdx = cmpLayout.getBlockIndex(instanceName.c_str()); 1627 bool isUsed = (block.getFlags() & (DECLARE_VERTEX | DECLARE_FRAGMENT)) != 0; 1628 1629 if ((block.getFlags() & LAYOUT_SHARED) == 0) 1630 continue; // Not shared layout. 1631 1632 DE_ASSERT(refBlockNdx >= 0); 1633 1634 if (cmpBlockNdx < 0) 1635 { 1636 // Not found, should it? 1637 if (isUsed) 1638 { 1639 log << TestLog::Message << "Error: Uniform block '" << instanceName << "' not found" 1640 << TestLog::EndMessage; 1641 isOk = false; 1642 } 1643 1644 continue; // Skip block. 1645 } 1646 1647 const BlockLayoutEntry& refBlockLayout = refLayout.blocks[refBlockNdx]; 1648 const BlockLayoutEntry& cmpBlockLayout = cmpLayout.blocks[cmpBlockNdx]; 1649 1650 if (refBlockLayout.activeUniformIndices.size() != cmpBlockLayout.activeUniformIndices.size()) 1651 { 1652 log << TestLog::Message << "Error: Number of active uniforms differ in block '" << instanceName 1653 << "' (expected " << refBlockLayout.activeUniformIndices.size() << ", got " 1654 << cmpBlockLayout.activeUniformIndices.size() << ")" << TestLog::EndMessage; 1655 isOk = false; 1656 } 1657 1658 for (vector<int>::const_iterator ndxIter = refBlockLayout.activeUniformIndices.begin(); 1659 ndxIter != refBlockLayout.activeUniformIndices.end(); ndxIter++) 1660 { 1661 const UniformLayoutEntry& refEntry = refLayout.uniforms[*ndxIter]; 1662 int cmpEntryNdx = cmpLayout.getUniformIndex(refEntry.name.c_str()); 1663 1664 if (cmpEntryNdx < 0) 1665 { 1666 log << TestLog::Message << "Error: Uniform '" << refEntry.name << "' not found" << TestLog::EndMessage; 1667 isOk = false; 1668 continue; 1669 } 1670 1671 const UniformLayoutEntry& cmpEntry = cmpLayout.uniforms[cmpEntryNdx]; 1672 1673 if (refEntry.type != cmpEntry.type || refEntry.size != cmpEntry.size || 1674 refEntry.isRowMajor != cmpEntry.isRowMajor) 1675 { 1676 log << TestLog::Message << "Error: Layout mismatch in '" << refEntry.name << "':\n" 1677 << " expected: type = " << glu::getDataTypeName(refEntry.type) << ", size = " << refEntry.size 1678 << ", row major = " << (refEntry.isRowMajor ? "true" : "false") << "\n" 1679 << " got: type = " << glu::getDataTypeName(cmpEntry.type) << ", size = " << cmpEntry.size 1680 << ", row major = " << (cmpEntry.isRowMajor ? "true" : "false") << TestLog::EndMessage; 1681 isOk = false; 1682 } 1683 } 1684 } 1685 1686 return isOk; 1687 } 1688 1689 bool UniformBlockCase::compareTypes(const UniformLayout& refLayout, const UniformLayout& cmpLayout) const 1690 { 1691 TestLog& log = m_testCtx.getLog(); 1692 bool isOk = true; 1693 int numBlocks = m_interface.getNumUniformBlocks(); 1694 1695 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 1696 { 1697 const UniformBlock& block = m_interface.getUniformBlock(blockNdx); 1698 bool isArray = block.isArray(); 1699 int numInstances = isArray ? block.getArraySize() : 1; 1700 1701 for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++) 1702 { 1703 std::ostringstream instanceName; 1704 1705 instanceName << block.getBlockName(); 1706 if (isArray) 1707 instanceName << "[" << instanceNdx << "]"; 1708 1709 int cmpBlockNdx = cmpLayout.getBlockIndex(instanceName.str().c_str()); 1710 1711 if (cmpBlockNdx < 0) 1712 continue; 1713 1714 const BlockLayoutEntry& cmpBlockLayout = cmpLayout.blocks[cmpBlockNdx]; 1715 1716 for (vector<int>::const_iterator ndxIter = cmpBlockLayout.activeUniformIndices.begin(); 1717 ndxIter != cmpBlockLayout.activeUniformIndices.end(); ndxIter++) 1718 { 1719 const UniformLayoutEntry& cmpEntry = cmpLayout.uniforms[*ndxIter]; 1720 int refEntryNdx = refLayout.getUniformIndex(cmpEntry.name.c_str()); 1721 1722 if (refEntryNdx < 0) 1723 { 1724 log << TestLog::Message << "Error: Uniform '" << cmpEntry.name << "' not found in reference layout" 1725 << TestLog::EndMessage; 1726 isOk = false; 1727 continue; 1728 } 1729 1730 const UniformLayoutEntry& refEntry = refLayout.uniforms[refEntryNdx]; 1731 1732 // \todo [2012-11-26 pyry] Should we check other properties as well? 1733 if (refEntry.type != cmpEntry.type) 1734 { 1735 log << TestLog::Message << "Error: Uniform type mismatch in '" << refEntry.name << "':\n" 1736 << " expected: " << glu::getDataTypeName(refEntry.type) << "\n" 1737 << " got: " << glu::getDataTypeName(cmpEntry.type) << TestLog::EndMessage; 1738 isOk = false; 1739 } 1740 } 1741 } 1742 } 1743 1744 return isOk; 1745 } 1746 1747 bool UniformBlockCase::checkLayoutIndices(const UniformLayout& layout) const 1748 { 1749 TestLog& log = m_testCtx.getLog(); 1750 int numUniforms = (int)layout.uniforms.size(); 1751 int numBlocks = (int)layout.blocks.size(); 1752 bool isOk = true; 1753 1754 // Check uniform block indices. 1755 for (int uniformNdx = 0; uniformNdx < numUniforms; uniformNdx++) 1756 { 1757 const UniformLayoutEntry& uniform = layout.uniforms[uniformNdx]; 1758 1759 if (uniform.blockNdx < 0 || !deInBounds32(uniform.blockNdx, 0, numBlocks)) 1760 { 1761 log << TestLog::Message << "Error: Invalid block index in uniform '" << uniform.name << "'" 1762 << TestLog::EndMessage; 1763 isOk = false; 1764 } 1765 } 1766 1767 // Check active uniforms. 1768 for (int blockNdx = 0; blockNdx < numBlocks; blockNdx++) 1769 { 1770 const BlockLayoutEntry& block = layout.blocks[blockNdx]; 1771 1772 for (vector<int>::const_iterator uniformIter = block.activeUniformIndices.begin(); 1773 uniformIter != block.activeUniformIndices.end(); uniformIter++) 1774 { 1775 if (!deInBounds32(*uniformIter, 0, numUniforms)) 1776 { 1777 log << TestLog::Message << "Error: Invalid active uniform index " << *uniformIter << " in block '" 1778 << block.name << "'" << TestLog::EndMessage; 1779 isOk = false; 1780 } 1781 } 1782 } 1783 1784 return isOk; 1785 } 1786 1787 bool UniformBlockCase::checkLayoutBounds(const UniformLayout& layout) const 1788 { 1789 TestLog& log = m_testCtx.getLog(); 1790 int numUniforms = (int)layout.uniforms.size(); 1791 bool isOk = true; 1792 1793 for (int uniformNdx = 0; uniformNdx < numUniforms; uniformNdx++) 1794 { 1795 const UniformLayoutEntry& uniform = layout.uniforms[uniformNdx]; 1796 1797 if (uniform.blockNdx < 0) 1798 continue; 1799 1800 const BlockLayoutEntry& block = layout.blocks[uniform.blockNdx]; 1801 bool isMatrix = glu::isDataTypeMatrix(uniform.type); 1802 int numVecs = isMatrix ? (uniform.isRowMajor ? glu::getDataTypeMatrixNumRows(uniform.type) : 1803 glu::getDataTypeMatrixNumColumns(uniform.type)) : 1804 1; 1805 int numComps = isMatrix ? (uniform.isRowMajor ? glu::getDataTypeMatrixNumColumns(uniform.type) : 1806 glu::getDataTypeMatrixNumRows(uniform.type)) : 1807 glu::getDataTypeScalarSize(uniform.type); 1808 int numElements = uniform.size; 1809 const int compSize = sizeof(deUint32); 1810 int vecSize = numComps * compSize; 1811 1812 int minOffset = 0; 1813 int maxOffset = 0; 1814 1815 // For negative strides. 1816 minOffset = de::min(minOffset, (numVecs - 1) * uniform.matrixStride); 1817 minOffset = de::min(minOffset, (numElements - 1) * uniform.arrayStride); 1818 minOffset = de::min(minOffset, (numElements - 1) * uniform.arrayStride + (numVecs - 1) * uniform.matrixStride); 1819 1820 maxOffset = de::max(maxOffset, vecSize); 1821 maxOffset = de::max(maxOffset, (numVecs - 1) * uniform.matrixStride + vecSize); 1822 maxOffset = de::max(maxOffset, (numElements - 1) * uniform.arrayStride + vecSize); 1823 maxOffset = de::max(maxOffset, 1824 (numElements - 1) * uniform.arrayStride + (numVecs - 1) * uniform.matrixStride + vecSize); 1825 1826 if (uniform.offset + minOffset < 0 || uniform.offset + maxOffset > block.size) 1827 { 1828 log << TestLog::Message << "Error: Uniform '" << uniform.name << "' out of block bounds" 1829 << TestLog::EndMessage; 1830 isOk = false; 1831 } 1832 } 1833 1834 return isOk; 1835 } 1836 1837 bool UniformBlockCase::checkIndexQueries(deUint32 program, const UniformLayout& layout) const 1838 { 1839 tcu::TestLog& log = m_testCtx.getLog(); 1840 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1841 bool allOk = true; 1842 1843 // \note Spec mandates that uniform blocks are assigned consecutive locations from 0 1844 // to ACTIVE_UNIFORM_BLOCKS. BlockLayoutEntries are stored in that order in UniformLayout. 1845 for (int blockNdx = 0; blockNdx < (int)layout.blocks.size(); blockNdx++) 1846 { 1847 const BlockLayoutEntry& block = layout.blocks[blockNdx]; 1848 const int queriedNdx = gl.getUniformBlockIndex(program, block.name.c_str()); 1849 1850 if (queriedNdx != blockNdx) 1851 { 1852 log << TestLog::Message << "ERROR: glGetUniformBlockIndex(" << block.name << ") returned " << queriedNdx 1853 << ", expected " << blockNdx << "!" << TestLog::EndMessage; 1854 allOk = false; 1855 } 1856 1857 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformBlockIndex()"); 1858 } 1859 1860 return allOk; 1861 } 1862 1863 bool UniformBlockCase::render(glu::ShaderProgram& program) const 1864 { 1865 tcu::TestLog& log = m_testCtx.getLog(); 1866 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1867 de::Random rnd(deStringHash(getName())); 1868 const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget(); 1869 const int viewportW = de::min(renderTarget.getWidth(), 128); 1870 const int viewportH = de::min(renderTarget.getHeight(), 128); 1871 const int viewportX = rnd.getInt(0, renderTarget.getWidth() - viewportW); 1872 const int viewportY = rnd.getInt(0, renderTarget.getHeight() - viewportH); 1873 1874 // Draw 1875 { 1876 const float position[] = { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, +1.0f, 0.0f, 1.0f, 1877 +1.0f, -1.0f, 0.0f, 1.0f, +1.0f, +1.0f, 0.0f, 1.0f }; 1878 const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 }; 1879 1880 gl.viewport(viewportX, viewportY, viewportW, viewportH); 1881 1882 glu::VertexArrayBinding posArray = glu::va::Float("a_position", 4, 4, 0, &position[0]); 1883 glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posArray, 1884 glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0])); 1885 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw failed"); 1886 } 1887 1888 // Verify that all pixels are white. 1889 { 1890 tcu::Surface pixels(viewportW, viewportH); 1891 int numFailedPixels = 0; 1892 1893 glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, pixels.getAccess()); 1894 GLU_EXPECT_NO_ERROR(gl.getError(), "Reading pixels failed"); 1895 1896 for (int y = 0; y < pixels.getHeight(); y++) 1897 { 1898 for (int x = 0; x < pixels.getWidth(); x++) 1899 { 1900 if (pixels.getPixel(x, y) != tcu::RGBA::white()) 1901 numFailedPixels += 1; 1902 } 1903 } 1904 1905 if (numFailedPixels > 0) 1906 { 1907 log << TestLog::Image("Image", "Rendered image", pixels); 1908 log << TestLog::Message << "Image comparison failed, got " << numFailedPixels << " non-white pixels" 1909 << TestLog::EndMessage; 1910 } 1911 1912 return numFailedPixels == 0; 1913 } 1914 } 1915 1916 } // deqp 1917