tor-browser

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

StructureHLSL.cpp (22089B)


      1 //
      2 // Copyright 2014 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 // StructureHLSL.cpp:
      7 //   HLSL translation of GLSL constructors and structures.
      8 //
      9 
     10 #include "compiler/translator/StructureHLSL.h"
     11 #include "common/utilities.h"
     12 #include "compiler/translator/OutputHLSL.h"
     13 #include "compiler/translator/Types.h"
     14 #include "compiler/translator/UtilsHLSL.h"
     15 #include "compiler/translator/util.h"
     16 
     17 namespace sh
     18 {
     19 
     20 namespace
     21 {
     22 
     23 TString Define(const TStructure &structure,
     24               bool useHLSLRowMajorPacking,
     25               bool useStd140Packing,
     26               bool forcePadding,
     27               Std140PaddingHelper *padHelper)
     28 {
     29    const TFieldList &fields    = structure.fields();
     30    const bool isNameless       = (structure.symbolType() == SymbolType::Empty);
     31    const TString &structName   = QualifiedStructNameString(structure, useHLSLRowMajorPacking,
     32                                                          useStd140Packing, forcePadding);
     33    const TString declareString = (isNameless ? "struct" : "struct " + structName);
     34 
     35    TString string;
     36    string += declareString +
     37              "\n"
     38              "{\n";
     39 
     40    size_t memberSize = fields.size();
     41    for (const TField *field : fields)
     42    {
     43        memberSize--;
     44        const TType &fieldType = *field->type();
     45        if (!IsSampler(fieldType.getBasicType()))
     46        {
     47            const TStructure *fieldStruct = fieldType.getStruct();
     48            const TString &fieldTypeString =
     49                fieldStruct ? QualifiedStructNameString(*fieldStruct, useHLSLRowMajorPacking,
     50                                                        useStd140Packing, false)
     51                            : TypeString(fieldType);
     52 
     53            if (padHelper)
     54            {
     55                string += padHelper->prePaddingString(
     56                    fieldType, (memberSize != fields.size() - 1) && forcePadding);
     57            }
     58 
     59            string += "    " + fieldTypeString + " " + DecorateField(field->name(), structure) +
     60                      ArrayString(fieldType).data() + ";\n";
     61 
     62            if (padHelper)
     63            {
     64                string += padHelper->postPaddingString(fieldType, useHLSLRowMajorPacking,
     65                                                       memberSize == 0, forcePadding);
     66            }
     67        }
     68    }
     69 
     70    // Nameless structs do not finish with a semicolon and newline, to leave room for an instance
     71    // variable
     72    string += (isNameless ? "} " : "};\n");
     73 
     74    return string;
     75 }
     76 
     77 TString WriteParameterList(const std::vector<TType> &parameters)
     78 {
     79    TString parameterList;
     80    for (size_t parameter = 0u; parameter < parameters.size(); parameter++)
     81    {
     82        const TType &paramType = parameters[parameter];
     83 
     84        parameterList +=
     85            TypeString(paramType) + " x" + str(parameter) + ArrayString(paramType).data();
     86 
     87        if (parameter < parameters.size() - 1u)
     88        {
     89            parameterList += ", ";
     90        }
     91    }
     92    return parameterList;
     93 }
     94 
     95 int GetElementPadding(int elementIndex, int alignment)
     96 {
     97    const int paddingOffset = elementIndex % alignment;
     98    return paddingOffset != 0 ? (alignment - paddingOffset) : 0;
     99 }
    100 
    101 }  // anonymous namespace
    102 
    103 Std140PaddingHelper::Std140PaddingHelper(const std::map<TString, int> &structElementIndexes,
    104                                         unsigned *uniqueCounter)
    105    : mPaddingCounter(uniqueCounter), mElementIndex(0), mStructElementIndexes(&structElementIndexes)
    106 {}
    107 
    108 Std140PaddingHelper::Std140PaddingHelper(const Std140PaddingHelper &other)
    109    : mPaddingCounter(other.mPaddingCounter),
    110      mElementIndex(other.mElementIndex),
    111      mStructElementIndexes(other.mStructElementIndexes)
    112 {}
    113 
    114 Std140PaddingHelper &Std140PaddingHelper::operator=(const Std140PaddingHelper &other)
    115 {
    116    mPaddingCounter       = other.mPaddingCounter;
    117    mElementIndex         = other.mElementIndex;
    118    mStructElementIndexes = other.mStructElementIndexes;
    119    return *this;
    120 }
    121 
    122 TString Std140PaddingHelper::next()
    123 {
    124    unsigned value = (*mPaddingCounter)++;
    125    return str(value);
    126 }
    127 
    128 int Std140PaddingHelper::prePadding(const TType &type, bool forcePadding)
    129 {
    130    if (type.getBasicType() == EbtStruct || type.isMatrix() || type.isArray())
    131    {
    132        if (forcePadding)
    133        {
    134            // Add padding between the structure's members to follow the std140 rules manually.
    135            const int forcePaddingCount = GetElementPadding(mElementIndex, 4);
    136            mElementIndex               = 0;
    137            return forcePaddingCount;
    138        }
    139        else
    140        {
    141            // no padding needed, HLSL will align the field to a new register
    142            mElementIndex = 0;
    143            return 0;
    144        }
    145    }
    146 
    147    const GLenum glType     = GLVariableType(type);
    148    const int numComponents = gl::VariableComponentCount(glType);
    149 
    150    if (numComponents >= 4)
    151    {
    152        if (forcePadding)
    153        {
    154            // Add padding between the structure's members to follow the std140 rules manually.
    155            const int forcePaddingCount = GetElementPadding(mElementIndex, 4);
    156            mElementIndex               = numComponents % 4;
    157            return forcePaddingCount;
    158        }
    159        else
    160        {
    161            // no padding needed, HLSL will align the field to a new register
    162            mElementIndex = 0;
    163            return 0;
    164        }
    165    }
    166 
    167    if (mElementIndex + numComponents > 4)
    168    {
    169        if (forcePadding)
    170        {
    171            // Add padding between the structure's members to follow the std140 rules manually.
    172            const int forcePaddingCount = GetElementPadding(mElementIndex, 4);
    173            mElementIndex               = numComponents;
    174            return forcePaddingCount;
    175        }
    176        else
    177        {
    178            // no padding needed, HLSL will align the field to a new register
    179            mElementIndex = numComponents;
    180            return 0;
    181        }
    182    }
    183 
    184    const int alignment    = numComponents == 3 ? 4 : numComponents;
    185    const int paddingCount = GetElementPadding(mElementIndex, alignment);
    186 
    187    mElementIndex += paddingCount;
    188    mElementIndex += numComponents;
    189    mElementIndex %= 4;
    190 
    191    return paddingCount;
    192 }
    193 
    194 TString Std140PaddingHelper::prePaddingString(const TType &type, bool forcePadding)
    195 {
    196    int paddingCount = prePadding(type, forcePadding);
    197 
    198    TString padding;
    199 
    200    for (int paddingIndex = 0; paddingIndex < paddingCount; paddingIndex++)
    201    {
    202        padding += "    float pad_" + next() + ";\n";
    203    }
    204 
    205    return padding;
    206 }
    207 
    208 TString Std140PaddingHelper::postPaddingString(const TType &type,
    209                                               bool useHLSLRowMajorPacking,
    210                                               bool isLastElement,
    211                                               bool forcePadding)
    212 {
    213    if (!type.isMatrix() && !type.isArray() && type.getBasicType() != EbtStruct)
    214    {
    215        if (forcePadding)
    216        {
    217            const GLenum glType     = GLVariableType(type);
    218            const int numComponents = gl::VariableComponentCount(glType);
    219            if (isLastElement || (numComponents >= 4))
    220            {
    221                // If this structure will be used as HLSL StructuredBuffer member's type, in
    222                // order to follow the std140 rules, add padding at the end of the structure
    223                // if necessary. Or if the current element straddles a vec4 boundary, add
    224                // padding to round up the base offset of the next element to the base
    225                // alignment of a vec4.
    226                TString forcePaddingStr;
    227                const int paddingCount = GetElementPadding(mElementIndex, 4);
    228                for (int paddingIndex = 0; paddingIndex < paddingCount; paddingIndex++)
    229                {
    230                    forcePaddingStr += "    float pad_" + next() + ";\n";
    231                }
    232                mElementIndex = 0;
    233                return forcePaddingStr;
    234            }
    235        }
    236 
    237        return "";
    238    }
    239 
    240    int numComponents           = 0;
    241    const TStructure *structure = type.getStruct();
    242 
    243    if (type.isMatrix())
    244    {
    245        // This method can also be called from structureString, which does not use layout
    246        // qualifiers.
    247        // Thus, use the method parameter for determining the matrix packing.
    248        //
    249        // Note HLSL row major packing corresponds to GL API column-major, and vice-versa, since we
    250        // wish to always transpose GL matrices to play well with HLSL's matrix array indexing.
    251        //
    252        const bool isRowMajorMatrix = !useHLSLRowMajorPacking;
    253        const GLenum glType         = GLVariableType(type);
    254        numComponents               = gl::MatrixComponentCount(glType, isRowMajorMatrix);
    255    }
    256    else if (structure)
    257    {
    258        const TString &structName =
    259            QualifiedStructNameString(*structure, useHLSLRowMajorPacking, true, false);
    260        numComponents = mStructElementIndexes->find(structName)->second;
    261 
    262        if (numComponents == 0)
    263        {
    264            return "";
    265        }
    266    }
    267    else
    268    {
    269        const GLenum glType = GLVariableType(type);
    270        numComponents       = gl::VariableComponentCount(glType);
    271    }
    272 
    273    TString padding;
    274    for (int paddingOffset = numComponents; paddingOffset < 4; paddingOffset++)
    275    {
    276        padding += "    float pad_" + next() + ";\n";
    277    }
    278    return padding;
    279 }
    280 
    281 StructureHLSL::StructureHLSL() : mUniquePaddingCounter(0) {}
    282 
    283 Std140PaddingHelper StructureHLSL::getPaddingHelper()
    284 {
    285    return Std140PaddingHelper(mStd140StructElementIndexes, &mUniquePaddingCounter);
    286 }
    287 
    288 TString StructureHLSL::defineQualified(const TStructure &structure,
    289                                       bool useHLSLRowMajorPacking,
    290                                       bool useStd140Packing,
    291                                       bool forcePadding)
    292 {
    293    if (useStd140Packing)
    294    {
    295        Std140PaddingHelper padHelper = getPaddingHelper();
    296        return Define(structure, useHLSLRowMajorPacking, useStd140Packing, forcePadding,
    297                      &padHelper);
    298    }
    299    else
    300    {
    301        return Define(structure, useHLSLRowMajorPacking, useStd140Packing, false, nullptr);
    302    }
    303 }
    304 
    305 TString StructureHLSL::defineNameless(const TStructure &structure)
    306 {
    307    return Define(structure, false, false, false, nullptr);
    308 }
    309 
    310 StructureHLSL::DefinedStructs::iterator StructureHLSL::defineVariants(const TStructure &structure,
    311                                                                      const TString &name)
    312 {
    313    ASSERT(mDefinedStructs.find(name) == mDefinedStructs.end());
    314 
    315    for (const TField *field : structure.fields())
    316    {
    317        const TType *fieldType = field->type();
    318        if (fieldType->getBasicType() == EbtStruct)
    319        {
    320            ensureStructDefined(*fieldType->getStruct());
    321        }
    322    }
    323 
    324    DefinedStructs::iterator addedStruct =
    325        mDefinedStructs.insert(std::make_pair(name, new TStructProperties())).first;
    326    // Add element index
    327    storeStd140ElementIndex(structure, false);
    328    storeStd140ElementIndex(structure, true);
    329 
    330    const TString &structString = defineQualified(structure, false, false, false);
    331 
    332    ASSERT(std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structString) ==
    333           mStructDeclarations.end());
    334    // Add row-major packed struct for interface blocks
    335    TString rowMajorString = "#pragma pack_matrix(row_major)\n" +
    336                             defineQualified(structure, true, false, false) +
    337                             "#pragma pack_matrix(column_major)\n";
    338 
    339    TString std140String         = defineQualified(structure, false, true, false);
    340    TString std140RowMajorString = "#pragma pack_matrix(row_major)\n" +
    341                                   defineQualified(structure, true, true, false) +
    342                                   "#pragma pack_matrix(column_major)\n";
    343 
    344    // Must force to pad the structure's elements for StructuredBuffer's element type, if qualifier
    345    // of structure is std140.
    346    TString std140ForcePaddingString         = defineQualified(structure, false, true, true);
    347    TString std140RowMajorForcePaddingString = "#pragma pack_matrix(row_major)\n" +
    348                                               defineQualified(structure, true, true, true) +
    349                                               "#pragma pack_matrix(column_major)\n";
    350 
    351    mStructDeclarations.push_back(structString);
    352    mStructDeclarations.push_back(rowMajorString);
    353    mStructDeclarations.push_back(std140String);
    354    mStructDeclarations.push_back(std140RowMajorString);
    355    mStructDeclarations.push_back(std140ForcePaddingString);
    356    mStructDeclarations.push_back(std140RowMajorForcePaddingString);
    357    return addedStruct;
    358 }
    359 
    360 void StructureHLSL::ensureStructDefined(const TStructure &structure)
    361 {
    362    const TString name = StructNameString(structure);
    363    if (name == "")
    364    {
    365        return;  // Nameless structures are not defined
    366    }
    367    if (mDefinedStructs.find(name) == mDefinedStructs.end())
    368    {
    369        defineVariants(structure, name);
    370    }
    371 }
    372 
    373 TString StructureHLSL::addStructConstructor(const TStructure &structure)
    374 {
    375    const TString name = StructNameString(structure);
    376 
    377    if (name == "")
    378    {
    379        return TString();  // Nameless structures don't have constructors
    380    }
    381 
    382    auto definedStruct = mDefinedStructs.find(name);
    383    if (definedStruct == mDefinedStructs.end())
    384    {
    385        definedStruct = defineVariants(structure, name);
    386    }
    387    const TString constructorFunctionName = TString(name) + "_ctor";
    388    TString *constructor                  = &definedStruct->second->constructor;
    389    if (!constructor->empty())
    390    {
    391        return constructorFunctionName;  // Already added
    392    }
    393    *constructor += name + " " + constructorFunctionName + "(";
    394 
    395    std::vector<TType> ctorParameters;
    396    const TFieldList &fields = structure.fields();
    397    for (const TField *field : fields)
    398    {
    399        const TType *fieldType = field->type();
    400        if (!IsSampler(fieldType->getBasicType()))
    401        {
    402            ctorParameters.push_back(*fieldType);
    403        }
    404    }
    405    // Structs that have sampler members should not have constructor calls, and otherwise structs
    406    // are guaranteed to be non-empty by the grammar. Structs can't contain empty declarations
    407    // either.
    408    ASSERT(!ctorParameters.empty());
    409 
    410    *constructor += WriteParameterList(ctorParameters);
    411 
    412    *constructor +=
    413        ")\n"
    414        "{\n"
    415        "    " +
    416        name + " structure = { ";
    417 
    418    for (size_t parameterIndex = 0u; parameterIndex < ctorParameters.size(); ++parameterIndex)
    419    {
    420        *constructor += "x" + str(parameterIndex);
    421        if (parameterIndex < ctorParameters.size() - 1u)
    422        {
    423            *constructor += ", ";
    424        }
    425    }
    426    *constructor +=
    427        "};\n"
    428        "    return structure;\n"
    429        "}\n";
    430 
    431    return constructorFunctionName;
    432 }
    433 
    434 TString StructureHLSL::addBuiltInConstructor(const TType &type, const TIntermSequence *parameters)
    435 {
    436    ASSERT(!type.isArray());
    437    ASSERT(type.getStruct() == nullptr);
    438    ASSERT(parameters);
    439 
    440    TType ctorType = type;
    441    ctorType.setPrecision(EbpHigh);
    442    ctorType.setQualifier(EvqTemporary);
    443 
    444    const TString constructorFunctionName =
    445        TString(type.getBuiltInTypeNameString()) + "_ctor" + DisambiguateFunctionName(parameters);
    446    TString constructor = TypeString(ctorType) + " " + constructorFunctionName + "(";
    447 
    448    std::vector<TType> ctorParameters;
    449    for (auto parameter : *parameters)
    450    {
    451        const TType &paramType = parameter->getAsTyped()->getType();
    452        ASSERT(!paramType.isArray());
    453        ctorParameters.push_back(paramType);
    454    }
    455    constructor += WriteParameterList(ctorParameters);
    456 
    457    constructor +=
    458        ")\n"
    459        "{\n"
    460        "    return " +
    461        TypeString(ctorType) + "(";
    462 
    463    if (ctorType.isMatrix() && ctorParameters.size() == 1)
    464    {
    465        uint8_t rows           = ctorType.getRows();
    466        uint8_t cols           = ctorType.getCols();
    467        const TType &parameter = ctorParameters[0];
    468 
    469        if (parameter.isScalar())
    470        {
    471            for (uint8_t col = 0; col < cols; col++)
    472            {
    473                for (uint8_t row = 0; row < rows; row++)
    474                {
    475                    constructor += TString((row == col) ? "x0" : "0.0");
    476 
    477                    if (row < rows - 1 || col < cols - 1)
    478                    {
    479                        constructor += ", ";
    480                    }
    481                }
    482            }
    483        }
    484        else if (parameter.isMatrix())
    485        {
    486            for (uint8_t col = 0; col < cols; col++)
    487            {
    488                for (uint8_t row = 0; row < rows; row++)
    489                {
    490                    if (row < parameter.getRows() && col < parameter.getCols())
    491                    {
    492                        constructor += TString("x0") + "[" + str(col) + "][" + str(row) + "]";
    493                    }
    494                    else
    495                    {
    496                        constructor += TString((row == col) ? "1.0" : "0.0");
    497                    }
    498 
    499                    if (row < rows - 1 || col < cols - 1)
    500                    {
    501                        constructor += ", ";
    502                    }
    503                }
    504            }
    505        }
    506        else
    507        {
    508            ASSERT(rows == 2 && cols == 2 && parameter.isVector() &&
    509                   parameter.getNominalSize() == 4);
    510 
    511            constructor += "x0";
    512        }
    513    }
    514    else
    515    {
    516        size_t remainingComponents = ctorType.getObjectSize();
    517        size_t parameterIndex      = 0;
    518 
    519        while (remainingComponents > 0)
    520        {
    521            const TType &parameter     = ctorParameters[parameterIndex];
    522            const size_t parameterSize = parameter.getObjectSize();
    523            bool moreParameters        = parameterIndex + 1 < ctorParameters.size();
    524 
    525            constructor += "x" + str(parameterIndex);
    526 
    527            if (parameter.isScalar())
    528            {
    529                remainingComponents -= parameter.getObjectSize();
    530            }
    531            else if (parameter.isVector())
    532            {
    533                if (remainingComponents == parameterSize || moreParameters)
    534                {
    535                    ASSERT(parameterSize <= remainingComponents);
    536                    remainingComponents -= parameterSize;
    537                }
    538                else if (remainingComponents < static_cast<size_t>(parameter.getNominalSize()))
    539                {
    540                    switch (remainingComponents)
    541                    {
    542                        case 1:
    543                            constructor += ".x";
    544                            break;
    545                        case 2:
    546                            constructor += ".xy";
    547                            break;
    548                        case 3:
    549                            constructor += ".xyz";
    550                            break;
    551                        case 4:
    552                            constructor += ".xyzw";
    553                            break;
    554                        default:
    555                            UNREACHABLE();
    556                    }
    557 
    558                    remainingComponents = 0;
    559                }
    560                else
    561                    UNREACHABLE();
    562            }
    563            else if (parameter.isMatrix())
    564            {
    565                uint8_t column = 0;
    566                while (remainingComponents > 0 && column < parameter.getCols())
    567                {
    568                    constructor += "[" + str(column) + "]";
    569 
    570                    if (remainingComponents < static_cast<size_t>(parameter.getRows()))
    571                    {
    572                        switch (remainingComponents)
    573                        {
    574                            case 1:
    575                                constructor += ".x";
    576                                break;
    577                            case 2:
    578                                constructor += ".xy";
    579                                break;
    580                            case 3:
    581                                constructor += ".xyz";
    582                                break;
    583                            default:
    584                                UNREACHABLE();
    585                        }
    586 
    587                        remainingComponents = 0;
    588                    }
    589                    else
    590                    {
    591                        remainingComponents -= parameter.getRows();
    592 
    593                        if (remainingComponents > 0)
    594                        {
    595                            constructor += ", x" + str(parameterIndex);
    596                        }
    597                    }
    598 
    599                    column++;
    600                }
    601            }
    602            else
    603            {
    604                UNREACHABLE();
    605            }
    606 
    607            if (moreParameters)
    608            {
    609                parameterIndex++;
    610            }
    611 
    612            if (remainingComponents)
    613            {
    614                constructor += ", ";
    615            }
    616        }
    617    }
    618 
    619    constructor +=
    620        ");\n"
    621        "}\n";
    622 
    623    mBuiltInConstructors.insert(constructor);
    624 
    625    return constructorFunctionName;
    626 }
    627 
    628 std::string StructureHLSL::structsHeader() const
    629 {
    630    TInfoSinkBase out;
    631 
    632    for (auto &declaration : mStructDeclarations)
    633    {
    634        out << declaration;
    635    }
    636 
    637    for (auto &structure : mDefinedStructs)
    638    {
    639        out << structure.second->constructor;
    640    }
    641 
    642    for (auto &constructor : mBuiltInConstructors)
    643    {
    644        out << constructor;
    645    }
    646 
    647    return out.str();
    648 }
    649 
    650 void StructureHLSL::storeStd140ElementIndex(const TStructure &structure,
    651                                            bool useHLSLRowMajorPacking)
    652 {
    653    Std140PaddingHelper padHelper = getPaddingHelper();
    654    const TFieldList &fields      = structure.fields();
    655 
    656    for (const TField *field : fields)
    657    {
    658        padHelper.prePadding(*field->type(), false);
    659    }
    660 
    661    // Add remaining element index to the global map, for use with nested structs in standard
    662    // layouts
    663    const TString &structName =
    664        QualifiedStructNameString(structure, useHLSLRowMajorPacking, true, false);
    665    mStd140StructElementIndexes[structName] = padHelper.elementIndex();
    666 }
    667 
    668 }  // namespace sh