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