Add support for structs in uniform blocks with standard layout.

TRAC #23327

Signed-off-by: Geoff Lang
Signed-off-by: Shannon Woods
Authored-by: Jamie Madill
diff --git a/src/compiler/OutputHLSL.cpp b/src/compiler/OutputHLSL.cpp
index 22a4e4f..4737400 100644
--- a/src/compiler/OutputHLSL.cpp
+++ b/src/compiler/OutputHLSL.cpp
@@ -253,7 +253,7 @@
     }
 }
 
-TString OutputHLSL::interfaceBlockMemberTypeString(const TType &memberType)
+TString OutputHLSL::interfaceBlockMemberTypeString(const TType &memberType, TLayoutBlockStorage blockStorage)
 {
     const TLayoutMatrixPacking matrixPacking = memberType.getLayoutQualifier().matrixPacking;
     ASSERT(matrixPacking != EmpUnspecified);
@@ -267,7 +267,7 @@
     else if (memberType.getBasicType() == EbtStruct)
     {
         // Use HLSL row-major packing for GLSL column-major matrices
-        return structureTypeName(memberType, matrixPacking == EmpColumnMajor);
+        return structureTypeName(memberType, matrixPacking == EmpColumnMajor, blockStorage == EbsStd140);
     }
     else
     {
@@ -325,21 +325,26 @@
 
 TString OutputHLSL::std140PostPaddingString(const TType &type)
 {
-    if (!type.isMatrix() && !type.isArray())
+    if (!type.isMatrix() && !type.isArray() && type.getBasicType() != EbtStruct)
     {
         return "";
     }
 
-    const GLenum glType = glVariableType(type);
     int numComponents = 0;
 
     if (type.isMatrix())
     {
         const bool isRowMajorMatrix = (type.getLayoutQualifier().matrixPacking == EmpRowMajor);
+        const GLenum glType = glVariableType(type);
         numComponents = gl::MatrixComponentCount(glType, isRowMajorMatrix);
     }
+    else if (type.getBasicType() == EbtStruct)
+    {
+        // TODO
+    }
     else
     {
+        const GLenum glType = glVariableType(type);
         numComponents = gl::UniformComponentCount(glType);
     }
 
@@ -363,18 +368,11 @@
 
         if (blockStorage == EbsStd140)
         {
-            if (memberType.getBasicType() == EbtStruct)
-            {
-                UNIMPLEMENTED();
-            }
-            else
-            {
-                // 2 and 3 component vector types in some cases need pre-padding
-                hlsl += std140PrePaddingString(memberType, &elementIndex);
-            }
+            // 2 and 3 component vector types in some cases need pre-padding
+            hlsl += std140PrePaddingString(memberType, &elementIndex);
         }
 
-        hlsl += "    " + interfaceBlockMemberTypeString(memberType) +
+        hlsl += "    " + interfaceBlockMemberTypeString(memberType, blockStorage) +
                 " " + decorate(memberType.getFieldName()) + arrayString(memberType) + ";\n";
 
         // must pad out after matrices and arrays, where HLSL usually allows itself room to pack stuff
@@ -2782,7 +2780,7 @@
         }
         else   // Nameless structure, define in place
         {
-            return structureString(type, false);
+            return structureString(type, false, false);
         }
     }
     else if (type.isMatrix())
@@ -2900,13 +2898,13 @@
     return "{" + string + "}";
 }
 
-TString OutputHLSL::structureString(const TType &structType, bool useHLSLRowMajorPacking)
+TString OutputHLSL::structureString(const TType &structType, bool useHLSLRowMajorPacking, bool useStd140Packing)
 {
     ASSERT(structType.getStruct());
 
     const TTypeList &fields = *structType.getStruct();
     const bool isNameless = (structType.getTypeName() == "");
-    const TString &structName = structureTypeName(structType, useHLSLRowMajorPacking);
+    const TString &structName = structureTypeName(structType, useHLSLRowMajorPacking, useStd140Packing);
 
     const TString declareString = (isNameless ? "struct" : "struct " + structName);
 
@@ -2914,12 +2912,24 @@
     structure += declareString + "\n"
                  "{\n";
 
+    int elementIndex = 0;
+
     for (unsigned int i = 0; i < fields.size(); i++)
     {
         const TType &field = *fields[i].type;
 
-        structure += "    " + structureTypeName(field, useHLSLRowMajorPacking) + " " +
+        if (useStd140Packing)
+        {
+            structure += std140PrePaddingString(field, &elementIndex);
+        }
+
+        structure += "    " + structureTypeName(field, useHLSLRowMajorPacking, useStd140Packing) + " " +
                      decorateField(field.getFieldName(), structType) + arrayString(field) + ";\n";
+
+        if (useStd140Packing)
+        {
+            structure += std140PostPaddingString(field);
+        }
     }
 
     // Nameless structs do not finish with a semicolon and newline, to leave room for an instance variable
@@ -2928,7 +2938,7 @@
     return structure;
 }
 
