Home | History | Annotate | Download | only in translator
      1 //
      2 // Copyright (c) 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 // UniformHLSL.cpp:
      7 //   Methods for GLSL to HLSL translation for uniforms and interface blocks.
      8 //
      9 
     10 #include "OutputHLSL.h"
     11 #include "common/blocklayout.h"
     12 #include "common/utilities.h"
     13 #include "compiler/translator/UniformHLSL.h"
     14 #include "compiler/translator/StructureHLSL.h"
     15 #include "compiler/translator/util.h"
     16 #include "compiler/translator/UtilsHLSL.h"
     17 #include "compiler/translator/TranslatorHLSL.h"
     18 
     19 namespace sh
     20 {
     21 
     22 static const char *UniformRegisterPrefix(const TType &type)
     23 {
     24     if (IsSampler(type.getBasicType()))
     25     {
     26         return "s";
     27     }
     28     else
     29     {
     30         return "c";
     31     }
     32 }
     33 
     34 static TString InterfaceBlockFieldTypeString(const TField &field, TLayoutBlockStorage blockStorage)
     35 {
     36     const TType &fieldType = *field.type();
     37     const TLayoutMatrixPacking matrixPacking = fieldType.getLayoutQualifier().matrixPacking;
     38     ASSERT(matrixPacking != EmpUnspecified);
     39     TStructure *structure = fieldType.getStruct();
     40 
     41     if (fieldType.isMatrix())
     42     {
     43         // Use HLSL row-major packing for GLSL column-major matrices
     44         const TString &matrixPackString = (matrixPacking == EmpRowMajor ? "column_major" : "row_major");
     45         return matrixPackString + " " + TypeString(fieldType);
     46     }
     47     else if (structure)
     48     {
     49         // Use HLSL row-major packing for GLSL column-major matrices
     50         return QualifiedStructNameString(*structure, matrixPacking == EmpColumnMajor,
     51             blockStorage == EbsStd140);
     52     }
     53     else
     54     {
     55         return TypeString(fieldType);
     56     }
     57 }
     58 
     59 static TString InterfaceBlockStructName(const TInterfaceBlock &interfaceBlock)
     60 {
     61     return DecoratePrivate(interfaceBlock.name()) + "_type";
     62 }
     63 
     64 UniformHLSL::UniformHLSL(StructureHLSL *structureHLSL, TranslatorHLSL *translator)
     65     : mUniformRegister(0),
     66       mInterfaceBlockRegister(0),
     67       mSamplerRegister(0),
     68       mStructureHLSL(structureHLSL),
     69       mOutputType(translator->getOutputType()),
     70       mUniforms(translator->getUniforms())
     71 {}
     72 
     73 void UniformHLSL::reserveUniformRegisters(unsigned int registerCount)
     74 {
     75     mUniformRegister = registerCount;
     76 }
     77 
     78 void UniformHLSL::reserveInterfaceBlockRegisters(unsigned int registerCount)
     79 {
     80     mInterfaceBlockRegister = registerCount;
     81 }
     82 
     83 const Uniform *UniformHLSL::findUniformByName(const TString &name) const
     84 {
     85     for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
     86     {
     87         if (mUniforms[uniformIndex].name == name.c_str())
     88         {
     89             return &mUniforms[uniformIndex];
     90         }
     91     }
     92 
     93     UNREACHABLE();
     94     return NULL;
     95 }
     96 
     97 unsigned int UniformHLSL::declareUniformAndAssignRegister(const TType &type, const TString &name)
     98 {
     99     unsigned int registerIndex = (IsSampler(type.getBasicType()) ? mSamplerRegister : mUniformRegister);
    100 
    101     const Uniform *uniform = findUniformByName(name);
    102     ASSERT(uniform);
    103 
    104     mUniformRegisterMap[uniform->name] = registerIndex;
    105 
    106     unsigned int registerCount = HLSLVariableRegisterCount(*uniform, mOutputType);
    107 
    108     if (gl::IsSampler(uniform->type))
    109     {
    110         mSamplerRegister += registerCount;
    111     }
    112     else
    113     {
    114         mUniformRegister += registerCount;
    115     }
    116 
    117     return registerIndex;
    118 }
    119 
    120 TString UniformHLSL::uniformsHeader(ShShaderOutput outputType, const ReferencedSymbols &referencedUniforms)
    121 {
    122     TString uniforms;
    123 
    124     for (ReferencedSymbols::const_iterator uniformIt = referencedUniforms.begin();
    125          uniformIt != referencedUniforms.end(); uniformIt++)
    126     {
    127         const TIntermSymbol &uniform = *uniformIt->second;
    128         const TType &type = uniform.getType();
    129         const TString &name = uniform.getSymbol();
    130 
    131         unsigned int registerIndex = declareUniformAndAssignRegister(type, name);
    132 
    133         if (outputType == SH_HLSL11_OUTPUT && IsSampler(type.getBasicType()))   // Also declare the texture
    134         {
    135             uniforms += "uniform " + SamplerString(type) + " sampler_" + DecorateUniform(name, type) + ArrayString(type) +
    136                         " : register(s" + str(registerIndex) + ");\n";
    137 
    138             uniforms += "uniform " + TextureString(type) + " texture_" + DecorateUniform(name, type) + ArrayString(type) +
    139                         " : register(t" + str(registerIndex) + ");\n";
    140         }
    141         else
    142         {
    143             const TStructure *structure = type.getStruct();
    144             // If this is a nameless struct, we need to use its full definition, rather than its (empty) name.
    145             // TypeString() will invoke defineNameless in this case; qualifier prefixes are unnecessary for
    146             // nameless structs in ES, as nameless structs cannot be used anywhere that layout qualifiers are
    147             // permitted.
    148             const TString &typeName = ((structure && !structure->name().empty()) ?
    149                                         QualifiedStructNameString(*structure, false, false) : TypeString(type));
    150 
    151             const TString &registerString = TString("register(") + UniformRegisterPrefix(type) + str(registerIndex) + ")";
    152 
    153             uniforms += "uniform " + typeName + " " + DecorateUniform(name, type) + ArrayString(type) + " : " + registerString + ";\n";
    154         }
    155     }
    156 
    157     return (uniforms.empty() ? "" : ("// Uniforms\n\n" + uniforms));
    158 }
    159 
    160 TString UniformHLSL::interfaceBlocksHeader(const ReferencedSymbols &referencedInterfaceBlocks)
    161 {
    162     TString interfaceBlocks;
    163 
    164     for (ReferencedSymbols::const_iterator interfaceBlockIt = referencedInterfaceBlocks.begin();
    165          interfaceBlockIt != referencedInterfaceBlocks.end(); interfaceBlockIt++)
    166     {
    167         const TType &nodeType = interfaceBlockIt->second->getType();
    168         const TInterfaceBlock &interfaceBlock = *nodeType.getInterfaceBlock();
    169 
    170         unsigned int arraySize = static_cast<unsigned int>(interfaceBlock.arraySize());
    171         unsigned int activeRegister = mInterfaceBlockRegister;
    172 
    173         mInterfaceBlockRegisterMap[interfaceBlock.name().c_str()] = activeRegister;
    174         mInterfaceBlockRegister += std::max(1u, arraySize);
    175 
    176         // FIXME: interface block field names
    177 
    178         if (interfaceBlock.hasInstanceName())
    179         {
    180             interfaceBlocks += interfaceBlockStructString(interfaceBlock);
    181         }
    182 
    183         if (arraySize > 0)
    184         {
    185             for (unsigned int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++)
    186             {
    187                 interfaceBlocks += interfaceBlockString(interfaceBlock, activeRegister + arrayIndex, arrayIndex);
    188             }
    189         }
    190         else
    191         {
    192             interfaceBlocks += interfaceBlockString(interfaceBlock, activeRegister, GL_INVALID_INDEX);
    193         }
    194     }
    195 
    196     return (interfaceBlocks.empty() ? "" : ("// Interface Blocks\n\n" + interfaceBlocks));
    197 }
    198 
    199 TString UniformHLSL::interfaceBlockString(const TInterfaceBlock &interfaceBlock, unsigned int registerIndex, unsigned int arrayIndex)
    200 {
    201     const TString &arrayIndexString =  (arrayIndex != GL_INVALID_INDEX ? Decorate(str(arrayIndex)) : "");
    202     const TString &blockName = interfaceBlock.name() + arrayIndexString;
    203     TString hlsl;
    204 
    205     hlsl += "cbuffer " + blockName + " : register(b" + str(registerIndex) + ")\n"
    206             "{\n";
    207 
    208     if (interfaceBlock.hasInstanceName())
    209     {
    210         hlsl += "    " + InterfaceBlockStructName(interfaceBlock) + " " +
    211                 interfaceBlockInstanceString(interfaceBlock, arrayIndex) + ";\n";
    212     }
    213     else
    214     {
    215         const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
    216         hlsl += interfaceBlockMembersString(interfaceBlock, blockStorage);
    217     }
    218 
    219     hlsl += "};\n\n";
    220 
    221     return hlsl;
    222 }
    223 
    224 TString UniformHLSL::interfaceBlockInstanceString(const TInterfaceBlock& interfaceBlock, unsigned int arrayIndex)
    225 {
    226     if (!interfaceBlock.hasInstanceName())
    227     {
    228         return "";
    229     }
    230     else if (interfaceBlock.isArray())
    231     {
    232         return DecoratePrivate(interfaceBlock.instanceName()) + "_" + str(arrayIndex);
    233     }
    234     else
    235     {
    236         return Decorate(interfaceBlock.instanceName());
    237     }
    238 }
    239 
    240 TString UniformHLSL::interfaceBlockMembersString(const TInterfaceBlock &interfaceBlock, TLayoutBlockStorage blockStorage)
    241 {
    242     TString hlsl;
    243 
    244     Std140PaddingHelper padHelper = mStructureHLSL->getPaddingHelper();
    245 
    246     for (unsigned int typeIndex = 0; typeIndex < interfaceBlock.fields().size(); typeIndex++)
    247     {
    248         const TField &field = *interfaceBlock.fields()[typeIndex];
    249         const TType &fieldType = *field.type();
    250 
    251         if (blockStorage == EbsStd140)
    252         {
    253             // 2 and 3 component vector types in some cases need pre-padding
    254             hlsl += padHelper.prePaddingString(fieldType);
    255         }
    256 
    257         hlsl += "    " + InterfaceBlockFieldTypeString(field, blockStorage) +
    258                 " " + Decorate(field.name()) + ArrayString(fieldType) + ";\n";
    259 
    260         // must pad out after matrices and arrays, where HLSL usually allows itself room to pack stuff
    261         if (blockStorage == EbsStd140)
    262         {
    263             const bool useHLSLRowMajorPacking = (fieldType.getLayoutQualifier().matrixPacking == EmpColumnMajor);
    264             hlsl += padHelper.postPaddingString(fieldType, useHLSLRowMajorPacking);
    265         }
    266     }
    267 
    268     return hlsl;
    269 }
    270 
    271 TString UniformHLSL::interfaceBlockStructString(const TInterfaceBlock &interfaceBlock)
    272 {
    273     const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage();
    274 
    275     return "struct " + InterfaceBlockStructName(interfaceBlock) + "\n"
    276            "{\n" +
    277            interfaceBlockMembersString(interfaceBlock, blockStorage) +
    278            "};\n\n";
    279 }
    280 
    281 }
    282