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 // StructureHLSL.cpp:
      7 //   Definitions of methods for HLSL translation of GLSL 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/util.h"
     15 #include "compiler/translator/UtilsHLSL.h"
     16 
     17 namespace sh
     18 {
     19 
     20 Std140PaddingHelper::Std140PaddingHelper(const std::map<TString, int> &structElementIndexes,
     21                                          unsigned *uniqueCounter)
     22     : mPaddingCounter(uniqueCounter),
     23       mElementIndex(0),
     24       mStructElementIndexes(structElementIndexes)
     25 {}
     26 
     27 TString Std140PaddingHelper::next()
     28 {
     29     unsigned value = (*mPaddingCounter)++;
     30     return str(value);
     31 }
     32 
     33 int Std140PaddingHelper::prePadding(const TType &type)
     34 {
     35     if (type.getBasicType() == EbtStruct || type.isMatrix() || type.isArray())
     36     {
     37         // no padding needed, HLSL will align the field to a new register
     38         mElementIndex = 0;
     39         return 0;
     40     }
     41 
     42     const GLenum glType = GLVariableType(type);
     43     const int numComponents = gl::VariableComponentCount(glType);
     44 
     45     if (numComponents >= 4)
     46     {
     47         // no padding needed, HLSL will align the field to a new register
     48         mElementIndex = 0;
     49         return 0;
     50     }
     51 
     52     if (mElementIndex + numComponents > 4)
     53     {
     54         // no padding needed, HLSL will align the field to a new register
     55         mElementIndex = numComponents;
     56         return 0;
     57     }
     58 
     59     const int alignment = numComponents == 3 ? 4 : numComponents;
     60     const int paddingOffset = (mElementIndex % alignment);
     61     const int paddingCount = (paddingOffset != 0 ? (alignment - paddingOffset) : 0);
     62 
     63     mElementIndex += paddingCount;
     64     mElementIndex += numComponents;
     65     mElementIndex %= 4;
     66 
     67     return paddingCount;
     68 }
     69 
     70 TString Std140PaddingHelper::prePaddingString(const TType &type)
     71 {
     72     int paddingCount = prePadding(type);
     73 
     74     TString padding;
     75 
     76     for (int paddingIndex = 0; paddingIndex < paddingCount; paddingIndex++)
     77     {
     78         padding += "    float pad_" + next() + ";\n";
     79     }
     80 
     81     return padding;
     82 }
     83 
     84 TString Std140PaddingHelper::postPaddingString(const TType &type, bool useHLSLRowMajorPacking)
     85 {
     86     if (!type.isMatrix() && !type.isArray() && type.getBasicType() != EbtStruct)
     87     {
     88         return "";
     89     }
     90 
     91     int numComponents = 0;
     92     TStructure *structure = type.getStruct();
     93 
     94     if (type.isMatrix())
     95     {
     96         // This method can also be called from structureString, which does not use layout qualifiers.
     97         // Thus, use the method parameter for determining the matrix packing.
     98         //
     99         // Note HLSL row major packing corresponds to GL API column-major, and vice-versa, since we
    100         // wish to always transpose GL matrices to play well with HLSL's matrix array indexing.
    101         //
    102         const bool isRowMajorMatrix = !useHLSLRowMajorPacking;
    103         const GLenum glType = GLVariableType(type);
    104         numComponents = gl::MatrixComponentCount(glType, isRowMajorMatrix);
    105     }
    106     else if (structure)
    107     {
    108         const TString &structName = QualifiedStructNameString(*structure,
    109                                                               useHLSLRowMajorPacking, true);
    110         numComponents = mStructElementIndexes.find(structName)->second;
    111 
    112         if (numComponents == 0)
    113         {
    114             return "";
    115         }
    116     }
    117     else
    118     {
    119         const GLenum glType = GLVariableType(type);
    120         numComponents = gl::VariableComponentCount(glType);
    121     }
    122 
    123     TString padding;
    124     for (int paddingOffset = numComponents; paddingOffset < 4; paddingOffset++)
    125     {
    126         padding += "    float pad_" + next() + ";\n";
    127     }
    128     return padding;
    129 }
    130 
    131 StructureHLSL::StructureHLSL()
    132     : mUniquePaddingCounter(0)
    133 {}
    134 
    135 Std140PaddingHelper StructureHLSL::getPaddingHelper()
    136 {
    137     return Std140PaddingHelper(mStd140StructElementIndexes, &mUniquePaddingCounter);
    138 }
    139 
    140 TString StructureHLSL::defineQualified(const TStructure &structure, bool useHLSLRowMajorPacking, bool useStd140Packing)
    141 {
    142     if (useStd140Packing)
    143     {
    144         Std140PaddingHelper padHelper = getPaddingHelper();
    145         return define(structure, useHLSLRowMajorPacking, useStd140Packing, &padHelper);
    146     }
    147     else
    148     {
    149         return define(structure, useHLSLRowMajorPacking, useStd140Packing, NULL);
    150     }
    151 }
    152 
    153 TString StructureHLSL::defineNameless(const TStructure &structure)
    154 {
    155     return define(structure, false, false, NULL);
    156 }
    157 
    158 TString StructureHLSL::define(const TStructure &structure, bool useHLSLRowMajorPacking,
    159                               bool useStd140Packing, Std140PaddingHelper *padHelper)
    160 {
    161     const TFieldList &fields = structure.fields();
    162     const bool isNameless = (structure.name() == "");
    163     const TString &structName = QualifiedStructNameString(structure, useHLSLRowMajorPacking,
    164                                                           useStd140Packing);
    165     const TString declareString = (isNameless ? "struct" : "struct " + structName);
    166 
    167     TString string;
    168     string += declareString + "\n"
    169               "{\n";
    170 
    171     for (unsigned int i = 0; i < fields.size(); i++)
    172     {
    173         const TField &field = *fields[i];
    174         const TType &fieldType = *field.type();
    175         const TStructure *fieldStruct = fieldType.getStruct();
    176         const TString &fieldTypeString = fieldStruct ?
    177                                          QualifiedStructNameString(*fieldStruct, useHLSLRowMajorPacking,
    178                                                                    useStd140Packing) :
    179                                          TypeString(fieldType);
    180 
    181         if (padHelper)
    182         {
    183             string += padHelper->prePaddingString(fieldType);
    184         }
    185 
    186         string += "    " + fieldTypeString + " " + DecorateField(field.name(), structure) + ArrayString(fieldType) + ";\n";
    187 
    188         if (padHelper)
    189         {
    190             string += padHelper->postPaddingString(fieldType, useHLSLRowMajorPacking);
    191         }
    192     }
    193 
    194     // Nameless structs do not finish with a semicolon and newline, to leave room for an instance variable
    195     string += (isNameless ? "} " : "};\n");
    196 
    197     return string;
    198 }
    199 
    200 void StructureHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters)
    201 {
    202     if (name == "")
    203     {
    204         return;   // Nameless structures don't have constructors
    205     }
    206 
    207     if (type.getStruct() && mStructNames.find(name) != mStructNames.end())
    208     {
    209         return;   // Already added
    210     }
    211 
    212     TType ctorType = type;
    213     ctorType.clearArrayness();
    214     ctorType.setPrecision(EbpHigh);
    215     ctorType.setQualifier(EvqTemporary);
    216 
    217     typedef std::vector<TType> ParameterArray;
    218     ParameterArray ctorParameters;
    219 
    220     const TStructure* structure = type.getStruct();
    221     if (structure)
    222     {
    223         mStructNames.insert(name);
    224 
    225         // Add element index
    226         storeStd140ElementIndex(*structure, false);
    227         storeStd140ElementIndex(*structure, true);
    228 
    229         const TString &structString = defineQualified(*structure, false, false);
    230 
    231         if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structString) == mStructDeclarations.end())
    232         {
    233             // Add row-major packed struct for interface blocks
    234             TString rowMajorString = "#pragma pack_matrix(row_major)\n" +
    235                 defineQualified(*structure, true, false) +
    236                 "#pragma pack_matrix(column_major)\n";
    237 
    238             TString std140String = defineQualified(*structure, false, true);
    239             TString std140RowMajorString = "#pragma pack_matrix(row_major)\n" +
    240                 defineQualified(*structure, true, true) +
    241                 "#pragma pack_matrix(column_major)\n";
    242 
    243             mStructDeclarations.push_back(structString);
    244             mStructDeclarations.push_back(rowMajorString);
    245             mStructDeclarations.push_back(std140String);
    246             mStructDeclarations.push_back(std140RowMajorString);
    247         }
    248 
    249         const TFieldList &fields = structure->fields();
    250         for (unsigned int i = 0; i < fields.size(); i++)
    251         {
    252             ctorParameters.push_back(*fields[i]->type());
    253         }
    254     }
    255     else if (parameters)
    256     {
    257         for (TIntermSequence::const_iterator parameter = parameters->begin(); parameter != parameters->end(); parameter++)
    258         {
    259             ctorParameters.push_back((*parameter)->getAsTyped()->getType());
    260         }
    261     }
    262     else UNREACHABLE();
    263 
    264     TString constructor;
    265 
    266     if (ctorType.getStruct())
    267     {
    268         constructor += name + " " + name + "_ctor(";
    269     }
    270     else   // Built-in type
    271     {
    272         constructor += TypeString(ctorType) + " " + name + "(";
    273     }
    274 
    275     for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++)
    276     {
    277         const TType &type = ctorParameters[parameter];
    278 
    279         constructor += TypeString(type) + " x" + str(parameter) + ArrayString(type);
    280 
    281         if (parameter < ctorParameters.size() - 1)
    282         {
    283             constructor += ", ";
    284         }
    285     }
    286 
    287     constructor += ")\n"
    288                    "{\n";
    289 
    290     if (ctorType.getStruct())
    291     {
    292         constructor += "    " + name + " structure = {";
    293     }
    294     else
    295     {
    296         constructor += "    return " + TypeString(ctorType) + "(";
    297     }
    298 
    299     if (ctorType.isMatrix() && ctorParameters.size() == 1)
    300     {
    301         int rows = ctorType.getRows();
    302         int cols = ctorType.getCols();
    303         const TType &parameter = ctorParameters[0];
    304 
    305         if (parameter.isScalar())
    306         {
    307             for (int col = 0; col < cols; col++)
    308             {
    309                 for (int row = 0; row < rows; row++)
    310                 {
    311                     constructor += TString((row == col) ? "x0" : "0.0");
    312 
    313                     if (row < rows - 1 || col < cols - 1)
    314                     {
    315                         constructor += ", ";
    316                     }
    317                 }
    318             }
    319         }
    320         else if (parameter.isMatrix())
    321         {
    322             for (int col = 0; col < cols; col++)
    323             {
    324                 for (int row = 0; row < rows; row++)
    325                 {
    326                     if (row < parameter.getRows() && col < parameter.getCols())
    327                     {
    328                         constructor += TString("x0") + "[" + str(col) + "][" + str(row) + "]";
    329                     }
    330                     else
    331                     {
    332                         constructor += TString((row == col) ? "1.0" : "0.0");
    333                     }
    334 
    335                     if (row < rows - 1 || col < cols - 1)
    336                     {
    337                         constructor += ", ";
    338                     }
    339                 }
    340             }
    341         }
    342         else
    343         {
    344             ASSERT(rows == 2 && cols == 2 && parameter.isVector() && parameter.getNominalSize() == 4);
    345 
    346             constructor += "x0";
    347         }
    348     }
    349     else
    350     {
    351         size_t remainingComponents = ctorType.getObjectSize();
    352         size_t parameterIndex = 0;
    353 
    354         while (remainingComponents > 0)
    355         {
    356             const TType &parameter = ctorParameters[parameterIndex];
    357             const size_t parameterSize = parameter.getObjectSize();
    358             bool moreParameters = parameterIndex + 1 < ctorParameters.size();
    359 
    360             constructor += "x" + str(parameterIndex);
    361 
    362             if (ctorType.getStruct())
    363             {
    364                 ASSERT(remainingComponents == parameterSize || moreParameters);
    365                 ASSERT(parameterSize <= remainingComponents);
    366 
    367                 remainingComponents -= parameterSize;
    368             }
    369             else if (parameter.isScalar())
    370             {
    371                 remainingComponents -= parameter.getObjectSize();
    372             }
    373             else if (parameter.isVector())
    374             {
    375                 if (remainingComponents == parameterSize || moreParameters)
    376                 {
    377                     ASSERT(parameterSize <= remainingComponents);
    378                     remainingComponents -= parameterSize;
    379                 }
    380                 else if (remainingComponents < static_cast<size_t>(parameter.getNominalSize()))
    381                 {
    382                     switch (remainingComponents)
    383                     {
    384                       case 1: constructor += ".x";    break;
    385                       case 2: constructor += ".xy";   break;
    386                       case 3: constructor += ".xyz";  break;
    387                       case 4: constructor += ".xyzw"; break;
    388                       default: UNREACHABLE();
    389                     }
    390 
    391                     remainingComponents = 0;
    392                 }
    393                 else UNREACHABLE();
    394             }
    395             else if (parameter.isMatrix())
    396             {
    397                 int column = 0;
    398                 while (remainingComponents > 0 && column < parameter.getCols())
    399                 {
    400                     constructor += "[" + str(column) + "]";
    401 
    402                     if (remainingComponents < static_cast<size_t>(parameter.getRows()))
    403                     {
    404                         switch (remainingComponents)
    405                         {
    406                           case 1:  constructor += ".x";    break;
    407                           case 2:  constructor += ".xy";   break;
    408                           case 3:  constructor += ".xyz";  break;
    409                           default: UNREACHABLE();
    410                         }
    411 
    412                         remainingComponents = 0;
    413                     }
    414                     else
    415                     {
    416                         remainingComponents -= parameter.getRows();
    417 
    418                         if (remainingComponents > 0)
    419                         {
    420                             constructor += ", x" + str(parameterIndex);
    421                         }
    422                     }
    423 
    424                     column++;
    425                 }
    426             }
    427             else UNREACHABLE();
    428 
    429             if (moreParameters)
    430             {
    431                 parameterIndex++;
    432             }
    433 
    434             if (remainingComponents)
    435             {
    436                 constructor += ", ";
    437             }
    438         }
    439     }
    440 
    441     if (ctorType.getStruct())
    442     {
    443         constructor += "};\n"
    444                         "    return structure;\n"
    445                         "}\n";
    446     }
    447     else
    448     {
    449         constructor += ");\n"
    450                        "}\n";
    451     }
    452 
    453     mConstructors.insert(constructor);
    454 }
    455 
    456 std::string StructureHLSL::structsHeader() const
    457 {
    458     TInfoSinkBase out;
    459 
    460     for (size_t structIndex = 0; structIndex < mStructDeclarations.size(); structIndex++)
    461     {
    462         out << mStructDeclarations[structIndex];
    463     }
    464 
    465     for (Constructors::const_iterator constructor = mConstructors.begin();
    466          constructor != mConstructors.end();
    467          constructor++)
    468     {
    469         out << *constructor;
    470     }
    471 
    472     return out.str();
    473 }
    474 
    475 void StructureHLSL::storeStd140ElementIndex(const TStructure &structure, bool useHLSLRowMajorPacking)
    476 {
    477     Std140PaddingHelper padHelper = getPaddingHelper();
    478     const TFieldList &fields = structure.fields();
    479 
    480     for (unsigned int i = 0; i < fields.size(); i++)
    481     {
    482         padHelper.prePadding(*fields[i]->type());
    483     }
    484 
    485     // Add remaining element index to the global map, for use with nested structs in standard layouts
    486     const TString &structName = QualifiedStructNameString(structure, useHLSLRowMajorPacking, true);
    487     mStd140StructElementIndexes[structName] = padHelper.elementIndex();
    488 }
    489 
    490 }
    491