-TString OutputHLSL::structureTypeName(const TType &structType, bool useHLSLRowMajorPacking)
+TString OutputHLSL::structureTypeName(const TType &structType, bool useHLSLRowMajorPacking, bool useStd140Packing)
 {
     if (structType.getBasicType() != EbtStruct)
     {
@@ -2944,8 +2954,15 @@
 
     // Structs packed with row-major matrices in HLSL are prefixed with "rm"
     // GLSL column-major maps to HLSL row-major, and the converse is true
+
+    if (useStd140Packing)
+    {
+        prefix += "std";
+    }
+
     if (useHLSLRowMajorPacking)
     {
+        if (prefix != "") prefix += "_";
         prefix += "rm";
     }
 
@@ -2978,17 +2995,27 @@
     {
         mStructNames.insert(decorate(name));
 
-        const TString &structure = structureString(type, false);
+        const TString &structure = structureString(type, false, false);
 
         if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structure) == mStructDeclarations.end())
         {
             // Add row-major packed struct for interface blocks
             TString rowMajorString = "#pragma pack_matrix(row_major)\n" +
-                                     structureString(type, true) +
+                                     structureString(type, true, false) +
                                      "#pragma pack_matrix(column_major)\n";
 
+            const TString &std140Prefix = "std";
+            TString std140String = structureString(type, false, true);
+
+            const TString &std140RowMajorPrefix = "std_rm";
+            TString std140RowMajorString = "#pragma pack_matrix(row_major)\n" +
+                                           structureString(type, true, true) +
+                                           "#pragma pack_matrix(column_major)\n";
+
             mStructDeclarations.push_back(structure);
             mStructDeclarations.push_back(rowMajorString);
+            mStructDeclarations.push_back(std140String);
+            mStructDeclarations.push_back(std140RowMajorString);
         }
 
         const TTypeList &fields = *type.getStruct();
diff --git a/src/compiler/OutputHLSL.h b/src/compiler/OutputHLSL.h
index fd32811..baa4675 100644
--- a/src/compiler/OutputHLSL.h
+++ b/src/compiler/OutputHLSL.h
@@ -40,8 +40,8 @@
     TString typeString(const TType &type);
     TString textureString(const TType &type);
     TString interpolationString(TQualifier qualifier);
-    TString structureString(const TType &structType, bool useHLSLRowMajorPacking);
-    TString structureTypeName(const TType &structType, bool useHLSLRowMajorPacking);
+    TString structureString(const TType &structType, bool useHLSLRowMajorPacking, bool useStd140Packing);
+    TString structureTypeName(const TType &structType, bool useHLSLRowMajorPacking, bool useStd140Packing);
     static TString qualifierString(TQualifier qualifier);
     static TString arrayString(const TType &type);
     static TString initializer(const TType &type);
@@ -193,7 +193,7 @@
     TString decoratePrivate(const TString &privateText);
     TString interfaceBlockStructName(const TType &interfaceBlockType);
     TString interfaceBlockInstanceString(const TType& interfaceBlockType, unsigned int arrayIndex);
-    TString interfaceBlockMemberTypeString(const TType &memberType);
+    TString interfaceBlockMemberTypeString(const TType &memberType, TLayoutBlockStorage blockStorage);
     TString interfaceBlockMemberString(const TTypeList &typeList, TLayoutBlockStorage blockStorage);
     TString interfaceBlockStructString(const TType &interfaceBlockType);
     TString interfaceBlockString(const TType &interfaceBlockType, unsigned int registerIndex, unsigned int arrayIndex);