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