1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 3.1 Module 3 * ------------------------------------------------- 4 * 5 * Copyright 2014 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief Program interface utilities 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es31fProgramInterfaceDefinitionUtil.hpp" 25 #include "es31fProgramInterfaceDefinition.hpp" 26 #include "gluVarType.hpp" 27 #include "gluVarTypeUtil.hpp" 28 #include "gluShaderUtil.hpp" 29 #include "deString.h" 30 #include "deStringUtil.hpp" 31 #include "glwEnums.hpp" 32 33 #include <set> 34 #include <map> 35 #include <sstream> 36 #include <vector> 37 #include <algorithm> 38 39 namespace deqp 40 { 41 namespace gles31 42 { 43 namespace Functional 44 { 45 namespace ProgramInterfaceDefinition 46 { 47 48 VariableSearchFilter::VariableSearchFilter (void) 49 : m_shaderTypeBits (0xFFFFFFFFul) 50 , m_storageBits (0xFFFFFFFFul) 51 { 52 } 53 54 VariableSearchFilter VariableSearchFilter::createShaderTypeFilter (glu::ShaderType type) 55 { 56 DE_ASSERT(type < glu::SHADERTYPE_LAST); 57 58 VariableSearchFilter filter; 59 filter.m_shaderTypeBits = (1u << type); 60 return filter; 61 } 62 63 VariableSearchFilter VariableSearchFilter::createStorageFilter (glu::Storage storage) 64 { 65 DE_ASSERT(storage < glu::STORAGE_LAST); 66 67 VariableSearchFilter filter; 68 filter.m_storageBits = (1u << storage); 69 return filter; 70 } 71 72 VariableSearchFilter VariableSearchFilter::createShaderTypeStorageFilter (glu::ShaderType type, glu::Storage storage) 73 { 74 return logicalAnd(createShaderTypeFilter(type), createStorageFilter(storage)); 75 } 76 77 VariableSearchFilter VariableSearchFilter::logicalOr (const VariableSearchFilter& a, const VariableSearchFilter& b) 78 { 79 VariableSearchFilter filter; 80 filter.m_shaderTypeBits = a.m_shaderTypeBits | b.m_shaderTypeBits; 81 filter.m_storageBits = a.m_storageBits | b.m_storageBits; 82 return filter; 83 } 84 85 VariableSearchFilter VariableSearchFilter::logicalAnd (const VariableSearchFilter& a, const VariableSearchFilter& b) 86 { 87 VariableSearchFilter filter; 88 filter.m_shaderTypeBits = a.m_shaderTypeBits & b.m_shaderTypeBits; 89 filter.m_storageBits = a.m_storageBits & b.m_storageBits; 90 return filter; 91 } 92 93 bool VariableSearchFilter::matchesFilter (const ProgramInterfaceDefinition::Shader* shader) const 94 { 95 DE_ASSERT(shader->getType() < glu::SHADERTYPE_LAST); 96 return (m_shaderTypeBits & (1u << shader->getType())) != 0; 97 } 98 99 bool VariableSearchFilter::matchesFilter (const glu::VariableDeclaration& variable) const 100 { 101 DE_ASSERT(variable.storage < glu::STORAGE_LAST); 102 return (m_storageBits & (1u << variable.storage)) != 0; 103 } 104 105 bool VariableSearchFilter::matchesFilter (const glu::InterfaceBlock& block) const 106 { 107 DE_ASSERT(block.storage < glu::STORAGE_LAST); 108 return (m_storageBits & (1u << block.storage)) != 0; 109 } 110 111 } // ProgramInterfaceDefinition 112 113 static bool incrementMultiDimensionIndex (std::vector<int>& index, const std::vector<int>& dimensions) 114 { 115 int incrementDimensionNdx = (int)(index.size() - 1); 116 117 while (incrementDimensionNdx >= 0) 118 { 119 if (++index[incrementDimensionNdx] == dimensions[incrementDimensionNdx]) 120 index[incrementDimensionNdx--] = 0; 121 else 122 break; 123 } 124 125 return (incrementDimensionNdx != -1); 126 } 127 128 bool programContainsIOBlocks (const ProgramInterfaceDefinition::Program* program) 129 { 130 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx) 131 { 132 if (shaderContainsIOBlocks(program->getShaders()[shaderNdx])) 133 return true; 134 } 135 136 return false; 137 } 138 139 bool shaderContainsIOBlocks (const ProgramInterfaceDefinition::Shader* shader) 140 { 141 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx) 142 { 143 const glu::Storage storage = shader->getDefaultBlock().interfaceBlocks[ndx].storage; 144 if (storage == glu::STORAGE_IN || 145 storage == glu::STORAGE_OUT || 146 storage == glu::STORAGE_PATCH_IN || 147 storage == glu::STORAGE_PATCH_OUT) 148 { 149 return true; 150 } 151 } 152 return false; 153 } 154 155 glu::ShaderType getProgramTransformFeedbackStage (const ProgramInterfaceDefinition::Program* program) 156 { 157 if (program->hasStage(glu::SHADERTYPE_GEOMETRY)) 158 return glu::SHADERTYPE_GEOMETRY; 159 160 if (program->hasStage(glu::SHADERTYPE_TESSELLATION_EVALUATION)) 161 return glu::SHADERTYPE_TESSELLATION_EVALUATION; 162 163 if (program->hasStage(glu::SHADERTYPE_VERTEX)) 164 return glu::SHADERTYPE_VERTEX; 165 166 DE_ASSERT(false); 167 return glu::SHADERTYPE_LAST; 168 } 169 170 void generateVariableTypeResourceNames (std::vector<std::string>& resources, const std::string& name, const glu::VarType& type, deUint32 resourceNameGenerationFlags) 171 { 172 DE_ASSERT((resourceNameGenerationFlags & (~RESOURCE_NAME_GENERATION_FLAG_MASK)) == 0); 173 174 // remove top-level flag from children 175 const deUint32 childFlags = resourceNameGenerationFlags & ~((deUint32)RESOURCE_NAME_GENERATION_FLAG_TOP_LEVEL_BUFFER_VARIABLE); 176 177 if (type.isBasicType()) 178 resources.push_back(name); 179 else if (type.isStructType()) 180 { 181 const glu::StructType* structType = type.getStructPtr(); 182 for (int ndx = 0; ndx < structType->getNumMembers(); ++ndx) 183 generateVariableTypeResourceNames(resources, name + "." + structType->getMember(ndx).getName(), structType->getMember(ndx).getType(), childFlags); 184 } 185 else if (type.isArrayType()) 186 { 187 // Bottom-level arrays of basic types of a transform feedback variable will produce only the first 188 // element but without the trailing "[0]" 189 if (type.getElementType().isBasicType() && 190 (resourceNameGenerationFlags & RESOURCE_NAME_GENERATION_FLAG_TRANSFORM_FEEDBACK_VARIABLE) != 0) 191 { 192 resources.push_back(name); 193 } 194 // Bottom-level arrays of basic types and SSBO top-level arrays of any type procude only first element 195 else if (type.getElementType().isBasicType() || 196 (resourceNameGenerationFlags & RESOURCE_NAME_GENERATION_FLAG_TOP_LEVEL_BUFFER_VARIABLE) != 0) 197 { 198 generateVariableTypeResourceNames(resources, name + "[0]", type.getElementType(), childFlags); 199 } 200 // Other arrays of aggregate types are expanded 201 else 202 { 203 for (int ndx = 0; ndx < type.getArraySize(); ++ndx) 204 generateVariableTypeResourceNames(resources, name + "[" + de::toString(ndx) + "]", type.getElementType(), childFlags); 205 } 206 } 207 else 208 DE_ASSERT(false); 209 } 210 211 // Program source generation 212 213 namespace 214 { 215 216 using ProgramInterfaceDefinition::VariablePathComponent; 217 using ProgramInterfaceDefinition::VariableSearchFilter; 218 219 static std::string getShaderExtensionDeclarations (const ProgramInterfaceDefinition::Shader* shader) 220 { 221 std::vector<std::string> extensions; 222 std::ostringstream buf; 223 224 if (shader->getType() == glu::SHADERTYPE_GEOMETRY) 225 { 226 extensions.push_back("GL_EXT_geometry_shader"); 227 } 228 else if (shader->getType() == glu::SHADERTYPE_TESSELLATION_CONTROL || 229 shader->getType() == glu::SHADERTYPE_TESSELLATION_EVALUATION) 230 { 231 extensions.push_back("GL_EXT_tessellation_shader"); 232 } 233 234 if (shaderContainsIOBlocks(shader)) 235 extensions.push_back("GL_EXT_shader_io_blocks"); 236 237 for (int ndx = 0; ndx < (int)extensions.size(); ++ndx) 238 buf << "#extension " << extensions[ndx] << " : require\n"; 239 return buf.str(); 240 } 241 242 static std::string getShaderTypeDeclarations (const ProgramInterfaceDefinition::Program* program, glu::ShaderType type) 243 { 244 switch (type) 245 { 246 case glu::SHADERTYPE_VERTEX: 247 return ""; 248 249 case glu::SHADERTYPE_FRAGMENT: 250 return ""; 251 252 case glu::SHADERTYPE_GEOMETRY: 253 { 254 std::ostringstream buf; 255 buf << "layout(points) in;\n" 256 "layout(points, max_vertices=" << program->getGeometryNumOutputVertices() << ") out;\n"; 257 return buf.str(); 258 } 259 260 case glu::SHADERTYPE_TESSELLATION_CONTROL: 261 { 262 std::ostringstream buf; 263 buf << "layout(vertices=" << program->getTessellationNumOutputPatchVertices() << ") out;\n"; 264 return buf.str(); 265 } 266 267 case glu::SHADERTYPE_TESSELLATION_EVALUATION: 268 return "layout(triangles, point_mode) in;\n"; 269 270 case glu::SHADERTYPE_COMPUTE: 271 return "layout(local_size_x=1) in;\n"; 272 273 default: 274 DE_ASSERT(false); 275 return ""; 276 } 277 } 278 279 class StructNameEqualPredicate 280 { 281 public: 282 StructNameEqualPredicate (const char* name) : m_name(name) { } 283 bool operator() (const glu::StructType* type) { return type->hasTypeName() && (deStringEqual(m_name, type->getTypeName()) == DE_TRUE); } 284 private: 285 const char* m_name; 286 }; 287 288 static void collectNamedStructureDefinitions (std::vector<const glu::StructType*>& dst, const glu::VarType& type) 289 { 290 if (type.isBasicType()) 291 return; 292 else if (type.isArrayType()) 293 return collectNamedStructureDefinitions(dst, type.getElementType()); 294 else if (type.isStructType()) 295 { 296 if (type.getStructPtr()->hasTypeName()) 297 { 298 // must be unique (may share the the same struct) 299 std::vector<const glu::StructType*>::iterator where = std::find_if(dst.begin(), dst.end(), StructNameEqualPredicate(type.getStructPtr()->getTypeName())); 300 if (where != dst.end()) 301 { 302 DE_ASSERT(**where == *type.getStructPtr()); 303 304 // identical type has been added already, types of members must be added too 305 return; 306 } 307 } 308 309 // Add types of members first 310 for (int ndx = 0; ndx < type.getStructPtr()->getNumMembers(); ++ndx) 311 collectNamedStructureDefinitions(dst, type.getStructPtr()->getMember(ndx).getType()); 312 313 dst.push_back(type.getStructPtr()); 314 } 315 else 316 DE_ASSERT(false); 317 } 318 319 static void writeStructureDefinitions (std::ostringstream& buf, const ProgramInterfaceDefinition::DefaultBlock& defaultBlock) 320 { 321 std::vector<const glu::StructType*> namedStructs; 322 323 // Collect all structs in post order 324 325 for (int ndx = 0; ndx < (int)defaultBlock.variables.size(); ++ndx) 326 collectNamedStructureDefinitions(namedStructs, defaultBlock.variables[ndx].varType); 327 328 for (int blockNdx = 0; blockNdx < (int)defaultBlock.interfaceBlocks.size(); ++blockNdx) 329 for (int ndx = 0; ndx < (int)defaultBlock.interfaceBlocks[blockNdx].variables.size(); ++ndx) 330 collectNamedStructureDefinitions(namedStructs, defaultBlock.interfaceBlocks[blockNdx].variables[ndx].varType); 331 332 // Write 333 334 for (int structNdx = 0; structNdx < (int)namedStructs.size(); ++structNdx) 335 { 336 buf << "struct " << namedStructs[structNdx]->getTypeName() << "\n" 337 "{\n"; 338 339 for (int memberNdx = 0; memberNdx < namedStructs[structNdx]->getNumMembers(); ++memberNdx) 340 buf << glu::indent(1) << glu::declare(namedStructs[structNdx]->getMember(memberNdx).getType(), namedStructs[structNdx]->getMember(memberNdx).getName(), 1) << ";\n"; 341 342 buf << "};\n"; 343 } 344 345 if (!namedStructs.empty()) 346 buf << "\n"; 347 } 348 349 static void writeInterfaceBlock (std::ostringstream& buf, const glu::InterfaceBlock& interfaceBlock) 350 { 351 buf << interfaceBlock.layout; 352 353 if (interfaceBlock.layout != glu::Layout()) 354 buf << " "; 355 356 buf << glu::getStorageName(interfaceBlock.storage) << " " << interfaceBlock.interfaceName << "\n" 357 << "{\n"; 358 359 for (int ndx = 0; ndx < (int)interfaceBlock.variables.size(); ++ndx) 360 buf << glu::indent(1) << interfaceBlock.variables[ndx] << ";\n"; 361 362 buf << "}"; 363 364 if (!interfaceBlock.instanceName.empty()) 365 buf << " " << interfaceBlock.instanceName; 366 367 for (int dimensionNdx = 0; dimensionNdx < (int)interfaceBlock.dimensions.size(); ++dimensionNdx) 368 buf << "[" << interfaceBlock.dimensions[dimensionNdx] << "]"; 369 370 buf << ";\n\n"; 371 } 372 373 static bool isReadableInterface (const glu::InterfaceBlock& interface) 374 { 375 return interface.storage == glu::STORAGE_UNIFORM || 376 interface.storage == glu::STORAGE_IN || 377 interface.storage == glu::STORAGE_PATCH_IN || 378 (interface.storage == glu::STORAGE_BUFFER && (interface.memoryAccessQualifierFlags & glu::MEMORYACCESSQUALIFIER_WRITEONLY_BIT) == 0); 379 } 380 381 static bool isWritableInterface (const glu::InterfaceBlock& interface) 382 { 383 return interface.storage == glu::STORAGE_OUT || 384 interface.storage == glu::STORAGE_PATCH_OUT || 385 (interface.storage == glu::STORAGE_BUFFER && (interface.memoryAccessQualifierFlags & glu::MEMORYACCESSQUALIFIER_READONLY_BIT) == 0); 386 } 387 388 389 static void writeVariableReadAccumulateExpression (std::ostringstream& buf, 390 const std::string& accumulatorName, 391 const std::string& name, 392 glu::ShaderType shaderType, 393 glu::Storage storage, 394 const ProgramInterfaceDefinition::Program* program, 395 const glu::VarType& varType) 396 { 397 if (varType.isBasicType()) 398 { 399 buf << "\t" << accumulatorName << " += "; 400 401 if (glu::isDataTypeScalar(varType.getBasicType())) 402 buf << "vec4(float(" << name << "))"; 403 else if (glu::isDataTypeVector(varType.getBasicType())) 404 buf << "vec4(" << name << ".xyxy)"; 405 else if (glu::isDataTypeMatrix(varType.getBasicType())) 406 buf << "vec4(float(" << name << "[0][0]))"; 407 else if (glu::isDataTypeSamplerMultisample(varType.getBasicType())) 408 buf << "vec4(float(textureSize(" << name << ").x))"; 409 else if (glu::isDataTypeSampler(varType.getBasicType())) 410 buf << "vec4(float(textureSize(" << name << ", 0).x))"; 411 else if (glu::isDataTypeImage(varType.getBasicType())) 412 buf << "vec4(float(imageSize(" << name << ").x))"; 413 else if (varType.getBasicType() == glu::TYPE_UINT_ATOMIC_COUNTER) 414 buf << "vec4(float(atomicCounterIncrement(" << name << ")))"; 415 else 416 DE_ASSERT(false); 417 418 buf << ";\n"; 419 } 420 else if (varType.isStructType()) 421 { 422 for (int ndx = 0; ndx < varType.getStructPtr()->getNumMembers(); ++ndx) 423 writeVariableReadAccumulateExpression(buf, 424 accumulatorName, 425 name + "." + varType.getStructPtr()->getMember(ndx).getName(), 426 shaderType, 427 storage, 428 program, 429 varType.getStructPtr()->getMember(ndx).getType()); 430 } 431 else if (varType.isArrayType()) 432 { 433 if (varType.getArraySize() != glu::VarType::UNSIZED_ARRAY) 434 { 435 for (int ndx = 0; ndx < varType.getArraySize(); ++ndx) 436 writeVariableReadAccumulateExpression(buf, 437 accumulatorName, 438 name + "[" + de::toString(ndx) + "]", 439 shaderType, 440 storage, 441 program, 442 varType.getElementType()); 443 } 444 else if (storage == glu::STORAGE_BUFFER) 445 { 446 // run-time sized array, read arbitrary 447 writeVariableReadAccumulateExpression(buf, 448 accumulatorName, 449 name + "[8]", 450 shaderType, 451 storage, 452 program, 453 varType.getElementType()); 454 } 455 else 456 { 457 DE_ASSERT(storage == glu::STORAGE_IN); 458 459 if (shaderType == glu::SHADERTYPE_GEOMETRY) 460 { 461 // implicit sized geometry input array, size = primitive size. Just reading first is enough 462 writeVariableReadAccumulateExpression(buf, 463 accumulatorName, 464 name + "[0]", 465 shaderType, 466 storage, 467 program, 468 varType.getElementType()); 469 } 470 else if (shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL) 471 { 472 // implicit sized tessellation input array, size = input patch max size. Just reading current is enough 473 writeVariableReadAccumulateExpression(buf, 474 accumulatorName, 475 name + "[gl_InvocationID]", 476 shaderType, 477 storage, 478 program, 479 varType.getElementType()); 480 } 481 else if (shaderType == glu::SHADERTYPE_TESSELLATION_EVALUATION) 482 { 483 // implicit sized tessellation input array, size = output patch max size. Read all to prevent optimizations 484 DE_ASSERT(program->getTessellationNumOutputPatchVertices() > 0); 485 for (int ndx = 0; ndx < (int)program->getTessellationNumOutputPatchVertices(); ++ndx) 486 { 487 writeVariableReadAccumulateExpression(buf, 488 accumulatorName, 489 name + "[" + de::toString(ndx) + "]", 490 shaderType, 491 storage, 492 program, 493 varType.getElementType()); 494 } 495 } 496 else 497 DE_ASSERT(false); 498 } 499 } 500 else 501 DE_ASSERT(false); 502 } 503 504 static void writeInterfaceReadAccumulateExpression (std::ostringstream& buf, 505 const std::string& accumulatorName, 506 const glu::InterfaceBlock& block, 507 glu::ShaderType shaderType, 508 const ProgramInterfaceDefinition::Program* program) 509 { 510 if (block.dimensions.empty()) 511 { 512 const std::string prefix = (block.instanceName.empty()) ? ("") : (block.instanceName + "."); 513 514 for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx) 515 { 516 writeVariableReadAccumulateExpression(buf, 517 accumulatorName, 518 prefix + block.variables[ndx].name, 519 shaderType, 520 block.storage, 521 program, 522 block.variables[ndx].varType); 523 } 524 } 525 else 526 { 527 std::vector<int> index(block.dimensions.size(), 0); 528 529 for (;;) 530 { 531 // access element 532 { 533 std::ostringstream name; 534 name << block.instanceName; 535 536 for (int dimensionNdx = 0; dimensionNdx < (int)block.dimensions.size(); ++dimensionNdx) 537 name << "[" << index[dimensionNdx] << "]"; 538 539 for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx) 540 { 541 writeVariableReadAccumulateExpression(buf, 542 accumulatorName, 543 name.str() + "." + block.variables[ndx].name, 544 shaderType, 545 block.storage, 546 program, 547 block.variables[ndx].varType); 548 } 549 } 550 551 // increment index 552 if (!incrementMultiDimensionIndex(index, block.dimensions)) 553 break; 554 } 555 } 556 } 557 558 static void writeVariableWriteExpression (std::ostringstream& buf, 559 const std::string& sourceVec4Name, 560 const std::string& name, 561 glu::ShaderType shaderType, 562 glu::Storage storage, 563 const ProgramInterfaceDefinition::Program* program, 564 const glu::VarType& varType) 565 { 566 if (varType.isBasicType()) 567 { 568 buf << "\t" << name << " = "; 569 570 if (glu::isDataTypeScalar(varType.getBasicType())) 571 buf << glu::getDataTypeName(varType.getBasicType()) << "(" << sourceVec4Name << ".y)"; 572 else if (glu::isDataTypeVector(varType.getBasicType()) || glu::isDataTypeMatrix(varType.getBasicType())) 573 buf << glu::getDataTypeName(varType.getBasicType()) << "(" << glu::getDataTypeName(glu::getDataTypeScalarType(varType.getBasicType())) << "(" << sourceVec4Name << ".y))"; 574 else 575 DE_ASSERT(false); 576 577 buf << ";\n"; 578 } 579 else if (varType.isStructType()) 580 { 581 for (int ndx = 0; ndx < varType.getStructPtr()->getNumMembers(); ++ndx) 582 writeVariableWriteExpression(buf, 583 sourceVec4Name, 584 name + "." + varType.getStructPtr()->getMember(ndx).getName(), 585 shaderType, 586 storage, 587 program, 588 varType.getStructPtr()->getMember(ndx).getType()); 589 } 590 else if (varType.isArrayType()) 591 { 592 if (varType.getArraySize() != glu::VarType::UNSIZED_ARRAY) 593 { 594 for (int ndx = 0; ndx < varType.getArraySize(); ++ndx) 595 writeVariableWriteExpression(buf, 596 sourceVec4Name, 597 name + "[" + de::toString(ndx) + "]", 598 shaderType, 599 storage, 600 program, 601 varType.getElementType()); 602 } 603 else if (storage == glu::STORAGE_BUFFER) 604 { 605 // run-time sized array, write arbitrary 606 writeVariableWriteExpression(buf, 607 sourceVec4Name, 608 name + "[9]", 609 shaderType, 610 storage, 611 program, 612 varType.getElementType()); 613 } 614 else 615 { 616 DE_ASSERT(storage == glu::STORAGE_OUT); 617 618 if (shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL) 619 { 620 // implicit sized tessellation onput array, size = output patch max size. Can only write to gl_InvocationID 621 writeVariableWriteExpression(buf, 622 sourceVec4Name, 623 name + "[gl_InvocationID]", 624 shaderType, 625 storage, 626 program, 627 varType.getElementType()); 628 } 629 else 630 DE_ASSERT(false); 631 } 632 } 633 else 634 DE_ASSERT(false); 635 } 636 637 static void writeInterfaceWriteExpression (std::ostringstream& buf, 638 const std::string& sourceVec4Name, 639 const glu::InterfaceBlock& block, 640 glu::ShaderType shaderType, 641 const ProgramInterfaceDefinition::Program* program) 642 { 643 if (block.dimensions.empty()) 644 { 645 const std::string prefix = (block.instanceName.empty()) ? ("") : (block.instanceName + "."); 646 647 for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx) 648 { 649 writeVariableWriteExpression(buf, 650 sourceVec4Name, 651 prefix + block.variables[ndx].name, 652 shaderType, 653 block.storage, 654 program, 655 block.variables[ndx].varType); 656 } 657 } 658 else 659 { 660 std::vector<int> index(block.dimensions.size(), 0); 661 662 for (;;) 663 { 664 // access element 665 { 666 std::ostringstream name; 667 name << block.instanceName; 668 669 for (int dimensionNdx = 0; dimensionNdx < (int)block.dimensions.size(); ++dimensionNdx) 670 name << "[" << index[dimensionNdx] << "]"; 671 672 for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx) 673 { 674 writeVariableWriteExpression(buf, 675 sourceVec4Name, 676 name.str() + "." + block.variables[ndx].name, 677 shaderType, 678 block.storage, 679 program, 680 block.variables[ndx].varType); 681 } 682 } 683 684 // increment index 685 if (!incrementMultiDimensionIndex(index, block.dimensions)) 686 break; 687 } 688 } 689 } 690 691 static bool traverseVariablePath (std::vector<VariablePathComponent>& typePath, const char* subPath, const glu::VarType& type) 692 { 693 glu::VarTokenizer tokenizer(subPath); 694 695 typePath.push_back(VariablePathComponent(&type)); 696 697 if (tokenizer.getToken() == glu::VarTokenizer::TOKEN_END) 698 return true; 699 700 if (type.isStructType() && tokenizer.getToken() == glu::VarTokenizer::TOKEN_PERIOD) 701 { 702 tokenizer.advance(); 703 704 // malformed path 705 if (tokenizer.getToken() != glu::VarTokenizer::TOKEN_IDENTIFIER) 706 return false; 707 708 for (int memberNdx = 0; memberNdx < type.getStructPtr()->getNumMembers(); ++memberNdx) 709 if (type.getStructPtr()->getMember(memberNdx).getName() == tokenizer.getIdentifier()) 710 return traverseVariablePath(typePath, subPath + tokenizer.getCurrentTokenEndLocation(), type.getStructPtr()->getMember(memberNdx).getType()); 711 712 // malformed path, no such member 713 return false; 714 } 715 else if (type.isArrayType() && tokenizer.getToken() == glu::VarTokenizer::TOKEN_LEFT_BRACKET) 716 { 717 tokenizer.advance(); 718 719 // malformed path 720 if (tokenizer.getToken() != glu::VarTokenizer::TOKEN_NUMBER) 721 return false; 722 723 tokenizer.advance(); 724 if (tokenizer.getToken() != glu::VarTokenizer::TOKEN_RIGHT_BRACKET) 725 return false; 726 727 return traverseVariablePath(typePath, subPath + tokenizer.getCurrentTokenEndLocation(), type.getElementType()); 728 } 729 730 return false; 731 } 732 733 static bool traverseVariablePath (std::vector<VariablePathComponent>& typePath, const std::string& path, const glu::VariableDeclaration& var) 734 { 735 if (glu::parseVariableName(path.c_str()) != var.name) 736 return false; 737 738 typePath.push_back(VariablePathComponent(&var)); 739 return traverseVariablePath(typePath, path.c_str() + var.name.length(), var.varType); 740 } 741 742 static bool traverseShaderVariablePath (std::vector<VariablePathComponent>& typePath, const ProgramInterfaceDefinition::Shader* shader, const std::string& path, const VariableSearchFilter& filter) 743 { 744 // Default block variable? 745 for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().variables.size(); ++varNdx) 746 if (filter.matchesFilter(shader->getDefaultBlock().variables[varNdx])) 747 if (traverseVariablePath(typePath, path, shader->getDefaultBlock().variables[varNdx])) 748 return true; 749 750 // is variable an interface block variable? 751 { 752 const std::string blockName = glu::parseVariableName(path.c_str()); 753 754 for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx) 755 { 756 if (!filter.matchesFilter(shader->getDefaultBlock().interfaceBlocks[interfaceNdx])) 757 continue; 758 759 if (shader->getDefaultBlock().interfaceBlocks[interfaceNdx].interfaceName == blockName) 760 { 761 // resource is a member of a named interface block 762 // \note there is no array index specifier even if the interface is declared as an array of instances 763 const std::string blockMemberPath = path.substr(blockName.size() + 1); 764 const std::string blockMemeberName = glu::parseVariableName(blockMemberPath.c_str()); 765 766 for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables.size(); ++varNdx) 767 { 768 if (shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables[varNdx].name == blockMemeberName) 769 { 770 typePath.push_back(VariablePathComponent(&shader->getDefaultBlock().interfaceBlocks[interfaceNdx])); 771 return traverseVariablePath(typePath, blockMemberPath, shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables[varNdx]); 772 } 773 } 774 775 // terminate search 776 return false; 777 } 778 else if (shader->getDefaultBlock().interfaceBlocks[interfaceNdx].instanceName.empty()) 779 { 780 const std::string blockMemeberName = glu::parseVariableName(path.c_str()); 781 782 // unnamed block contains such variable? 783 for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables.size(); ++varNdx) 784 { 785 if (shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables[varNdx].name == blockMemeberName) 786 { 787 typePath.push_back(VariablePathComponent(&shader->getDefaultBlock().interfaceBlocks[interfaceNdx])); 788 return traverseVariablePath(typePath, path, shader->getDefaultBlock().interfaceBlocks[interfaceNdx].variables[varNdx]); 789 } 790 } 791 792 // continue search 793 } 794 } 795 } 796 797 return false; 798 } 799 800 static bool traverseProgramVariablePath (std::vector<VariablePathComponent>& typePath, const ProgramInterfaceDefinition::Program* program, const std::string& path, const VariableSearchFilter& filter) 801 { 802 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx) 803 { 804 const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx]; 805 806 if (filter.matchesFilter(shader)) 807 { 808 // \note modifying output variable even when returning false 809 typePath.clear(); 810 if (traverseShaderVariablePath(typePath, shader, path, filter)) 811 return true; 812 } 813 } 814 815 return false; 816 } 817 818 static bool containsSubType (const glu::VarType& complexType, glu::DataType basicType) 819 { 820 if (complexType.isBasicType()) 821 { 822 return complexType.getBasicType() == basicType; 823 } 824 else if (complexType.isArrayType()) 825 { 826 return containsSubType(complexType.getElementType(), basicType); 827 } 828 else if (complexType.isStructType()) 829 { 830 for (int ndx = 0; ndx < complexType.getStructPtr()->getNumMembers(); ++ndx) 831 if (containsSubType(complexType.getStructPtr()->getMember(ndx).getType(), basicType)) 832 return true; 833 return false; 834 } 835 else 836 { 837 DE_ASSERT(false); 838 return false; 839 } 840 } 841 842 static int getNumShaderBlocks (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage) 843 { 844 int retVal = 0; 845 846 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx) 847 { 848 if (shader->getDefaultBlock().interfaceBlocks[ndx].storage == storage) 849 { 850 int numInstances = 1; 851 852 for (int dimensionNdx = 0; dimensionNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].dimensions.size(); ++dimensionNdx) 853 numInstances *= shader->getDefaultBlock().interfaceBlocks[ndx].dimensions[dimensionNdx]; 854 855 retVal += numInstances; 856 } 857 } 858 859 return retVal; 860 } 861 862 static int getNumAtomicCounterBuffers (const ProgramInterfaceDefinition::Shader* shader) 863 { 864 std::set<int> buffers; 865 866 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx) 867 { 868 if (containsSubType(shader->getDefaultBlock().variables[ndx].varType, glu::TYPE_UINT_ATOMIC_COUNTER)) 869 { 870 DE_ASSERT(shader->getDefaultBlock().variables[ndx].layout.binding != -1); 871 buffers.insert(shader->getDefaultBlock().variables[ndx].layout.binding); 872 } 873 } 874 875 return (int)buffers.size(); 876 } 877 878 template <typename DataTypeMap> 879 static int accumulateComplexType (const glu::VarType& complexType, const DataTypeMap& dTypeMap) 880 { 881 if (complexType.isBasicType()) 882 return dTypeMap(complexType.getBasicType()); 883 else if (complexType.isArrayType()) 884 { 885 const int arraySize = (complexType.getArraySize() == glu::VarType::UNSIZED_ARRAY) ? (1) : (complexType.getArraySize()); 886 return arraySize * accumulateComplexType(complexType.getElementType(), dTypeMap); 887 } 888 else if (complexType.isStructType()) 889 { 890 int sum = 0; 891 for (int ndx = 0; ndx < complexType.getStructPtr()->getNumMembers(); ++ndx) 892 sum += accumulateComplexType(complexType.getStructPtr()->getMember(ndx).getType(), dTypeMap); 893 return sum; 894 } 895 else 896 { 897 DE_ASSERT(false); 898 return false; 899 } 900 } 901 902 template <typename InterfaceBlockFilter, typename VarDeclFilter, typename DataTypeMap> 903 static int accumulateShader (const ProgramInterfaceDefinition::Shader* shader, 904 const InterfaceBlockFilter& ibFilter, 905 const VarDeclFilter& vdFilter, 906 const DataTypeMap& dMap) 907 { 908 int retVal = 0; 909 910 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx) 911 { 912 if (ibFilter(shader->getDefaultBlock().interfaceBlocks[ndx])) 913 { 914 int numInstances = 1; 915 916 for (int dimensionNdx = 0; dimensionNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].dimensions.size(); ++dimensionNdx) 917 numInstances *= shader->getDefaultBlock().interfaceBlocks[ndx].dimensions[dimensionNdx]; 918 919 for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].variables.size(); ++varNdx) 920 retVal += numInstances * accumulateComplexType(shader->getDefaultBlock().interfaceBlocks[ndx].variables[varNdx].varType, dMap); 921 } 922 } 923 924 for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().variables.size(); ++varNdx) 925 if (vdFilter(shader->getDefaultBlock().variables[varNdx])) 926 retVal += accumulateComplexType(shader->getDefaultBlock().variables[varNdx].varType, dMap); 927 928 return retVal; 929 } 930 931 static bool dummyTrueConstantTypeFilter (glu::DataType d) 932 { 933 DE_UNREF(d); 934 return true; 935 } 936 937 class InstanceCounter 938 { 939 public: 940 InstanceCounter (bool (*predicate)(glu::DataType)) 941 : m_predicate(predicate) 942 { 943 } 944 945 int operator() (glu::DataType t) const 946 { 947 return (m_predicate(t)) ? (1) : (0); 948 } 949 950 private: 951 bool (*const m_predicate)(glu::DataType); 952 }; 953 954 class InterfaceBlockStorageFilter 955 { 956 public: 957 InterfaceBlockStorageFilter (glu::Storage storage) 958 : m_storage(storage) 959 { 960 } 961 962 bool operator() (const glu::InterfaceBlock& b) const 963 { 964 return m_storage == b.storage; 965 } 966 967 private: 968 const glu::Storage m_storage; 969 }; 970 971 class VariableDeclarationStorageFilter 972 { 973 public: 974 VariableDeclarationStorageFilter (glu::Storage storage) 975 : m_storage(storage) 976 { 977 } 978 979 bool operator() (const glu::VariableDeclaration& d) const 980 { 981 return m_storage == d.storage; 982 } 983 984 private: 985 const glu::Storage m_storage; 986 }; 987 988 static int getNumTypeInstances (const glu::VarType& complexType, bool (*predicate)(glu::DataType)) 989 { 990 return accumulateComplexType(complexType, InstanceCounter(predicate)); 991 } 992 993 static int getNumTypeInstances (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage, bool (*predicate)(glu::DataType)) 994 { 995 return accumulateShader(shader, InterfaceBlockStorageFilter(storage), VariableDeclarationStorageFilter(storage), InstanceCounter(predicate)); 996 } 997 998 static int getNumTypeInstances (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage) 999 { 1000 return getNumTypeInstances(shader, storage, dummyTrueConstantTypeFilter); 1001 } 1002 1003 static int accumulateShaderStorage (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage, int (*typeMap)(glu::DataType)) 1004 { 1005 return accumulateShader(shader, InterfaceBlockStorageFilter(storage), VariableDeclarationStorageFilter(storage), typeMap); 1006 } 1007 1008 static int getNumDataTypeComponents (glu::DataType type) 1009 { 1010 if (glu::isDataTypeScalarOrVector(type) || glu::isDataTypeMatrix(type)) 1011 return glu::getDataTypeScalarSize(type); 1012 else 1013 return 0; 1014 } 1015 1016 static int getNumDataTypeVectors (glu::DataType type) 1017 { 1018 if (glu::isDataTypeScalar(type)) 1019 return 1; 1020 else if (glu::isDataTypeVector(type)) 1021 return 1; 1022 else if (glu::isDataTypeMatrix(type)) 1023 return glu::getDataTypeMatrixNumColumns(type); 1024 else 1025 return 0; 1026 } 1027 1028 static int getNumComponents (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage) 1029 { 1030 return accumulateShaderStorage(shader, storage, getNumDataTypeComponents); 1031 } 1032 1033 static int getNumVectors (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage) 1034 { 1035 return accumulateShaderStorage(shader, storage, getNumDataTypeVectors); 1036 } 1037 1038 static int getNumDefaultBlockComponents (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage) 1039 { 1040 int retVal = 0; 1041 1042 for (int varNdx = 0; varNdx < (int)shader->getDefaultBlock().variables.size(); ++varNdx) 1043 if (shader->getDefaultBlock().variables[varNdx].storage == storage) 1044 retVal += accumulateComplexType(shader->getDefaultBlock().variables[varNdx].varType, getNumDataTypeComponents); 1045 1046 return retVal; 1047 } 1048 1049 static int getMaxBufferBinding (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage) 1050 { 1051 int maxBinding = -1; 1052 1053 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx) 1054 { 1055 if (shader->getDefaultBlock().interfaceBlocks[ndx].storage == storage) 1056 { 1057 const int binding = (shader->getDefaultBlock().interfaceBlocks[ndx].layout.binding == -1) ? (0) : (shader->getDefaultBlock().interfaceBlocks[ndx].layout.binding); 1058 int numInstances = 1; 1059 1060 for (int dimensionNdx = 0; dimensionNdx < (int)shader->getDefaultBlock().interfaceBlocks[ndx].dimensions.size(); ++dimensionNdx) 1061 numInstances *= shader->getDefaultBlock().interfaceBlocks[ndx].dimensions[dimensionNdx]; 1062 1063 maxBinding = de::max(maxBinding, binding + numInstances - 1); 1064 } 1065 } 1066 1067 return (int)maxBinding; 1068 } 1069 1070 static int getBufferTypeSize (glu::DataType type, glu::MatrixOrder order) 1071 { 1072 // assume vec4 alignments, should produce values greater than or equal to the actual resource usage 1073 int numVectors = 0; 1074 1075 if (glu::isDataTypeScalarOrVector(type)) 1076 numVectors = 1; 1077 else if (glu::isDataTypeMatrix(type) && order == glu::MATRIXORDER_ROW_MAJOR) 1078 numVectors = glu::getDataTypeMatrixNumRows(type); 1079 else if (glu::isDataTypeMatrix(type) && order != glu::MATRIXORDER_ROW_MAJOR) 1080 numVectors = glu::getDataTypeMatrixNumColumns(type); 1081 else 1082 DE_ASSERT(false); 1083 1084 return 4 * numVectors; 1085 } 1086 1087 static int getBufferVariableSize (const glu::VarType& type, glu::MatrixOrder order) 1088 { 1089 if (type.isBasicType()) 1090 return getBufferTypeSize(type.getBasicType(), order); 1091 else if (type.isArrayType()) 1092 { 1093 const int arraySize = (type.getArraySize() == glu::VarType::UNSIZED_ARRAY) ? (1) : (type.getArraySize()); 1094 return arraySize * getBufferVariableSize(type.getElementType(), order); 1095 } 1096 else if (type.isStructType()) 1097 { 1098 int sum = 0; 1099 for (int ndx = 0; ndx < type.getStructPtr()->getNumMembers(); ++ndx) 1100 sum += getBufferVariableSize(type.getStructPtr()->getMember(ndx).getType(), order); 1101 return sum; 1102 } 1103 else 1104 { 1105 DE_ASSERT(false); 1106 return false; 1107 } 1108 } 1109 1110 static int getBufferSize (const glu::InterfaceBlock& block, glu::MatrixOrder blockOrder) 1111 { 1112 int size = 0; 1113 1114 for (int ndx = 0; ndx < (int)block.variables.size(); ++ndx) 1115 size += getBufferVariableSize(block.variables[ndx].varType, (block.variables[ndx].layout.matrixOrder == glu::MATRIXORDER_LAST) ? (blockOrder) : (block.variables[ndx].layout.matrixOrder)); 1116 1117 return size; 1118 } 1119 1120 static int getBufferMaxSize (const ProgramInterfaceDefinition::Shader* shader, glu::Storage storage) 1121 { 1122 int maxSize = 0; 1123 1124 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx) 1125 if (shader->getDefaultBlock().interfaceBlocks[ndx].storage == storage) 1126 maxSize = de::max(maxSize, getBufferSize(shader->getDefaultBlock().interfaceBlocks[ndx], shader->getDefaultBlock().interfaceBlocks[ndx].layout.matrixOrder)); 1127 1128 return (int)maxSize; 1129 } 1130 1131 static int getAtomicCounterMaxBinding (const ProgramInterfaceDefinition::Shader* shader) 1132 { 1133 int maxBinding = -1; 1134 1135 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx) 1136 { 1137 if (containsSubType(shader->getDefaultBlock().variables[ndx].varType, glu::TYPE_UINT_ATOMIC_COUNTER)) 1138 { 1139 DE_ASSERT(shader->getDefaultBlock().variables[ndx].layout.binding != -1); 1140 maxBinding = de::max(maxBinding, shader->getDefaultBlock().variables[ndx].layout.binding); 1141 } 1142 } 1143 1144 return (int)maxBinding; 1145 } 1146 1147 static int getUniformMaxBinding (const ProgramInterfaceDefinition::Shader* shader, bool (*predicate)(glu::DataType)) 1148 { 1149 int maxBinding = -1; 1150 1151 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx) 1152 { 1153 const int binding = (shader->getDefaultBlock().variables[ndx].layout.binding == -1) ? (0) : (shader->getDefaultBlock().variables[ndx].layout.binding); 1154 const int numInstances = getNumTypeInstances(shader->getDefaultBlock().variables[ndx].varType, predicate); 1155 1156 maxBinding = de::max(maxBinding, binding + numInstances - 1); 1157 } 1158 1159 return maxBinding; 1160 } 1161 1162 static int getAtomicCounterMaxBufferSize (const ProgramInterfaceDefinition::Shader* shader) 1163 { 1164 std::map<int, int> bufferSizes; 1165 int maxSize = 0; 1166 1167 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx) 1168 { 1169 if (containsSubType(shader->getDefaultBlock().variables[ndx].varType, glu::TYPE_UINT_ATOMIC_COUNTER)) 1170 { 1171 const int bufferBinding = shader->getDefaultBlock().variables[ndx].layout.binding; 1172 const int offset = (shader->getDefaultBlock().variables[ndx].layout.offset == -1) ? (0) : (shader->getDefaultBlock().variables[ndx].layout.offset); 1173 const int size = offset + 4 * getNumTypeInstances(shader->getDefaultBlock().variables[ndx].varType, glu::isDataTypeAtomicCounter); 1174 1175 DE_ASSERT(shader->getDefaultBlock().variables[ndx].layout.binding != -1); 1176 1177 if (bufferSizes.find(bufferBinding) == bufferSizes.end()) 1178 bufferSizes[bufferBinding] = size; 1179 else 1180 bufferSizes[bufferBinding] = de::max<int>(bufferSizes[bufferBinding], size); 1181 } 1182 } 1183 1184 for (std::map<int, int>::iterator it = bufferSizes.begin(); it != bufferSizes.end(); ++it) 1185 maxSize = de::max<int>(maxSize, it->second); 1186 1187 return maxSize; 1188 } 1189 1190 static int getNumFeedbackVaryingComponents (const ProgramInterfaceDefinition::Program* program, const std::string& name) 1191 { 1192 std::vector<VariablePathComponent> path; 1193 1194 if (name == "gl_Position") 1195 return 4; 1196 1197 DE_ASSERT(deStringBeginsWith(name.c_str(), "gl_") == DE_FALSE); 1198 1199 if (!traverseProgramVariablePath(path, program, name, VariableSearchFilter::createShaderTypeStorageFilter(getProgramTransformFeedbackStage(program), glu::STORAGE_OUT))) 1200 DE_ASSERT(false); // Program failed validate, invalid operation 1201 1202 return accumulateComplexType(*path.back().getVariableType(), getNumDataTypeComponents); 1203 } 1204 1205 static int getNumXFBComponents (const ProgramInterfaceDefinition::Program* program) 1206 { 1207 int numComponents = 0; 1208 1209 for (int ndx = 0; ndx < (int)program->getTransformFeedbackVaryings().size(); ++ndx) 1210 numComponents += getNumFeedbackVaryingComponents(program, program->getTransformFeedbackVaryings()[ndx]); 1211 1212 return numComponents; 1213 } 1214 1215 static int getNumMaxXFBOutputComponents (const ProgramInterfaceDefinition::Program* program) 1216 { 1217 int numComponents = 0; 1218 1219 for (int ndx = 0; ndx < (int)program->getTransformFeedbackVaryings().size(); ++ndx) 1220 numComponents = de::max(numComponents, getNumFeedbackVaryingComponents(program, program->getTransformFeedbackVaryings()[ndx])); 1221 1222 return numComponents; 1223 } 1224 1225 static int getFragmentOutputMaxLocation (const ProgramInterfaceDefinition::Shader* shader) 1226 { 1227 DE_ASSERT(shader->getType() == glu::SHADERTYPE_FRAGMENT); 1228 1229 int maxOutputLocation = -1; 1230 1231 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx) 1232 { 1233 if (shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_OUT) 1234 { 1235 // missing location qualifier means location == 0 1236 const int outputLocation = (shader->getDefaultBlock().variables[ndx].layout.location == -1) 1237 ? (0) 1238 : (shader->getDefaultBlock().variables[ndx].layout.location); 1239 1240 // only basic types or arrays of basic types possible 1241 DE_ASSERT(!shader->getDefaultBlock().variables[ndx].varType.isStructType()); 1242 1243 const int locationSlotsTaken = (shader->getDefaultBlock().variables[ndx].varType.isArrayType()) 1244 ? (shader->getDefaultBlock().variables[ndx].varType.getArraySize()) 1245 : (1); 1246 1247 maxOutputLocation = de::max(maxOutputLocation, outputLocation + locationSlotsTaken - 1); 1248 } 1249 } 1250 1251 return maxOutputLocation; 1252 } 1253 1254 } // anonymous 1255 1256 std::vector<std::string> getProgramInterfaceBlockMemberResourceList (const glu::InterfaceBlock& interfaceBlock) 1257 { 1258 const std::string namePrefix = (!interfaceBlock.instanceName.empty()) ? (interfaceBlock.interfaceName + ".") : (""); 1259 const bool isTopLevelBufferVariable = (interfaceBlock.storage == glu::STORAGE_BUFFER); 1260 std::vector<std::string> resources; 1261 1262 // \note this is defined in the GLSL spec, not in the GL spec 1263 for (int variableNdx = 0; variableNdx < (int)interfaceBlock.variables.size(); ++variableNdx) 1264 generateVariableTypeResourceNames(resources, 1265 namePrefix + interfaceBlock.variables[variableNdx].name, 1266 interfaceBlock.variables[variableNdx].varType, 1267 (isTopLevelBufferVariable) ? 1268 (RESOURCE_NAME_GENERATION_FLAG_TOP_LEVEL_BUFFER_VARIABLE) : 1269 (RESOURCE_NAME_GENERATION_FLAG_DEFAULT)); 1270 1271 return resources; 1272 } 1273 1274 std::vector<std::string> getProgramInterfaceResourceList (const ProgramInterfaceDefinition::Program* program, ProgramInterface interface) 1275 { 1276 // The same {uniform (block), buffer (variable)} can exist in multiple shaders, remove duplicates but keep order 1277 const bool removeDuplicated = (interface == PROGRAMINTERFACE_UNIFORM) || 1278 (interface == PROGRAMINTERFACE_UNIFORM_BLOCK) || 1279 (interface == PROGRAMINTERFACE_BUFFER_VARIABLE) || 1280 (interface == PROGRAMINTERFACE_SHADER_STORAGE_BLOCK); 1281 std::vector<std::string> resources; 1282 1283 switch (interface) 1284 { 1285 case PROGRAMINTERFACE_UNIFORM: 1286 case PROGRAMINTERFACE_BUFFER_VARIABLE: 1287 { 1288 const glu::Storage storage = (interface == PROGRAMINTERFACE_UNIFORM) ? (glu::STORAGE_UNIFORM) : (glu::STORAGE_BUFFER); 1289 1290 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx) 1291 { 1292 const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx]; 1293 1294 for (int variableNdx = 0; variableNdx < (int)shader->getDefaultBlock().variables.size(); ++variableNdx) 1295 if (shader->getDefaultBlock().variables[variableNdx].storage == storage) 1296 generateVariableTypeResourceNames(resources, 1297 shader->getDefaultBlock().variables[variableNdx].name, 1298 shader->getDefaultBlock().variables[variableNdx].varType, 1299 RESOURCE_NAME_GENERATION_FLAG_DEFAULT); 1300 1301 for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx) 1302 { 1303 const glu::InterfaceBlock& interfaceBlock = shader->getDefaultBlock().interfaceBlocks[interfaceNdx]; 1304 if (interfaceBlock.storage == storage) 1305 { 1306 const std::vector<std::string> blockResources = getProgramInterfaceBlockMemberResourceList(interfaceBlock); 1307 resources.insert(resources.end(), blockResources.begin(), blockResources.end()); 1308 } 1309 } 1310 } 1311 break; 1312 } 1313 1314 case PROGRAMINTERFACE_UNIFORM_BLOCK: 1315 case PROGRAMINTERFACE_SHADER_STORAGE_BLOCK: 1316 { 1317 const glu::Storage storage = (interface == PROGRAMINTERFACE_UNIFORM_BLOCK) ? (glu::STORAGE_UNIFORM) : (glu::STORAGE_BUFFER); 1318 1319 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx) 1320 { 1321 const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx]; 1322 for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx) 1323 { 1324 const glu::InterfaceBlock& interfaceBlock = shader->getDefaultBlock().interfaceBlocks[interfaceNdx]; 1325 if (interfaceBlock.storage == storage) 1326 { 1327 std::vector<int> index(interfaceBlock.dimensions.size(), 0); 1328 1329 for (;;) 1330 { 1331 // add resource string for each element 1332 { 1333 std::ostringstream name; 1334 name << interfaceBlock.interfaceName; 1335 1336 for (int dimensionNdx = 0; dimensionNdx < (int)interfaceBlock.dimensions.size(); ++dimensionNdx) 1337 name << "[" << index[dimensionNdx] << "]"; 1338 1339 resources.push_back(name.str()); 1340 } 1341 1342 // increment index 1343 if (!incrementMultiDimensionIndex(index, interfaceBlock.dimensions)) 1344 break; 1345 } 1346 } 1347 } 1348 } 1349 break; 1350 } 1351 1352 case PROGRAMINTERFACE_PROGRAM_INPUT: 1353 case PROGRAMINTERFACE_PROGRAM_OUTPUT: 1354 { 1355 const glu::Storage queryStorage = (interface == PROGRAMINTERFACE_PROGRAM_INPUT) ? (glu::STORAGE_IN) : (glu::STORAGE_OUT); 1356 const glu::Storage queryPatchStorage = (interface == PROGRAMINTERFACE_PROGRAM_INPUT) ? (glu::STORAGE_PATCH_IN) : (glu::STORAGE_PATCH_OUT); 1357 const glu::ShaderType shaderType = (interface == PROGRAMINTERFACE_PROGRAM_INPUT) ? (program->getFirstStage()) : (program->getLastStage()); 1358 1359 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx) 1360 { 1361 const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx]; 1362 1363 if (shader->getType() != shaderType) 1364 continue; 1365 1366 for (int variableNdx = 0; variableNdx < (int)shader->getDefaultBlock().variables.size(); ++variableNdx) 1367 { 1368 const glu::Storage variableStorage = shader->getDefaultBlock().variables[variableNdx].storage; 1369 if (variableStorage == queryStorage || variableStorage == queryPatchStorage) 1370 generateVariableTypeResourceNames(resources, 1371 shader->getDefaultBlock().variables[variableNdx].name, 1372 shader->getDefaultBlock().variables[variableNdx].varType, 1373 RESOURCE_NAME_GENERATION_FLAG_DEFAULT); 1374 } 1375 1376 for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx) 1377 { 1378 const glu::InterfaceBlock& interfaceBlock = shader->getDefaultBlock().interfaceBlocks[interfaceNdx]; 1379 if (interfaceBlock.storage == queryStorage || interfaceBlock.storage == queryPatchStorage) 1380 { 1381 const std::vector<std::string> blockResources = getProgramInterfaceBlockMemberResourceList(interfaceBlock); 1382 resources.insert(resources.end(), blockResources.begin(), blockResources.end()); 1383 } 1384 } 1385 } 1386 1387 // built-ins 1388 if (interface == PROGRAMINTERFACE_PROGRAM_INPUT) 1389 { 1390 if (shaderType == glu::SHADERTYPE_VERTEX && resources.empty()) 1391 resources.push_back("gl_VertexID"); // only read from when there are no other inputs 1392 else if (shaderType == glu::SHADERTYPE_FRAGMENT && resources.empty()) 1393 resources.push_back("gl_FragCoord"); // only read from when there are no other inputs 1394 else if (shaderType == glu::SHADERTYPE_GEOMETRY) 1395 resources.push_back("gl_PerVertex.gl_Position"); 1396 else if (shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL) 1397 { 1398 resources.push_back("gl_InvocationID"); 1399 resources.push_back("gl_PerVertex.gl_Position"); 1400 } 1401 else if (shaderType == glu::SHADERTYPE_TESSELLATION_EVALUATION) 1402 resources.push_back("gl_PerVertex.gl_Position"); 1403 else if (shaderType == glu::SHADERTYPE_COMPUTE && resources.empty()) 1404 resources.push_back("gl_NumWorkGroups"); // only read from when there are no other inputs 1405 } 1406 else if (interface == PROGRAMINTERFACE_PROGRAM_OUTPUT) 1407 { 1408 if (shaderType == glu::SHADERTYPE_VERTEX) 1409 resources.push_back("gl_Position"); 1410 else if (shaderType == glu::SHADERTYPE_FRAGMENT && resources.empty()) 1411 resources.push_back("gl_FragDepth"); // only written to when there are no other outputs 1412 else if (shaderType == glu::SHADERTYPE_GEOMETRY) 1413 resources.push_back("gl_Position"); 1414 else if (shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL) 1415 { 1416 resources.push_back("gl_PerVertex.gl_Position"); 1417 resources.push_back("gl_TessLevelOuter[0]"); 1418 resources.push_back("gl_TessLevelInner[0]"); 1419 } 1420 else if (shaderType == glu::SHADERTYPE_TESSELLATION_EVALUATION) 1421 resources.push_back("gl_Position"); 1422 } 1423 1424 break; 1425 } 1426 1427 case PROGRAMINTERFACE_TRANSFORM_FEEDBACK_VARYING: 1428 { 1429 const glu::ShaderType xfbStage = getProgramTransformFeedbackStage(program); 1430 1431 for (int varyingNdx = 0; varyingNdx < (int)program->getTransformFeedbackVaryings().size(); ++varyingNdx) 1432 { 1433 const std::string& varyingName = program->getTransformFeedbackVaryings()[varyingNdx]; 1434 1435 if (deStringBeginsWith(varyingName.c_str(), "gl_")) 1436 resources.push_back(varyingName); // builtin 1437 else 1438 { 1439 std::vector<VariablePathComponent> path; 1440 1441 if (!traverseProgramVariablePath(path, program, varyingName, VariableSearchFilter::createShaderTypeStorageFilter(xfbStage, glu::STORAGE_OUT))) 1442 DE_ASSERT(false); // Program failed validate, invalid operation 1443 1444 generateVariableTypeResourceNames(resources, 1445 varyingName, 1446 *path.back().getVariableType(), 1447 RESOURCE_NAME_GENERATION_FLAG_TRANSFORM_FEEDBACK_VARIABLE); 1448 } 1449 } 1450 1451 break; 1452 } 1453 1454 default: 1455 DE_ASSERT(false); 1456 } 1457 1458 if (removeDuplicated) 1459 { 1460 std::set<std::string> addedVariables; 1461 std::vector<std::string> uniqueResouces; 1462 1463 for (int ndx = 0; ndx < (int)resources.size(); ++ndx) 1464 { 1465 if (addedVariables.find(resources[ndx]) == addedVariables.end()) 1466 { 1467 addedVariables.insert(resources[ndx]); 1468 uniqueResouces.push_back(resources[ndx]); 1469 } 1470 } 1471 1472 uniqueResouces.swap(resources); 1473 } 1474 1475 return resources; 1476 } 1477 1478 glu::ProgramSources generateProgramInterfaceProgramSources (const ProgramInterfaceDefinition::Program* program) 1479 { 1480 glu::ProgramSources sources; 1481 1482 DE_ASSERT(program->isValid()); 1483 1484 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx) 1485 { 1486 const ProgramInterfaceDefinition::Shader* shader = program->getShaders()[shaderNdx]; 1487 bool containsUserDefinedOutputs = false; 1488 bool containsUserDefinedInputs = false; 1489 std::ostringstream sourceBuf; 1490 std::ostringstream usageBuf; 1491 1492 sourceBuf << glu::getGLSLVersionDeclaration(shader->getVersion()) << "\n" 1493 << getShaderExtensionDeclarations(shader) 1494 << getShaderTypeDeclarations(program, shader->getType()) 1495 << "\n"; 1496 1497 // Struct definitions 1498 1499 writeStructureDefinitions(sourceBuf, shader->getDefaultBlock()); 1500 1501 // variables in the default scope 1502 1503 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx) 1504 sourceBuf << shader->getDefaultBlock().variables[ndx] << ";\n"; 1505 1506 if (!shader->getDefaultBlock().variables.empty()) 1507 sourceBuf << "\n"; 1508 1509 // Interface blocks 1510 1511 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++ndx) 1512 writeInterfaceBlock(sourceBuf, shader->getDefaultBlock().interfaceBlocks[ndx]); 1513 1514 // Use inputs and outputs so that they won't be removed by the optimizer 1515 1516 usageBuf << "highp vec4 readInputs()\n" 1517 "{\n" 1518 " highp vec4 retValue = vec4(0.0);\n"; 1519 1520 // User-defined inputs 1521 1522 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx) 1523 { 1524 if (shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_IN || 1525 shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_PATCH_IN || 1526 shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_UNIFORM) 1527 { 1528 writeVariableReadAccumulateExpression(usageBuf, 1529 "retValue", 1530 shader->getDefaultBlock().variables[ndx].name, 1531 shader->getType(), 1532 shader->getDefaultBlock().variables[ndx].storage, 1533 program, 1534 shader->getDefaultBlock().variables[ndx].varType); 1535 containsUserDefinedInputs = true; 1536 } 1537 } 1538 1539 for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx) 1540 { 1541 const glu::InterfaceBlock& interface = shader->getDefaultBlock().interfaceBlocks[interfaceNdx]; 1542 if (isReadableInterface(interface)) 1543 { 1544 writeInterfaceReadAccumulateExpression(usageBuf, 1545 "retValue", 1546 interface, 1547 shader->getType(), 1548 program); 1549 containsUserDefinedInputs = true; 1550 } 1551 } 1552 1553 // Built-in-inputs 1554 1555 switch (shader->getType()) 1556 { 1557 case glu::SHADERTYPE_VERTEX: 1558 // make readInputs to never be compile time constant 1559 if (!containsUserDefinedInputs) 1560 usageBuf << " retValue += vec4(float(gl_VertexID));\n"; 1561 break; 1562 1563 case glu::SHADERTYPE_FRAGMENT: 1564 // make readInputs to never be compile time constant 1565 if (!containsUserDefinedInputs) 1566 usageBuf << " retValue += gl_FragCoord;\n"; 1567 break; 1568 case glu::SHADERTYPE_GEOMETRY: 1569 // always use previous stage's output values so that previous stage won't be optimized out 1570 usageBuf << " retValue += gl_in[0].gl_Position;\n"; 1571 break; 1572 case glu::SHADERTYPE_TESSELLATION_CONTROL: 1573 // always use previous stage's output values so that previous stage won't be optimized out 1574 usageBuf << " retValue += gl_in[0].gl_Position;\n"; 1575 break; 1576 case glu::SHADERTYPE_TESSELLATION_EVALUATION: 1577 // always use previous stage's output values so that previous stage won't be optimized out 1578 usageBuf << " retValue += gl_in[0].gl_Position;\n"; 1579 break; 1580 1581 case glu::SHADERTYPE_COMPUTE: 1582 // make readInputs to never be compile time constant 1583 if (!containsUserDefinedInputs) 1584 usageBuf << " retValue += vec4(float(gl_NumWorkGroups.x));\n"; 1585 break; 1586 default: 1587 DE_ASSERT(false); 1588 } 1589 1590 usageBuf << " return retValue;\n" 1591 "}\n\n"; 1592 1593 usageBuf << "void writeOutputs(in highp vec4 dummyValue)\n" 1594 "{\n"; 1595 1596 // User-defined outputs 1597 1598 for (int ndx = 0; ndx < (int)shader->getDefaultBlock().variables.size(); ++ndx) 1599 { 1600 if (shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_OUT || 1601 shader->getDefaultBlock().variables[ndx].storage == glu::STORAGE_PATCH_OUT) 1602 { 1603 writeVariableWriteExpression(usageBuf, 1604 "dummyValue", 1605 shader->getDefaultBlock().variables[ndx].name, 1606 shader->getType(), 1607 shader->getDefaultBlock().variables[ndx].storage, 1608 program, 1609 shader->getDefaultBlock().variables[ndx].varType); 1610 containsUserDefinedOutputs = true; 1611 } 1612 } 1613 1614 for (int interfaceNdx = 0; interfaceNdx < (int)shader->getDefaultBlock().interfaceBlocks.size(); ++interfaceNdx) 1615 { 1616 const glu::InterfaceBlock& interface = shader->getDefaultBlock().interfaceBlocks[interfaceNdx]; 1617 if (isWritableInterface(interface)) 1618 { 1619 writeInterfaceWriteExpression(usageBuf, "dummyValue", interface, shader->getType(), program); 1620 containsUserDefinedOutputs = true; 1621 } 1622 } 1623 1624 // Builtin-outputs that must be written to 1625 1626 if (shader->getType() == glu::SHADERTYPE_VERTEX) 1627 usageBuf << " gl_Position = dummyValue;\n"; 1628 else if (shader->getType() == glu::SHADERTYPE_GEOMETRY) 1629 usageBuf << " gl_Position = dummyValue;\n" 1630 " EmitVertex();\n"; 1631 else if (shader->getType() == glu::SHADERTYPE_TESSELLATION_CONTROL) 1632 usageBuf << " gl_out[gl_InvocationID].gl_Position = dummyValue;\n" 1633 " gl_TessLevelOuter[0] = 2.8;\n" 1634 " gl_TessLevelOuter[1] = 2.8;\n" 1635 " gl_TessLevelOuter[2] = 2.8;\n" 1636 " gl_TessLevelOuter[3] = 2.8;\n" 1637 " gl_TessLevelInner[0] = 2.8;\n" 1638 " gl_TessLevelInner[1] = 2.8;\n"; 1639 else if (shader->getType() == glu::SHADERTYPE_TESSELLATION_EVALUATION) 1640 usageBuf << " gl_Position = dummyValue;\n"; 1641 1642 // Output to sink input data to 1643 1644 if (!containsUserDefinedOutputs) 1645 { 1646 if (shader->getType() == glu::SHADERTYPE_FRAGMENT) 1647 usageBuf << " gl_FragDepth = dot(dummyValue.xy, dummyValue.xw);\n"; 1648 else if (shader->getType() == glu::SHADERTYPE_COMPUTE) 1649 usageBuf << " dummyOutputBlock.dummyValue = dummyValue;\n"; 1650 } 1651 1652 usageBuf << "}\n\n" 1653 "void main()\n" 1654 "{\n" 1655 " writeOutputs(readInputs());\n" 1656 "}\n"; 1657 1658 // Interface for dummy output 1659 1660 if (shader->getType() == glu::SHADERTYPE_COMPUTE && !containsUserDefinedOutputs) 1661 { 1662 sourceBuf << "writeonly buffer DummyOutputInterface\n" 1663 << "{\n" 1664 << " highp vec4 dummyValue;\n" 1665 << "} dummyOutputBlock;\n\n"; 1666 } 1667 1668 sources << glu::ShaderSource(shader->getType(), sourceBuf.str() + usageBuf.str()); 1669 } 1670 1671 if (program->isSeparable()) 1672 sources << glu::ProgramSeparable(true); 1673 1674 for (int ndx = 0; ndx < (int)program->getTransformFeedbackVaryings().size(); ++ndx) 1675 sources << glu::TransformFeedbackVarying(program->getTransformFeedbackVaryings()[ndx]); 1676 1677 if (program->getTransformFeedbackMode()) 1678 sources << glu::TransformFeedbackMode(program->getTransformFeedbackMode()); 1679 1680 return sources; 1681 } 1682 1683 bool findProgramVariablePathByPathName (std::vector<VariablePathComponent>& typePath, const ProgramInterfaceDefinition::Program* program, const std::string& pathName, const VariableSearchFilter& filter) 1684 { 1685 std::vector<VariablePathComponent> modifiedPath; 1686 1687 if (!traverseProgramVariablePath(modifiedPath, program, pathName, filter)) 1688 return false; 1689 1690 // modify param only on success 1691 typePath.swap(modifiedPath); 1692 return true; 1693 } 1694 1695 ProgramInterfaceDefinition::ShaderResourceUsage getShaderResourceUsage (const ProgramInterfaceDefinition::Program* program, const ProgramInterfaceDefinition::Shader* shader) 1696 { 1697 ProgramInterfaceDefinition::ShaderResourceUsage retVal; 1698 1699 retVal.numInputs = getNumTypeInstances(shader, glu::STORAGE_IN); 1700 retVal.numInputVectors = getNumVectors(shader, glu::STORAGE_IN); 1701 retVal.numInputComponents = getNumComponents(shader, glu::STORAGE_IN); 1702 1703 retVal.numOutputs = getNumTypeInstances(shader, glu::STORAGE_OUT); 1704 retVal.numOutputVectors = getNumVectors(shader, glu::STORAGE_OUT); 1705 retVal.numOutputComponents = getNumComponents(shader, glu::STORAGE_OUT); 1706 1707 retVal.numPatchInputComponents = getNumComponents(shader, glu::STORAGE_PATCH_IN); 1708 retVal.numPatchOutputComponents = getNumComponents(shader, glu::STORAGE_PATCH_OUT); 1709 1710 retVal.numDefaultBlockUniformComponents = getNumDefaultBlockComponents(shader, glu::STORAGE_UNIFORM); 1711 retVal.numCombinedUniformComponents = getNumComponents(shader, glu::STORAGE_UNIFORM); 1712 retVal.numUniformVectors = getNumVectors(shader, glu::STORAGE_UNIFORM); 1713 1714 retVal.numSamplers = getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeSampler); 1715 retVal.numImages = getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeImage); 1716 1717 retVal.numAtomicCounterBuffers = getNumAtomicCounterBuffers(shader); 1718 retVal.numAtomicCounters = getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeAtomicCounter); 1719 1720 retVal.numUniformBlocks = getNumShaderBlocks(shader, glu::STORAGE_UNIFORM); 1721 retVal.numShaderStorageBlocks = getNumShaderBlocks(shader, glu::STORAGE_BUFFER); 1722 1723 // add builtins 1724 switch (shader->getType()) 1725 { 1726 case glu::SHADERTYPE_VERTEX: 1727 // gl_Position is not counted 1728 break; 1729 1730 case glu::SHADERTYPE_FRAGMENT: 1731 // nada 1732 break; 1733 1734 case glu::SHADERTYPE_GEOMETRY: 1735 // gl_Position in (point mode => size 1) 1736 retVal.numInputs += 1; 1737 retVal.numInputVectors += 1; 1738 retVal.numInputComponents += 4; 1739 1740 // gl_Position out 1741 retVal.numOutputs += 1; 1742 retVal.numOutputVectors += 1; 1743 retVal.numOutputComponents += 4; 1744 break; 1745 1746 case glu::SHADERTYPE_TESSELLATION_CONTROL: 1747 // gl_Position in is read up to gl_InstanceID 1748 retVal.numInputs += 1 * program->getTessellationNumOutputPatchVertices(); 1749 retVal.numInputVectors += 1 * program->getTessellationNumOutputPatchVertices(); 1750 retVal.numInputComponents += 4 * program->getTessellationNumOutputPatchVertices(); 1751 1752 // gl_Position out, size = num patch out vertices 1753 retVal.numOutputs += 1 * program->getTessellationNumOutputPatchVertices(); 1754 retVal.numOutputVectors += 1 * program->getTessellationNumOutputPatchVertices(); 1755 retVal.numOutputComponents += 4 * program->getTessellationNumOutputPatchVertices(); 1756 break; 1757 1758 case glu::SHADERTYPE_TESSELLATION_EVALUATION: 1759 // gl_Position in is read up to gl_InstanceID 1760 retVal.numInputs += 1 * program->getTessellationNumOutputPatchVertices(); 1761 retVal.numInputVectors += 1 * program->getTessellationNumOutputPatchVertices(); 1762 retVal.numInputComponents += 4 * program->getTessellationNumOutputPatchVertices(); 1763 1764 // gl_Position out 1765 retVal.numOutputs += 1; 1766 retVal.numOutputVectors += 1; 1767 retVal.numOutputComponents += 4; 1768 break; 1769 1770 case glu::SHADERTYPE_COMPUTE: 1771 // nada 1772 break; 1773 1774 default: 1775 DE_ASSERT(false); 1776 break; 1777 } 1778 return retVal; 1779 } 1780 1781 ProgramInterfaceDefinition::ProgramResourceUsage getCombinedProgramResourceUsage (const ProgramInterfaceDefinition::Program* program) 1782 { 1783 ProgramInterfaceDefinition::ProgramResourceUsage retVal; 1784 int numVertexOutputComponents = 0; 1785 int numFragmentInputComponents = 0; 1786 int numVertexOutputVectors = 0; 1787 int numFragmentInputVectors = 0; 1788 1789 retVal.uniformBufferMaxBinding = -1; // max binding is inclusive upper bound. Allow 0 bindings by using negative value 1790 retVal.uniformBufferMaxSize = 0; 1791 retVal.numUniformBlocks = 0; 1792 retVal.numCombinedVertexUniformComponents = 0; 1793 retVal.numCombinedFragmentUniformComponents = 0; 1794 retVal.numCombinedGeometryUniformComponents = 0; 1795 retVal.numCombinedTessControlUniformComponents = 0; 1796 retVal.numCombinedTessEvalUniformComponents = 0; 1797 retVal.shaderStorageBufferMaxBinding = -1; // see above 1798 retVal.shaderStorageBufferMaxSize = 0; 1799 retVal.numShaderStorageBlocks = 0; 1800 retVal.numVaryingComponents = 0; 1801 retVal.numVaryingVectors = 0; 1802 retVal.numCombinedSamplers = 0; 1803 retVal.atomicCounterBufferMaxBinding = -1; // see above 1804 retVal.atomicCounterBufferMaxSize = 0; 1805 retVal.numAtomicCounterBuffers = 0; 1806 retVal.numAtomicCounters = 0; 1807 retVal.maxImageBinding = -1; // see above 1808 retVal.numCombinedImages = 0; 1809 retVal.numCombinedOutputResources = 0; 1810 retVal.numXFBInterleavedComponents = 0; 1811 retVal.numXFBSeparateAttribs = 0; 1812 retVal.numXFBSeparateComponents = 0; 1813 retVal.fragmentOutputMaxBinding = -1; // see above 1814 1815 for (int shaderNdx = 0; shaderNdx < (int)program->getShaders().size(); ++shaderNdx) 1816 { 1817 const ProgramInterfaceDefinition::Shader* const shader = program->getShaders()[shaderNdx]; 1818 1819 retVal.uniformBufferMaxBinding = de::max(retVal.uniformBufferMaxBinding, getMaxBufferBinding(shader, glu::STORAGE_UNIFORM)); 1820 retVal.uniformBufferMaxSize = de::max(retVal.uniformBufferMaxSize, getBufferMaxSize(shader, glu::STORAGE_UNIFORM)); 1821 retVal.numUniformBlocks += getNumShaderBlocks(shader, glu::STORAGE_UNIFORM); 1822 1823 switch (shader->getType()) 1824 { 1825 case glu::SHADERTYPE_VERTEX: retVal.numCombinedVertexUniformComponents += getNumComponents(shader, glu::STORAGE_UNIFORM); break; 1826 case glu::SHADERTYPE_FRAGMENT: retVal.numCombinedFragmentUniformComponents += getNumComponents(shader, glu::STORAGE_UNIFORM); break; 1827 case glu::SHADERTYPE_GEOMETRY: retVal.numCombinedGeometryUniformComponents += getNumComponents(shader, glu::STORAGE_UNIFORM); break; 1828 case glu::SHADERTYPE_TESSELLATION_CONTROL: retVal.numCombinedTessControlUniformComponents += getNumComponents(shader, glu::STORAGE_UNIFORM); break; 1829 case glu::SHADERTYPE_TESSELLATION_EVALUATION: retVal.numCombinedTessEvalUniformComponents += getNumComponents(shader, glu::STORAGE_UNIFORM); break; 1830 default: break; 1831 } 1832 1833 retVal.shaderStorageBufferMaxBinding = de::max(retVal.shaderStorageBufferMaxBinding, getMaxBufferBinding(shader, glu::STORAGE_BUFFER)); 1834 retVal.shaderStorageBufferMaxSize = de::max(retVal.shaderStorageBufferMaxSize, getBufferMaxSize(shader, glu::STORAGE_BUFFER)); 1835 retVal.numShaderStorageBlocks += getNumShaderBlocks(shader, glu::STORAGE_BUFFER); 1836 1837 if (shader->getType() == glu::SHADERTYPE_VERTEX) 1838 { 1839 numVertexOutputComponents += getNumComponents(shader, glu::STORAGE_OUT); 1840 numVertexOutputVectors += getNumVectors(shader, glu::STORAGE_OUT); 1841 } 1842 else if (shader->getType() == glu::SHADERTYPE_FRAGMENT) 1843 { 1844 numFragmentInputComponents += getNumComponents(shader, glu::STORAGE_IN); 1845 numFragmentInputVectors += getNumVectors(shader, glu::STORAGE_IN); 1846 } 1847 1848 retVal.numCombinedSamplers += getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeSampler); 1849 1850 retVal.atomicCounterBufferMaxBinding = de::max(retVal.atomicCounterBufferMaxBinding, getAtomicCounterMaxBinding(shader)); 1851 retVal.atomicCounterBufferMaxSize = de::max(retVal.atomicCounterBufferMaxSize, getAtomicCounterMaxBufferSize(shader)); 1852 retVal.numAtomicCounterBuffers += getNumAtomicCounterBuffers(shader); 1853 retVal.numAtomicCounters += getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeAtomicCounter); 1854 retVal.maxImageBinding = de::max(retVal.maxImageBinding, getUniformMaxBinding(shader, glu::isDataTypeImage)); 1855 retVal.numCombinedImages += getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeImage); 1856 1857 retVal.numCombinedOutputResources += getNumTypeInstances(shader, glu::STORAGE_UNIFORM, glu::isDataTypeImage); 1858 retVal.numCombinedOutputResources += getNumShaderBlocks(shader, glu::STORAGE_BUFFER); 1859 1860 if (shader->getType() == glu::SHADERTYPE_FRAGMENT) 1861 { 1862 retVal.numCombinedOutputResources += getNumVectors(shader, glu::STORAGE_OUT); 1863 retVal.fragmentOutputMaxBinding = de::max(retVal.fragmentOutputMaxBinding, getFragmentOutputMaxLocation(shader)); 1864 } 1865 } 1866 1867 if (program->getTransformFeedbackMode() == GL_INTERLEAVED_ATTRIBS) 1868 retVal.numXFBInterleavedComponents = getNumXFBComponents(program); 1869 else if (program->getTransformFeedbackMode() == GL_SEPARATE_ATTRIBS) 1870 { 1871 retVal.numXFBSeparateAttribs = (int)program->getTransformFeedbackVaryings().size(); 1872 retVal.numXFBSeparateComponents = getNumMaxXFBOutputComponents(program); 1873 } 1874 1875 // legacy limits 1876 retVal.numVaryingComponents = de::max(numVertexOutputComponents, numFragmentInputComponents); 1877 retVal.numVaryingVectors = de::max(numVertexOutputVectors, numFragmentInputVectors); 1878 1879 return retVal; 1880 } 1881 1882 } // Functional 1883 } // gles31 1884 } // deqp 1885