tor-browser

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

blocklayout.cpp (22792B)


      1 //
      2 // Copyright 2013 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 // blocklayout.cpp:
      7 //   Implementation for block layout classes and methods.
      8 //
      9 
     10 #include "compiler/translator/blocklayout.h"
     11 
     12 #include "common/mathutil.h"
     13 #include "common/utilities.h"
     14 #include "compiler/translator/Common.h"
     15 
     16 namespace sh
     17 {
     18 
     19 namespace
     20 {
     21 class BlockLayoutMapVisitor : public BlockEncoderVisitor
     22 {
     23  public:
     24    BlockLayoutMapVisitor(BlockLayoutMap *blockInfoOut,
     25                          const std::string &instanceName,
     26                          BlockLayoutEncoder *encoder)
     27        : BlockEncoderVisitor(instanceName, instanceName, encoder), mInfoOut(blockInfoOut)
     28    {}
     29 
     30    void encodeVariable(const ShaderVariable &variable,
     31                        const BlockMemberInfo &variableInfo,
     32                        const std::string &name,
     33                        const std::string &mappedName) override
     34    {
     35        ASSERT(!gl::IsSamplerType(variable.type));
     36        if (!gl::IsOpaqueType(variable.type))
     37        {
     38            (*mInfoOut)[name] = variableInfo;
     39        }
     40    }
     41 
     42  private:
     43    BlockLayoutMap *mInfoOut;
     44 };
     45 
     46 template <typename VarT>
     47 void GetInterfaceBlockInfo(const std::vector<VarT> &fields,
     48                           const std::string &prefix,
     49                           BlockLayoutEncoder *encoder,
     50                           bool inRowMajorLayout,
     51                           bool onlyActiveVariables,
     52                           BlockLayoutMap *blockInfoOut)
     53 {
     54    BlockLayoutMapVisitor visitor(blockInfoOut, prefix, encoder);
     55    if (onlyActiveVariables)
     56    {
     57        TraverseActiveShaderVariables(fields, inRowMajorLayout, &visitor);
     58    }
     59    else
     60    {
     61        TraverseShaderVariables(fields, inRowMajorLayout, &visitor);
     62    }
     63 }
     64 
     65 void TraverseStructVariable(const ShaderVariable &variable,
     66                            bool isRowMajorLayout,
     67                            ShaderVariableVisitor *visitor)
     68 {
     69    const std::vector<ShaderVariable> &fields = variable.fields;
     70 
     71    visitor->enterStructAccess(variable, isRowMajorLayout);
     72    TraverseShaderVariables(fields, isRowMajorLayout, visitor);
     73    visitor->exitStructAccess(variable, isRowMajorLayout);
     74 }
     75 
     76 void TraverseStructArrayVariable(const ShaderVariable &variable,
     77                                 bool inRowMajorLayout,
     78                                 ShaderVariableVisitor *visitor)
     79 {
     80    visitor->enterArray(variable);
     81 
     82    // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
     83    // innermost. We make a special case for unsized arrays.
     84    const unsigned int currentArraySize = variable.getNestedArraySize(0);
     85    for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement)
     86    {
     87        visitor->enterArrayElement(variable, arrayElement);
     88        ShaderVariable elementVar = variable;
     89        elementVar.indexIntoArray(arrayElement);
     90 
     91        if (variable.arraySizes.size() > 1u)
     92        {
     93            TraverseStructArrayVariable(elementVar, inRowMajorLayout, visitor);
     94        }
     95        else
     96        {
     97            TraverseStructVariable(elementVar, inRowMajorLayout, visitor);
     98        }
     99 
    100        visitor->exitArrayElement(variable, arrayElement);
    101    }
    102 
    103    visitor->exitArray(variable);
    104 }
    105 
    106 void TraverseArrayOfArraysVariable(const ShaderVariable &variable,
    107                                   unsigned int arrayNestingIndex,
    108                                   bool isRowMajorMatrix,
    109                                   ShaderVariableVisitor *visitor)
    110 {
    111    visitor->enterArray(variable);
    112 
    113    const unsigned int currentArraySize = variable.getNestedArraySize(arrayNestingIndex);
    114    unsigned int count                  = std::max(currentArraySize, 1u);
    115    for (unsigned int arrayElement = 0u; arrayElement < count; ++arrayElement)
    116    {
    117        visitor->enterArrayElement(variable, arrayElement);
    118 
    119        ShaderVariable elementVar = variable;
    120        elementVar.indexIntoArray(arrayElement);
    121 
    122        if (arrayNestingIndex + 2u < variable.arraySizes.size())
    123        {
    124            TraverseArrayOfArraysVariable(elementVar, arrayNestingIndex, isRowMajorMatrix, visitor);
    125        }
    126        else
    127        {
    128            if (gl::IsSamplerType(variable.type) || gl::IsImageType(variable.type) ||
    129                variable.isFragmentInOut)
    130            {
    131                visitor->visitOpaqueObject(elementVar);
    132            }
    133            else
    134            {
    135                visitor->visitVariable(elementVar, isRowMajorMatrix);
    136            }
    137        }
    138 
    139        visitor->exitArrayElement(variable, arrayElement);
    140    }
    141 
    142    visitor->exitArray(variable);
    143 }
    144 
    145 std::string CollapseNameStack(const std::vector<std::string> &nameStack)
    146 {
    147    std::stringstream strstr = sh::InitializeStream<std::stringstream>();
    148    for (const std::string &part : nameStack)
    149    {
    150        strstr << part;
    151    }
    152    return strstr.str();
    153 }
    154 
    155 size_t GetStd430BaseAlignment(GLenum variableType, bool isRowMajor)
    156 {
    157    GLenum flippedType   = isRowMajor ? variableType : gl::TransposeMatrixType(variableType);
    158    size_t numComponents = static_cast<size_t>(gl::VariableColumnCount(flippedType));
    159    return ComponentAlignment(numComponents);
    160 }
    161 
    162 class BaseAlignmentVisitor : public ShaderVariableVisitor
    163 {
    164  public:
    165    BaseAlignmentVisitor() = default;
    166    void visitVariable(const ShaderVariable &variable, bool isRowMajor) override
    167    {
    168        size_t baseAlignment = GetStd430BaseAlignment(variable.type, isRowMajor);
    169        mCurrentAlignment    = std::max(mCurrentAlignment, baseAlignment);
    170    }
    171 
    172    // This is in components rather than bytes.
    173    size_t getBaseAlignment() const { return mCurrentAlignment; }
    174 
    175  private:
    176    size_t mCurrentAlignment = 0;
    177 };
    178 }  // anonymous namespace
    179 
    180 // BlockLayoutEncoder implementation.
    181 BlockLayoutEncoder::BlockLayoutEncoder() : mCurrentOffset(0) {}
    182 
    183 BlockMemberInfo BlockLayoutEncoder::encodeType(GLenum type,
    184                                               const std::vector<unsigned int> &arraySizes,
    185                                               bool isRowMajorMatrix)
    186 {
    187    int arrayStride;
    188    int matrixStride;
    189 
    190    getBlockLayoutInfo(type, arraySizes, isRowMajorMatrix, &arrayStride, &matrixStride);
    191 
    192    const BlockMemberInfo memberInfo(static_cast<int>(mCurrentOffset * kBytesPerComponent),
    193                                     static_cast<int>(arrayStride * kBytesPerComponent),
    194                                     static_cast<int>(matrixStride * kBytesPerComponent),
    195                                     isRowMajorMatrix);
    196 
    197    advanceOffset(type, arraySizes, isRowMajorMatrix, arrayStride, matrixStride);
    198 
    199    return memberInfo;
    200 }
    201 
    202 BlockMemberInfo BlockLayoutEncoder::encodeArrayOfPreEncodedStructs(
    203    size_t size,
    204    const std::vector<unsigned int> &arraySizes)
    205 {
    206    const unsigned int innerArraySizeProduct = gl::InnerArraySizeProduct(arraySizes);
    207    const unsigned int outermostArraySize    = gl::OutermostArraySize(arraySizes);
    208 
    209    // The size of struct is expected to be already aligned appropriately.
    210    const size_t arrayStride = size * innerArraySizeProduct;
    211 
    212    const BlockMemberInfo memberInfo(static_cast<int>(mCurrentOffset * kBytesPerComponent),
    213                                     static_cast<int>(arrayStride), -1, false);
    214 
    215    angle::base::CheckedNumeric<size_t> checkedOffset(arrayStride);
    216    checkedOffset *= outermostArraySize;
    217    checkedOffset /= kBytesPerComponent;
    218    checkedOffset += mCurrentOffset;
    219    mCurrentOffset = checkedOffset.ValueOrDefault(std::numeric_limits<size_t>::max());
    220 
    221    return memberInfo;
    222 }
    223 
    224 size_t BlockLayoutEncoder::getCurrentOffset() const
    225 {
    226    angle::base::CheckedNumeric<size_t> checkedOffset(mCurrentOffset);
    227    checkedOffset *= kBytesPerComponent;
    228    return checkedOffset.ValueOrDefault(std::numeric_limits<size_t>::max());
    229 }
    230 
    231 size_t BlockLayoutEncoder::getShaderVariableSize(const ShaderVariable &structVar, bool isRowMajor)
    232 {
    233    size_t currentOffset = mCurrentOffset;
    234    mCurrentOffset       = 0;
    235    BlockEncoderVisitor visitor("", "", this);
    236    enterAggregateType(structVar);
    237    TraverseShaderVariables(structVar.fields, isRowMajor, &visitor);
    238    exitAggregateType(structVar);
    239    size_t structVarSize = getCurrentOffset();
    240    mCurrentOffset       = currentOffset;
    241    return structVarSize;
    242 }
    243 
    244 // static
    245 size_t BlockLayoutEncoder::GetBlockRegister(const BlockMemberInfo &info)
    246 {
    247    return (info.offset / kBytesPerComponent) / kComponentsPerRegister;
    248 }
    249 
    250 // static
    251 size_t BlockLayoutEncoder::GetBlockRegisterElement(const BlockMemberInfo &info)
    252 {
    253    return (info.offset / kBytesPerComponent) % kComponentsPerRegister;
    254 }
    255 
    256 void BlockLayoutEncoder::align(size_t baseAlignment)
    257 {
    258    angle::base::CheckedNumeric<size_t> checkedOffset(mCurrentOffset);
    259    checkedOffset += baseAlignment;
    260    checkedOffset -= 1;
    261    angle::base::CheckedNumeric<size_t> checkedAlignmentOffset = checkedOffset;
    262    checkedAlignmentOffset %= baseAlignment;
    263    checkedOffset -= checkedAlignmentOffset.ValueOrDefault(std::numeric_limits<size_t>::max());
    264    mCurrentOffset = checkedOffset.ValueOrDefault(std::numeric_limits<size_t>::max());
    265 }
    266 
    267 // StubBlockEncoder implementation.
    268 void StubBlockEncoder::getBlockLayoutInfo(GLenum type,
    269                                          const std::vector<unsigned int> &arraySizes,
    270                                          bool isRowMajorMatrix,
    271                                          int *arrayStrideOut,
    272                                          int *matrixStrideOut)
    273 {
    274    *arrayStrideOut  = 0;
    275    *matrixStrideOut = 0;
    276 }
    277 
    278 // Std140BlockEncoder implementation.
    279 Std140BlockEncoder::Std140BlockEncoder() {}
    280 
    281 void Std140BlockEncoder::enterAggregateType(const ShaderVariable &structVar)
    282 {
    283    align(getBaseAlignment(structVar));
    284 }
    285 
    286 void Std140BlockEncoder::exitAggregateType(const ShaderVariable &structVar)
    287 {
    288    align(getBaseAlignment(structVar));
    289 }
    290 
    291 void Std140BlockEncoder::getBlockLayoutInfo(GLenum type,
    292                                            const std::vector<unsigned int> &arraySizes,
    293                                            bool isRowMajorMatrix,
    294                                            int *arrayStrideOut,
    295                                            int *matrixStrideOut)
    296 {
    297    // We assume we are only dealing with 4 byte components (no doubles or half-words currently)
    298    ASSERT(gl::VariableComponentSize(gl::VariableComponentType(type)) == kBytesPerComponent);
    299 
    300    size_t baseAlignment = 0;
    301    int matrixStride     = 0;
    302    int arrayStride      = 0;
    303 
    304    if (gl::IsMatrixType(type))
    305    {
    306        baseAlignment = getTypeBaseAlignment(type, isRowMajorMatrix);
    307        matrixStride  = static_cast<int>(getTypeBaseAlignment(type, isRowMajorMatrix));
    308 
    309        if (!arraySizes.empty())
    310        {
    311            const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
    312            arrayStride =
    313                static_cast<int>(getTypeBaseAlignment(type, isRowMajorMatrix) * numRegisters);
    314        }
    315    }
    316    else if (!arraySizes.empty())
    317    {
    318        baseAlignment = static_cast<int>(getTypeBaseAlignment(type, false));
    319        arrayStride   = static_cast<int>(getTypeBaseAlignment(type, false));
    320    }
    321    else
    322    {
    323        const size_t numComponents = static_cast<size_t>(gl::VariableComponentCount(type));
    324        baseAlignment              = ComponentAlignment(numComponents);
    325    }
    326 
    327    align(baseAlignment);
    328 
    329    *matrixStrideOut = matrixStride;
    330    *arrayStrideOut  = arrayStride;
    331 }
    332 
    333 void Std140BlockEncoder::advanceOffset(GLenum type,
    334                                       const std::vector<unsigned int> &arraySizes,
    335                                       bool isRowMajorMatrix,
    336                                       int arrayStride,
    337                                       int matrixStride)
    338 {
    339    if (!arraySizes.empty())
    340    {
    341        angle::base::CheckedNumeric<size_t> checkedOffset(arrayStride);
    342        checkedOffset *= gl::ArraySizeProduct(arraySizes);
    343        checkedOffset += mCurrentOffset;
    344        mCurrentOffset = checkedOffset.ValueOrDefault(std::numeric_limits<size_t>::max());
    345    }
    346    else if (gl::IsMatrixType(type))
    347    {
    348        angle::base::CheckedNumeric<size_t> checkedOffset(matrixStride);
    349        checkedOffset *= gl::MatrixRegisterCount(type, isRowMajorMatrix);
    350        checkedOffset += mCurrentOffset;
    351        mCurrentOffset = checkedOffset.ValueOrDefault(std::numeric_limits<size_t>::max());
    352    }
    353    else
    354    {
    355        angle::base::CheckedNumeric<size_t> checkedOffset(mCurrentOffset);
    356        checkedOffset += gl::VariableComponentCount(type);
    357        mCurrentOffset = checkedOffset.ValueOrDefault(std::numeric_limits<size_t>::max());
    358    }
    359 }
    360 
    361 size_t Std140BlockEncoder::getBaseAlignment(const ShaderVariable &variable) const
    362 {
    363    return kComponentsPerRegister;
    364 }
    365 
    366 size_t Std140BlockEncoder::getTypeBaseAlignment(GLenum type, bool isRowMajorMatrix) const
    367 {
    368    return kComponentsPerRegister;
    369 }
    370 
    371 // Std430BlockEncoder implementation.
    372 Std430BlockEncoder::Std430BlockEncoder() {}
    373 
    374 size_t Std430BlockEncoder::getBaseAlignment(const ShaderVariable &shaderVar) const
    375 {
    376    if (shaderVar.isStruct())
    377    {
    378        BaseAlignmentVisitor visitor;
    379        TraverseShaderVariables(shaderVar.fields, false, &visitor);
    380        return visitor.getBaseAlignment();
    381    }
    382 
    383    return GetStd430BaseAlignment(shaderVar.type, shaderVar.isRowMajorLayout);
    384 }
    385 
    386 size_t Std430BlockEncoder::getTypeBaseAlignment(GLenum type, bool isRowMajorMatrix) const
    387 {
    388    return GetStd430BaseAlignment(type, isRowMajorMatrix);
    389 }
    390 
    391 void GetInterfaceBlockInfo(const std::vector<ShaderVariable> &fields,
    392                           const std::string &prefix,
    393                           BlockLayoutEncoder *encoder,
    394                           BlockLayoutMap *blockInfoOut)
    395 {
    396    // Matrix packing is always recorded in individual fields, so they'll set the row major layout
    397    // flag to true if needed.
    398    // Iterates over all variables.
    399    GetInterfaceBlockInfo(fields, prefix, encoder, false, false, blockInfoOut);
    400 }
    401 
    402 void GetActiveUniformBlockInfo(const std::vector<ShaderVariable> &uniforms,
    403                               const std::string &prefix,
    404                               BlockLayoutEncoder *encoder,
    405                               BlockLayoutMap *blockInfoOut)
    406 {
    407    // Matrix packing is always recorded in individual fields, so they'll set the row major layout
    408    // flag to true if needed.
    409    // Iterates only over the active variables.
    410    GetInterfaceBlockInfo(uniforms, prefix, encoder, false, true, blockInfoOut);
    411 }
    412 
    413 // VariableNameVisitor implementation.
    414 VariableNameVisitor::VariableNameVisitor(const std::string &namePrefix,
    415                                         const std::string &mappedNamePrefix)
    416 {
    417    if (!namePrefix.empty())
    418    {
    419        mNameStack.push_back(namePrefix + ".");
    420    }
    421 
    422    if (!mappedNamePrefix.empty())
    423    {
    424        mMappedNameStack.push_back(mappedNamePrefix + ".");
    425    }
    426 }
    427 
    428 VariableNameVisitor::~VariableNameVisitor() = default;
    429 
    430 void VariableNameVisitor::enterStruct(const ShaderVariable &structVar)
    431 {
    432    mNameStack.push_back(structVar.name);
    433    mMappedNameStack.push_back(structVar.mappedName);
    434 }
    435 
    436 void VariableNameVisitor::exitStruct(const ShaderVariable &structVar)
    437 {
    438    mNameStack.pop_back();
    439    mMappedNameStack.pop_back();
    440 }
    441 
    442 void VariableNameVisitor::enterStructAccess(const ShaderVariable &structVar, bool isRowMajor)
    443 {
    444    mNameStack.push_back(".");
    445    mMappedNameStack.push_back(".");
    446 }
    447 
    448 void VariableNameVisitor::exitStructAccess(const ShaderVariable &structVar, bool isRowMajor)
    449 {
    450    mNameStack.pop_back();
    451    mMappedNameStack.pop_back();
    452 }
    453 
    454 void VariableNameVisitor::enterArray(const ShaderVariable &arrayVar)
    455 {
    456    if (!arrayVar.hasParentArrayIndex() && !arrayVar.isStruct())
    457    {
    458        mNameStack.push_back(arrayVar.name);
    459        mMappedNameStack.push_back(arrayVar.mappedName);
    460    }
    461    mArraySizeStack.push_back(arrayVar.getOutermostArraySize());
    462 }
    463 
    464 void VariableNameVisitor::exitArray(const ShaderVariable &arrayVar)
    465 {
    466    if (!arrayVar.hasParentArrayIndex() && !arrayVar.isStruct())
    467    {
    468        mNameStack.pop_back();
    469        mMappedNameStack.pop_back();
    470    }
    471    mArraySizeStack.pop_back();
    472 }
    473 
    474 void VariableNameVisitor::enterArrayElement(const ShaderVariable &arrayVar,
    475                                            unsigned int arrayElement)
    476 {
    477    std::stringstream strstr = sh::InitializeStream<std::stringstream>();
    478    strstr << "[" << arrayElement << "]";
    479    std::string elementString = strstr.str();
    480    mNameStack.push_back(elementString);
    481    mMappedNameStack.push_back(elementString);
    482 }
    483 
    484 void VariableNameVisitor::exitArrayElement(const ShaderVariable &arrayVar,
    485                                           unsigned int arrayElement)
    486 {
    487    mNameStack.pop_back();
    488    mMappedNameStack.pop_back();
    489 }
    490 
    491 std::string VariableNameVisitor::collapseNameStack() const
    492 {
    493    return CollapseNameStack(mNameStack);
    494 }
    495 
    496 std::string VariableNameVisitor::collapseMappedNameStack() const
    497 {
    498    return CollapseNameStack(mMappedNameStack);
    499 }
    500 
    501 void VariableNameVisitor::visitOpaqueObject(const sh::ShaderVariable &variable)
    502 {
    503    if (!variable.hasParentArrayIndex())
    504    {
    505        mNameStack.push_back(variable.name);
    506        mMappedNameStack.push_back(variable.mappedName);
    507    }
    508 
    509    std::string name       = collapseNameStack();
    510    std::string mappedName = collapseMappedNameStack();
    511 
    512    if (!variable.hasParentArrayIndex())
    513    {
    514        mNameStack.pop_back();
    515        mMappedNameStack.pop_back();
    516    }
    517 
    518    visitNamedOpaqueObject(variable, name, mappedName, mArraySizeStack);
    519 }
    520 
    521 void VariableNameVisitor::visitVariable(const ShaderVariable &variable, bool isRowMajor)
    522 {
    523    if (!variable.hasParentArrayIndex())
    524    {
    525        mNameStack.push_back(variable.name);
    526        mMappedNameStack.push_back(variable.mappedName);
    527    }
    528 
    529    std::string name       = collapseNameStack();
    530    std::string mappedName = collapseMappedNameStack();
    531 
    532    if (!variable.hasParentArrayIndex())
    533    {
    534        mNameStack.pop_back();
    535        mMappedNameStack.pop_back();
    536    }
    537 
    538    visitNamedVariable(variable, isRowMajor, name, mappedName, mArraySizeStack);
    539 }
    540 
    541 // BlockEncoderVisitor implementation.
    542 BlockEncoderVisitor::BlockEncoderVisitor(const std::string &namePrefix,
    543                                         const std::string &mappedNamePrefix,
    544                                         BlockLayoutEncoder *encoder)
    545    : VariableNameVisitor(namePrefix, mappedNamePrefix), mEncoder(encoder)
    546 {}
    547 
    548 BlockEncoderVisitor::~BlockEncoderVisitor() = default;
    549 
    550 void BlockEncoderVisitor::enterStructAccess(const ShaderVariable &structVar, bool isRowMajor)
    551 {
    552    mStructStackSize++;
    553    if (!mIsTopLevelArrayStrideReady)
    554    {
    555        size_t structSize = mEncoder->getShaderVariableSize(structVar, isRowMajor);
    556        mTopLevelArrayStride *= structSize;
    557        mIsTopLevelArrayStrideReady = true;
    558    }
    559 
    560    VariableNameVisitor::enterStructAccess(structVar, isRowMajor);
    561    mEncoder->enterAggregateType(structVar);
    562 }
    563 
    564 void BlockEncoderVisitor::exitStructAccess(const ShaderVariable &structVar, bool isRowMajor)
    565 {
    566    mStructStackSize--;
    567    mEncoder->exitAggregateType(structVar);
    568    VariableNameVisitor::exitStructAccess(structVar, isRowMajor);
    569 }
    570 
    571 void BlockEncoderVisitor::enterArrayElement(const sh::ShaderVariable &arrayVar,
    572                                            unsigned int arrayElement)
    573 {
    574    if (mStructStackSize == 0 && !arrayVar.hasParentArrayIndex())
    575    {
    576        // From the ES 3.1 spec "7.3.1.1 Naming Active Resources":
    577        // For an active shader storage block member declared as an array of an aggregate type,
    578        // an entry will be generated only for the first array element, regardless of its type.
    579        // Such block members are referred to as top-level arrays. If the block member is an
    580        // aggregate type, the enumeration rules are then applied recursively.
    581        if (arrayElement == 0)
    582        {
    583            mTopLevelArraySize          = arrayVar.getOutermostArraySize();
    584            mTopLevelArrayStride        = arrayVar.getInnerArraySizeProduct();
    585            mIsTopLevelArrayStrideReady = false;
    586        }
    587        else
    588        {
    589            mSkipEnabled = true;
    590        }
    591    }
    592    VariableNameVisitor::enterArrayElement(arrayVar, arrayElement);
    593 }
    594 
    595 void BlockEncoderVisitor::exitArrayElement(const sh::ShaderVariable &arrayVar,
    596                                           unsigned int arrayElement)
    597 {
    598    if (mStructStackSize == 0 && !arrayVar.hasParentArrayIndex())
    599    {
    600        mTopLevelArraySize          = 1;
    601        mTopLevelArrayStride        = 0;
    602        mIsTopLevelArrayStrideReady = true;
    603        mSkipEnabled                = false;
    604    }
    605    VariableNameVisitor::exitArrayElement(arrayVar, arrayElement);
    606 }
    607 
    608 void BlockEncoderVisitor::visitNamedVariable(const ShaderVariable &variable,
    609                                             bool isRowMajor,
    610                                             const std::string &name,
    611                                             const std::string &mappedName,
    612                                             const std::vector<unsigned int> &arraySizes)
    613 {
    614    std::vector<unsigned int> innermostArraySize;
    615 
    616    if (variable.isArray())
    617    {
    618        innermostArraySize.push_back(variable.getNestedArraySize(0));
    619    }
    620    BlockMemberInfo variableInfo =
    621        mEncoder->encodeType(variable.type, innermostArraySize, isRowMajor);
    622    if (!mIsTopLevelArrayStrideReady)
    623    {
    624        ASSERT(mTopLevelArrayStride);
    625        mTopLevelArrayStride *= variableInfo.arrayStride;
    626        mIsTopLevelArrayStrideReady = true;
    627    }
    628    variableInfo.topLevelArrayStride = mTopLevelArrayStride;
    629    encodeVariable(variable, variableInfo, name, mappedName);
    630 }
    631 
    632 void TraverseShaderVariable(const ShaderVariable &variable,
    633                            bool isRowMajorLayout,
    634                            ShaderVariableVisitor *visitor)
    635 {
    636    bool rowMajorLayout = (isRowMajorLayout || variable.isRowMajorLayout);
    637    bool isRowMajor     = rowMajorLayout && gl::IsMatrixType(variable.type);
    638 
    639    if (variable.isStruct())
    640    {
    641        visitor->enterStruct(variable);
    642        if (variable.isArray())
    643        {
    644            TraverseStructArrayVariable(variable, rowMajorLayout, visitor);
    645        }
    646        else
    647        {
    648            TraverseStructVariable(variable, rowMajorLayout, visitor);
    649        }
    650        visitor->exitStruct(variable);
    651    }
    652    else if (variable.isArrayOfArrays())
    653    {
    654        TraverseArrayOfArraysVariable(variable, 0u, isRowMajor, visitor);
    655    }
    656    else if (gl::IsSamplerType(variable.type) || gl::IsImageType(variable.type) ||
    657             variable.isFragmentInOut)
    658    {
    659        visitor->visitOpaqueObject(variable);
    660    }
    661    else
    662    {
    663        visitor->visitVariable(variable, isRowMajor);
    664    }
    665 }
    666 }  // namespace sh