tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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