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