CollectVariables.cpp (50157B)
1 // 2 // Copyright 2002 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 // CollectVariables.cpp: Collect lists of shader interface variables based on the AST. 7 8 #include "compiler/translator/CollectVariables.h" 9 10 #include "angle_gl.h" 11 #include "common/utilities.h" 12 #include "compiler/translator/HashNames.h" 13 #include "compiler/translator/SymbolTable.h" 14 #include "compiler/translator/tree_util/IntermTraverse.h" 15 #include "compiler/translator/util.h" 16 17 namespace sh 18 { 19 20 namespace 21 { 22 23 BlockLayoutType GetBlockLayoutType(TLayoutBlockStorage blockStorage) 24 { 25 switch (blockStorage) 26 { 27 case EbsPacked: 28 return BLOCKLAYOUT_PACKED; 29 case EbsShared: 30 return BLOCKLAYOUT_SHARED; 31 case EbsStd140: 32 return BLOCKLAYOUT_STD140; 33 case EbsStd430: 34 return BLOCKLAYOUT_STD430; 35 default: 36 UNREACHABLE(); 37 return BLOCKLAYOUT_SHARED; 38 } 39 } 40 41 BlockType GetBlockType(TQualifier qualifier) 42 { 43 switch (qualifier) 44 { 45 case EvqUniform: 46 return BlockType::BLOCK_UNIFORM; 47 case EvqBuffer: 48 return BlockType::BLOCK_BUFFER; 49 default: 50 UNREACHABLE(); 51 return BlockType::BLOCK_UNIFORM; 52 } 53 } 54 55 template <class VarT> 56 VarT *FindVariable(const ImmutableString &name, std::vector<VarT> *infoList) 57 { 58 // TODO(zmo): optimize this function. 59 for (size_t ii = 0; ii < infoList->size(); ++ii) 60 { 61 if (name == (*infoList)[ii].name) 62 return &((*infoList)[ii]); 63 } 64 65 return nullptr; 66 } 67 68 void MarkActive(ShaderVariable *variable) 69 { 70 if (!variable->active) 71 { 72 if (variable->isStruct()) 73 { 74 // Conservatively assume all fields are statically used as well. 75 for (auto &field : variable->fields) 76 { 77 MarkActive(&field); 78 } 79 } 80 variable->staticUse = true; 81 variable->active = true; 82 } 83 } 84 85 ShaderVariable *FindVariableInInterfaceBlock(const ImmutableString &name, 86 const TInterfaceBlock *interfaceBlock, 87 std::vector<InterfaceBlock> *infoList) 88 { 89 ASSERT(interfaceBlock); 90 InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), infoList); 91 ASSERT(namedBlock); 92 93 // Set static use on the parent interface block here 94 namedBlock->staticUse = true; 95 namedBlock->active = true; 96 return FindVariable(name, &namedBlock->fields); 97 } 98 99 ShaderVariable *FindShaderIOBlockVariable(const ImmutableString &blockName, 100 std::vector<ShaderVariable> *infoList) 101 { 102 for (size_t index = 0; index < infoList->size(); ++index) 103 { 104 if (blockName == (*infoList)[index].structOrBlockName) 105 return &(*infoList)[index]; 106 } 107 108 return nullptr; 109 } 110 111 // Traverses the intermediate tree to collect all attributes, uniforms, varyings, fragment outputs, 112 // shared data and interface blocks. 113 class CollectVariablesTraverser : public TIntermTraverser 114 { 115 public: 116 CollectVariablesTraverser(std::vector<ShaderVariable> *attribs, 117 std::vector<ShaderVariable> *outputVariables, 118 std::vector<ShaderVariable> *uniforms, 119 std::vector<ShaderVariable> *inputVaryings, 120 std::vector<ShaderVariable> *outputVaryings, 121 std::vector<ShaderVariable> *sharedVariables, 122 std::vector<InterfaceBlock> *uniformBlocks, 123 std::vector<InterfaceBlock> *shaderStorageBlocks, 124 ShHashFunction64 hashFunction, 125 TSymbolTable *symbolTable, 126 GLenum shaderType, 127 const TExtensionBehavior &extensionBehavior, 128 const ShBuiltInResources &resources, 129 int tessControlShaderOutputVertices); 130 131 bool visitGlobalQualifierDeclaration(Visit visit, 132 TIntermGlobalQualifierDeclaration *node) override; 133 void visitSymbol(TIntermSymbol *symbol) override; 134 bool visitDeclaration(Visit, TIntermDeclaration *node) override; 135 bool visitBinary(Visit visit, TIntermBinary *binaryNode) override; 136 137 private: 138 std::string getMappedName(const TSymbol *symbol) const; 139 140 void setFieldOrVariableProperties(const TType &type, 141 bool staticUse, 142 bool isShaderIOBlock, 143 bool isPatch, 144 ShaderVariable *variableOut) const; 145 void setFieldProperties(const TType &type, 146 const ImmutableString &name, 147 bool staticUse, 148 bool isShaderIOBlock, 149 bool isPatch, 150 SymbolType symbolType, 151 ShaderVariable *variableOut) const; 152 void setCommonVariableProperties(const TType &type, 153 const TVariable &variable, 154 ShaderVariable *variableOut) const; 155 156 ShaderVariable recordAttribute(const TIntermSymbol &variable) const; 157 ShaderVariable recordOutputVariable(const TIntermSymbol &variable) const; 158 ShaderVariable recordVarying(const TIntermSymbol &variable) const; 159 void recordInterfaceBlock(const char *instanceName, 160 const TType &interfaceBlockType, 161 InterfaceBlock *interfaceBlock) const; 162 ShaderVariable recordUniform(const TIntermSymbol &variable) const; 163 164 void setBuiltInInfoFromSymbol(const TVariable &variable, ShaderVariable *info); 165 166 void recordBuiltInVaryingUsed(const TVariable &variable, 167 bool *addedFlag, 168 std::vector<ShaderVariable> *varyings); 169 void recordBuiltInFragmentOutputUsed(const TVariable &variable, bool *addedFlag); 170 void recordBuiltInAttributeUsed(const TVariable &variable, bool *addedFlag); 171 InterfaceBlock *findNamedInterfaceBlock(const ImmutableString &name) const; 172 173 std::vector<ShaderVariable> *mAttribs; 174 std::vector<ShaderVariable> *mOutputVariables; 175 std::vector<ShaderVariable> *mUniforms; 176 std::vector<ShaderVariable> *mInputVaryings; 177 std::vector<ShaderVariable> *mOutputVaryings; 178 std::vector<ShaderVariable> *mSharedVariables; 179 std::vector<InterfaceBlock> *mUniformBlocks; 180 std::vector<InterfaceBlock> *mShaderStorageBlocks; 181 182 std::map<std::string, ShaderVariable *> mInterfaceBlockFields; 183 184 // Shader uniforms 185 bool mDepthRangeAdded; 186 bool mNumSamplesAdded; 187 188 // Compute Shader builtins 189 bool mNumWorkGroupsAdded; 190 bool mWorkGroupIDAdded; 191 bool mLocalInvocationIDAdded; 192 bool mGlobalInvocationIDAdded; 193 bool mLocalInvocationIndexAdded; 194 195 // Vertex Shader builtins 196 bool mInstanceIDAdded; 197 bool mVertexIDAdded; 198 bool mPointSizeAdded; 199 bool mDrawIDAdded; 200 201 // Vertex Shader and Geometry Shader builtins 202 bool mPositionAdded; 203 bool mClipDistanceAdded; 204 bool mCullDistanceAdded; 205 206 // Fragment Shader builtins 207 bool mPointCoordAdded; 208 bool mFrontFacingAdded; 209 bool mHelperInvocationAdded; 210 bool mFragCoordAdded; 211 bool mLastFragDataAdded; 212 bool mFragColorAdded; 213 bool mFragDataAdded; 214 bool mFragDepthAdded; 215 bool mSecondaryFragColorEXTAdded; 216 bool mSecondaryFragDataEXTAdded; 217 bool mSampleIDAdded; 218 bool mSamplePositionAdded; 219 bool mSampleMaskAdded; 220 bool mSampleMaskInAdded; 221 222 // Geometry and Tessellation Shader builtins 223 bool mPerVertexInAdded; 224 bool mPerVertexOutAdded; 225 226 // Geometry Shader builtins 227 bool mPrimitiveIDInAdded; 228 bool mInvocationIDAdded; 229 230 // Geometry Shader and Fragment Shader builtins 231 bool mPrimitiveIDAdded; 232 bool mLayerAdded; 233 234 // Shared memory variables 235 bool mSharedVariableAdded; 236 237 // Tessellation Shader builtins 238 bool mPatchVerticesInAdded; 239 bool mTessLevelOuterAdded; 240 bool mTessLevelInnerAdded; 241 bool mBoundingBoxAdded; 242 bool mTessCoordAdded; 243 const int mTessControlShaderOutputVertices; 244 245 ShHashFunction64 mHashFunction; 246 247 GLenum mShaderType; 248 const TExtensionBehavior &mExtensionBehavior; 249 const ShBuiltInResources &mResources; 250 }; 251 252 CollectVariablesTraverser::CollectVariablesTraverser( 253 std::vector<sh::ShaderVariable> *attribs, 254 std::vector<sh::ShaderVariable> *outputVariables, 255 std::vector<sh::ShaderVariable> *uniforms, 256 std::vector<sh::ShaderVariable> *inputVaryings, 257 std::vector<sh::ShaderVariable> *outputVaryings, 258 std::vector<sh::ShaderVariable> *sharedVariables, 259 std::vector<sh::InterfaceBlock> *uniformBlocks, 260 std::vector<sh::InterfaceBlock> *shaderStorageBlocks, 261 ShHashFunction64 hashFunction, 262 TSymbolTable *symbolTable, 263 GLenum shaderType, 264 const TExtensionBehavior &extensionBehavior, 265 const ShBuiltInResources &resources, 266 int tessControlShaderOutputVertices) 267 : TIntermTraverser(true, false, false, symbolTable), 268 mAttribs(attribs), 269 mOutputVariables(outputVariables), 270 mUniforms(uniforms), 271 mInputVaryings(inputVaryings), 272 mOutputVaryings(outputVaryings), 273 mSharedVariables(sharedVariables), 274 mUniformBlocks(uniformBlocks), 275 mShaderStorageBlocks(shaderStorageBlocks), 276 mDepthRangeAdded(false), 277 mNumSamplesAdded(false), 278 mNumWorkGroupsAdded(false), 279 mWorkGroupIDAdded(false), 280 mLocalInvocationIDAdded(false), 281 mGlobalInvocationIDAdded(false), 282 mLocalInvocationIndexAdded(false), 283 mInstanceIDAdded(false), 284 mVertexIDAdded(false), 285 mPointSizeAdded(false), 286 mDrawIDAdded(false), 287 mPositionAdded(false), 288 mClipDistanceAdded(false), 289 mCullDistanceAdded(false), 290 mPointCoordAdded(false), 291 mFrontFacingAdded(false), 292 mHelperInvocationAdded(false), 293 mFragCoordAdded(false), 294 mLastFragDataAdded(false), 295 mFragColorAdded(false), 296 mFragDataAdded(false), 297 mFragDepthAdded(false), 298 mSecondaryFragColorEXTAdded(false), 299 mSecondaryFragDataEXTAdded(false), 300 mSampleIDAdded(false), 301 mSamplePositionAdded(false), 302 mSampleMaskAdded(false), 303 mSampleMaskInAdded(false), 304 mPerVertexInAdded(false), 305 mPerVertexOutAdded(false), 306 mPrimitiveIDInAdded(false), 307 mInvocationIDAdded(false), 308 mPrimitiveIDAdded(false), 309 mLayerAdded(false), 310 mSharedVariableAdded(false), 311 mPatchVerticesInAdded(false), 312 mTessLevelOuterAdded(false), 313 mTessLevelInnerAdded(false), 314 mBoundingBoxAdded(false), 315 mTessCoordAdded(false), 316 mTessControlShaderOutputVertices(tessControlShaderOutputVertices), 317 mHashFunction(hashFunction), 318 mShaderType(shaderType), 319 mExtensionBehavior(extensionBehavior), 320 mResources(resources) 321 {} 322 323 std::string CollectVariablesTraverser::getMappedName(const TSymbol *symbol) const 324 { 325 return HashName(symbol, mHashFunction, nullptr).data(); 326 } 327 328 void CollectVariablesTraverser::setBuiltInInfoFromSymbol(const TVariable &variable, 329 ShaderVariable *info) 330 { 331 const TType &type = variable.getType(); 332 333 info->name = variable.name().data(); 334 info->mappedName = variable.name().data(); 335 336 bool isShaderIOBlock = 337 IsShaderIoBlock(type.getQualifier()) && type.getInterfaceBlock() != nullptr; 338 bool isPatch = type.getQualifier() == EvqTessLevelInner || 339 type.getQualifier() == EvqTessLevelOuter || 340 type.getQualifier() == EvqBoundingBox; 341 342 setFieldOrVariableProperties(type, true, isShaderIOBlock, isPatch, info); 343 } 344 345 void CollectVariablesTraverser::recordBuiltInVaryingUsed(const TVariable &variable, 346 bool *addedFlag, 347 std::vector<ShaderVariable> *varyings) 348 { 349 ASSERT(varyings); 350 if (!(*addedFlag)) 351 { 352 ShaderVariable info; 353 setBuiltInInfoFromSymbol(variable, &info); 354 info.active = true; 355 info.isInvariant = mSymbolTable->isVaryingInvariant(variable); 356 357 varyings->push_back(info); 358 (*addedFlag) = true; 359 } 360 } 361 362 void CollectVariablesTraverser::recordBuiltInFragmentOutputUsed(const TVariable &variable, 363 bool *addedFlag) 364 { 365 if (!(*addedFlag)) 366 { 367 ShaderVariable info; 368 setBuiltInInfoFromSymbol(variable, &info); 369 info.active = true; 370 mOutputVariables->push_back(info); 371 (*addedFlag) = true; 372 } 373 } 374 375 void CollectVariablesTraverser::recordBuiltInAttributeUsed(const TVariable &variable, 376 bool *addedFlag) 377 { 378 if (!(*addedFlag)) 379 { 380 ShaderVariable info; 381 setBuiltInInfoFromSymbol(variable, &info); 382 info.active = true; 383 info.location = -1; 384 mAttribs->push_back(info); 385 (*addedFlag) = true; 386 } 387 } 388 389 bool CollectVariablesTraverser::visitGlobalQualifierDeclaration( 390 Visit visit, 391 TIntermGlobalQualifierDeclaration *node) 392 { 393 // We should not mark variables as active just based on an invariant/precise declaration, so we 394 // don't traverse the symbols declared invariant. 395 return false; 396 } 397 398 // We want to check whether a uniform/varying is active because we need to skip updating inactive 399 // ones. We also only count the active ones in packing computing. Also, gl_FragCoord, gl_PointCoord, 400 // and gl_FrontFacing count toward varying counting if they are active in a fragment shader. 401 void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol) 402 { 403 ASSERT(symbol != nullptr); 404 405 if (symbol->variable().symbolType() == SymbolType::AngleInternal || 406 symbol->variable().symbolType() == SymbolType::Empty) 407 { 408 // Internal variables or nameless variables are not collected. 409 return; 410 } 411 412 ShaderVariable *var = nullptr; 413 414 const ImmutableString &symbolName = symbol->getName(); 415 416 // Check the qualifier from the variable, not from the symbol node. The node may have a 417 // different qualifier if it's the result of a folded ternary node. 418 TQualifier qualifier = symbol->variable().getType().getQualifier(); 419 const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock(); 420 421 if (IsVaryingIn(qualifier)) 422 { 423 if (interfaceBlock) 424 { 425 var = FindShaderIOBlockVariable(interfaceBlock->name(), mInputVaryings); 426 } 427 else 428 { 429 var = FindVariable(symbolName, mInputVaryings); 430 } 431 } 432 else if (IsVaryingOut(qualifier)) 433 { 434 if (interfaceBlock) 435 { 436 var = FindShaderIOBlockVariable(interfaceBlock->name(), mOutputVaryings); 437 } 438 else 439 { 440 var = FindVariable(symbolName, mOutputVaryings); 441 } 442 } 443 else if (symbol->getType().getBasicType() == EbtInterfaceBlock) 444 { 445 UNREACHABLE(); 446 } 447 else if (symbolName == "gl_DepthRange") 448 { 449 ASSERT(qualifier == EvqUniform); 450 451 if (!mDepthRangeAdded) 452 { 453 ShaderVariable info; 454 const char kName[] = "gl_DepthRange"; 455 info.name = kName; 456 info.mappedName = kName; 457 info.type = GL_NONE; 458 info.precision = GL_NONE; 459 info.staticUse = true; 460 info.active = true; 461 462 ShaderVariable nearInfo(GL_FLOAT); 463 const char kNearName[] = "near"; 464 nearInfo.name = kNearName; 465 nearInfo.mappedName = kNearName; 466 nearInfo.precision = GL_HIGH_FLOAT; 467 nearInfo.staticUse = true; 468 nearInfo.active = true; 469 470 ShaderVariable farInfo(GL_FLOAT); 471 const char kFarName[] = "far"; 472 farInfo.name = kFarName; 473 farInfo.mappedName = kFarName; 474 farInfo.precision = GL_HIGH_FLOAT; 475 farInfo.staticUse = true; 476 farInfo.active = true; 477 478 ShaderVariable diffInfo(GL_FLOAT); 479 const char kDiffName[] = "diff"; 480 diffInfo.name = kDiffName; 481 diffInfo.mappedName = kDiffName; 482 diffInfo.precision = GL_HIGH_FLOAT; 483 diffInfo.staticUse = true; 484 diffInfo.active = true; 485 486 info.fields.push_back(nearInfo); 487 info.fields.push_back(farInfo); 488 info.fields.push_back(diffInfo); 489 490 mUniforms->push_back(info); 491 mDepthRangeAdded = true; 492 } 493 } 494 else if (symbolName == "gl_NumSamples") 495 { 496 ASSERT(qualifier == EvqUniform); 497 498 if (!mNumSamplesAdded) 499 { 500 ShaderVariable info; 501 const char kName[] = "gl_NumSamples"; 502 info.name = kName; 503 info.mappedName = kName; 504 info.type = GL_INT; 505 info.precision = GL_LOW_INT; 506 info.staticUse = true; 507 info.active = true; 508 509 mUniforms->push_back(info); 510 mNumSamplesAdded = true; 511 } 512 } 513 else 514 { 515 switch (qualifier) 516 { 517 case EvqAttribute: 518 case EvqVertexIn: 519 var = FindVariable(symbolName, mAttribs); 520 break; 521 case EvqFragmentOut: 522 case EvqFragmentInOut: 523 var = FindVariable(symbolName, mOutputVariables); 524 var->isFragmentInOut = qualifier == EvqFragmentInOut; 525 break; 526 case EvqUniform: 527 { 528 if (interfaceBlock) 529 { 530 var = FindVariableInInterfaceBlock(symbolName, interfaceBlock, mUniformBlocks); 531 } 532 else 533 { 534 var = FindVariable(symbolName, mUniforms); 535 } 536 537 // It's an internal error to reference an undefined user uniform 538 ASSERT(!gl::IsBuiltInName(symbolName.data()) || var); 539 } 540 break; 541 case EvqBuffer: 542 { 543 var = 544 FindVariableInInterfaceBlock(symbolName, interfaceBlock, mShaderStorageBlocks); 545 } 546 break; 547 case EvqFragCoord: 548 recordBuiltInVaryingUsed(symbol->variable(), &mFragCoordAdded, mInputVaryings); 549 return; 550 case EvqFrontFacing: 551 recordBuiltInVaryingUsed(symbol->variable(), &mFrontFacingAdded, mInputVaryings); 552 return; 553 case EvqHelperInvocation: 554 recordBuiltInVaryingUsed(symbol->variable(), &mHelperInvocationAdded, 555 mInputVaryings); 556 return; 557 case EvqPointCoord: 558 recordBuiltInVaryingUsed(symbol->variable(), &mPointCoordAdded, mInputVaryings); 559 return; 560 case EvqNumWorkGroups: 561 recordBuiltInAttributeUsed(symbol->variable(), &mNumWorkGroupsAdded); 562 return; 563 case EvqWorkGroupID: 564 recordBuiltInAttributeUsed(symbol->variable(), &mWorkGroupIDAdded); 565 return; 566 case EvqLocalInvocationID: 567 recordBuiltInAttributeUsed(symbol->variable(), &mLocalInvocationIDAdded); 568 return; 569 case EvqGlobalInvocationID: 570 recordBuiltInAttributeUsed(symbol->variable(), &mGlobalInvocationIDAdded); 571 return; 572 case EvqLocalInvocationIndex: 573 recordBuiltInAttributeUsed(symbol->variable(), &mLocalInvocationIndexAdded); 574 return; 575 case EvqInstanceID: 576 // Whenever the initializeBuiltinsForInstancedMultiview option is set, 577 // gl_InstanceID is added inside expressions to initialize ViewID_OVR and 578 // InstanceID. Note that gl_InstanceID is not added to the symbol table for ESSL1 579 // shaders. 580 recordBuiltInAttributeUsed(symbol->variable(), &mInstanceIDAdded); 581 return; 582 case EvqVertexID: 583 recordBuiltInAttributeUsed(symbol->variable(), &mVertexIDAdded); 584 return; 585 case EvqPosition: 586 recordBuiltInVaryingUsed(symbol->variable(), &mPositionAdded, mOutputVaryings); 587 return; 588 case EvqPointSize: 589 recordBuiltInVaryingUsed(symbol->variable(), &mPointSizeAdded, mOutputVaryings); 590 return; 591 case EvqDrawID: 592 recordBuiltInAttributeUsed(symbol->variable(), &mDrawIDAdded); 593 return; 594 case EvqLastFragData: 595 recordBuiltInVaryingUsed(symbol->variable(), &mLastFragDataAdded, mInputVaryings); 596 return; 597 case EvqFragColor: 598 recordBuiltInFragmentOutputUsed(symbol->variable(), &mFragColorAdded); 599 return; 600 case EvqFragData: 601 recordBuiltInFragmentOutputUsed(symbol->variable(), &mFragDataAdded); 602 return; 603 case EvqFragDepth: 604 recordBuiltInFragmentOutputUsed(symbol->variable(), &mFragDepthAdded); 605 return; 606 case EvqSecondaryFragColorEXT: 607 recordBuiltInFragmentOutputUsed(symbol->variable(), &mSecondaryFragColorEXTAdded); 608 return; 609 case EvqSecondaryFragDataEXT: 610 recordBuiltInFragmentOutputUsed(symbol->variable(), &mSecondaryFragDataEXTAdded); 611 return; 612 case EvqInvocationID: 613 recordBuiltInVaryingUsed(symbol->variable(), &mInvocationIDAdded, mInputVaryings); 614 break; 615 case EvqPrimitiveIDIn: 616 recordBuiltInVaryingUsed(symbol->variable(), &mPrimitiveIDInAdded, mInputVaryings); 617 break; 618 case EvqPrimitiveID: 619 if (mShaderType == GL_GEOMETRY_SHADER_EXT) 620 { 621 recordBuiltInVaryingUsed(symbol->variable(), &mPrimitiveIDAdded, 622 mOutputVaryings); 623 } 624 else 625 { 626 ASSERT(mShaderType == GL_FRAGMENT_SHADER || 627 mShaderType == GL_TESS_CONTROL_SHADER || 628 mShaderType == GL_TESS_EVALUATION_SHADER); 629 recordBuiltInVaryingUsed(symbol->variable(), &mPrimitiveIDAdded, 630 mInputVaryings); 631 } 632 break; 633 case EvqLayerOut: 634 if (mShaderType == GL_GEOMETRY_SHADER_EXT) 635 { 636 recordBuiltInVaryingUsed(symbol->variable(), &mLayerAdded, mOutputVaryings); 637 } 638 else 639 { 640 ASSERT(mShaderType == GL_VERTEX_SHADER && 641 (IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview2) || 642 IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview))); 643 } 644 break; 645 case EvqLayerIn: 646 ASSERT(mShaderType == GL_FRAGMENT_SHADER); 647 recordBuiltInVaryingUsed(symbol->variable(), &mLayerAdded, mInputVaryings); 648 break; 649 case EvqShared: 650 if (mShaderType == GL_COMPUTE_SHADER) 651 { 652 recordBuiltInVaryingUsed(symbol->variable(), &mSharedVariableAdded, 653 mSharedVariables); 654 } 655 break; 656 case EvqClipDistance: 657 recordBuiltInVaryingUsed( 658 symbol->variable(), &mClipDistanceAdded, 659 mShaderType == GL_FRAGMENT_SHADER ? mInputVaryings : mOutputVaryings); 660 return; 661 case EvqCullDistance: 662 recordBuiltInVaryingUsed( 663 symbol->variable(), &mCullDistanceAdded, 664 mShaderType == GL_FRAGMENT_SHADER ? mInputVaryings : mOutputVaryings); 665 return; 666 case EvqSampleID: 667 recordBuiltInVaryingUsed(symbol->variable(), &mSampleIDAdded, mInputVaryings); 668 return; 669 case EvqSamplePosition: 670 recordBuiltInVaryingUsed(symbol->variable(), &mSamplePositionAdded, mInputVaryings); 671 return; 672 case EvqSampleMaskIn: 673 recordBuiltInVaryingUsed(symbol->variable(), &mSampleMaskInAdded, mInputVaryings); 674 return; 675 case EvqSampleMask: 676 recordBuiltInFragmentOutputUsed(symbol->variable(), &mSampleMaskAdded); 677 return; 678 case EvqPatchVerticesIn: 679 recordBuiltInVaryingUsed(symbol->variable(), &mPatchVerticesInAdded, 680 mInputVaryings); 681 break; 682 case EvqTessCoord: 683 recordBuiltInVaryingUsed(symbol->variable(), &mTessCoordAdded, mInputVaryings); 684 break; 685 case EvqTessLevelOuter: 686 if (mShaderType == GL_TESS_CONTROL_SHADER) 687 { 688 recordBuiltInVaryingUsed(symbol->variable(), &mTessLevelOuterAdded, 689 mOutputVaryings); 690 } 691 else 692 { 693 ASSERT(mShaderType == GL_TESS_EVALUATION_SHADER); 694 recordBuiltInVaryingUsed(symbol->variable(), &mTessLevelOuterAdded, 695 mInputVaryings); 696 } 697 break; 698 case EvqTessLevelInner: 699 if (mShaderType == GL_TESS_CONTROL_SHADER) 700 { 701 recordBuiltInVaryingUsed(symbol->variable(), &mTessLevelInnerAdded, 702 mOutputVaryings); 703 } 704 else 705 { 706 ASSERT(mShaderType == GL_TESS_EVALUATION_SHADER); 707 recordBuiltInVaryingUsed(symbol->variable(), &mTessLevelInnerAdded, 708 mInputVaryings); 709 } 710 break; 711 case EvqBoundingBox: 712 recordBuiltInVaryingUsed(symbol->variable(), &mBoundingBoxAdded, mOutputVaryings); 713 break; 714 default: 715 break; 716 } 717 } 718 if (var) 719 { 720 MarkActive(var); 721 } 722 } 723 724 void CollectVariablesTraverser::setFieldOrVariableProperties(const TType &type, 725 bool staticUse, 726 bool isShaderIOBlock, 727 bool isPatch, 728 ShaderVariable *variableOut) const 729 { 730 ASSERT(variableOut); 731 732 variableOut->staticUse = staticUse; 733 variableOut->isShaderIOBlock = isShaderIOBlock; 734 variableOut->isPatch = isPatch; 735 736 const TStructure *structure = type.getStruct(); 737 const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock(); 738 if (structure) 739 { 740 // Structures use a NONE type that isn't exposed outside ANGLE. 741 variableOut->type = GL_NONE; 742 if (structure->symbolType() != SymbolType::Empty) 743 { 744 variableOut->structOrBlockName = structure->name().data(); 745 } 746 747 const TFieldList &fields = structure->fields(); 748 749 for (const TField *field : fields) 750 { 751 // Regardless of the variable type (uniform, in/out etc.) its fields are always plain 752 // ShaderVariable objects. 753 ShaderVariable fieldVariable; 754 setFieldProperties(*field->type(), field->name(), staticUse, isShaderIOBlock, isPatch, 755 field->symbolType(), &fieldVariable); 756 variableOut->fields.push_back(fieldVariable); 757 } 758 } 759 else if (interfaceBlock && isShaderIOBlock) 760 { 761 const bool isPerVertex = (interfaceBlock->name() == "gl_PerVertex"); 762 variableOut->type = GL_NONE; 763 if (interfaceBlock->symbolType() != SymbolType::Empty) 764 { 765 variableOut->structOrBlockName = interfaceBlock->name().data(); 766 variableOut->mappedStructOrBlockName = 767 isPerVertex ? interfaceBlock->name().data() 768 : HashName(interfaceBlock->name(), mHashFunction, nullptr).data(); 769 } 770 const TFieldList &fields = interfaceBlock->fields(); 771 for (const TField *field : fields) 772 { 773 ShaderVariable fieldVariable; 774 775 setFieldProperties(*field->type(), field->name(), staticUse, true, isPatch, 776 field->symbolType(), &fieldVariable); 777 fieldVariable.isShaderIOBlock = true; 778 variableOut->fields.push_back(fieldVariable); 779 } 780 } 781 else 782 { 783 variableOut->type = GLVariableType(type); 784 variableOut->precision = GLVariablePrecision(type); 785 } 786 787 const TSpan<const unsigned int> &arraySizes = type.getArraySizes(); 788 if (!arraySizes.empty()) 789 { 790 variableOut->arraySizes.assign(arraySizes.begin(), arraySizes.end()); 791 792 if (arraySizes[0] == 0) 793 { 794 // Tessellation Control & Evaluation shader inputs: 795 // Declaring an array size is optional. If no size is specified, it will be taken from 796 // the implementation-dependent maximum patch size (gl_MaxPatchVertices). 797 if (type.getQualifier() == EvqTessControlIn || 798 type.getQualifier() == EvqTessEvaluationIn) 799 { 800 variableOut->arraySizes[0] = mResources.MaxPatchVertices; 801 } 802 803 // Tessellation Control shader outputs: 804 // Declaring an array size is optional. If no size is specified, it will be taken from 805 // output patch size declared in the shader. 806 if (type.getQualifier() == EvqTessControlOut) 807 { 808 ASSERT(mTessControlShaderOutputVertices > 0); 809 variableOut->arraySizes[0] = mTessControlShaderOutputVertices; 810 } 811 } 812 } 813 } 814 815 void CollectVariablesTraverser::setFieldProperties(const TType &type, 816 const ImmutableString &name, 817 bool staticUse, 818 bool isShaderIOBlock, 819 bool isPatch, 820 SymbolType symbolType, 821 ShaderVariable *variableOut) const 822 { 823 ASSERT(variableOut); 824 setFieldOrVariableProperties(type, staticUse, isShaderIOBlock, isPatch, variableOut); 825 variableOut->name.assign(name.data(), name.length()); 826 variableOut->mappedName = (symbolType == SymbolType::BuiltIn) 827 ? name.data() 828 : HashName(name, mHashFunction, nullptr).data(); 829 } 830 831 void CollectVariablesTraverser::setCommonVariableProperties(const TType &type, 832 const TVariable &variable, 833 ShaderVariable *variableOut) const 834 { 835 ASSERT(variableOut); 836 ASSERT(type.getInterfaceBlock() == nullptr || IsShaderIoBlock(type.getQualifier()) || 837 type.getQualifier() == EvqPatchIn || type.getQualifier() == EvqPatchOut); 838 839 const bool staticUse = mSymbolTable->isStaticallyUsed(variable); 840 const bool isShaderIOBlock = type.getInterfaceBlock() != nullptr; 841 const bool isPatch = type.getQualifier() == EvqPatchIn || type.getQualifier() == EvqPatchOut; 842 843 setFieldOrVariableProperties(type, staticUse, isShaderIOBlock, isPatch, variableOut); 844 845 const bool isNamed = variable.symbolType() != SymbolType::Empty; 846 847 ASSERT(isNamed || isShaderIOBlock); 848 if (isNamed) 849 { 850 variableOut->name.assign(variable.name().data(), variable.name().length()); 851 variableOut->mappedName = getMappedName(&variable); 852 } 853 854 // For I/O blocks, additionally store the name of the block as blockName. If the variable is 855 // unnamed, this name will be used instead for the purpose of interface matching. 856 if (isShaderIOBlock) 857 { 858 const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock(); 859 ASSERT(interfaceBlock); 860 861 variableOut->structOrBlockName.assign(interfaceBlock->name().data(), 862 interfaceBlock->name().length()); 863 variableOut->mappedStructOrBlockName = 864 HashName(interfaceBlock->name(), mHashFunction, nullptr).data(); 865 variableOut->isShaderIOBlock = true; 866 } 867 } 868 869 ShaderVariable CollectVariablesTraverser::recordAttribute(const TIntermSymbol &variable) const 870 { 871 const TType &type = variable.getType(); 872 ASSERT(!type.getStruct()); 873 874 ShaderVariable attribute; 875 setCommonVariableProperties(type, variable.variable(), &attribute); 876 877 attribute.location = type.getLayoutQualifier().location; 878 return attribute; 879 } 880 881 ShaderVariable CollectVariablesTraverser::recordOutputVariable(const TIntermSymbol &variable) const 882 { 883 const TType &type = variable.getType(); 884 ASSERT(!type.getStruct()); 885 886 ShaderVariable outputVariable; 887 setCommonVariableProperties(type, variable.variable(), &outputVariable); 888 889 outputVariable.location = type.getLayoutQualifier().location; 890 outputVariable.index = type.getLayoutQualifier().index; 891 outputVariable.yuv = type.getLayoutQualifier().yuv; 892 return outputVariable; 893 } 894 895 ShaderVariable CollectVariablesTraverser::recordVarying(const TIntermSymbol &variable) const 896 { 897 const TType &type = variable.getType(); 898 899 ShaderVariable varying; 900 setCommonVariableProperties(type, variable.variable(), &varying); 901 varying.location = type.getLayoutQualifier().location; 902 903 switch (type.getQualifier()) 904 { 905 case EvqVaryingIn: 906 case EvqVaryingOut: 907 case EvqVertexOut: 908 case EvqSmoothOut: 909 case EvqFlatOut: 910 case EvqNoPerspectiveOut: 911 case EvqCentroidOut: 912 case EvqGeometryOut: 913 case EvqSampleOut: 914 if (mSymbolTable->isVaryingInvariant(variable.variable()) || type.isInvariant()) 915 { 916 varying.isInvariant = true; 917 } 918 break; 919 case EvqPatchIn: 920 case EvqPatchOut: 921 varying.isPatch = true; 922 break; 923 default: 924 break; 925 } 926 927 varying.interpolation = GetInterpolationType(type.getQualifier()); 928 929 // Shader I/O block properties 930 if (type.getBasicType() == EbtInterfaceBlock) 931 { 932 bool isBlockImplicitLocation = false; 933 int location = type.getLayoutQualifier().location; 934 935 // when a interface has not location in layout, assign to the zero. 936 if (location < 0) 937 { 938 location = 0; 939 isBlockImplicitLocation = true; 940 } 941 942 const TInterfaceBlock *blockType = type.getInterfaceBlock(); 943 ASSERT(blockType->fields().size() == varying.fields.size()); 944 945 for (size_t fieldIndex = 0; fieldIndex < varying.fields.size(); ++fieldIndex) 946 { 947 const TField *blockField = blockType->fields()[fieldIndex]; 948 ShaderVariable &fieldVariable = varying.fields[fieldIndex]; 949 const TType &fieldType = *blockField->type(); 950 951 fieldVariable.hasImplicitLocation = isBlockImplicitLocation; 952 fieldVariable.isPatch = varying.isPatch; 953 954 int fieldLocation = fieldType.getLayoutQualifier().location; 955 if (fieldLocation >= 0) 956 { 957 fieldVariable.hasImplicitLocation = false; 958 fieldVariable.location = fieldLocation; 959 location = fieldLocation; 960 } 961 else 962 { 963 fieldVariable.location = location; 964 location += fieldType.getLocationCount(); 965 } 966 967 if (fieldType.getQualifier() != EvqGlobal) 968 { 969 fieldVariable.interpolation = GetFieldInterpolationType(fieldType.getQualifier()); 970 } 971 } 972 } 973 974 return varying; 975 } 976 977 void CollectVariablesTraverser::recordInterfaceBlock(const char *instanceName, 978 const TType &interfaceBlockType, 979 InterfaceBlock *interfaceBlock) const 980 { 981 ASSERT(interfaceBlockType.getBasicType() == EbtInterfaceBlock); 982 ASSERT(interfaceBlock); 983 984 const TInterfaceBlock *blockType = interfaceBlockType.getInterfaceBlock(); 985 ASSERT(blockType); 986 987 interfaceBlock->name = blockType->name().data(); 988 interfaceBlock->mappedName = getMappedName(blockType); 989 990 const bool isGLInBuiltin = (instanceName != nullptr) && strncmp(instanceName, "gl_in", 5u) == 0; 991 if (instanceName != nullptr) 992 { 993 interfaceBlock->instanceName = instanceName; 994 const TSymbol *blockSymbol = nullptr; 995 if (isGLInBuiltin) 996 { 997 blockSymbol = mSymbolTable->getGlInVariableWithArraySize(); 998 } 999 else 1000 { 1001 blockSymbol = mSymbolTable->findGlobal(ImmutableString(instanceName)); 1002 } 1003 ASSERT(blockSymbol && blockSymbol->isVariable()); 1004 interfaceBlock->staticUse = 1005 mSymbolTable->isStaticallyUsed(*static_cast<const TVariable *>(blockSymbol)); 1006 } 1007 1008 ASSERT(!interfaceBlockType.isArrayOfArrays()); // Disallowed by GLSL ES 3.10 section 4.3.9 1009 interfaceBlock->arraySize = 1010 interfaceBlockType.isArray() ? interfaceBlockType.getOutermostArraySize() : 0; 1011 1012 interfaceBlock->blockType = GetBlockType(interfaceBlockType.getQualifier()); 1013 if (interfaceBlock->blockType == BlockType::BLOCK_UNIFORM || 1014 interfaceBlock->blockType == BlockType::BLOCK_BUFFER) 1015 { 1016 // TODO(oetuaho): Remove setting isRowMajorLayout. 1017 interfaceBlock->isRowMajorLayout = false; 1018 interfaceBlock->binding = blockType->blockBinding(); 1019 interfaceBlock->layout = GetBlockLayoutType(blockType->blockStorage()); 1020 } 1021 1022 // Gather field information 1023 bool anyFieldStaticallyUsed = false; 1024 1025 for (const TField *field : blockType->fields()) 1026 { 1027 const TType &fieldType = *field->type(); 1028 1029 bool staticUse = false; 1030 if (instanceName == nullptr) 1031 { 1032 // Static use of individual fields has been recorded, since they are present in the 1033 // symbol table as variables. 1034 const TSymbol *fieldSymbol = mSymbolTable->findGlobal(field->name()); 1035 ASSERT(fieldSymbol && fieldSymbol->isVariable()); 1036 staticUse = 1037 mSymbolTable->isStaticallyUsed(*static_cast<const TVariable *>(fieldSymbol)); 1038 if (staticUse) 1039 { 1040 anyFieldStaticallyUsed = true; 1041 } 1042 } 1043 1044 ShaderVariable fieldVariable; 1045 setFieldProperties(fieldType, field->name(), staticUse, false, false, field->symbolType(), 1046 &fieldVariable); 1047 fieldVariable.isRowMajorLayout = 1048 (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor); 1049 interfaceBlock->fields.push_back(fieldVariable); 1050 } 1051 if (anyFieldStaticallyUsed) 1052 { 1053 interfaceBlock->staticUse = true; 1054 } 1055 } 1056 1057 ShaderVariable CollectVariablesTraverser::recordUniform(const TIntermSymbol &variable) const 1058 { 1059 ShaderVariable uniform; 1060 setCommonVariableProperties(variable.getType(), variable.variable(), &uniform); 1061 uniform.binding = variable.getType().getLayoutQualifier().binding; 1062 uniform.imageUnitFormat = 1063 GetImageInternalFormatType(variable.getType().getLayoutQualifier().imageInternalFormat); 1064 uniform.location = variable.getType().getLayoutQualifier().location; 1065 uniform.offset = variable.getType().getLayoutQualifier().offset; 1066 uniform.rasterOrdered = variable.getType().getLayoutQualifier().rasterOrdered; 1067 uniform.readonly = variable.getType().getMemoryQualifier().readonly; 1068 uniform.writeonly = variable.getType().getMemoryQualifier().writeonly; 1069 return uniform; 1070 } 1071 1072 bool CollectVariablesTraverser::visitDeclaration(Visit, TIntermDeclaration *node) 1073 { 1074 const TIntermSequence &sequence = *(node->getSequence()); 1075 ASSERT(!sequence.empty()); 1076 1077 const TIntermTyped &typedNode = *(sequence.front()->getAsTyped()); 1078 TQualifier qualifier = typedNode.getQualifier(); 1079 1080 bool isShaderVariable = qualifier == EvqAttribute || qualifier == EvqVertexIn || 1081 qualifier == EvqFragmentOut || qualifier == EvqFragmentInOut || 1082 qualifier == EvqUniform || IsVarying(qualifier); 1083 1084 if (typedNode.getBasicType() != EbtInterfaceBlock && !isShaderVariable) 1085 { 1086 return true; 1087 } 1088 1089 for (TIntermNode *variableNode : sequence) 1090 { 1091 // The only case in which the sequence will not contain a TIntermSymbol node is 1092 // initialization. It will contain a TInterBinary node in that case. Since attributes, 1093 // uniforms, varyings, outputs and interface blocks cannot be initialized in a shader, we 1094 // must have only TIntermSymbol nodes in the sequence in the cases we are interested in. 1095 const TIntermSymbol &variable = *variableNode->getAsSymbolNode(); 1096 if (variable.variable().symbolType() == SymbolType::AngleInternal) 1097 { 1098 // Internal variables are not collected. 1099 continue; 1100 } 1101 1102 // SpirvTransformer::transform uses a map of ShaderVariables, it needs member variables and 1103 // (named or unnamed) structure as ShaderVariable. at link between two shaders, validation 1104 // between of named and unnamed, needs the same structure, its members, and members order 1105 // except instance name. 1106 if (typedNode.getBasicType() == EbtInterfaceBlock && !IsShaderIoBlock(qualifier) && 1107 qualifier != EvqPatchIn && qualifier != EvqPatchOut) 1108 { 1109 InterfaceBlock interfaceBlock; 1110 bool isUnnamed = variable.variable().symbolType() == SymbolType::Empty; 1111 const TType &type = variable.getType(); 1112 recordInterfaceBlock(isUnnamed ? nullptr : variable.getName().data(), type, 1113 &interfaceBlock); 1114 1115 // all fields in interface block will be added for updating interface variables because 1116 // the temporal structure variable will be ignored. 1117 switch (qualifier) 1118 { 1119 case EvqUniform: 1120 mUniformBlocks->push_back(interfaceBlock); 1121 break; 1122 case EvqBuffer: 1123 mShaderStorageBlocks->push_back(interfaceBlock); 1124 break; 1125 default: 1126 UNREACHABLE(); 1127 } 1128 } 1129 else 1130 { 1131 ASSERT(variable.variable().symbolType() != SymbolType::Empty || 1132 IsShaderIoBlock(qualifier) || qualifier == EvqPatchIn || 1133 qualifier == EvqPatchOut); 1134 switch (qualifier) 1135 { 1136 case EvqAttribute: 1137 case EvqVertexIn: 1138 mAttribs->push_back(recordAttribute(variable)); 1139 break; 1140 case EvqFragmentOut: 1141 case EvqFragmentInOut: 1142 mOutputVariables->push_back(recordOutputVariable(variable)); 1143 break; 1144 case EvqUniform: 1145 mUniforms->push_back(recordUniform(variable)); 1146 break; 1147 default: 1148 if (IsVaryingIn(qualifier)) 1149 { 1150 mInputVaryings->push_back(recordVarying(variable)); 1151 } 1152 else 1153 { 1154 ASSERT(IsVaryingOut(qualifier)); 1155 mOutputVaryings->push_back(recordVarying(variable)); 1156 } 1157 break; 1158 } 1159 } 1160 } 1161 1162 // None of the recorded variables can have initializers, so we don't need to traverse the 1163 // declarators. 1164 return false; 1165 } 1166 1167 InterfaceBlock *CollectVariablesTraverser::findNamedInterfaceBlock( 1168 const ImmutableString &blockName) const 1169 { 1170 InterfaceBlock *namedBlock = FindVariable(blockName, mUniformBlocks); 1171 if (!namedBlock) 1172 { 1173 namedBlock = FindVariable(blockName, mShaderStorageBlocks); 1174 } 1175 return namedBlock; 1176 } 1177 1178 bool CollectVariablesTraverser::visitBinary(Visit, TIntermBinary *binaryNode) 1179 { 1180 if (binaryNode->getOp() == EOpIndexDirectInterfaceBlock) 1181 { 1182 // NOTE: we do not determine static use / activeness for individual blocks of an array. 1183 TIntermTyped *blockNode = binaryNode->getLeft()->getAsTyped(); 1184 ASSERT(blockNode); 1185 1186 TIntermConstantUnion *constantUnion = binaryNode->getRight()->getAsConstantUnion(); 1187 ASSERT(constantUnion); 1188 1189 InterfaceBlock *namedBlock = nullptr; 1190 1191 bool traverseIndexExpression = false; 1192 TIntermBinary *interfaceIndexingNode = blockNode->getAsBinaryNode(); 1193 if (interfaceIndexingNode) 1194 { 1195 ASSERT(interfaceIndexingNode->getOp() == EOpIndexDirect || 1196 interfaceIndexingNode->getOp() == EOpIndexIndirect); 1197 traverseIndexExpression = true; 1198 blockNode = interfaceIndexingNode->getLeft(); 1199 } 1200 1201 const TType &interfaceNodeType = blockNode->getType(); 1202 const TInterfaceBlock *interfaceBlock = interfaceNodeType.getInterfaceBlock(); 1203 const TQualifier qualifier = interfaceNodeType.getQualifier(); 1204 1205 // If it's a shader I/O block, look in varyings 1206 ShaderVariable *ioBlockVar = nullptr; 1207 if (qualifier == EvqPerVertexIn) 1208 { 1209 TIntermSymbol *symbolNode = blockNode->getAsSymbolNode(); 1210 ASSERT(symbolNode); 1211 recordBuiltInVaryingUsed(symbolNode->variable(), &mPerVertexInAdded, mInputVaryings); 1212 ioBlockVar = FindShaderIOBlockVariable(interfaceBlock->name(), mInputVaryings); 1213 } 1214 else if (IsVaryingIn(qualifier)) 1215 { 1216 ioBlockVar = FindShaderIOBlockVariable(interfaceBlock->name(), mInputVaryings); 1217 } 1218 else if (qualifier == EvqPerVertexOut) 1219 { 1220 TIntermSymbol *symbolNode = blockNode->getAsSymbolNode(); 1221 ASSERT(symbolNode); 1222 recordBuiltInVaryingUsed(symbolNode->variable(), &mPerVertexOutAdded, mOutputVaryings); 1223 ioBlockVar = FindShaderIOBlockVariable(interfaceBlock->name(), mOutputVaryings); 1224 } 1225 else if (IsVaryingOut(qualifier)) 1226 { 1227 ioBlockVar = FindShaderIOBlockVariable(interfaceBlock->name(), mOutputVaryings); 1228 } 1229 1230 if (ioBlockVar) 1231 { 1232 MarkActive(ioBlockVar); 1233 } 1234 else 1235 { 1236 if (!namedBlock) 1237 { 1238 namedBlock = findNamedInterfaceBlock(interfaceBlock->name()); 1239 } 1240 ASSERT(namedBlock); 1241 ASSERT(namedBlock->staticUse); 1242 namedBlock->active = true; 1243 unsigned int fieldIndex = static_cast<unsigned int>(constantUnion->getIConst(0)); 1244 ASSERT(fieldIndex < namedBlock->fields.size()); 1245 // TODO(oetuaho): Would be nicer to record static use of fields of named interface 1246 // blocks more accurately at parse time - now we only mark the fields statically used if 1247 // they are active. http://anglebug.com/2440 We need to mark this field and all of its 1248 // sub-fields, as static/active 1249 MarkActive(&namedBlock->fields[fieldIndex]); 1250 } 1251 1252 if (traverseIndexExpression) 1253 { 1254 ASSERT(interfaceIndexingNode); 1255 interfaceIndexingNode->getRight()->traverse(this); 1256 } 1257 return false; 1258 } 1259 1260 return true; 1261 } 1262 1263 } // anonymous namespace 1264 1265 void CollectVariables(TIntermBlock *root, 1266 std::vector<ShaderVariable> *attributes, 1267 std::vector<ShaderVariable> *outputVariables, 1268 std::vector<ShaderVariable> *uniforms, 1269 std::vector<ShaderVariable> *inputVaryings, 1270 std::vector<ShaderVariable> *outputVaryings, 1271 std::vector<ShaderVariable> *sharedVariables, 1272 std::vector<InterfaceBlock> *uniformBlocks, 1273 std::vector<InterfaceBlock> *shaderStorageBlocks, 1274 ShHashFunction64 hashFunction, 1275 TSymbolTable *symbolTable, 1276 GLenum shaderType, 1277 const TExtensionBehavior &extensionBehavior, 1278 const ShBuiltInResources &resources, 1279 int tessControlShaderOutputVertices) 1280 { 1281 CollectVariablesTraverser collect( 1282 attributes, outputVariables, uniforms, inputVaryings, outputVaryings, sharedVariables, 1283 uniformBlocks, shaderStorageBlocks, hashFunction, symbolTable, shaderType, 1284 extensionBehavior, resources, tessControlShaderOutputVertices); 1285 root->traverse(&collect); 1286 } 1287 1288 } // namespace sh