Refactor code for generating structure strings to a separate function.

This could fix a potential regression, which might define structs multiple times in generated HLSL.

TRAC #23271

Signed-off-by: Nicolas Capens
Signed-off-by: Shannon Woods
Authored-by: Jamie Madill
diff --git a/src/compiler/OutputHLSL.cpp b/src/compiler/OutputHLSL.cpp
index 6aab921..9d2c5d7 100644
--- a/src/compiler/OutputHLSL.cpp
+++ b/src/compiler/OutputHLSL.cpp
@@ -218,11 +218,13 @@
 
     if (memberType.isMatrix())
     {
-        return " row_major " + typeString(memberType);
+        // Use HLSL row-major packing for GLSL column-major matrices
+        return "row_major " + typeString(memberType);
     }
     else if (memberType.getBasicType() == EbtStruct)
     {
-        return "rm" + typeString(memberType);
+        // Use HLSL row-major packing for GLSL column-major matrices
+        return structureTypeName(memberType, true);
     }
     else
     {
@@ -2920,21 +2922,7 @@
         }
         else   // Nameless structure, define in place
         {
-            const TTypeList &fields = *type.getStruct();
-
-            TString string = "struct\n"
-                             "{\n";
-
-            for (unsigned int i = 0; i < fields.size(); i++)
-            {
-                const TType &field = *fields[i].type;
-
-                string += "    " + typeString(field) + " " + decorate(field.getFieldName()) + arrayString(field) + ";\n";
-            }
-
-            string += "} ";
-
-            return string;
+            return structureString(type, false);
         }
     }
     else if (type.isMatrix())
@@ -3041,6 +3029,58 @@
     return "{" + string + "}";
 }
 
+TString OutputHLSL::structureString(const TType &structType, bool useHLSLRowMajorPacking)
+{
+    ASSERT(structType.getStruct());
+
+    const TTypeList &fields = *structType.getStruct();
+    const bool isNameless = (structType.getTypeName() == "");
+    const TString &structName = structureTypeName(structType, useHLSLRowMajorPacking);
+
+    const TString declareString = (isNameless ? "struct" : "struct " + structName);
+
+    TString structure;
+    structure += declareString + "\n"
+                 "{\n";
+
+    for (unsigned int i = 0; i < fields.size(); i++)
+    {
+        const TType &field = *fields[i].type;
+
+        structure += "    " + structureTypeName(field, useHLSLRowMajorPacking) + " " +
+                     decorateField(field.getFieldName(), structType) + arrayString(field) + ";\n";
+    }
+
+    // Nameless structs do not finish with a semicolon and newline, to leave room for an instance variable
+    structure += (isNameless ? "} " : "};\n");
+
+    return structure;
+}
+
+TString OutputHLSL::structureTypeName(const TType &structType, bool useHLSLRowMajorPacking)
+{
+    if (structType.getBasicType() != EbtStruct)
+    {
+        return typeString(structType);
+    }
+
+    if (structType.getTypeName() == "")
+    {
+        return "";
+    }
+
+    TString prefix = "";
+
+    // 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 (useHLSLRowMajorPacking)
+    {
+        prefix += "rm";
+    }
+
+    return prefix + typeString(structType);
+}
+
 void OutputHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters)
 {
     if (name == "")
@@ -3067,32 +3107,20 @@
     {
         mStructNames.insert(decorate(name));
 
-        TString structure;
-        structure += "{\n";
-
-        const TTypeList &fields = *type.getStruct();
-
-        for (unsigned int i = 0; i < fields.size(); i++)
-        {
-            const TType &field = *fields[i].type;
-
-            structure += "    " + typeString(field) + " " + decorateField(field.getFieldName(), type) + arrayString(field) + ";\n";
-        }
-
-        structure += "};\n";
+        const TString &structure = structureString(type, false);
 
         if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structure) == mStructDeclarations.end())
         {
-            TString columnMajorString = "struct " + decorate(name) + "\n" + structure;
-            TString rowMajorString = "#pragma pack_matrix(row_major)\n"
-                                     "struct rm" + decorate(name) + "\n" +
-                                     structure +
+            // Add row-major packed struct for interface blocks
+            TString rowMajorString = "#pragma pack_matrix(row_major)\n" +
+                                     structureString(type, true) +
                                      "#pragma pack_matrix(column_major)\n";
 
-            mStructDeclarations.push_back(columnMajorString);
+            mStructDeclarations.push_back(structure);
             mStructDeclarations.push_back(rowMajorString);
         }
 
+        const TTypeList &fields = *type.getStruct();
         for (unsigned int i = 0; i < fields.size(); i++)
         {
             ctorParameters.push_back(*fields[i].type);