Split OutputHLSL structure code into new module.

Refactoring patch only.

BUG=angle:466

Change-Id: I2c57096e1e24574e7de3d35d608645fde3b0c681
Reviewed-on: https://chromium-review.googlesource.com/203730
Tested-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Zhenyao Mo <zmo@chromium.org>
Reviewed-by: Nicolas Capens <nicolascapens@chromium.org>
diff --git a/projects/src/translator_lib.vcxproj b/projects/src/translator_lib.vcxproj
index 7d2cef9..f466531 100644
--- a/projects/src/translator_lib.vcxproj
+++ b/projects/src/translator_lib.vcxproj
@@ -159,6 +159,7 @@
     <ClInclude Include="..\..\src\compiler\translator\InitializeVariables.h"/>
     <ClInclude Include="..\..\src\compiler\translator\localintermediate.h"/>
     <ClInclude Include="..\..\src\compiler\translator\ShHandle.h"/>
+    <ClInclude Include="..\..\src\compiler\translator\StructureHLSL.h"/>
     <ClInclude Include="..\..\src\compiler\translator\OutputGLSLBase.h"/>
     <ClInclude Include="..\..\src\compiler\translator\ForLoopUnroll.h"/>
     <ClInclude Include="..\..\src\compiler\translator\Pragma.h"/>
@@ -249,6 +250,7 @@
     <ClCompile Include="..\..\src\compiler\translator\LoopInfo.cpp"/>
     <ClCompile Include="..\..\src\compiler\translator\OutputHLSL.cpp"/>
     <ClCompile Include="..\..\src\compiler\translator\DetectDiscontinuity.cpp"/>
+    <ClCompile Include="..\..\src\compiler\translator\StructureHLSL.cpp"/>
     <ClCompile Include="..\..\src\compiler\translator\UnfoldShortCircuit.cpp"/>
     <ClCompile Include="..\..\src\compiler\translator\compilerdebug.cpp"/>
     <ClCompile Include="..\..\src\compiler\translator\VariableInfo.cpp"/>
diff --git a/projects/src/translator_lib.vcxproj.filters b/projects/src/translator_lib.vcxproj.filters
index aa9b061..57f1a65 100644
--- a/projects/src/translator_lib.vcxproj.filters
+++ b/projects/src/translator_lib.vcxproj.filters
@@ -261,6 +261,9 @@
     <ClInclude Include="..\..\src\compiler\translator\ShHandle.h">
       <Filter>src\compiler\translator</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\compiler\translator\StructureHLSL.h">
+      <Filter>src\compiler\translator</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\src\compiler\translator\OutputGLSLBase.h">
       <Filter>src\compiler\translator</Filter>
     </ClInclude>
@@ -390,6 +393,9 @@
     <ClCompile Include="..\..\src\compiler\translator\DetectDiscontinuity.cpp">
       <Filter>src\compiler\translator</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\compiler\translator\StructureHLSL.cpp">
+      <Filter>src\compiler\translator</Filter>
+    </ClCompile>
     <ClInclude Include="..\..\src\compiler\translator\glslang_tab.h">
       <Filter>src\compiler\translator</Filter>
     </ClInclude>
diff --git a/src/compiler/translator/OutputHLSL.cpp b/src/compiler/translator/OutputHLSL.cpp
index 2e88b52..220898e 100644
--- a/src/compiler/translator/OutputHLSL.cpp
+++ b/src/compiler/translator/OutputHLSL.cpp
@@ -19,6 +19,7 @@
 #include "compiler/translator/RewriteElseBlocks.h"
 #include "compiler/translator/UtilsHLSL.h"
 #include "compiler/translator/util.h"
+#include "compiler/translator/StructureHLSL.h"
 
 #include <algorithm>
 #include <cfloat>
