tor-browser

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

ResourcesHLSL.cpp (37826B)


      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 // ResourcesHLSL.cpp:
      7 //   Methods for GLSL to HLSL translation for uniforms and interface blocks.
      8 //
      9 
     10 #include "compiler/translator/ResourcesHLSL.h"
     11 
     12 #include "common/utilities.h"
     13 #include "compiler/translator/AtomicCounterFunctionHLSL.h"
     14 #include "compiler/translator/ImmutableStringBuilder.h"
     15 #include "compiler/translator/StructureHLSL.h"
     16 #include "compiler/translator/UtilsHLSL.h"
     17 #include "compiler/translator/blocklayoutHLSL.h"
     18 #include "compiler/translator/util.h"
     19 
     20 namespace sh
     21 {
     22 
     23 namespace
     24 {
     25 
     26 constexpr const ImmutableString kAngleDecorString("angle_");
     27 
     28 static const char *UniformRegisterPrefix(const TType &type)
     29 {
     30    if (IsSampler(type.getBasicType()))
     31    {
     32        return "s";
     33    }
     34    else
     35    {
     36        return "c";
     37    }
     38 }
     39 
     40 static TString InterfaceBlockFieldTypeString(const TField &field,
     41                                             TLayoutBlockStorage blockStorage,
     42                                             bool usedStructuredbuffer)
     43 {
     44    const TType &fieldType                   = *field.type();
     45    const TLayoutMatrixPacking matrixPacking = fieldType.getLayoutQualifier().matrixPacking;
     46    ASSERT(matrixPacking != EmpUnspecified);
     47    const TStructure *structure = fieldType.getStruct();
     48 
     49    if (fieldType.isMatrix())
     50    {
     51        // Use HLSL row-major packing for GLSL column-major matrices
     52        const TString &matrixPackString =
     53            (matrixPacking == EmpRowMajor ? "column_major" : "row_major");
     54        return matrixPackString + " " + TypeString(fieldType);
     55    }
     56    else if (structure)
     57    {
     58        // If uniform block's layout is std140 and translating it to StructuredBuffer,
     59        // should pack structure in the end, in order to fit API buffer.
     60        bool forcePackingEnd = usedStructuredbuffer && (blockStorage == EbsStd140);
     61        // Use HLSL row-major packing for GLSL column-major matrices
     62        return QualifiedStructNameString(*structure, matrixPacking == EmpColumnMajor,
     63                                         blockStorage == EbsStd140, forcePackingEnd);
     64    }
     65    else
     66    {
     67        return TypeString(fieldType);
     68    }
     69 }
     70 
     71 static TString InterfaceBlockStructName(const TInterfaceBlock &interfaceBlock)
     72 {
     73    return DecoratePrivate(interfaceBlock.name()) + "_type";
     74 }
     75 
     76 void OutputUniformIndexArrayInitializer(TInfoSinkBase &out,
     77                                        const TType &type,
     78                                        unsigned int startIndex)
     79 {
     80    out << "{";
     81    TType elementType(type);
     82    elementType.toArrayElementType();
     83    for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i)
     84    {
     85        if (i > 0u)
     86        {
     87            out << ", ";
     88        }
     89        if (elementType.isArray())
     90        {
     91            OutputUniformIndexArrayInitializer(out, elementType,
     92                                               startIndex + i * elementType.getArraySizeProduct());
     93        }
     94        else
     95        {
     96            out << (startIndex + i);
     97        }
     98    }
     99    out << "}";
    100 }
    101 
    102 static TString InterfaceBlockScalarVectorFieldPaddingString(const TType &type)
    103 {
    104    switch (type.getBasicType())
    105    {
    106        case EbtFloat:
    107            switch (type.getNominalSize())
    108            {
    109                case 1:
    110                    return "float3 padding;";
    111                case 2:
    112                    return "float2 padding;";
    113                case 3:
    114                    return "float padding;";
    115                default:
    116                    break;
    117            }
    118            break;
    119        case EbtInt:
    120            switch (type.getNominalSize())
    121            {
    122                case 1:
    123                    return "int3 padding;";
    124                case 2:
    125                    return "int2 padding;";
    126                case 3:
    127                    return "int padding";
    128                default:
    129                    break;
    130            }
    131            break;
    132        case EbtUInt:
    133            switch (type.getNominalSize())
    134            {
    135                case 1:
    136                    return "uint3 padding;";
    137                case 2:
    138                    return "uint2 padding;";
    139                case 3:
    140                    return "uint padding;";
    141                default:
    142                    break;
    143            }
    144            break;
    145        case EbtBool:
    146            switch (type.getNominalSize())
    147            {
    148                case 1:
    149                    return "bool3 padding;";
    150                case 2:
    151                    return "bool2 padding;";
    152                case 3:
    153                    return "bool padding;";
    154                default:
    155                    break;
    156            }
    157            break;
    158        default:
    159            break;
    160    }
    161    return "";
    162 }
    163 
    164 static bool IsAnyRasterOrdered(const TVector<const TVariable *> &imageVars)
    165 {
    166    for (const TVariable *imageVar : imageVars)
    167    {
    168        if (imageVar->getType().getLayoutQualifier().rasterOrdered)
    169        {
    170            return true;
    171        }
    172    }
    173    return false;
    174 }
    175 
    176 }  // anonymous namespace
    177 
    178 ResourcesHLSL::ResourcesHLSL(StructureHLSL *structureHLSL,
    179                             ShShaderOutput outputType,
    180                             const std::vector<ShaderVariable> &uniforms,
    181                             unsigned int firstUniformRegister)
    182    : mUniformRegister(firstUniformRegister),
    183      mUniformBlockRegister(0),
    184      mSRVRegister(0),
    185      mUAVRegister(0),
    186      mSamplerCount(0),
    187      mStructureHLSL(structureHLSL),
    188      mOutputType(outputType),
    189      mUniforms(uniforms)
    190 {}
    191 
    192 void ResourcesHLSL::reserveUniformRegisters(unsigned int registerCount)
    193 {
    194    mUniformRegister = registerCount;
    195 }
    196 
    197 void ResourcesHLSL::reserveUniformBlockRegisters(unsigned int registerCount)
    198 {
    199    mUniformBlockRegister = registerCount;
    200 }
    201 
    202 const ShaderVariable *ResourcesHLSL::findUniformByName(const ImmutableString &name) const
    203 {
    204    for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
    205    {
    206        if (name == mUniforms[uniformIndex].name)
    207        {
    208            return &mUniforms[uniformIndex];
    209        }
    210    }
    211 
    212    return nullptr;
    213 }
    214 
    215 unsigned int ResourcesHLSL::assignUniformRegister(const TType &type,
    216                                                  const ImmutableString &name,
    217                                                  unsigned int *outRegisterCount)
    218 {
    219    unsigned int registerIndex;
    220    const ShaderVariable *uniform = findUniformByName(name);
    221    ASSERT(uniform);
    222 
    223    if (IsSampler(type.getBasicType()) ||
    224        (IsImage(type.getBasicType()) && type.getMemoryQualifier().readonly))
    225    {
    226        registerIndex = mSRVRegister;
    227    }
    228    else if (IsImage(type.getBasicType()))
    229    {
    230        registerIndex = mUAVRegister;
    231    }
    232    else
    233    {
    234        registerIndex = mUniformRegister;
    235    }
    236 
    237    if (uniform->name == "angle_DrawID" && uniform->mappedName == "angle_DrawID")
    238    {
    239        mUniformRegisterMap["gl_DrawID"] = registerIndex;
    240    }
    241    else
    242    {
    243        mUniformRegisterMap[uniform->name] = registerIndex;
    244    }
    245 
    246    if (uniform->name == "angle_BaseVertex" && uniform->mappedName == "angle_BaseVertex")
    247    {
    248        mUniformRegisterMap["gl_BaseVertex"] = registerIndex;
    249    }
    250    else
    251    {
    252        mUniformRegisterMap[uniform->name] = registerIndex;
    253    }
    254 
    255    if (uniform->name == "angle_BaseInstance" && uniform->mappedName == "angle_BaseInstance")
    256    {
    257        mUniformRegisterMap["gl_BaseInstance"] = registerIndex;
    258    }
    259    else
    260    {
    261        mUniformRegisterMap[uniform->name] = registerIndex;
    262    }
    263 
    264    unsigned int registerCount = HLSLVariableRegisterCount(*uniform, mOutputType);
    265 
    266    if (IsSampler(type.getBasicType()) ||
    267        (IsImage(type.getBasicType()) && type.getMemoryQualifier().readonly))
    268    {
    269        mSRVRegister += registerCount;
    270    }
    271    else if (IsImage(type.getBasicType()))
    272    {
    273        mUAVRegister += registerCount;
    274    }
    275    else
    276    {
    277        mUniformRegister += registerCount;
    278    }
    279    if (outRegisterCount)
    280    {
    281        *outRegisterCount = registerCount;
    282    }
    283    return registerIndex;
    284 }
    285 
    286 unsigned int ResourcesHLSL::assignSamplerInStructUniformRegister(const TType &type,
    287                                                                 const TString &name,
    288                                                                 unsigned int *outRegisterCount)
    289 {
    290    // Sampler that is a field of a uniform structure.
    291    ASSERT(IsSampler(type.getBasicType()));
    292    unsigned int registerIndex                     = mSRVRegister;
    293    mUniformRegisterMap[std::string(name.c_str())] = registerIndex;
    294    unsigned int registerCount = type.isArray() ? type.getArraySizeProduct() : 1u;
    295    mSRVRegister += registerCount;
    296    if (outRegisterCount)
    297    {
    298        *outRegisterCount = registerCount;
    299    }
    300    return registerIndex;
    301 }
    302 
    303 void ResourcesHLSL::outputHLSLSamplerUniformGroup(
    304    TInfoSinkBase &out,
    305    const HLSLTextureGroup textureGroup,
    306    const TVector<const TVariable *> &group,
    307    const TMap<const TVariable *, TString> &samplerInStructSymbolsToAPINames,
    308    unsigned int *groupTextureRegisterIndex)
    309 {
    310    if (group.empty())
    311    {
    312        return;
    313    }
    314    unsigned int groupRegisterCount = 0;
    315    for (const TVariable *uniform : group)
    316    {
    317        const TType &type           = uniform->getType();
    318        const ImmutableString &name = uniform->name();
    319        unsigned int registerCount;
    320 
    321        // The uniform might be just a regular sampler or one extracted from a struct.
    322        unsigned int samplerArrayIndex      = 0u;
    323        const ShaderVariable *uniformByName = findUniformByName(name);
    324        if (uniformByName)
    325        {
    326            samplerArrayIndex = assignUniformRegister(type, name, &registerCount);
    327        }
    328        else
    329        {
    330            ASSERT(samplerInStructSymbolsToAPINames.find(uniform) !=
    331                   samplerInStructSymbolsToAPINames.end());
    332            samplerArrayIndex = assignSamplerInStructUniformRegister(
    333                type, samplerInStructSymbolsToAPINames.at(uniform), &registerCount);
    334        }
    335        groupRegisterCount += registerCount;
    336 
    337        if (type.isArray())
    338        {
    339            out << "static const uint " << DecorateVariableIfNeeded(*uniform) << ArrayString(type)
    340                << " = ";
    341            OutputUniformIndexArrayInitializer(out, type, samplerArrayIndex);
    342            out << ";\n";
    343        }
    344        else
    345        {
    346            out << "static const uint " << DecorateVariableIfNeeded(*uniform) << " = "
    347                << samplerArrayIndex << ";\n";
    348        }
    349    }
    350    TString suffix = TextureGroupSuffix(textureGroup);
    351    // Since HLSL_TEXTURE_2D is the first group, it has a fixed offset of zero.
    352    if (textureGroup != HLSL_TEXTURE_2D)
    353    {
    354        out << "static const uint textureIndexOffset" << suffix << " = "
    355            << (*groupTextureRegisterIndex) << ";\n";
    356        out << "static const uint samplerIndexOffset" << suffix << " = "
    357            << (*groupTextureRegisterIndex) << ";\n";
    358    }
    359    out << "uniform " << TextureString(textureGroup) << " textures" << suffix << "["
    360        << groupRegisterCount << "]"
    361        << " : register(t" << (*groupTextureRegisterIndex) << ");\n";
    362    out << "uniform " << SamplerString(textureGroup) << " samplers" << suffix << "["
    363        << groupRegisterCount << "]"
    364        << " : register(s" << (*groupTextureRegisterIndex) << ");\n";
    365    *groupTextureRegisterIndex += groupRegisterCount;
    366 }
    367 
    368 void ResourcesHLSL::outputHLSLImageUniformIndices(TInfoSinkBase &out,
    369                                                  const TVector<const TVariable *> &group,
    370                                                  unsigned int imageArrayIndex,
    371                                                  unsigned int *groupRegisterCount)
    372 {
    373    for (const TVariable *uniform : group)
    374    {
    375        const TType &type           = uniform->getType();
    376        const ImmutableString &name = uniform->name();
    377        unsigned int registerCount  = 0;
    378 
    379        assignUniformRegister(type, name, &registerCount);
    380        *groupRegisterCount += registerCount;
    381 
    382        if (type.isArray())
    383        {
    384            out << "static const uint " << DecorateVariableIfNeeded(*uniform) << ArrayString(type)
    385                << " = ";
    386            OutputUniformIndexArrayInitializer(out, type, imageArrayIndex);
    387            out << ";\n";
    388        }
    389        else
    390        {
    391            out << "static const uint " << DecorateVariableIfNeeded(*uniform) << " = "
    392                << imageArrayIndex << ";\n";
    393        }
    394 
    395        imageArrayIndex += registerCount;
    396    }
    397 }
    398 
    399 void ResourcesHLSL::outputHLSLReadonlyImageUniformGroup(TInfoSinkBase &out,
    400                                                        const HLSLTextureGroup textureGroup,
    401                                                        const TVector<const TVariable *> &group,
    402                                                        unsigned int *groupTextureRegisterIndex)
    403 {
    404    if (group.empty())
    405    {
    406        return;
    407    }
    408 
    409    unsigned int groupRegisterCount = 0;
    410    outputHLSLImageUniformIndices(out, group, *groupTextureRegisterIndex, &groupRegisterCount);
    411 
    412    TString suffix = TextureGroupSuffix(textureGroup);
    413    out << "static const uint readonlyImageIndexOffset" << suffix << " = "
    414        << (*groupTextureRegisterIndex) << ";\n";
    415    out << "uniform " << TextureString(textureGroup) << " readonlyImages" << suffix << "["
    416        << groupRegisterCount << "]"
    417        << " : register(t" << (*groupTextureRegisterIndex) << ");\n";
    418    *groupTextureRegisterIndex += groupRegisterCount;
    419 }
    420 
    421 void ResourcesHLSL::outputHLSLImageUniformGroup(TInfoSinkBase &out,
    422                                                const HLSLRWTextureGroup textureGroup,
    423                                                const TVector<const TVariable *> &group,
    424                                                unsigned int *groupTextureRegisterIndex)
    425 {
    426    if (group.empty())
    427    {
    428        return;
    429    }
    430 
    431    // ROVs should all be written out in DynamicImage2DHLSL.cpp.
    432    ASSERT(!IsAnyRasterOrdered(group));
    433 
    434    unsigned int groupRegisterCount = 0;
    435    outputHLSLImageUniformIndices(out, group, *groupTextureRegisterIndex, &groupRegisterCount);
    436 
    437    TString suffix = RWTextureGroupSuffix(textureGroup);
    438    out << "static const uint imageIndexOffset" << suffix << " = " << (*groupTextureRegisterIndex)
    439        << ";\n";
    440    out << "uniform " << RWTextureString(textureGroup) << " images" << suffix << "["
    441        << groupRegisterCount << "]"
    442        << " : register(u" << (*groupTextureRegisterIndex) << ");\n";
    443    *groupTextureRegisterIndex += groupRegisterCount;
    444 }
    445 
    446 void ResourcesHLSL::outputHLSL4_0_FL9_3Sampler(TInfoSinkBase &out,
    447                                               const TType &type,
    448                                               const TVariable &variable,
    449                                               const unsigned int registerIndex)
    450 {
    451    out << "uniform " << SamplerString(type.getBasicType()) << " sampler_"
    452        << DecorateVariableIfNeeded(variable) << ArrayString(type) << " : register(s"
    453        << str(registerIndex) << ");\n";
    454    out << "uniform " << TextureString(type.getBasicType()) << " texture_"
    455        << DecorateVariableIfNeeded(variable) << ArrayString(type) << " : register(t"
    456        << str(registerIndex) << ");\n";
    457 }
    458 
    459 void ResourcesHLSL::outputUniform(TInfoSinkBase &out,
    460                                  const TType &type,
    461                                  const TVariable &variable,
    462                                  const unsigned int registerIndex)
    463 {
    464    const TStructure *structure = type.getStruct();
    465    // If this is a nameless struct, we need to use its full definition, rather than its (empty)
    466    // name.
    467    // TypeString() will invoke defineNameless in this case; qualifier prefixes are unnecessary for
    468    // nameless structs in ES, as nameless structs cannot be used anywhere that layout qualifiers
    469    // are permitted.
    470    const TString &typeName = ((structure && structure->symbolType() != SymbolType::Empty)
    471                                   ? QualifiedStructNameString(*structure, false, false, false)
    472                                   : TypeString(type));
    473 
    474    const TString &registerString =
    475        TString("register(") + UniformRegisterPrefix(type) + str(registerIndex) + ")";
    476 
    477    out << "uniform " << typeName << " ";
    478 
    479    out << DecorateVariableIfNeeded(variable);
    480 
    481    out << ArrayString(type) << " : " << registerString << ";\n";
    482 }
    483 
    484 void ResourcesHLSL::outputAtomicCounterBuffer(TInfoSinkBase &out,
    485                                              const int binding,
    486                                              const unsigned int registerIndex)
    487 {
    488    // Atomic counter memory access is not incoherent
    489    out << "uniform globallycoherent RWByteAddressBuffer "
    490        << getAtomicCounterNameForBinding(binding) << " : register(u" << registerIndex << ");\n";
    491 }
    492 
    493 void ResourcesHLSL::uniformsHeader(TInfoSinkBase &out,
    494                                   ShShaderOutput outputType,
    495                                   const ReferencedVariables &referencedUniforms,
    496                                   TSymbolTable *symbolTable)
    497 {
    498    if (!referencedUniforms.empty())
    499    {
    500        out << "// Uniforms\n\n";
    501    }
    502    // In the case of HLSL 4, sampler uniforms need to be grouped by type before the code is
    503    // written. They are grouped based on the combination of the HLSL texture type and
    504    // HLSL sampler type, enumerated in HLSLTextureSamplerGroup.
    505    TVector<TVector<const TVariable *>> groupedSamplerUniforms(HLSL_TEXTURE_MAX + 1);
    506    TMap<const TVariable *, TString> samplerInStructSymbolsToAPINames;
    507    TVector<TVector<const TVariable *>> groupedReadonlyImageUniforms(HLSL_TEXTURE_MAX + 1);
    508    TVector<TVector<const TVariable *>> groupedImageUniforms(HLSL_RWTEXTURE_MAX + 1);
    509 
    510    TUnorderedMap<int, unsigned int> assignedAtomicCounterBindings;
    511    unsigned int reservedReadonlyImageRegisterCount = 0, reservedImageRegisterCount = 0;
    512    for (auto &uniformIt : referencedUniforms)
    513    {
    514        // Output regular uniforms. Group sampler uniforms by type.
    515        const TVariable &variable = *uniformIt.second;
    516        const TType &type         = variable.getType();
    517 
    518        if (outputType == SH_HLSL_4_1_OUTPUT && IsSampler(type.getBasicType()))
    519        {
    520            HLSLTextureGroup group = TextureGroup(type.getBasicType());
    521            groupedSamplerUniforms[group].push_back(&variable);
    522        }
    523        else if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(type.getBasicType()))
    524        {
    525            unsigned int registerIndex = assignUniformRegister(type, variable.name(), nullptr);
    526            outputHLSL4_0_FL9_3Sampler(out, type, variable, registerIndex);
    527        }
    528        else if (outputType == SH_HLSL_4_1_OUTPUT && IsImage(type.getBasicType()))
    529        {
    530            if (IsImage2D(type.getBasicType()))
    531            {
    532                const ShaderVariable *uniform = findUniformByName(variable.name());
    533                if (type.getMemoryQualifier().readonly)
    534                {
    535                    reservedReadonlyImageRegisterCount +=
    536                        HLSLVariableRegisterCount(*uniform, mOutputType);
    537                }
    538                else
    539                {
    540                    reservedImageRegisterCount += HLSLVariableRegisterCount(*uniform, mOutputType);
    541                }
    542                continue;
    543            }
    544            if (type.getMemoryQualifier().readonly)
    545            {
    546                HLSLTextureGroup group = TextureGroup(
    547                    type.getBasicType(), type.getLayoutQualifier().imageInternalFormat);
    548                groupedReadonlyImageUniforms[group].push_back(&variable);
    549            }
    550            else
    551            {
    552                HLSLRWTextureGroup group = RWTextureGroup(
    553                    type.getBasicType(), type.getLayoutQualifier().imageInternalFormat);
    554                groupedImageUniforms[group].push_back(&variable);
    555            }
    556        }
    557        else if (outputType == SH_HLSL_4_1_OUTPUT && IsAtomicCounter(type.getBasicType()))
    558        {
    559            TLayoutQualifier layout = type.getLayoutQualifier();
    560            int binding             = layout.binding;
    561            unsigned int registerIndex;
    562            if (assignedAtomicCounterBindings.find(binding) == assignedAtomicCounterBindings.end())
    563            {
    564                registerIndex                          = mUAVRegister++;
    565                assignedAtomicCounterBindings[binding] = registerIndex;
    566                outputAtomicCounterBuffer(out, binding, registerIndex);
    567            }
    568            else
    569            {
    570                registerIndex = assignedAtomicCounterBindings[binding];
    571            }
    572            const ShaderVariable *uniform      = findUniformByName(variable.name());
    573            mUniformRegisterMap[uniform->name] = registerIndex;
    574        }
    575        else
    576        {
    577            if (type.isStructureContainingSamplers())
    578            {
    579                TVector<const TVariable *> samplerSymbols;
    580                TMap<const TVariable *, TString> symbolsToAPINames;
    581                ImmutableStringBuilder namePrefix(kAngleDecorString.length() +
    582                                                  variable.name().length());
    583                namePrefix << kAngleDecorString;
    584                namePrefix << variable.name();
    585                type.createSamplerSymbols(namePrefix, TString(variable.name().data()),
    586                                          &samplerSymbols, &symbolsToAPINames, symbolTable);
    587                for (const TVariable *sampler : samplerSymbols)
    588                {
    589                    const TType &samplerType = sampler->getType();
    590 
    591                    if (outputType == SH_HLSL_4_1_OUTPUT)
    592                    {
    593                        HLSLTextureGroup group = TextureGroup(samplerType.getBasicType());
    594                        groupedSamplerUniforms[group].push_back(sampler);
    595                        samplerInStructSymbolsToAPINames[sampler] = symbolsToAPINames[sampler];
    596                    }
    597                    else if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
    598                    {
    599                        unsigned int registerIndex = assignSamplerInStructUniformRegister(
    600                            samplerType, symbolsToAPINames[sampler], nullptr);
    601                        outputHLSL4_0_FL9_3Sampler(out, samplerType, *sampler, registerIndex);
    602                    }
    603                    else
    604                    {
    605                        ASSERT(outputType == SH_HLSL_3_0_OUTPUT);
    606                        unsigned int registerIndex = assignSamplerInStructUniformRegister(
    607                            samplerType, symbolsToAPINames[sampler], nullptr);
    608                        outputUniform(out, samplerType, *sampler, registerIndex);
    609                    }
    610                }
    611            }
    612            unsigned int registerIndex = assignUniformRegister(type, variable.name(), nullptr);
    613            outputUniform(out, type, variable, registerIndex);
    614        }
    615    }
    616 
    617    if (outputType == SH_HLSL_4_1_OUTPUT)
    618    {
    619        unsigned int groupTextureRegisterIndex = 0;
    620        // Atomic counters and RW texture share the same resources. Therefore, RW texture need to
    621        // start counting after the last atomic counter.
    622        unsigned int groupRWTextureRegisterIndex = mUAVRegister;
    623        // TEXTURE_2D is special, index offset is assumed to be 0 and omitted in that case.
    624        ASSERT(HLSL_TEXTURE_MIN == HLSL_TEXTURE_2D);
    625        for (int groupId = HLSL_TEXTURE_MIN; groupId < HLSL_TEXTURE_MAX; ++groupId)
    626        {
    627            outputHLSLSamplerUniformGroup(
    628                out, HLSLTextureGroup(groupId), groupedSamplerUniforms[groupId],
    629                samplerInStructSymbolsToAPINames, &groupTextureRegisterIndex);
    630        }
    631        mSamplerCount = groupTextureRegisterIndex;
    632 
    633        // Reserve t type register for readonly image2D variables.
    634        mReadonlyImage2DRegisterIndex = mSRVRegister;
    635        groupTextureRegisterIndex += reservedReadonlyImageRegisterCount;
    636        mSRVRegister += reservedReadonlyImageRegisterCount;
    637 
    638        for (int groupId = HLSL_TEXTURE_MIN; groupId < HLSL_TEXTURE_MAX; ++groupId)
    639        {
    640            outputHLSLReadonlyImageUniformGroup(out, HLSLTextureGroup(groupId),
    641                                                groupedReadonlyImageUniforms[groupId],
    642                                                &groupTextureRegisterIndex);
    643        }
    644        mReadonlyImageCount = groupTextureRegisterIndex - mReadonlyImage2DRegisterIndex;
    645        if (mReadonlyImageCount)
    646        {
    647            out << "static const uint readonlyImageIndexStart = " << mReadonlyImage2DRegisterIndex
    648                << ";\n";
    649        }
    650 
    651        // Reserve u type register for writable image2D variables.
    652        mImage2DRegisterIndex = mUAVRegister;
    653        groupRWTextureRegisterIndex += reservedImageRegisterCount;
    654        mUAVRegister += reservedImageRegisterCount;
    655 
    656        for (int groupId = HLSL_RWTEXTURE_MIN; groupId < HLSL_RWTEXTURE_MAX; ++groupId)
    657        {
    658            outputHLSLImageUniformGroup(out, HLSLRWTextureGroup(groupId),
    659                                        groupedImageUniforms[groupId],
    660                                        &groupRWTextureRegisterIndex);
    661        }
    662        mImageCount = groupRWTextureRegisterIndex - mImage2DRegisterIndex;
    663        if (mImageCount)
    664        {
    665            out << "static const uint imageIndexStart = " << mImage2DRegisterIndex << ";\n";
    666        }
    667    }
    668 }
    669 
    670 void ResourcesHLSL::samplerMetadataUniforms(TInfoSinkBase &out, unsigned int regIndex)
    671 {
    672    // If mSamplerCount is 0 the shader doesn't use any textures for samplers.
    673    if (mSamplerCount > 0)
    674    {
    675        out << "    struct SamplerMetadata\n"
    676               "    {\n"
    677               "        int baseLevel;\n"
    678               "        int internalFormatBits;\n"
    679               "        int wrapModes;\n"
    680               "        int padding;\n"
    681               "        int4 intBorderColor;\n"
    682               "    };\n"
    683               "    SamplerMetadata samplerMetadata["
    684            << mSamplerCount << "] : packoffset(c" << regIndex << ");\n";
    685    }
    686 }
    687 
    688 void ResourcesHLSL::imageMetadataUniforms(TInfoSinkBase &out, unsigned int regIndex)
    689 {
    690    if (mReadonlyImageCount > 0 || mImageCount > 0)
    691    {
    692        out << "    struct ImageMetadata\n"
    693               "    {\n"
    694               "        int layer;\n"
    695               "        uint level;\n"
    696               "        int2 padding;\n"
    697               "    };\n";
    698 
    699        if (mReadonlyImageCount > 0)
    700        {
    701            out << "    ImageMetadata readonlyImageMetadata[" << mReadonlyImageCount
    702                << "] : packoffset(c" << regIndex << ");\n";
    703        }
    704 
    705        if (mImageCount > 0)
    706        {
    707            out << "    ImageMetadata imageMetadata[" << mImageCount << "] : packoffset(c"
    708                << regIndex + mReadonlyImageCount << ");\n";
    709        }
    710    }
    711 }
    712 
    713 TString ResourcesHLSL::uniformBlocksHeader(
    714    const ReferencedInterfaceBlocks &referencedInterfaceBlocks,
    715    const std::map<int, const TInterfaceBlock *> &uniformBlockOptimizedMap)
    716 {
    717    TString interfaceBlocks;
    718 
    719    for (const auto &blockReference : referencedInterfaceBlocks)
    720    {
    721        const TInterfaceBlock &interfaceBlock = *blockReference.second->block;
    722        const TVariable *instanceVariable     = blockReference.second->instanceVariable;
    723        if (instanceVariable != nullptr)
    724        {
    725            interfaceBlocks += uniformBlockStructString(interfaceBlock);
    726        }
    727 
    728        // In order to avoid compile performance issue, translate uniform block to structured
    729        // buffer. anglebug.com/3682.
    730        if (uniformBlockOptimizedMap.count(interfaceBlock.uniqueId().get()) != 0)
    731        {
    732            unsigned int structuredBufferRegister = mSRVRegister;
    733            if (instanceVariable != nullptr && instanceVariable->getType().isArray())
    734            {
    735                unsigned int instanceArraySize =
    736                    instanceVariable->getType().getOutermostArraySize();
    737                for (unsigned int arrayIndex = 0; arrayIndex < instanceArraySize; arrayIndex++)
    738                {
    739                    interfaceBlocks += uniformBlockWithOneLargeArrayMemberString(
    740                        interfaceBlock, instanceVariable, structuredBufferRegister + arrayIndex,
    741                        arrayIndex);
    742                }
    743                mSRVRegister += instanceArraySize;
    744            }
    745            else
    746            {
    747                interfaceBlocks += uniformBlockWithOneLargeArrayMemberString(
    748                    interfaceBlock, instanceVariable, structuredBufferRegister, GL_INVALID_INDEX);
    749                mSRVRegister += 1u;
    750            }
    751            mUniformBlockRegisterMap[interfaceBlock.name().data()] = structuredBufferRegister;
    752            mUniformBlockUseStructuredBufferMap[interfaceBlock.name().data()] = true;
    753            continue;
    754        }
    755 
    756        unsigned int activeRegister                            = mUniformBlockRegister;
    757        mUniformBlockRegisterMap[interfaceBlock.name().data()] = activeRegister;
    758 
    759        if (instanceVariable != nullptr && instanceVariable->getType().isArray())
    760        {
    761            unsigned int instanceArraySize = instanceVariable->getType().getOutermostArraySize();
    762            for (unsigned int arrayIndex = 0; arrayIndex < instanceArraySize; arrayIndex++)
    763            {
    764                interfaceBlocks += uniformBlockString(interfaceBlock, instanceVariable,
    765                                                      activeRegister + arrayIndex, arrayIndex);
    766            }
    767            mUniformBlockRegister += instanceArraySize;
    768        }
    769        else
    770        {
    771            interfaceBlocks += uniformBlockString(interfaceBlock, instanceVariable, activeRegister,
    772                                                  GL_INVALID_INDEX);
    773            mUniformBlockRegister += 1u;
    774        }
    775    }
    776 
    777    return (interfaceBlocks.empty() ? "" : ("// Uniform Blocks\n\n" + interfaceBlocks));
    778 }
    779 
    780 void ResourcesHLSL::allocateShaderStorageBlockRegisters(
    781    const ReferencedInterfaceBlocks &referencedInterfaceBlocks)
    782 {
    783    for (const auto &interfaceBlockReference : referencedInterfaceBlocks)
    784    {
    785        const TInterfaceBlock &interfaceBlock = *interfaceBlockReference.second->block;
    786        const TVariable *instanceVariable     = interfaceBlockReference.second->instanceVariable;
    787 
    788        mShaderStorageBlockRegisterMap[interfaceBlock.name().data()] = mUAVRegister;
    789 
    790        if (instanceVariable != nullptr && instanceVariable->getType().isArray())
    791        {
    792            mUAVRegister += instanceVariable->getType().getOutermostArraySize();
    793        }
    794        else
    795        {
    796            mUAVRegister += 1u;
    797        }
    798    }
    799 }
    800 
    801 TString ResourcesHLSL::shaderStorageBlocksHeader(
    802    const ReferencedInterfaceBlocks &referencedInterfaceBlocks)
    803 {
    804    TString interfaceBlocks;
    805 
    806    for (const auto &interfaceBlockReference : referencedInterfaceBlocks)
    807    {
    808        const TInterfaceBlock &interfaceBlock = *interfaceBlockReference.second->block;
    809        const TVariable *instanceVariable     = interfaceBlockReference.second->instanceVariable;
    810 
    811        unsigned int activeRegister = mShaderStorageBlockRegisterMap[interfaceBlock.name().data()];
    812 
    813        if (instanceVariable != nullptr && instanceVariable->getType().isArray())
    814        {
    815            unsigned int instanceArraySize = instanceVariable->getType().getOutermostArraySize();
    816            for (unsigned int arrayIndex = 0; arrayIndex < instanceArraySize; arrayIndex++)
    817            {
    818                interfaceBlocks += shaderStorageBlockString(
    819                    interfaceBlock, instanceVariable, activeRegister + arrayIndex, arrayIndex);
    820            }
    821        }
    822        else
    823        {
    824            interfaceBlocks += shaderStorageBlockString(interfaceBlock, instanceVariable,
    825                                                        activeRegister, GL_INVALID_INDEX);
    826        }
    827    }
    828 
    829    return interfaceBlocks;
    830 }
    831 
    832 TString ResourcesHLSL::uniformBlockString(const TInterfaceBlock &interfaceBlock,
    833                                          const TVariable *instanceVariable,
    834                                          unsigned int registerIndex,
    835                                          unsigned int arrayIndex)
    836 {
    837    const TString &arrayIndexString = (arrayIndex != GL_INVALID_INDEX ? str(arrayIndex) : "");
    838    const TString &blockName        = TString(interfaceBlock.name().data()) + arrayIndexString;
    839    TString hlsl;
    840 
    841    hlsl += "cbuffer " + blockName + " : register(b" + str(registerIndex) +
    842            ")\n"
    843            "{\n";
    844 
    845    if (instanceVariable != nullptr)
    846    {
    847        hlsl += "    " + InterfaceBlockStructName(interfaceBlock) + " " +
    848                InterfaceBlockInstanceString(instanceVariable->name(), arrayIndex) + ";\n";
    849    }
    850    else
    851    {
    852        const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
    853        hlsl += uniformBlockMembersString(interfaceBlock, blockStorage);
    854    }
    855 
    856    hlsl += "};\n\n";
    857 
    858    return hlsl;
    859 }
    860 
    861 TString ResourcesHLSL::uniformBlockWithOneLargeArrayMemberString(
    862    const TInterfaceBlock &interfaceBlock,
    863    const TVariable *instanceVariable,
    864    unsigned int registerIndex,
    865    unsigned int arrayIndex)
    866 {
    867    TString hlsl, typeString;
    868 
    869    const TField &field                    = *interfaceBlock.fields()[0];
    870    const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
    871    typeString             = InterfaceBlockFieldTypeString(field, blockStorage, true);
    872    const TType &fieldType = *field.type();
    873    if (fieldType.isMatrix())
    874    {
    875        if (arrayIndex == GL_INVALID_INDEX || arrayIndex == 0)
    876        {
    877            hlsl += "struct pack" + Decorate(interfaceBlock.name()) + " { " + typeString + " " +
    878                    Decorate(field.name()) + "; };\n";
    879        }
    880        typeString = "pack" + Decorate(interfaceBlock.name());
    881    }
    882    else if (fieldType.isVectorArray() || fieldType.isScalarArray())
    883    {
    884        // If the member is an array of scalars or vectors, std140 rules require the base array
    885        // stride are rounded up to the base alignment of a vec4.
    886        if (arrayIndex == GL_INVALID_INDEX || arrayIndex == 0)
    887        {
    888            hlsl += "struct pack" + Decorate(interfaceBlock.name()) + " { " + typeString + " " +
    889                    Decorate(field.name()) + ";\n";
    890            hlsl += InterfaceBlockScalarVectorFieldPaddingString(fieldType) + " };\n";
    891        }
    892        typeString = "pack" + Decorate(interfaceBlock.name());
    893    }
    894 
    895    if (instanceVariable != nullptr)
    896    {
    897 
    898        hlsl += "StructuredBuffer <" + typeString + "> " +
    899                InterfaceBlockInstanceString(instanceVariable->name(), arrayIndex) + "_" +
    900                Decorate(field.name()) + +" : register(t" + str(registerIndex) + ");\n";
    901    }
    902    else
    903    {
    904        hlsl += "StructuredBuffer <" + typeString + "> " + Decorate(field.name()) +
    905                " : register(t" + str(registerIndex) + ");\n";
    906    }
    907 
    908    return hlsl;
    909 }
    910 
    911 TString ResourcesHLSL::shaderStorageBlockString(const TInterfaceBlock &interfaceBlock,
    912                                                const TVariable *instanceVariable,
    913                                                unsigned int registerIndex,
    914                                                unsigned int arrayIndex)
    915 {
    916    TString hlsl;
    917    if (instanceVariable != nullptr)
    918    {
    919        hlsl += "RWByteAddressBuffer " +
    920                InterfaceBlockInstanceString(instanceVariable->name(), arrayIndex) +
    921                ": register(u" + str(registerIndex) + ");\n";
    922    }
    923    else
    924    {
    925        hlsl += "RWByteAddressBuffer " + Decorate(interfaceBlock.name()) + ": register(u" +
    926                str(registerIndex) + ");\n";
    927    }
    928    return hlsl;
    929 }
    930 
    931 TString ResourcesHLSL::InterfaceBlockInstanceString(const ImmutableString &instanceName,
    932                                                    unsigned int arrayIndex)
    933 {
    934    if (arrayIndex != GL_INVALID_INDEX)
    935    {
    936        return DecoratePrivate(instanceName) + "_" + str(arrayIndex);
    937    }
    938    else
    939    {
    940        return Decorate(instanceName);
    941    }
    942 }
    943 
    944 TString ResourcesHLSL::uniformBlockMembersString(const TInterfaceBlock &interfaceBlock,
    945                                                 TLayoutBlockStorage blockStorage)
    946 {
    947    TString hlsl;
    948 
    949    Std140PaddingHelper padHelper = mStructureHLSL->getPaddingHelper();
    950 
    951    const unsigned int fieldCount = static_cast<unsigned int>(interfaceBlock.fields().size());
    952    for (unsigned int typeIndex = 0; typeIndex < fieldCount; typeIndex++)
    953    {
    954        const TField &field    = *interfaceBlock.fields()[typeIndex];
    955        const TType &fieldType = *field.type();
    956 
    957        if (blockStorage == EbsStd140)
    958        {
    959            // 2 and 3 component vector types in some cases need pre-padding
    960            hlsl += padHelper.prePaddingString(fieldType, false);
    961        }
    962 
    963        hlsl += "    " + InterfaceBlockFieldTypeString(field, blockStorage, false) + " " +
    964                Decorate(field.name()) + ArrayString(fieldType).data() + ";\n";
    965 
    966        // must pad out after matrices and arrays, where HLSL usually allows itself room to pack
    967        // stuff
    968        if (blockStorage == EbsStd140)
    969        {
    970            const bool useHLSLRowMajorPacking =
    971                (fieldType.getLayoutQualifier().matrixPacking == EmpColumnMajor);
    972            hlsl += padHelper.postPaddingString(fieldType, useHLSLRowMajorPacking,
    973                                                typeIndex == fieldCount - 1, false);
    974        }
    975    }
    976 
    977    return hlsl;
    978 }
    979 
    980 TString ResourcesHLSL::uniformBlockStructString(const TInterfaceBlock &interfaceBlock)
    981 {
    982    const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
    983 
    984    return "struct " + InterfaceBlockStructName(interfaceBlock) +
    985           "\n"
    986           "{\n" +
    987           uniformBlockMembersString(interfaceBlock, blockStorage) + "};\n\n";
    988 }
    989 }  // namespace sh