tor-browser

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

VaryingPacking.cpp (44791B)


      1 //
      2 // Copyright 2015 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 // VaryingPacking:
      7 //   Class which describes a mapping from varyings to registers, according
      8 //   to the spec, or using custom packing algorithms. We also keep a register
      9 //   allocation list for the D3D renderer.
     10 //
     11 
     12 #include "libANGLE/VaryingPacking.h"
     13 
     14 #include "common/utilities.h"
     15 #include "libANGLE/Program.h"
     16 #include "libANGLE/ProgramExecutable.h"
     17 #include "libANGLE/Shader.h"
     18 
     19 namespace gl
     20 {
     21 
     22 namespace
     23 {
     24 
     25 // true if varying x has a higher priority in packing than y
     26 bool ComparePackedVarying(const PackedVarying &x, const PackedVarying &y)
     27 {
     28    // If the PackedVarying 'x' or 'y' to be compared is an array element for transform feedback,
     29    // this clones an equivalent non-array shader variable 'vx' or 'vy' for actual comparison
     30    // instead.  For I/O block arrays, the array index is used in the comparison.
     31    sh::ShaderVariable vx, vy;
     32    const sh::ShaderVariable *px, *py;
     33 
     34    px = &x.varying();
     35    py = &y.varying();
     36 
     37    if (x.isTransformFeedbackArrayElement())
     38    {
     39        vx = *px;
     40        vx.arraySizes.clear();
     41        px = &vx;
     42    }
     43 
     44    if (y.isTransformFeedbackArrayElement())
     45    {
     46        vy = *py;
     47        vy.arraySizes.clear();
     48        py = &vy;
     49    }
     50 
     51    // Make sure struct fields end up together.
     52    if (x.isStructField() != y.isStructField())
     53    {
     54        return x.isStructField();
     55    }
     56 
     57    if (x.isStructField())
     58    {
     59        ASSERT(y.isStructField());
     60 
     61        if (x.getParentStructName() != y.getParentStructName())
     62        {
     63            return x.getParentStructName() < y.getParentStructName();
     64        }
     65    }
     66 
     67    // For I/O block fields, order first by array index:
     68    if (!x.isTransformFeedbackArrayElement() && !y.isTransformFeedbackArrayElement())
     69    {
     70        if (x.arrayIndex != y.arrayIndex)
     71        {
     72            return x.arrayIndex < y.arrayIndex;
     73        }
     74    }
     75 
     76    // Then order by field index
     77    if (x.fieldIndex != y.fieldIndex)
     78    {
     79        return x.fieldIndex < y.fieldIndex;
     80    }
     81 
     82    // Then order by secondary field index
     83    if (x.secondaryFieldIndex != y.secondaryFieldIndex)
     84    {
     85        return x.secondaryFieldIndex < y.secondaryFieldIndex;
     86    }
     87 
     88    // Otherwise order by variable
     89    return gl::CompareShaderVar(*px, *py);
     90 }
     91 
     92 bool InterfaceVariablesMatch(const sh::ShaderVariable &front, const sh::ShaderVariable &back)
     93 {
     94    // Matching ruels from 7.4.1 Shader Interface Matching from the GLES 3.2 spec:
     95    // - the two variables match in name, type, and qualification; or
     96    // - the two variables are declared with the same location qualifier and match in type and
     97    // qualification. Note that we use a more permissive check here thanks to front-end validation.
     98    if (back.location != -1 && back.location == front.location)
     99    {
    100        return true;
    101    }
    102 
    103    if (front.isShaderIOBlock != back.isShaderIOBlock)
    104    {
    105        return false;
    106    }
    107 
    108    // Compare names, or if shader I/O blocks, block names.
    109    const std::string &backName  = back.isShaderIOBlock ? back.structOrBlockName : back.name;
    110    const std::string &frontName = front.isShaderIOBlock ? front.structOrBlockName : front.name;
    111    return backName == frontName;
    112 }
    113 
    114 GLint GetMaxShaderInputVectors(const Caps &caps, ShaderType shaderStage)
    115 {
    116    switch (shaderStage)
    117    {
    118        case ShaderType::TessControl:
    119            return caps.maxTessControlInputComponents / 4;
    120        case ShaderType::TessEvaluation:
    121            return caps.maxTessEvaluationInputComponents / 4;
    122        case ShaderType::Geometry:
    123            return caps.maxGeometryInputComponents / 4;
    124        case ShaderType::Fragment:
    125            return caps.maxFragmentInputComponents / 4;
    126        default:
    127            return std::numeric_limits<GLint>::max();
    128    }
    129 }
    130 
    131 GLint GetMaxShaderOutputVectors(const Caps &caps, ShaderType shaderStage)
    132 {
    133    switch (shaderStage)
    134    {
    135        case ShaderType::Vertex:
    136            return caps.maxVertexOutputComponents / 4;
    137        case ShaderType::TessControl:
    138            return caps.maxTessControlOutputComponents / 4;
    139        case ShaderType::TessEvaluation:
    140            return caps.maxTessEvaluationOutputComponents / 4;
    141        case ShaderType::Geometry:
    142            return caps.maxGeometryOutputComponents / 4;
    143        default:
    144            return std::numeric_limits<GLint>::max();
    145    }
    146 }
    147 
    148 bool ShouldSkipPackedVarying(const sh::ShaderVariable &varying, PackMode packMode)
    149 {
    150    // Don't pack gl_Position. Also don't count gl_PointSize for D3D9.
    151    return varying.name == "gl_Position" ||
    152           (varying.name == "gl_PointSize" && packMode == PackMode::ANGLE_NON_CONFORMANT_D3D9);
    153 }
    154 
    155 std::vector<unsigned int> StripVaryingArrayDimension(const sh::ShaderVariable *frontVarying,
    156                                                     ShaderType frontShaderStage,
    157                                                     const sh::ShaderVariable *backVarying,
    158                                                     ShaderType backShaderStage,
    159                                                     bool isStructField)
    160 {
    161    // "Geometry shader inputs, tessellation control shader inputs and outputs, and tessellation
    162    // evaluation inputs all have an additional level of arrayness relative to other shader inputs
    163    // and outputs. This outer array level is removed from the type before considering how many
    164    // locations the type consumes."
    165 
    166    if (backVarying && backVarying->isArray() && !backVarying->isPatch && !isStructField &&
    167        (backShaderStage == ShaderType::Geometry || backShaderStage == ShaderType::TessEvaluation ||
    168         backShaderStage == ShaderType::TessControl))
    169    {
    170        std::vector<unsigned int> arr = backVarying->arraySizes;
    171        arr.pop_back();
    172        return arr;
    173    }
    174 
    175    if (frontVarying && frontVarying->isArray() && !frontVarying->isPatch && !isStructField &&
    176        frontShaderStage == ShaderType::TessControl)
    177    {
    178        std::vector<unsigned int> arr = frontVarying->arraySizes;
    179        arr.pop_back();
    180        return arr;
    181    }
    182 
    183    return frontVarying ? frontVarying->arraySizes : backVarying->arraySizes;
    184 }
    185 }  // anonymous namespace
    186 
    187 // Implementation of VaryingInShaderRef
    188 VaryingInShaderRef::VaryingInShaderRef(ShaderType stageIn, const sh::ShaderVariable *varyingIn)
    189    : varying(varyingIn), stage(stageIn)
    190 {}
    191 
    192 VaryingInShaderRef::~VaryingInShaderRef() = default;
    193 
    194 VaryingInShaderRef::VaryingInShaderRef(VaryingInShaderRef &&other)
    195    : varying(other.varying),
    196      stage(other.stage),
    197      parentStructName(std::move(other.parentStructName)),
    198      parentStructMappedName(std::move(other.parentStructMappedName))
    199 {}
    200 
    201 VaryingInShaderRef &VaryingInShaderRef::operator=(VaryingInShaderRef &&other)
    202 {
    203    std::swap(varying, other.varying);
    204    std::swap(stage, other.stage);
    205    std::swap(parentStructName, other.parentStructName);
    206    std::swap(parentStructMappedName, other.parentStructMappedName);
    207 
    208    return *this;
    209 }
    210 
    211 // Implementation of PackedVarying
    212 PackedVarying::PackedVarying(VaryingInShaderRef &&frontVaryingIn,
    213                             VaryingInShaderRef &&backVaryingIn,
    214                             sh::InterpolationType interpolationIn)
    215    : PackedVarying(std::move(frontVaryingIn),
    216                    std::move(backVaryingIn),
    217                    interpolationIn,
    218                    GL_INVALID_INDEX,
    219                    0,
    220                    0)
    221 {}
    222 
    223 PackedVarying::PackedVarying(VaryingInShaderRef &&frontVaryingIn,
    224                             VaryingInShaderRef &&backVaryingIn,
    225                             sh::InterpolationType interpolationIn,
    226                             GLuint arrayIndexIn,
    227                             GLuint fieldIndexIn,
    228                             GLuint secondaryFieldIndexIn)
    229    : frontVarying(std::move(frontVaryingIn)),
    230      backVarying(std::move(backVaryingIn)),
    231      interpolation(interpolationIn),
    232      arrayIndex(arrayIndexIn),
    233      isTransformFeedback(false),
    234      fieldIndex(fieldIndexIn),
    235      secondaryFieldIndex(secondaryFieldIndexIn)
    236 {}
    237 
    238 PackedVarying::~PackedVarying() = default;
    239 
    240 PackedVarying::PackedVarying(PackedVarying &&other)
    241    : frontVarying(std::move(other.frontVarying)),
    242      backVarying(std::move(other.backVarying)),
    243      interpolation(other.interpolation),
    244      arrayIndex(other.arrayIndex),
    245      isTransformFeedback(other.isTransformFeedback),
    246      fieldIndex(other.fieldIndex),
    247      secondaryFieldIndex(other.secondaryFieldIndex)
    248 {}
    249 
    250 PackedVarying &PackedVarying::operator=(PackedVarying &&other)
    251 {
    252    std::swap(frontVarying, other.frontVarying);
    253    std::swap(backVarying, other.backVarying);
    254    std::swap(interpolation, other.interpolation);
    255    std::swap(arrayIndex, other.arrayIndex);
    256    std::swap(isTransformFeedback, other.isTransformFeedback);
    257    std::swap(fieldIndex, other.fieldIndex);
    258    std::swap(secondaryFieldIndex, other.secondaryFieldIndex);
    259 
    260    return *this;
    261 }
    262 
    263 unsigned int PackedVarying::getBasicTypeElementCount() const
    264 {
    265    // "Geometry shader inputs, tessellation control shader inputs and outputs, and tessellation
    266    // evaluation inputs all have an additional level of arrayness relative to other shader inputs
    267    // and outputs. This outer array level is removed from the type before considering how many
    268    // locations the type consumes."
    269    std::vector<unsigned int> arr =
    270        StripVaryingArrayDimension(frontVarying.varying, frontVarying.stage, backVarying.varying,
    271                                   backVarying.stage, isStructField());
    272    return arr.empty() ? 1u : arr.back();
    273 }
    274 
    275 // Implementation of VaryingPacking
    276 VaryingPacking::VaryingPacking() = default;
    277 
    278 VaryingPacking::~VaryingPacking() = default;
    279 
    280 void VaryingPacking::reset()
    281 {
    282    clearRegisterMap();
    283    mRegisterList.clear();
    284    mPackedVaryings.clear();
    285 
    286    for (std::vector<std::string> &inactiveVaryingMappedNames : mInactiveVaryingMappedNames)
    287    {
    288        inactiveVaryingMappedNames.clear();
    289    }
    290 
    291    for (std::vector<std::string> &activeBuiltIns : mActiveOutputBuiltIns)
    292    {
    293        activeBuiltIns.clear();
    294    }
    295 }
    296 
    297 void VaryingPacking::clearRegisterMap()
    298 {
    299    std::fill(mRegisterMap.begin(), mRegisterMap.end(), Register());
    300 }
    301 
    302 // Packs varyings into generic varying registers, using the algorithm from
    303 // See [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
    304 // Also [OpenGL ES Shading Language 3.00 rev. 4] Section 11 page 119
    305 // Returns false if unsuccessful.
    306 bool VaryingPacking::packVaryingIntoRegisterMap(PackMode packMode,
    307                                                const PackedVarying &packedVarying)
    308 {
    309    const sh::ShaderVariable &varying = packedVarying.varying();
    310 
    311    // "Non - square matrices of type matCxR consume the same space as a square matrix of type matN
    312    // where N is the greater of C and R."
    313    // Here we are a bit more conservative and allow packing non-square matrices more tightly.
    314    // Make sure we use transposed matrix types to count registers correctly.
    315    ASSERT(!varying.isStruct());
    316    GLenum transposedType       = gl::TransposeMatrixType(varying.type);
    317    unsigned int varyingRows    = gl::VariableRowCount(transposedType);
    318    unsigned int varyingColumns = gl::VariableColumnCount(transposedType);
    319 
    320    // Special pack mode for D3D9. Each varying takes a full register, no sharing.
    321    // TODO(jmadill): Implement more sophisticated component packing in D3D9.
    322    if (packMode == PackMode::ANGLE_NON_CONFORMANT_D3D9)
    323    {
    324        varyingColumns = 4;
    325    }
    326 
    327    // "Variables of type mat2 occupies 2 complete rows."
    328    // For non-WebGL contexts, we allow mat2 to occupy only two columns per row.
    329    else if (packMode == PackMode::WEBGL_STRICT && varying.type == GL_FLOAT_MAT2)
    330    {
    331        varyingColumns = 4;
    332    }
    333 
    334    // "Arrays of size N are assumed to take N times the size of the base type"
    335    // GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of
    336    // structures, so we may use getBasicTypeElementCount().
    337    const unsigned int elementCount = packedVarying.getBasicTypeElementCount();
    338    varyingRows *= (packedVarying.isTransformFeedbackArrayElement() ? 1 : elementCount);
    339 
    340    unsigned int maxVaryingVectors = static_cast<unsigned int>(mRegisterMap.size());
    341 
    342    // Fail if we are packing a single over-large varying.
    343    if (varyingRows > maxVaryingVectors)
    344    {
    345        return false;
    346    }
    347 
    348    // "For 2, 3 and 4 component variables packing is started using the 1st column of the 1st row.
    349    // Variables are then allocated to successive rows, aligning them to the 1st column."
    350    if (varyingColumns >= 2 && varyingColumns <= 4)
    351    {
    352        for (unsigned int row = 0; row <= maxVaryingVectors - varyingRows; ++row)
    353        {
    354            if (isRegisterRangeFree(row, 0, varyingRows, varyingColumns))
    355            {
    356                insertVaryingIntoRegisterMap(row, 0, varyingColumns, packedVarying);
    357                return true;
    358            }
    359        }
    360 
    361        // "For 2 component variables, when there are no spare rows, the strategy is switched to
    362        // using the highest numbered row and the lowest numbered column where the variable will
    363        // fit."
    364        if (varyingColumns == 2)
    365        {
    366            for (unsigned int r = maxVaryingVectors - varyingRows + 1; r-- >= 1;)
    367            {
    368                if (isRegisterRangeFree(r, 2, varyingRows, 2))
    369                {
    370                    insertVaryingIntoRegisterMap(r, 2, varyingColumns, packedVarying);
    371                    return true;
    372                }
    373            }
    374        }
    375 
    376        return false;
    377    }
    378 
    379    // "1 component variables have their own packing rule. They are packed in order of size, largest
    380    // first. Each variable is placed in the column that leaves the least amount of space in the
    381    // column and aligned to the lowest available rows within that column."
    382    ASSERT(varyingColumns == 1);
    383    unsigned int contiguousSpace[4]     = {0};
    384    unsigned int bestContiguousSpace[4] = {0};
    385    unsigned int totalSpace[4]          = {0};
    386 
    387    for (unsigned int row = 0; row < maxVaryingVectors; ++row)
    388    {
    389        for (unsigned int column = 0; column < 4; ++column)
    390        {
    391            if (mRegisterMap[row][column])
    392            {
    393                contiguousSpace[column] = 0;
    394            }
    395            else
    396            {
    397                contiguousSpace[column]++;
    398                totalSpace[column]++;
    399 
    400                if (contiguousSpace[column] > bestContiguousSpace[column])
    401                {
    402                    bestContiguousSpace[column] = contiguousSpace[column];
    403                }
    404            }
    405        }
    406    }
    407 
    408    unsigned int bestColumn = 0;
    409    for (unsigned int column = 1; column < 4; ++column)
    410    {
    411        if (bestContiguousSpace[column] >= varyingRows &&
    412            (bestContiguousSpace[bestColumn] < varyingRows ||
    413             totalSpace[column] < totalSpace[bestColumn]))
    414        {
    415            bestColumn = column;
    416        }
    417    }
    418 
    419    if (bestContiguousSpace[bestColumn] >= varyingRows)
    420    {
    421        for (unsigned int row = 0; row < maxVaryingVectors; row++)
    422        {
    423            if (isRegisterRangeFree(row, bestColumn, varyingRows, 1))
    424            {
    425                for (unsigned int arrayIndex = 0; arrayIndex < varyingRows; ++arrayIndex)
    426                {
    427                    // If varyingRows > 1, it must be an array.
    428                    PackedVaryingRegister registerInfo;
    429                    registerInfo.packedVarying  = &packedVarying;
    430                    registerInfo.registerRow    = row + arrayIndex;
    431                    registerInfo.registerColumn = bestColumn;
    432                    registerInfo.varyingArrayIndex =
    433                        (packedVarying.isTransformFeedbackArrayElement() ? packedVarying.arrayIndex
    434                                                                         : arrayIndex);
    435                    registerInfo.varyingRowIndex = 0;
    436                    // Do not record register info for builtins.
    437                    // TODO(jmadill): Clean this up.
    438                    if (!varying.isBuiltIn())
    439                    {
    440                        mRegisterList.push_back(registerInfo);
    441                    }
    442                    mRegisterMap[row + arrayIndex][bestColumn] = true;
    443                }
    444                break;
    445            }
    446        }
    447        return true;
    448    }
    449 
    450    return false;
    451 }
    452 
    453 bool VaryingPacking::isRegisterRangeFree(unsigned int registerRow,
    454                                         unsigned int registerColumn,
    455                                         unsigned int varyingRows,
    456                                         unsigned int varyingColumns) const
    457 {
    458    for (unsigned int row = 0; row < varyingRows; ++row)
    459    {
    460        ASSERT(registerRow + row < mRegisterMap.size());
    461        for (unsigned int column = 0; column < varyingColumns; ++column)
    462        {
    463            ASSERT(registerColumn + column < 4);
    464            if (mRegisterMap[registerRow + row][registerColumn + column])
    465            {
    466                return false;
    467            }
    468        }
    469    }
    470 
    471    return true;
    472 }
    473 
    474 void VaryingPacking::insertVaryingIntoRegisterMap(unsigned int registerRow,
    475                                                  unsigned int registerColumn,
    476                                                  unsigned int varyingColumns,
    477                                                  const PackedVarying &packedVarying)
    478 {
    479    unsigned int varyingRows = 0;
    480 
    481    const sh::ShaderVariable &varying = packedVarying.varying();
    482    ASSERT(!varying.isStruct());
    483    GLenum transposedType = gl::TransposeMatrixType(varying.type);
    484    varyingRows           = gl::VariableRowCount(transposedType);
    485 
    486    PackedVaryingRegister registerInfo;
    487    registerInfo.packedVarying  = &packedVarying;
    488    registerInfo.registerColumn = registerColumn;
    489 
    490    // GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of
    491    // structures, so we may use getBasicTypeElementCount().
    492    const unsigned int arrayElementCount = packedVarying.getBasicTypeElementCount();
    493    for (unsigned int arrayElement = 0; arrayElement < arrayElementCount; ++arrayElement)
    494    {
    495        if (packedVarying.isTransformFeedbackArrayElement() &&
    496            arrayElement != packedVarying.arrayIndex)
    497        {
    498            continue;
    499        }
    500        for (unsigned int varyingRow = 0; varyingRow < varyingRows; ++varyingRow)
    501        {
    502            registerInfo.registerRow     = registerRow + (arrayElement * varyingRows) + varyingRow;
    503            registerInfo.varyingRowIndex = varyingRow;
    504            registerInfo.varyingArrayIndex = arrayElement;
    505            // Do not record register info for builtins.
    506            // TODO(jmadill): Clean this up.
    507            if (!varying.isBuiltIn())
    508            {
    509                mRegisterList.push_back(registerInfo);
    510            }
    511 
    512            for (unsigned int columnIndex = 0; columnIndex < varyingColumns; ++columnIndex)
    513            {
    514                mRegisterMap[registerInfo.registerRow][registerColumn + columnIndex] = true;
    515            }
    516        }
    517    }
    518 }
    519 
    520 void VaryingPacking::collectUserVarying(const ProgramVaryingRef &ref,
    521                                        VaryingUniqueFullNames *uniqueFullNames)
    522 {
    523    const sh::ShaderVariable *input  = ref.frontShader;
    524    const sh::ShaderVariable *output = ref.backShader;
    525 
    526    // Will get the vertex shader interpolation by default.
    527    sh::InterpolationType interpolation = input ? input->interpolation : output->interpolation;
    528 
    529    VaryingInShaderRef frontVarying(ref.frontShaderStage, input);
    530    VaryingInShaderRef backVarying(ref.backShaderStage, output);
    531 
    532    mPackedVaryings.emplace_back(std::move(frontVarying), std::move(backVarying), interpolation);
    533    if (input && !input->isBuiltIn())
    534    {
    535        (*uniqueFullNames)[ref.frontShaderStage].insert(
    536            mPackedVaryings.back().fullName(ref.frontShaderStage));
    537    }
    538    if (output && !output->isBuiltIn())
    539    {
    540        (*uniqueFullNames)[ref.backShaderStage].insert(
    541            mPackedVaryings.back().fullName(ref.backShaderStage));
    542    }
    543 }
    544 
    545 void VaryingPacking::collectUserVaryingField(const ProgramVaryingRef &ref,
    546                                             GLuint arrayIndex,
    547                                             GLuint fieldIndex,
    548                                             GLuint secondaryFieldIndex,
    549                                             VaryingUniqueFullNames *uniqueFullNames)
    550 {
    551    const sh::ShaderVariable *input  = ref.frontShader;
    552    const sh::ShaderVariable *output = ref.backShader;
    553 
    554    // Will get the vertex shader interpolation by default.
    555    sh::InterpolationType interpolation = input ? input->interpolation : output->interpolation;
    556 
    557    const sh::ShaderVariable *frontField = input ? &input->fields[fieldIndex] : nullptr;
    558    const sh::ShaderVariable *backField  = output ? &output->fields[fieldIndex] : nullptr;
    559 
    560    if (secondaryFieldIndex != GL_INVALID_INDEX)
    561    {
    562        frontField = frontField ? &frontField->fields[secondaryFieldIndex] : nullptr;
    563        backField  = backField ? &backField->fields[secondaryFieldIndex] : nullptr;
    564    }
    565 
    566    VaryingInShaderRef frontVarying(ref.frontShaderStage, frontField);
    567    VaryingInShaderRef backVarying(ref.backShaderStage, backField);
    568 
    569    if (input)
    570    {
    571        if (frontField->isShaderIOBlock)
    572        {
    573            frontVarying.parentStructName       = input->structOrBlockName;
    574            frontVarying.parentStructMappedName = input->mappedStructOrBlockName;
    575        }
    576        else
    577        {
    578            ASSERT(!frontField->isStruct() && !frontField->isArray());
    579            frontVarying.parentStructName       = input->name;
    580            frontVarying.parentStructMappedName = input->mappedName;
    581        }
    582    }
    583    if (output)
    584    {
    585        if (backField->isShaderIOBlock)
    586        {
    587            backVarying.parentStructName       = output->structOrBlockName;
    588            backVarying.parentStructMappedName = output->mappedStructOrBlockName;
    589        }
    590        else
    591        {
    592            ASSERT(!backField->isStruct() && !backField->isArray());
    593            backVarying.parentStructName       = output->name;
    594            backVarying.parentStructMappedName = output->mappedName;
    595        }
    596    }
    597 
    598    mPackedVaryings.emplace_back(std::move(frontVarying), std::move(backVarying), interpolation,
    599                                 arrayIndex, fieldIndex,
    600                                 secondaryFieldIndex == GL_INVALID_INDEX ? 0 : secondaryFieldIndex);
    601 
    602    if (input)
    603    {
    604        (*uniqueFullNames)[ref.frontShaderStage].insert(
    605            mPackedVaryings.back().fullName(ref.frontShaderStage));
    606    }
    607    if (output)
    608    {
    609        (*uniqueFullNames)[ref.backShaderStage].insert(
    610            mPackedVaryings.back().fullName(ref.backShaderStage));
    611    }
    612 }
    613 
    614 void VaryingPacking::collectUserVaryingTF(const ProgramVaryingRef &ref, size_t subscript)
    615 {
    616    const sh::ShaderVariable *input = ref.frontShader;
    617 
    618    VaryingInShaderRef frontVarying(ref.frontShaderStage, input);
    619    VaryingInShaderRef backVarying(ref.backShaderStage, nullptr);
    620 
    621    mPackedVaryings.emplace_back(std::move(frontVarying), std::move(backVarying),
    622                                 input->interpolation);
    623    mPackedVaryings.back().arrayIndex          = static_cast<GLuint>(subscript);
    624    mPackedVaryings.back().isTransformFeedback = true;
    625 }
    626 
    627 void VaryingPacking::collectUserVaryingFieldTF(const ProgramVaryingRef &ref,
    628                                               const sh::ShaderVariable &field,
    629                                               GLuint fieldIndex,
    630                                               GLuint secondaryFieldIndex)
    631 {
    632    const sh::ShaderVariable *input = ref.frontShader;
    633 
    634    const sh::ShaderVariable *frontField = &field;
    635    if (secondaryFieldIndex != GL_INVALID_INDEX)
    636    {
    637        frontField = &frontField->fields[secondaryFieldIndex];
    638    }
    639 
    640    VaryingInShaderRef frontVarying(ref.frontShaderStage, frontField);
    641    VaryingInShaderRef backVarying(ref.backShaderStage, nullptr);
    642 
    643    if (frontField->isShaderIOBlock)
    644    {
    645        frontVarying.parentStructName       = input->structOrBlockName;
    646        frontVarying.parentStructMappedName = input->mappedStructOrBlockName;
    647    }
    648    else
    649    {
    650        ASSERT(!frontField->isStruct() && !frontField->isArray());
    651        frontVarying.parentStructName       = input->name;
    652        frontVarying.parentStructMappedName = input->mappedName;
    653    }
    654 
    655    mPackedVaryings.emplace_back(std::move(frontVarying), std::move(backVarying),
    656                                 input->interpolation, GL_INVALID_INDEX, fieldIndex,
    657                                 secondaryFieldIndex == GL_INVALID_INDEX ? 0 : secondaryFieldIndex);
    658 }
    659 
    660 void VaryingPacking::collectVarying(const sh::ShaderVariable &varying,
    661                                    const ProgramVaryingRef &ref,
    662                                    PackMode packMode,
    663                                    VaryingUniqueFullNames *uniqueFullNames)
    664 {
    665    const sh::ShaderVariable *input  = ref.frontShader;
    666    const sh::ShaderVariable *output = ref.backShader;
    667 
    668    if (varying.isStruct())
    669    {
    670        std::vector<unsigned int> arraySizes = StripVaryingArrayDimension(
    671            ref.frontShader, ref.frontShaderStage, ref.backShader, ref.backShaderStage, false);
    672        const bool isArray     = !arraySizes.empty();
    673        const GLuint arraySize = isArray ? arraySizes[0] : 1;
    674 
    675        for (GLuint arrayIndex = 0; arrayIndex < arraySize; ++arrayIndex)
    676        {
    677            const GLuint effectiveArrayIndex = isArray ? arrayIndex : GL_INVALID_INDEX;
    678            for (GLuint fieldIndex = 0; fieldIndex < varying.fields.size(); ++fieldIndex)
    679            {
    680                const sh::ShaderVariable &fieldVarying = varying.fields[fieldIndex];
    681                if (ShouldSkipPackedVarying(fieldVarying, packMode))
    682                {
    683                    continue;
    684                }
    685 
    686                if (fieldVarying.isStruct())
    687                {
    688                    if (fieldVarying.isArray())
    689                    {
    690                        unsigned int structFieldArraySize = fieldVarying.arraySizes[0];
    691                        for (unsigned int fieldArrayIndex = 0;
    692                             fieldArrayIndex < structFieldArraySize; ++fieldArrayIndex)
    693                        {
    694                            for (GLuint nestedIndex = 0; nestedIndex < fieldVarying.fields.size();
    695                                 nestedIndex++)
    696                            {
    697                                collectUserVaryingField(ref, effectiveArrayIndex, fieldIndex,
    698                                                        nestedIndex, uniqueFullNames);
    699                            }
    700                        }
    701                    }
    702                    else
    703                    {
    704                        for (GLuint nestedIndex = 0; nestedIndex < fieldVarying.fields.size();
    705                             nestedIndex++)
    706                        {
    707                            collectUserVaryingField(ref, effectiveArrayIndex, fieldIndex,
    708                                                    nestedIndex, uniqueFullNames);
    709                        }
    710                    }
    711                }
    712                else
    713                {
    714                    collectUserVaryingField(ref, effectiveArrayIndex, fieldIndex, GL_INVALID_INDEX,
    715                                            uniqueFullNames);
    716                }
    717            }
    718        }
    719        if (input)
    720        {
    721            (*uniqueFullNames)[ref.frontShaderStage].insert(input->name);
    722            if (input->isShaderIOBlock)
    723            {
    724                (*uniqueFullNames)[ref.frontShaderStage].insert(input->structOrBlockName);
    725            }
    726        }
    727        if (output)
    728        {
    729            (*uniqueFullNames)[ref.backShaderStage].insert(output->name);
    730        }
    731    }
    732    else
    733    {
    734        collectUserVarying(ref, uniqueFullNames);
    735    }
    736 }
    737 
    738 void VaryingPacking::collectTFVarying(const std::string &tfVarying,
    739                                      const ProgramVaryingRef &ref,
    740                                      VaryingUniqueFullNames *uniqueFullNames)
    741 {
    742    const sh::ShaderVariable *input = ref.frontShader;
    743 
    744    std::vector<unsigned int> subscripts;
    745    std::string baseName = ParseResourceName(tfVarying, &subscripts);
    746 
    747    // Already packed as active varying.
    748    if ((*uniqueFullNames)[ref.frontShaderStage].count(tfVarying) > 0 ||
    749        (*uniqueFullNames)[ref.frontShaderStage].count(baseName) > 0 ||
    750        (input->isShaderIOBlock &&
    751         (*uniqueFullNames)[ref.frontShaderStage].count(input->structOrBlockName) > 0))
    752    {
    753        return;
    754    }
    755 
    756    if (input->isStruct())
    757    {
    758        GLuint fieldIndex               = 0;
    759        const sh::ShaderVariable *field = input->findField(tfVarying, &fieldIndex);
    760        if (field != nullptr)
    761        {
    762            ASSERT(input->isShaderIOBlock || (!field->isStruct() && !field->isArray()));
    763 
    764            // If it's an I/O block whose member is being captured, pack every member of the
    765            // block.  Currently, we pack either all or none of an I/O block.
    766            if (input->isShaderIOBlock)
    767            {
    768                for (fieldIndex = 0; fieldIndex < input->fields.size(); ++fieldIndex)
    769                {
    770                    if (input->fields[fieldIndex].isStruct())
    771                    {
    772 
    773                        for (GLuint nestedIndex = 0;
    774                             nestedIndex < input->fields[fieldIndex].fields.size(); nestedIndex++)
    775                        {
    776                            collectUserVaryingFieldTF(ref, input->fields[fieldIndex], fieldIndex,
    777                                                      nestedIndex);
    778                        }
    779                    }
    780                    else
    781                    {
    782                        collectUserVaryingFieldTF(ref, input->fields[fieldIndex], fieldIndex,
    783                                                  GL_INVALID_INDEX);
    784                    }
    785                }
    786 
    787                (*uniqueFullNames)[ref.frontShaderStage].insert(input->structOrBlockName);
    788            }
    789            else
    790            {
    791                collectUserVaryingFieldTF(ref, *field, fieldIndex, GL_INVALID_INDEX);
    792            }
    793            (*uniqueFullNames)[ref.frontShaderStage].insert(tfVarying);
    794            (*uniqueFullNames)[ref.frontShaderStage].insert(input->name);
    795        }
    796    }
    797    // Array as a whole and array element conflict has already been checked in
    798    // linkValidateTransformFeedback.
    799    else if (baseName == input->name)
    800    {
    801        size_t subscript = GL_INVALID_INDEX;
    802        if (!subscripts.empty())
    803        {
    804            subscript = subscripts.back();
    805        }
    806 
    807        // only pack varyings that are not builtins.
    808        if (tfVarying.compare(0, 3, "gl_") != 0)
    809        {
    810            collectUserVaryingTF(ref, subscript);
    811            (*uniqueFullNames)[ref.frontShaderStage].insert(tfVarying);
    812        }
    813    }
    814 }
    815 
    816 bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog,
    817                                                GLint maxVaryingVectors,
    818                                                PackMode packMode,
    819                                                ShaderType frontShaderStage,
    820                                                ShaderType backShaderStage,
    821                                                const ProgramMergedVaryings &mergedVaryings,
    822                                                const std::vector<std::string> &tfVaryings,
    823                                                const bool isSeparableProgram)
    824 {
    825    VaryingUniqueFullNames uniqueFullNames;
    826 
    827    reset();
    828 
    829    for (const ProgramVaryingRef &ref : mergedVaryings)
    830    {
    831        const sh::ShaderVariable *input  = ref.frontShader;
    832        const sh::ShaderVariable *output = ref.backShader;
    833 
    834        if ((input && ref.frontShaderStage != frontShaderStage) ||
    835            (output && ref.backShaderStage != backShaderStage))
    836        {
    837            continue;
    838        }
    839 
    840        const bool isActiveBuiltInInput  = input && input->isBuiltIn() && input->active;
    841        const bool isActiveBuiltInOutput = output && output->isBuiltIn() && output->active;
    842 
    843        // Keep track of output builtins that are used by the shader, such as gl_Position,
    844        // gl_PointSize etc.
    845        if (isActiveBuiltInInput)
    846        {
    847            mActiveOutputBuiltIns[ref.frontShaderStage].push_back(input->name);
    848            // Keep track of members of builtins, such as gl_out[].gl_Position, too.
    849            for (sh::ShaderVariable field : input->fields)
    850            {
    851                mActiveOutputBuiltIns[ref.frontShaderStage].push_back(field.name);
    852            }
    853        }
    854 
    855        // Only pack statically used varyings that have a matched input or output, plus special
    856        // builtins. Note that we pack all statically used user-defined varyings even if they are
    857        // not active. GLES specs are a bit vague on whether it's allowed to only pack active
    858        // varyings, though GLES 3.1 spec section 11.1.2.1 says that "device-dependent
    859        // optimizations" may be used to make vertex shader outputs fit.
    860        //
    861        // When separable programs are linked, varyings at the separable program's boundary are
    862        // treated as active. See section 7.4.1 in
    863        // https://www.khronos.org/registry/OpenGL/specs/es/3.2/es_spec_3.2.pdf
    864        bool matchedInputOutputStaticUse = (input && output && output->staticUse);
    865        bool activeBuiltIn               = (isActiveBuiltInInput || isActiveBuiltInOutput);
    866 
    867        // Output variable in TCS can be read as input in another invocation by barrier.
    868        // See section 11.2.1.2.4 Tessellation Control Shader Execution Order in OpenGL ES 3.2.
    869        bool staticUseInTCS =
    870            (input && input->staticUse && ref.frontShaderStage == ShaderType::TessControl);
    871 
    872        // Separable program requirements
    873        bool separableActiveInput  = (input && (input->active || !output));
    874        bool separableActiveOutput = (output && (output->active || !input));
    875        bool separableActiveVarying =
    876            (isSeparableProgram && (separableActiveInput || separableActiveOutput));
    877 
    878        if (matchedInputOutputStaticUse || activeBuiltIn || separableActiveVarying ||
    879            staticUseInTCS)
    880        {
    881            const sh::ShaderVariable *varying = output ? output : input;
    882 
    883            if (!ShouldSkipPackedVarying(*varying, packMode))
    884            {
    885                collectVarying(*varying, ref, packMode, &uniqueFullNames);
    886                continue;
    887            }
    888        }
    889 
    890        // If the varying is not used in the input, we know it is inactive, unless it's a separable
    891        // program, in which case the input shader may not exist in this program.
    892        if (!input && !isSeparableProgram)
    893        {
    894            if (!output->isBuiltIn())
    895            {
    896                mInactiveVaryingMappedNames[ref.backShaderStage].push_back(output->mappedName);
    897                if (output->isShaderIOBlock)
    898                {
    899                    mInactiveVaryingMappedNames[ref.backShaderStage].push_back(
    900                        output->mappedStructOrBlockName);
    901                }
    902            }
    903            continue;
    904        }
    905 
    906        // Keep Transform FB varyings in the merged list always.
    907        for (const std::string &tfVarying : tfVaryings)
    908        {
    909            collectTFVarying(tfVarying, ref, &uniqueFullNames);
    910        }
    911 
    912        if (input && !input->isBuiltIn() &&
    913            uniqueFullNames[ref.frontShaderStage].count(input->name) == 0)
    914        {
    915            mInactiveVaryingMappedNames[ref.frontShaderStage].push_back(input->mappedName);
    916            if (input->isShaderIOBlock)
    917            {
    918                mInactiveVaryingMappedNames[ref.frontShaderStage].push_back(
    919                    input->mappedStructOrBlockName);
    920            }
    921        }
    922        if (output && !output->isBuiltIn() &&
    923            uniqueFullNames[ref.backShaderStage].count(output->name) == 0)
    924        {
    925            mInactiveVaryingMappedNames[ref.backShaderStage].push_back(output->mappedName);
    926            if (output->isShaderIOBlock)
    927            {
    928                mInactiveVaryingMappedNames[ref.backShaderStage].push_back(
    929                    output->mappedStructOrBlockName);
    930            }
    931        }
    932    }
    933 
    934    std::sort(mPackedVaryings.begin(), mPackedVaryings.end(), ComparePackedVarying);
    935 
    936    return packUserVaryings(infoLog, maxVaryingVectors, packMode, mPackedVaryings);
    937 }
    938 
    939 // See comment on packVarying.
    940 bool VaryingPacking::packUserVaryings(gl::InfoLog &infoLog,
    941                                      GLint maxVaryingVectors,
    942                                      PackMode packMode,
    943                                      const std::vector<PackedVarying> &packedVaryings)
    944 {
    945    clearRegisterMap();
    946    mRegisterMap.resize(maxVaryingVectors);
    947 
    948    // "Variables are packed into the registers one at a time so that they each occupy a contiguous
    949    // subrectangle. No splitting of variables is permitted."
    950    for (const PackedVarying &packedVarying : packedVaryings)
    951    {
    952        if (!packVaryingIntoRegisterMap(packMode, packedVarying))
    953        {
    954            ShaderType eitherStage = packedVarying.frontVarying.varying
    955                                         ? packedVarying.frontVarying.stage
    956                                         : packedVarying.backVarying.stage;
    957            infoLog << "Could not pack varying " << packedVarying.fullName(eitherStage);
    958 
    959            // TODO(jmadill): Implement more sophisticated component packing in D3D9.
    960            if (packMode == PackMode::ANGLE_NON_CONFORMANT_D3D9)
    961            {
    962                infoLog << "Note: Additional non-conformant packing restrictions are enforced on "
    963                           "D3D9.";
    964            }
    965 
    966            return false;
    967        }
    968    }
    969 
    970    // Sort the packed register list
    971    std::sort(mRegisterList.begin(), mRegisterList.end());
    972 
    973    return true;
    974 }
    975 
    976 // ProgramVaryingPacking implementation.
    977 ProgramVaryingPacking::ProgramVaryingPacking() = default;
    978 
    979 ProgramVaryingPacking::~ProgramVaryingPacking() = default;
    980 
    981 const VaryingPacking &ProgramVaryingPacking::getInputPacking(ShaderType backShaderStage) const
    982 {
    983    ShaderType frontShaderStage = mBackToFrontStageMap[backShaderStage];
    984 
    985    // If there's a missing shader stage, return the compute shader packing which is always empty.
    986    if (frontShaderStage == ShaderType::InvalidEnum)
    987    {
    988        ASSERT(mVaryingPackings[ShaderType::Compute].getMaxSemanticIndex() == 0);
    989        return mVaryingPackings[ShaderType::Compute];
    990    }
    991 
    992    return mVaryingPackings[frontShaderStage];
    993 }
    994 
    995 const VaryingPacking &ProgramVaryingPacking::getOutputPacking(ShaderType frontShaderStage) const
    996 {
    997    return mVaryingPackings[frontShaderStage];
    998 }
    999 
   1000 bool ProgramVaryingPacking::collectAndPackUserVaryings(InfoLog &infoLog,
   1001                                                       const Caps &caps,
   1002                                                       PackMode packMode,
   1003                                                       const ShaderBitSet &activeShadersMask,
   1004                                                       const ProgramMergedVaryings &mergedVaryings,
   1005                                                       const std::vector<std::string> &tfVaryings,
   1006                                                       bool isSeparableProgram)
   1007 {
   1008    mBackToFrontStageMap.fill(ShaderType::InvalidEnum);
   1009 
   1010    ShaderBitSet activeShaders = activeShadersMask;
   1011 
   1012    ASSERT(activeShaders.any());
   1013    ShaderType frontShaderStage     = activeShaders.first();
   1014    activeShaders[frontShaderStage] = false;
   1015 
   1016    // Special case for start-after-vertex.
   1017    if (frontShaderStage != ShaderType::Vertex)
   1018    {
   1019        ShaderType emulatedFrontShaderStage = ShaderType::Vertex;
   1020        ShaderType backShaderStage          = frontShaderStage;
   1021 
   1022        if (!mVaryingPackings[emulatedFrontShaderStage].collectAndPackUserVaryings(
   1023                infoLog, GetMaxShaderInputVectors(caps, backShaderStage), packMode,
   1024                ShaderType::InvalidEnum, backShaderStage, mergedVaryings, tfVaryings,
   1025                isSeparableProgram))
   1026        {
   1027            return false;
   1028        }
   1029        mBackToFrontStageMap[backShaderStage] = emulatedFrontShaderStage;
   1030    }
   1031 
   1032    // Process input/output shader pairs.
   1033    for (ShaderType backShaderStage : activeShaders)
   1034    {
   1035        GLint maxVaryingVectors;
   1036        if (frontShaderStage == ShaderType::Vertex && backShaderStage == ShaderType::Fragment)
   1037        {
   1038            maxVaryingVectors = caps.maxVaryingVectors;
   1039        }
   1040        else
   1041        {
   1042            GLint outputVaryingsMax = GetMaxShaderOutputVectors(caps, frontShaderStage);
   1043            GLint inputVaryingsMax  = GetMaxShaderInputVectors(caps, backShaderStage);
   1044            maxVaryingVectors       = std::min(inputVaryingsMax, outputVaryingsMax);
   1045        }
   1046 
   1047        ASSERT(maxVaryingVectors > 0 && maxVaryingVectors < std::numeric_limits<GLint>::max());
   1048 
   1049        if (!mVaryingPackings[frontShaderStage].collectAndPackUserVaryings(
   1050                infoLog, maxVaryingVectors, packMode, frontShaderStage, backShaderStage,
   1051                mergedVaryings, tfVaryings, isSeparableProgram))
   1052        {
   1053            return false;
   1054        }
   1055 
   1056        mBackToFrontStageMap[backShaderStage] = frontShaderStage;
   1057        frontShaderStage                      = backShaderStage;
   1058    }
   1059 
   1060    // Special case for stop-before-fragment.
   1061    if (frontShaderStage != ShaderType::Fragment)
   1062    {
   1063        if (!mVaryingPackings[frontShaderStage].collectAndPackUserVaryings(
   1064                infoLog, GetMaxShaderOutputVectors(caps, frontShaderStage), packMode,
   1065                frontShaderStage, ShaderType::InvalidEnum, mergedVaryings, tfVaryings,
   1066                isSeparableProgram))
   1067        {
   1068            return false;
   1069        }
   1070 
   1071        ShaderType emulatedBackShaderStage            = ShaderType::Fragment;
   1072        mBackToFrontStageMap[emulatedBackShaderStage] = frontShaderStage;
   1073    }
   1074 
   1075    return true;
   1076 }
   1077 
   1078 ProgramMergedVaryings GetMergedVaryingsFromLinkingVariables(
   1079    const LinkingVariables &linkingVariables)
   1080 {
   1081    ShaderType frontShaderType = ShaderType::InvalidEnum;
   1082    ProgramMergedVaryings merged;
   1083 
   1084    for (ShaderType backShaderType : kAllGraphicsShaderTypes)
   1085    {
   1086        if (!linkingVariables.isShaderStageUsedBitset[backShaderType])
   1087        {
   1088            continue;
   1089        }
   1090        const std::vector<sh::ShaderVariable> &backShaderOutputVaryings =
   1091            linkingVariables.outputVaryings[backShaderType];
   1092        const std::vector<sh::ShaderVariable> &backShaderInputVaryings =
   1093            linkingVariables.inputVaryings[backShaderType];
   1094 
   1095        // Add outputs. These are always unmatched since we walk shader stages sequentially.
   1096        for (const sh::ShaderVariable &frontVarying : backShaderOutputVaryings)
   1097        {
   1098            ProgramVaryingRef ref;
   1099            ref.frontShader      = &frontVarying;
   1100            ref.frontShaderStage = backShaderType;
   1101            merged.push_back(ref);
   1102        }
   1103 
   1104        if (frontShaderType == ShaderType::InvalidEnum)
   1105        {
   1106            // If this is our first shader stage, and not a VS, we might have unmatched inputs.
   1107            for (const sh::ShaderVariable &backVarying : backShaderInputVaryings)
   1108            {
   1109                ProgramVaryingRef ref;
   1110                ref.backShader      = &backVarying;
   1111                ref.backShaderStage = backShaderType;
   1112                merged.push_back(ref);
   1113            }
   1114        }
   1115        else
   1116        {
   1117            // Match inputs with the prior shader stage outputs.
   1118            for (const sh::ShaderVariable &backVarying : backShaderInputVaryings)
   1119            {
   1120                bool found = false;
   1121                for (ProgramVaryingRef &ref : merged)
   1122                {
   1123                    if (ref.frontShader && ref.frontShaderStage == frontShaderType &&
   1124                        InterfaceVariablesMatch(*ref.frontShader, backVarying))
   1125                    {
   1126                        ASSERT(ref.backShader == nullptr);
   1127 
   1128                        ref.backShader      = &backVarying;
   1129                        ref.backShaderStage = backShaderType;
   1130                        found               = true;
   1131                        break;
   1132                    }
   1133                }
   1134 
   1135                // Some outputs are never matched, e.g. some builtin variables.
   1136                if (!found)
   1137                {
   1138                    ProgramVaryingRef ref;
   1139                    ref.backShader      = &backVarying;
   1140                    ref.backShaderStage = backShaderType;
   1141                    merged.push_back(ref);
   1142                }
   1143            }
   1144        }
   1145 
   1146        // Save the current back shader to use as the next front shader.
   1147        frontShaderType = backShaderType;
   1148    }
   1149 
   1150    return merged;
   1151 }
   1152 }  // namespace gl