@@ -27,119 +28,6 @@
 namespace sh
 {
 
-class Std140PaddingHelper
-{
-  public:
-    explicit Std140PaddingHelper(const std::map<TString, int> &structElementIndexes)
-        : mPaddingCounter(0),
-          mElementIndex(0),
-          mStructElementIndexes(structElementIndexes)
-    {}
-
-    int elementIndex() const { return mElementIndex; }
-
-    int prePadding(const TType &type)
-    {
-        if (type.getBasicType() == EbtStruct || type.isMatrix() || type.isArray())
-        {
-            // no padding needed, HLSL will align the field to a new register
-            mElementIndex = 0;
-            return 0;
-        }
-
-        const GLenum glType = GLVariableType(type);
-        const int numComponents = gl::UniformComponentCount(glType);
-
-        if (numComponents >= 4)
-        {
-            // no padding needed, HLSL will align the field to a new register
-            mElementIndex = 0;
-            return 0;
-        }
-
-        if (mElementIndex + numComponents > 4)
-        {
-            // no padding needed, HLSL will align the field to a new register
-            mElementIndex = numComponents;
-            return 0;
-        }
-
-        const int alignment = numComponents == 3 ? 4 : numComponents;
-        const int paddingOffset = (mElementIndex % alignment);
-        const int paddingCount = (paddingOffset != 0 ? (alignment - paddingOffset) : 0);
-
-        mElementIndex += paddingCount;
-        mElementIndex += numComponents;
-        mElementIndex %= 4;
-
-        return paddingCount;
-    }
-
-    TString prePaddingString(const TType &type)
-    {
-        int paddingCount = prePadding(type);
-
-        TString padding;
-
-        for (int paddingIndex = 0; paddingIndex < paddingCount; paddingIndex++)
-        {
-            padding += "    float pad_" + str(mPaddingCounter++) + ";\n";
-        }
-
-        return padding;
-    }
-
-    TString postPaddingString(const TType &type, bool useHLSLRowMajorPacking)
-    {
-        if (!type.isMatrix() && !type.isArray() && type.getBasicType() != EbtStruct)
-        {
-            return "";
-        }
-
-        int numComponents = 0;
-
-        if (type.isMatrix())
-        {
-            // This method can also be called from structureString, which does not use layout qualifiers.
-            // Thus, use the method parameter for determining the matrix packing.
-            //
-            // Note HLSL row major packing corresponds to GL API column-major, and vice-versa, since we
-            // wish to always transpose GL matrices to play well with HLSL's matrix array indexing.
-            //
-            const bool isRowMajorMatrix = !useHLSLRowMajorPacking;
-            const GLenum glType = GLVariableType(type);
-            numComponents = gl::MatrixComponentCount(glType, isRowMajorMatrix);
-        }
-        else if (type.getStruct())
-        {
-            const TString &structName = QualifiedStructNameString(*type.getStruct(), useHLSLRowMajorPacking, true);
-            numComponents = mStructElementIndexes.find(structName)->second;
-
-            if (numComponents == 0)
-            {
-                return "";
-            }
-        }
-        else
-        {
-            const GLenum glType = GLVariableType(type);
-            numComponents = gl::UniformComponentCount(glType);
-        }
-
-        TString padding;
-        for (int paddingOffset = numComponents; paddingOffset < 4; paddingOffset++)
-        {
-            padding += "    float pad_" + str(mPaddingCounter++) + ";\n";
-        }
-        return padding;
-    }
-
-  private:
-    int mPaddingCounter;
-    int mElementIndex;
-    const std::map<TString, int> &mStructElementIndexes;
-};
-
 TString OutputHLSL::TextureFunction::name() const
 {
     TString name = "gl_texture";
@@ -260,6 +148,8 @@
 
     mExcessiveLoopIndex = NULL;
 
+    mStructureHLSL = new StructureHLSL;
+
     if (mOutputType == SH_HLSL9_OUTPUT)
     {
         if (mContext.shaderType == SH_FRAGMENT_SHADER)
@@ -282,7 +172,8 @@
 
 OutputHLSL::~OutputHLSL()
 {
-    delete mUnfoldShortCircuit;
+    SafeDelete(mUnfoldShortCircuit);
+    SafeDelete(mStructureHLSL);
 }
 
 void OutputHLSL::output()
@@ -426,7 +317,7 @@
 {
     TString hlsl;
 
-    Std140PaddingHelper padHelper(mStd140StructElementIndexes);
+    Std140PaddingHelper padHelper = mStructureHLSL->getPaddingHelper();
 
     for (unsigned int typeIndex = 0; typeIndex < interfaceBlock.fields().size(); typeIndex++)
     {
@@ -688,15 +579,7 @@
         mActiveAttributes.push_back(attributeVar);
     }
 
-    for (StructDeclarations::iterator structDeclaration = mStructDeclarations.begin(); structDeclaration != mStructDeclarations.end(); structDeclaration++)
-    {
-        out << *structDeclaration;
-    }
-
-    for (Constructors::iterator constructor = mConstructors.begin(); constructor != mConstructors.end(); constructor++)
-    {
-        out << *constructor;
-    }
+    out << mStructureHLSL->structsHeader();
 
     if (mUsesDiscardRewriting)
     {
@@ -2251,9 +2134,11 @@
 
             if (variable && (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal))
             {
-                if (variable->getType().getStruct())
+                TStructure *structure = variable->getType().getStruct();
+
+                if (structure)
                 {
-                    addConstructor(variable->getType(), StructNameString(*variable->getType().getStruct()), NULL);
+                    mStructureHLSL->addConstructor(variable->getType(), StructNameString(*structure), NULL);
                 }
 
                 if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "")   // Variable declaration
@@ -2378,9 +2263,11 @@
 
                 if (symbol)
                 {
-                    if (symbol->getType().getStruct())
+                    TStructure *structure = symbol->getType().getStruct();
+
+                    if (structure)
                     {
-                        addConstructor(symbol->getType(), StructNameString(*symbol->getType().getStruct()), NULL);
+                        mStructureHLSL->addConstructor(symbol->getType(), StructNameString(*structure), NULL);
                     }
 
                     out << argumentString(symbol);
@@ -2593,7 +2480,7 @@
       case EOpConstructStruct:
         {
             const TString &structName = StructNameString(*node->getType().getStruct());
-            addConstructor(node->getType(), structName, &node->getSequence());
+            mStructureHLSL->addConstructor(node->getType(), structName, &node->getSequence());
             outputTriplet(visit, structName + "_ctor(", ", ", ")");
         }
         break;
@@ -3194,73 +3081,13 @@
     return "{" + string + "}";
 }
 
-TString OutputHLSL::defineNamelessStruct(const TStructure &structure)
-{
-    return defineStruct(structure, false, false, NULL);
-}
-
-TString OutputHLSL::defineQualifiedStruct(const TStructure &structure, bool useHLSLRowMajorPacking,
-                                          bool useStd140Packing)
-{
-    if (useStd140Packing)
-    {
-        Std140PaddingHelper padHelper(mStd140StructElementIndexes);
-        return defineStruct(structure, useHLSLRowMajorPacking, true, &padHelper);
-    }
-    else
-    {
-        return defineStruct(structure, useHLSLRowMajorPacking, false, NULL);
-    }
-}
-
-TString OutputHLSL::defineStruct(const TStructure &structure, bool useHLSLRowMajorPacking,
-                                 bool useStd140Packing, Std140PaddingHelper *padHelper)
-{
-    const TFieldList &fields = structure.fields();
-    const bool isNameless = (structure.name() == "");
-    const TString &structName = QualifiedStructNameString(structure, useHLSLRowMajorPacking, useStd140Packing);
-    const TString declareString = (isNameless ? "struct" : "struct " + structName);
-
-    TString string;
-    string += declareString + "\n"
-              "{\n";
-
-    for (unsigned int i = 0; i < fields.size(); i++)
-    {
-        const TField &field = *fields[i];
-        const TType &fieldType = *field.type();
-        const TStructure *fieldStruct = fieldType.getStruct();
-        const TString &fieldTypeString = fieldStruct ?
-                                         QualifiedStructNameString(*fieldStruct, useHLSLRowMajorPacking,
-                                                                   useStd140Packing) :
-                                         TypeString(fieldType);
-
-        if (padHelper)
-        {
-            string += padHelper->prePaddingString(fieldType);
-        }
-
-        string += "    " + fieldTypeString + " " + DecorateField(field.name(), structure) + ArrayString(fieldType) + ";\n";
-
-        if (padHelper)
-        {
-            string += padHelper->postPaddingString(fieldType, useHLSLRowMajorPacking);
-        }
-    }
-
-    // Nameless structs do not finish with a semicolon and newline, to leave room for an instance variable
-    string += (isNameless ? "} " : "};\n");
-
-    return string;
-}
-
 void OutputHLSL::outputConstructor(Visit visit, const TType &type, const TString &name, const TIntermSequence *parameters)
 {
     TInfoSinkBase &out = mBody;
 
     if (visit == PreVisit)
     {
-        addConstructor(type, name, parameters);
+        mStructureHLSL->addConstructor(type, name, parameters);
 
         out << name + "(";
     }
@@ -3274,277 +3101,6 @@
     }
 }
 
-void OutputHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters)
-{
-    if (name == "")
-    {
-        return;   // Nameless structures don't have constructors
-    }
-
-    if (type.getStruct() && mStructNames.find(name) != mStructNames.end())
-    {
-        return;   // Already added
-    }
-
-    TType ctorType = type;
-    ctorType.clearArrayness();
-    ctorType.setPrecision(EbpHigh);
-    ctorType.setQualifier(EvqTemporary);
-
-    typedef std::vector<TType> ParameterArray;
-    ParameterArray ctorParameters;
-
-    const TStructure* structure = type.getStruct();
-    if (structure)
-    {
-        mStructNames.insert(name);
-
-        // Add element index
-        storeStd140ElementIndex(*structure, false);
-        storeStd140ElementIndex(*structure, true);
-
-        const TString &structString = defineQualifiedStruct(*structure, false, false);
-
-        if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structString) == mStructDeclarations.end())
-        {
-            // Add row-major packed struct for interface blocks
-            TString rowMajorString = "#pragma pack_matrix(row_major)\n" +
-                                     defineQualifiedStruct(*structure, true, false) +
-                                     "#pragma pack_matrix(column_major)\n";
-
-            TString std140String = defineQualifiedStruct(*structure, false, true);
-            TString std140RowMajorString = "#pragma pack_matrix(row_major)\n" +
-                                           defineQualifiedStruct(*structure, true, true) +
-                                           "#pragma pack_matrix(column_major)\n";
-
-            mStructDeclarations.push_back(structString);
-            mStructDeclarations.push_back(rowMajorString);
-            mStructDeclarations.push_back(std140String);
-            mStructDeclarations.push_back(std140RowMajorString);
-        }
-
-        const TFieldList &fields = structure->fields();
-        for (unsigned int i = 0; i < fields.size(); i++)
-        {
-            ctorParameters.push_back(*fields[i]->type());
-        }
-    }
-    else if (parameters)
-    {
-        for (TIntermSequence::const_iterator parameter = parameters->begin(); parameter != parameters->end(); parameter++)
-        {
-            ctorParameters.push_back((*parameter)->getAsTyped()->getType());
-        }
-    }
-    else UNREACHABLE();
-
-    TString constructor;
-
-    if (ctorType.getStruct())
-    {
-        constructor += name + " " + name + "_ctor(";
-    }
-    else   // Built-in type
-    {
-        constructor += TypeString(ctorType) + " " + name + "(";
-    }
-
-    for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++)
-    {
-        const TType &type = ctorParameters[parameter];
-
-        constructor += TypeString(type) + " x" + str(parameter) + ArrayString(type);
-
-        if (parameter < ctorParameters.size() - 1)
-        {
-            constructor += ", ";
-        }
-    }
-
-    constructor += ")\n"
-                   "{\n";
-
-    if (ctorType.getStruct())
-    {
-        constructor += "    " + name + " structure = {";
-    }
-    else
-    {
-        constructor += "    return " + TypeString(ctorType) + "(";
-    }
-
-    if (ctorType.isMatrix() && ctorParameters.size() == 1)
-    {
-        int rows = ctorType.getRows();
-        int cols = ctorType.getCols();
-        const TType &parameter = ctorParameters[0];
-
-        if (parameter.isScalar())
-        {
-            for (int row = 0; row < rows; row++)
-            {
-                for (int col = 0; col < cols; col++)
-                {
-                    constructor += TString((row == col) ? "x0" : "0.0");
-                    
-                    if (row < rows - 1 || col < cols - 1)
-                    {
-                        constructor += ", ";
-                    }
-                }
-            }
-        }
-        else if (parameter.isMatrix())
-        {
-            for (int row = 0; row < rows; row++)
-            {
-                for (int col = 0; col < cols; col++)
-                {
-                    if (row < parameter.getRows() && col < parameter.getCols())
-                    {
-                        constructor += TString("x0") + "[" + str(row) + "][" + str(col) + "]";
-                    }
-                    else
-                    {
-                        constructor += TString((row == col) ? "1.0" : "0.0");
-                    }
-
-                    if (row < rows - 1 || col < cols - 1)
-                    {
-                        constructor += ", ";
-                    }
-                }
-            }
-        }
-        else
-        {
-            ASSERT(rows == 2 && cols == 2 && parameter.isVector() && parameter.getNominalSize() == 4);
-
-            constructor += "x0";
-        }
-    }
-    else
-    {
-        size_t remainingComponents = ctorType.getObjectSize();
-        size_t parameterIndex = 0;
-
-        while (remainingComponents > 0)
-        {
-            const TType &parameter = ctorParameters[parameterIndex];
-            const size_t parameterSize = parameter.getObjectSize();
-            bool moreParameters = parameterIndex + 1 < ctorParameters.size();
-
-            constructor += "x" + str(parameterIndex);
-
-            if (ctorType.getStruct())
-            {
-                ASSERT(remainingComponents == parameterSize || moreParameters);
-                ASSERT(parameterSize <= remainingComponents);
-
-                remainingComponents -= parameterSize;
-            }
-            else if (parameter.isScalar())
-            {
-                remainingComponents -= parameter.getObjectSize();
-            }
-            else if (parameter.isVector())
-            {
-                if (remainingComponents == parameterSize || moreParameters)
-                {
-                    ASSERT(parameterSize <= remainingComponents);
-                    remainingComponents -= parameterSize;
-                }
-                else if (remainingComponents < static_cast<size_t>(parameter.getNominalSize()))
-                {
-                    switch (remainingComponents)
-                    {
-                      case 1: constructor += ".x";    break;
-                      case 2: constructor += ".xy";   break;
-                      case 3: constructor += ".xyz";  break;
-                      case 4: constructor += ".xyzw"; break;
-                      default: UNREACHABLE();
-                    }
-
-                    remainingComponents = 0;
-                }
-                else UNREACHABLE();
-            }
-            else if (parameter.isMatrix())
-            {
-                int column = 0;
-                while (remainingComponents > 0 && column < parameter.getCols())
-                {
-                    constructor += "[" + str(column) + "]";
-
-                    if (remainingComponents < static_cast<size_t>(parameter.getRows()))
-                    {
-                        switch (remainingComponents)
-                        {
-                          case 1:  constructor += ".x";    break;
-                          case 2:  constructor += ".xy";   break;
-                          case 3:  constructor += ".xyz";  break;
-                          default: UNREACHABLE();
-                        }
-
-                        remainingComponents = 0;
-                    }
-                    else
-                    {
-                        remainingComponents -= parameter.getRows();
-
-                        if (remainingComponents > 0)
-                        {
-                            constructor += ", x" + str(parameterIndex);
-                        }
-                    }
-
-                    column++;
-                }
-            }
-            else UNREACHABLE();
-
-            if (moreParameters)
-            {
-                parameterIndex++;
-            }
-
-            if (remainingComponents)
-            {
-                constructor += ", ";
-            }
-        }
-    }
-
-    if (ctorType.getStruct())
-    {
-        constructor += "};\n"
-                       "    return structure;\n"
-                       "}\n";
-    }
-    else
-    {
-        constructor += ");\n"
-                       "}\n";
-    }
-
-    mConstructors.insert(constructor);
-}
-
-void OutputHLSL::storeStd140ElementIndex(const TStructure &structure, bool useHLSLRowMajorPacking)
-{
-    Std140PaddingHelper padHelper(mStd140StructElementIndexes);
-    const TFieldList &fields = structure.fields();
-
-    for (unsigned int i = 0; i < fields.size(); i++)
-    {
-        padHelper.prePadding(*fields[i]->type());
-    }
-
-    // Add remaining element index to the global map, for use with nested structs in standard layouts
-    const TString &structName = QualifiedStructNameString(structure, useHLSLRowMajorPacking, true);
-    mStd140StructElementIndexes[structName] = padHelper.elementIndex();
-}
-
 const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const ConstantUnion *constUnion)
 {
     TInfoSinkBase &out = mBody;
diff --git a/src/compiler/translator/OutputHLSL.h b/src/compiler/translator/OutputHLSL.h
index 1daf643..214ed42 100644
--- a/src/compiler/translator/OutputHLSL.h
+++ b/src/compiler/translator/OutputHLSL.h
@@ -21,7 +21,7 @@
 namespace sh
 {
 class UnfoldShortCircuit;
-class Std140PaddingHelper;
+class StructureHLSL;
 
 class OutputHLSL : public TIntermTraverser
 {
@@ -38,8 +38,6 @@
     const std::vector<gl::Attribute> &getAttributes() const;
     const std::vector<gl::Varying> &getVaryings() const;
 
-    static TString defineNamelessStruct(const TStructure &structure);
-    TString defineQualifiedStruct(const TStructure &structure, bool useHLSLRowMajorPacking, bool useStd140Packing);
     static TString initializer(const TType &type);
 
   protected:
@@ -64,8 +62,6 @@
     int vectorSize(const TType &type) const;
 
     void outputConstructor(Visit visit, const TType &type, const TString &name, const TIntermSequence *parameters);
-    void addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters);
-    void storeStd140ElementIndex(const TStructure &structure, bool useHLSLRowMajorPacking);
     const ConstantUnion *writeConstantUnion(const TType &type, const ConstantUnion *constUnion);
 
     TParseContext &mContext;
@@ -85,6 +81,8 @@
     ReferencedSymbols mReferencedVaryings;
     ReferencedSymbols mReferencedOutputVariables;
 
+    StructureHLSL *mStructureHLSL;
+
     struct TextureFunction
     {
         enum Method
@@ -143,15 +141,6 @@
 
     int mNumRenderTargets;
 
-    typedef std::set<TString> Constructors;
-    Constructors mConstructors;
-
-    typedef std::set<TString> StructNames;
-    StructNames mStructNames;
-
-    typedef std::list<TString> StructDeclarations;
-    StructDeclarations mStructDeclarations;
-
     int mUniqueIndex;   // For creating unique names
 
     bool mContainsLoopDiscontinuity;
@@ -184,20 +173,18 @@
     TString interfaceBlockStructString(const TInterfaceBlock &interfaceBlock);
     TString interfaceBlockString(const TInterfaceBlock &interfaceBlock, unsigned int registerIndex, unsigned int arrayIndex);
     TString structInitializerString(int indent, const TStructure &structure, const TString &rhsStructName);
-    static TString defineStruct(const TStructure &structure, bool useHLSLRowMajorPacking,
-                                bool useStd140Packing, Std140PaddingHelper *padHelper);
 
     std::vector<gl::Uniform> mActiveUniforms;
     std::vector<gl::InterfaceBlock> mActiveInterfaceBlocks;
     std::vector<gl::Attribute> mActiveOutputVariables;
     std::vector<gl::Attribute> mActiveAttributes;
     std::vector<gl::Varying> mActiveVaryings;
-    std::map<TString, int> mStd140StructElementIndexes;
     std::map<TIntermTyped*, TString> mFlaggedStructMappedNames;
     std::map<TIntermTyped*, TString> mFlaggedStructOriginalNames;
 
     void makeFlaggedStructMaps(const std::vector<TIntermTyped *> &flaggedStructs);
 };
+
 }
 
 #endif   // COMPILER_OUTPUTHLSL_H_
diff --git a/src/compiler/translator/StructureHLSL.cpp b/src/compiler/translator/StructureHLSL.cpp
new file mode 100644
index 0000000..e19058f
--- /dev/null
+++ b/src/compiler/translator/StructureHLSL.cpp
@@ -0,0 +1,475 @@
+//
+// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// StructureHLSL.cpp:
+//   Definitions of methods for HLSL translation of GLSL structures.
+//
+
+#include "compiler/translator/StructureHLSL.h"
+#include "common/utilities.h"
+#include "compiler/translator/OutputHLSL.h"
+#include "compiler/translator/Types.h"
+#include "compiler/translator/util.h"
+#include "compiler/translator/UtilsHLSL.h"
+
+namespace sh
+{
+
+Std140PaddingHelper::Std140PaddingHelper(const std::map<TString, int> &structElementIndexes)
+    : mPaddingCounter(0),
+      mElementIndex(0),
+      mStructElementIndexes(structElementIndexes)
+{}
+
+int Std140PaddingHelper::prePadding(const TType &type)
+{
+    if (type.getBasicType() == EbtStruct || type.isMatrix() || type.isArray())
+    {
+        // no padding needed, HLSL will align the field to a new register
+        mElementIndex = 0;
+        return 0;
+    }
+
+    const GLenum glType = GLVariableType(type);
+    const int numComponents = gl::UniformComponentCount(glType);
+
+    if (numComponents >= 4)
+    {
+        // no padding needed, HLSL will align the field to a new register
+        mElementIndex = 0;
+        return 0;
+    }
+
+    if (mElementIndex + numComponents > 4)
+    {
+        // no padding needed, HLSL will align the field to a new register
+        mElementIndex = numComponents;
+        return 0;
+    }
+
+    const int alignment = numComponents == 3 ? 4 : numComponents;
+    const int paddingOffset = (mElementIndex % alignment);
+    const int paddingCount = (paddingOffset != 0 ? (alignment - paddingOffset) : 0);
+
+    mElementIndex += paddingCount;
+    mElementIndex += numComponents;
+    mElementIndex %= 4;
+
+    return paddingCount;
+}
+
+TString Std140PaddingHelper::prePaddingString(const TType &type)
+{
+    int paddingCount = prePadding(type);
+
+    TString padding;
+
+    for (int paddingIndex = 0; paddingIndex < paddingCount; paddingIndex++)
+    {
+        padding += "    float pad_" + str(mPaddingCounter++) + ";\n";
+    }
+
+    return padding;
+}
+
+TString Std140PaddingHelper::postPaddingString(const TType &type, bool useHLSLRowMajorPacking)
+{
+    if (!type.isMatrix() && !type.isArray() && type.getBasicType() != EbtStruct)
+    {
+        return "";
+    }
+
+    int numComponents = 0;
+    TStructure *structure = type.getStruct();
+
+    if (type.isMatrix())
+    {
+        // This method can also be called from structureString, which does not use layout qualifiers.
+        // Thus, use the method parameter for determining the matrix packing.
+        //
+        // Note HLSL row major packing corresponds to GL API column-major, and vice-versa, since we
+        // wish to always transpose GL matrices to play well with HLSL's matrix array indexing.
+        //
+        const bool isRowMajorMatrix = !useHLSLRowMajorPacking;
+        const GLenum glType = GLVariableType(type);
+        numComponents = gl::MatrixComponentCount(glType, isRowMajorMatrix);
+    }
+    else if (structure)
+    {
+        const TString &structName = QualifiedStructNameString(*structure,
+                                                              useHLSLRowMajorPacking, true);
+        numComponents = mStructElementIndexes.find(structName)->second;
+
+        if (numComponents == 0)
+        {
+            return "";
+        }
+    }
+    else
+    {
+        const GLenum glType = GLVariableType(type);
+        numComponents = gl::UniformComponentCount(glType);
+    }
+
+    TString padding;
+    for (int paddingOffset = numComponents; paddingOffset < 4; paddingOffset++)
+    {
+        padding += "    float pad_" + str(mPaddingCounter++) + ";\n";
+    }
+    return padding;
+}
+
+StructureHLSL::StructureHLSL()
+{}
+
+TString StructureHLSL::defineQualified(const TStructure &structure, bool useHLSLRowMajorPacking, bool useStd140Packing)
+{
+    if (useStd140Packing)
+    {
+        Std140PaddingHelper padHelper(mStd140StructElementIndexes);
+        return define(structure, useHLSLRowMajorPacking, useStd140Packing, &padHelper);
+    }
+    else
+    {
+        return define(structure, useHLSLRowMajorPacking, useStd140Packing, NULL);
+    }
+}
+
+TString StructureHLSL::defineNameless(const TStructure &structure)
+{
+    return define(structure, false, false, NULL);
+}
+
+TString StructureHLSL::define(const TStructure &structure, bool useHLSLRowMajorPacking,
+                              bool useStd140Packing, Std140PaddingHelper *padHelper)
+{
+    const TFieldList &fields = structure.fields();
+    const bool isNameless = (structure.name() == "");
+    const TString &structName = QualifiedStructNameString(structure, useHLSLRowMajorPacking,
+                                                          useStd140Packing);
+    const TString declareString = (isNameless ? "struct" : "struct " + structName);
+
+    TString string;
+    string += declareString + "\n"
+              "{\n";
+
+    for (unsigned int i = 0; i < fields.size(); i++)
+    {
+        const TField &field = *fields[i];
+        const TType &fieldType = *field.type();
+        const TStructure *fieldStruct = fieldType.getStruct();
+        const TString &fieldTypeString = fieldStruct ?
+                                         QualifiedStructNameString(*fieldStruct, useHLSLRowMajorPacking,
+                                                                   useStd140Packing) :
+                                         TypeString(fieldType);
+
+        if (padHelper)
+        {
+            string += padHelper->prePaddingString(fieldType);
+        }
+
+        string += "    " + fieldTypeString + " " + DecorateField(field.name(), structure) + ArrayString(fieldType) + ";\n";
+
+        if (padHelper)
+        {
+            string += padHelper->postPaddingString(fieldType, useHLSLRowMajorPacking);
+        }
+    }
+
+    // Nameless structs do not finish with a semicolon and newline, to leave room for an instance variable
+    string += (isNameless ? "} " : "};\n");
+
+    return string;
+}
+
+void StructureHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters)
+{
+    if (name == "")
+    {
+        return;   // Nameless structures don't have constructors
+    }
+
+    if (type.getStruct() && mStructNames.find(name) != mStructNames.end())
+    {
+        return;   // Already added
+    }
+
+    TType ctorType = type;
+    ctorType.clearArrayness();
+    ctorType.setPrecision(EbpHigh);
+    ctorType.setQualifier(EvqTemporary);
+
+    typedef std::vector<TType> ParameterArray;
+    ParameterArray ctorParameters;
+
+    const TStructure* structure = type.getStruct();
+    if (structure)
+    {
+        mStructNames.insert(name);
+
+        // Add element index
+        storeStd140ElementIndex(*structure, false);
+        storeStd140ElementIndex(*structure, true);
+
+        const TString &structString = defineQualified(*structure, false, false);
+
+        if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structString) == mStructDeclarations.end())
+        {
+            // Add row-major packed struct for interface blocks
+            TString rowMajorString = "#pragma pack_matrix(row_major)\n" +
+                defineQualified(*structure, true, false) +
+                "#pragma pack_matrix(column_major)\n";
+
+            TString std140String = defineQualified(*structure, false, true);
+            TString std140RowMajorString = "#pragma pack_matrix(row_major)\n" +
+                defineQualified(*structure, true, true) +
+                "#pragma pack_matrix(column_major)\n";
+
+            mStructDeclarations.push_back(structString);
+            mStructDeclarations.push_back(rowMajorString);
+            mStructDeclarations.push_back(std140String);
+            mStructDeclarations.push_back(std140RowMajorString);
+        }
+
+        const TFieldList &fields = structure->fields();
+        for (unsigned int i = 0; i < fields.size(); i++)
+        {
+            ctorParameters.push_back(*fields[i]->type());
+        }
+    }
+    else if (parameters)
+    {
+        for (TIntermSequence::const_iterator parameter = parameters->begin(); parameter != parameters->end(); parameter++)
+        {
+            ctorParameters.push_back((*parameter)->getAsTyped()->getType());
+        }
+    }
+    else UNREACHABLE();
+
+    TString constructor;
+
+    if (ctorType.getStruct())
+    {
+        constructor += name + " " + name + "_ctor(";
+    }
+    else   // Built-in type
+    {
+        constructor += TypeString(ctorType) + " " + name + "(";
+    }
+
+    for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++)
+    {
+        const TType &type = ctorParameters[parameter];
+
+        constructor += TypeString(type) + " x" + str(parameter) + ArrayString(type);
+
+        if (parameter < ctorParameters.size() - 1)
+        {
+            constructor += ", ";
+        }
+    }
+
+    constructor += ")\n"
+                   "{\n";
+
+    if (ctorType.getStruct())
+    {
+        constructor += "    " + name + " structure = {";
+    }
+    else
+    {
+        constructor += "    return " + TypeString(ctorType) + "(";
+    }
+
+    if (ctorType.isMatrix() && ctorParameters.size() == 1)
+    {
+        int rows = ctorType.getRows();
+        int cols = ctorType.getCols();
+        const TType &parameter = ctorParameters[0];
+
+        if (parameter.isScalar())
+        {
+            for (int row = 0; row < rows; row++)
+            {
+                for (int col = 0; col < cols; col++)
+                {
+                    constructor += TString((row == col) ? "x0" : "0.0");
+
+                    if (row < rows - 1 || col < cols - 1)
+                    {
+                        constructor += ", ";
+                    }
+                }
+            }
+        }
+        else if (parameter.isMatrix())
+        {
+            for (int row = 0; row < rows; row++)
+            {
+                for (int col = 0; col < cols; col++)
+                {
+                    if (row < parameter.getRows() && col < parameter.getCols())
+                    {
+                        constructor += TString("x0") + "[" + str(row) + "][" + str(col) + "]";
+                    }
+                    else
+                    {
+                        constructor += TString((row == col) ? "1.0" : "0.0");
+                    }
+
+                    if (row < rows - 1 || col < cols - 1)
+                    {
+                        constructor += ", ";
+                    }
+                }
+            }
+        }
+        else
+        {
+            ASSERT(rows == 2 && cols == 2 && parameter.isVector() && parameter.getNominalSize() == 4);
+
+            constructor += "x0";
+        }
+    }
+    else
+    {
+        size_t remainingComponents = ctorType.getObjectSize();
+        size_t parameterIndex = 0;
+
+        while (remainingComponents > 0)
+        {
+            const TType &parameter = ctorParameters[parameterIndex];
+            const size_t parameterSize = parameter.getObjectSize();
+            bool moreParameters = parameterIndex + 1 < ctorParameters.size();
+
+            constructor += "x" + str(parameterIndex);
+
+            if (ctorType.getStruct())
+            {
+                ASSERT(remainingComponents == parameterSize || moreParameters);
+                ASSERT(parameterSize <= remainingComponents);
+
+                remainingComponents -= parameterSize;
+            }
+            else if (parameter.isScalar())
+            {
+                remainingComponents -= parameter.getObjectSize();
+            }
+            else if (parameter.isVector())
+            {
+                if (remainingComponents == parameterSize || moreParameters)
+                {
+                    ASSERT(parameterSize <= remainingComponents);
+                    remainingComponents -= parameterSize;
+                }
+                else if (remainingComponents < static_cast<size_t>(parameter.getNominalSize()))
+                {
+                    switch (remainingComponents)
+                    {
+                      case 1: constructor += ".x";    break;
+                      case 2: constructor += ".xy";   break;
+                      case 3: constructor += ".xyz";  break;
+                      case 4: constructor += ".xyzw"; break;
+                      default: UNREACHABLE();
+                    }
+
+                    remainingComponents = 0;
+                }
+                else UNREACHABLE();
+            }
+            else if (parameter.isMatrix())
+            {
+                int column = 0;
+                while (remainingComponents > 0 && column < parameter.getCols())
+                {
+                    constructor += "[" + str(column) + "]";
+
+                    if (remainingComponents < static_cast<size_t>(parameter.getRows()))
+                    {
+                        switch (remainingComponents)
+                        {
+                          case 1:  constructor += ".x";    break;
+                          case 2:  constructor += ".xy";   break;
+                          case 3:  constructor += ".xyz";  break;
+                          default: UNREACHABLE();
+                        }
+
+                        remainingComponents = 0;
+                    }
+                    else
+                    {
+                        remainingComponents -= parameter.getRows();
+
+                        if (remainingComponents > 0)
+                        {
+                            constructor += ", x" + str(parameterIndex);
+                        }
+                    }
+
+                    column++;
+                }
+            }
+            else UNREACHABLE();
+
+            if (moreParameters)
+            {
+                parameterIndex++;
+            }
+
+            if (remainingComponents)
+            {
+                constructor += ", ";
+            }
+        }
+    }
+
+    if (ctorType.getStruct())
+    {
+        constructor += "};\n"
+                        "    return structure;\n"
+                        "}\n";
+    }
+    else
+    {
+        constructor += ");\n"
+                       "}\n";
+    }
+
+    mConstructors.insert(constructor);
+}
+
+std::string StructureHLSL::structsHeader() const
+{
+    TInfoSinkBase out;
+
+    for (size_t structIndex = 0; structIndex < mStructDeclarations.size(); structIndex++)
+    {
+        out << mStructDeclarations[structIndex];
+    }
+
+    for (Constructors::iterator constructor = mConstructors.begin(); constructor != mConstructors.end(); constructor++)
+    {
+        out << *constructor;
+    }
+
+    return out.str();
+}
+
+void StructureHLSL::storeStd140ElementIndex(const TStructure &structure, bool useHLSLRowMajorPacking)
+{
+    Std140PaddingHelper padHelper(mStd140StructElementIndexes);
+    const TFieldList &fields = structure.fields();
+
+    for (unsigned int i = 0; i < fields.size(); i++)
+    {
+        padHelper.prePadding(*fields[i]->type());
+    }
+
+    // Add remaining element index to the global map, for use with nested structs in standard layouts
+    const TString &structName = QualifiedStructNameString(structure, useHLSLRowMajorPacking, true);
+    mStd140StructElementIndexes[structName] = padHelper.elementIndex();
+}
+
+}
\ No newline at end of file
diff --git a/src/compiler/translator/StructureHLSL.h b/src/compiler/translator/StructureHLSL.h
new file mode 100644
index 0000000..63fbaaa
--- /dev/null
+++ b/src/compiler/translator/StructureHLSL.h
@@ -0,0 +1,74 @@
+//
+// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// StructureHLSL.h:
+//   Interfaces of methods for HLSL translation of GLSL structures.
+//
+
+#ifndef TRANSLATOR_STRUCTUREHLSL_H_
+#define TRANSLATOR_STRUCTUREHLSL_H_
+
+#include "compiler/translator/Common.h"
+#include "compiler/translator/intermediate.h"
+
+#include <set>
+
+class TInfoSinkBase;
+class TScopeBracket;
+
+namespace sh
+{
+
+// This helper class assists structure and interface block definitions in determining
+// how to pack std140 structs within HLSL's packing rules.
+class Std140PaddingHelper
+{
+  public:
+    explicit Std140PaddingHelper(const std::map<TString, int> &structElementIndexes);
+
+    int elementIndex() const { return mElementIndex; }
+    int prePadding(const TType &type);
+    TString prePaddingString(const TType &type);
+    TString postPaddingString(const TType &type, bool useHLSLRowMajorPacking);
+
+  private:
+    int mPaddingCounter;
+    int mElementIndex;
+    const std::map<TString, int> &mStructElementIndexes;
+};
+
+class StructureHLSL
+{
+  public:
+    StructureHLSL();
+
+    void addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters);
+    std::string structsHeader() const;
+
+    TString defineQualified(const TStructure &structure, bool useHLSLRowMajorPacking, bool useStd140Packing);
+    static TString defineNameless(const TStructure &structure);
+
+    Std140PaddingHelper getPaddingHelper() const { return Std140PaddingHelper(mStd140StructElementIndexes); }
+
+  private:
+    std::map<TString, int> mStd140StructElementIndexes;
+
+    typedef std::set<TString> StructNames;
+    StructNames mStructNames;
+
+    typedef std::set<TString> Constructors;
+    Constructors mConstructors;
+
+    typedef std::vector<TString> StructDeclarations;
+    StructDeclarations mStructDeclarations;
+
+    void storeStd140ElementIndex(const TStructure &structure, bool useHLSLRowMajorPacking);
+    static TString define(const TStructure &structure, bool useHLSLRowMajorPacking,
+                         bool useStd140Packing, Std140PaddingHelper *padHelper);
+};
+
+}
+
+#endif // COMPILER_STRUCTUREHLSL_H_
diff --git a/src/compiler/translator/UtilsHLSL.cpp b/src/compiler/translator/UtilsHLSL.cpp
index fa9b494..dbe35a5 100644
--- a/src/compiler/translator/UtilsHLSL.cpp
+++ b/src/compiler/translator/UtilsHLSL.cpp
@@ -8,7 +8,7 @@
 //
 
 #include "compiler/translator/UtilsHLSL.h"
-#include "compiler/translator/OutputHLSL.h"
+#include "compiler/translator/StructureHLSL.h"
 #include "compiler/translator/SymbolTable.h"
 
 namespace sh
@@ -99,7 +99,7 @@
         }
         else   // Nameless structure, define in place
         {
-            return OutputHLSL::defineNamelessStruct(*structure);
+            return StructureHLSL::defineNameless(*structure);
         }
     }
     else if (type.isMatrix())
@@ -175,7 +175,7 @@
         return "";
     }
 
-    return "ss_" + str(structure.uniqueId()) + structure.name();
+    return "ss" + str(structure.uniqueId()) + "_" + structure.name();
 }
 
 TString QualifiedStructNameString(const TStructure &structure, bool useHLSLRowMajorPacking,
@@ -193,13 +193,12 @@
 
     if (useStd140Packing)
     {
-        prefix += "std";
+        prefix += "std_";
     }
 
     if (useHLSLRowMajorPacking)
     {
-        if (prefix != "") prefix += "_";
-        prefix += "rm";
+        prefix += "rm_";
     }
 
     return prefix + StructNameString(structure);