HLSL: Flatten vertex input and fragment output structures.
authorJohn Kessenich <cepheus@frii.com>
Fri, 9 Sep 2016 22:32:09 +0000 (16:32 -0600)
committerJohn Kessenich <cepheus@frii.com>
Sat, 10 Sep 2016 17:09:24 +0000 (11:09 -0600)
Vulkan can't handle structures into the vertex stage or out
of the fragment stage.

Test/baseResults/hlsl.entry-out.frag.out
Test/baseResults/hlsl.structin.vert.out [new file with mode: 0755]
Test/hlsl.structin.vert [new file with mode: 0644]
glslang/Include/revision.h
gtests/Hlsl.FromFile.cpp
hlsl/hlslParseHelper.cpp
hlsl/hlslParseHelper.h

index b76d452..015136e 100755 (executable)
@@ -5,32 +5,26 @@ gl_FragCoord origin is upper left
 0:7  Function Definition: PixelShaderFunction(vf4;vf4;struct-OutParam-vf2-vi21; (global 4-component vector of float)
 0:7    Function Parameters: 
 0:7      'input' (layout(location=0 ) in 4-component vector of float)
-0:7      'out1' (out 4-component vector of float)
-0:7      'out2' (out structure{temp 2-component vector of float v, temp 2-component vector of int i})
+0:7      'out1' (layout(location=1 ) out 4-component vector of float)
+0:7      'out2' (layout(location=2 ) out structure{temp 2-component vector of float v, temp 2-component vector of int i})
 0:?     Sequence
 0:8      move second child to first child (temp 4-component vector of float)
-0:8        'out1' (out 4-component vector of float)
+0:8        'out1' (layout(location=1 ) out 4-component vector of float)
 0:8        'input' (layout(location=0 ) in 4-component vector of float)
 0:9      move second child to first child (temp 2-component vector of float)
-0:9        v: direct index for structure (temp 2-component vector of float)
-0:9          'out2' (out structure{temp 2-component vector of float v, temp 2-component vector of int i})
-0:9          Constant:
-0:9            0 (const int)
+0:?         'v' (layout(location=2 ) out 2-component vector of float)
 0:9        Constant:
 0:9          2.000000
 0:9          2.000000
 0:10      move second child to first child (temp 2-component vector of int)
-0:10        i: direct index for structure (temp 2-component vector of int)
-0:10          'out2' (out structure{temp 2-component vector of float v, temp 2-component vector of int i})
-0:10          Constant:
-0:10            1 (const int)
+0:?         'i' (layout(location=3 ) out 2-component vector of int)
 0:10        Constant:
 0:10          3 (const int)
 0:10          3 (const int)
 0:11      Sequence
 0:11        move second child to first child (temp 4-component vector of float)
 0:?           '@entryPointOutput' (layout(location=0 ) out 4-component vector of float)
-0:11          'out1' (out 4-component vector of float)
+0:11          'out1' (layout(location=1 ) out 4-component vector of float)
 0:11        Branch: Return
 0:?   Linker Objects
 
@@ -44,54 +38,49 @@ gl_FragCoord origin is upper left
 0:7  Function Definition: PixelShaderFunction(vf4;vf4;struct-OutParam-vf2-vi21; (global 4-component vector of float)
 0:7    Function Parameters: 
 0:7      'input' (layout(location=0 ) in 4-component vector of float)
-0:7      'out1' (out 4-component vector of float)
-0:7      'out2' (out structure{temp 2-component vector of float v, temp 2-component vector of int i})
+0:7      'out1' (layout(location=1 ) out 4-component vector of float)
+0:7      'out2' (layout(location=2 ) out structure{temp 2-component vector of float v, temp 2-component vector of int i})
 0:?     Sequence
 0:8      move second child to first child (temp 4-component vector of float)
-0:8        'out1' (out 4-component vector of float)
+0:8        'out1' (layout(location=1 ) out 4-component vector of float)
 0:8        'input' (layout(location=0 ) in 4-component vector of float)
 0:9      move second child to first child (temp 2-component vector of float)
-0:9        v: direct index for structure (temp 2-component vector of float)
-0:9          'out2' (out structure{temp 2-component vector of float v, temp 2-component vector of int i})
-0:9          Constant:
-0:9            0 (const int)
+0:?         'v' (layout(location=2 ) out 2-component vector of float)
 0:9        Constant:
 0:9          2.000000
 0:9          2.000000
 0:10      move second child to first child (temp 2-component vector of int)
-0:10        i: direct index for structure (temp 2-component vector of int)
-0:10          'out2' (out structure{temp 2-component vector of float v, temp 2-component vector of int i})
-0:10          Constant:
-0:10            1 (const int)
+0:?         'i' (layout(location=3 ) out 2-component vector of int)
 0:10        Constant:
 0:10          3 (const int)
 0:10          3 (const int)
 0:11      Sequence
 0:11        move second child to first child (temp 4-component vector of float)
 0:?           '@entryPointOutput' (layout(location=0 ) out 4-component vector of float)
-0:11          'out1' (out 4-component vector of float)
+0:11          'out1' (layout(location=1 ) out 4-component vector of float)
 0:11        Branch: Return
 0:?   Linker Objects
 
 // Module Version 10000
 // Generated by (magic number): 80001
-// Id's are bound by 32
+// Id's are bound by 27
 
                               Capability Shader
                1:             ExtInstImport  "GLSL.std.450"
                               MemoryModel Logical GLSL450
-                              EntryPoint Fragment 4  "PixelShaderFunction" 9 11 18 29
+                              EntryPoint Fragment 4  "PixelShaderFunction" 9 11 15 21 24
                               ExecutionMode 4 OriginUpperLeft
                               Name 4  "PixelShaderFunction"
                               Name 9  "out1"
                               Name 11  "input"
-                              Name 16  "OutParam"
-                              MemberName 16(OutParam) 0  "v"
-                              MemberName 16(OutParam) 1  "i"
-                              Name 18  "out2"
-                              Name 29  "@entryPointOutput"
+                              Name 15  "v"
+                              Name 21  "i"
+                              Name 24  "@entryPointOutput"
+                              Decorate 9(out1) Location 1
                               Decorate 11(input) Location 0
-                              Decorate 29(@entryPointOutput) Location 0
+                              Decorate 15(v) Location 2
+                              Decorate 21(i) Location 3
+                              Decorate 24(@entryPointOutput) Location 0
                2:             TypeVoid
                3:             TypeFunction 2
                6:             TypeFloat 32
@@ -101,29 +90,24 @@ gl_FragCoord origin is upper left
               10:             TypePointer Input 7(fvec4)
        11(input):     10(ptr) Variable Input
               13:             TypeVector 6(float) 2
-              14:             TypeInt 32 1
-              15:             TypeVector 14(int) 2
-    16(OutParam):             TypeStruct 13(fvec2) 15(ivec2)
-              17:             TypePointer Output 16(OutParam)
-        18(out2):     17(ptr) Variable Output
-              19:     14(int) Constant 0
-              20:    6(float) Constant 1073741824
-              21:   13(fvec2) ConstantComposite 20 20
-              22:             TypePointer Output 13(fvec2)
-              24:     14(int) Constant 1
-              25:     14(int) Constant 3
-              26:   15(ivec2) ConstantComposite 25 25
-              27:             TypePointer Output 15(ivec2)
-29(@entryPointOutput):      8(ptr) Variable Output
+              14:             TypePointer Output 13(fvec2)
+           15(v):     14(ptr) Variable Output
+              16:    6(float) Constant 1073741824
+              17:   13(fvec2) ConstantComposite 16 16
+              18:             TypeInt 32 1
+              19:             TypeVector 18(int) 2
+              20:             TypePointer Output 19(ivec2)
+           21(i):     20(ptr) Variable Output
+              22:     18(int) Constant 3
+              23:   19(ivec2) ConstantComposite 22 22
+24(@entryPointOutput):      8(ptr) Variable Output
 4(PixelShaderFunction):           2 Function None 3
                5:             Label
               12:    7(fvec4) Load 11(input)
                               Store 9(out1) 12
-              23:     22(ptr) AccessChain 18(out2) 19
-                              Store 23 21
-              28:     27(ptr) AccessChain 18(out2) 24
-                              Store 28 26
-              30:    7(fvec4) Load 9(out1)
-                              Store 29(@entryPointOutput) 30
+                              Store 15(v) 17
+                              Store 21(i) 23
+              25:    7(fvec4) Load 9(out1)
+                              Store 24(@entryPointOutput) 25
                               Return
                               FunctionEnd
diff --git a/Test/baseResults/hlsl.structin.vert.out b/Test/baseResults/hlsl.structin.vert.out
new file mode 100755 (executable)
index 0000000..c68ba83
--- /dev/null
@@ -0,0 +1,133 @@
+hlsl.structin.vert
+Shader version: 450
+0:? Sequence
+0:7  Function Definition: main(vf4;struct-VI-vf4[2]-vu21;vf4; (global 4-component vector of float Position)
+0:7    Function Parameters: 
+0:7      'd' (layout(location=0 ) in 4-component vector of float)
+0:7      'vi' (layout(location=1 ) in structure{temp 2-element array of 4-component vector of float m, temp 2-component vector of uint coord})
+0:7      'e' (layout(location=4 ) in 4-component vector of float)
+0:?     Sequence
+0:8      Sequence
+0:8        move second child to first child (temp 4-component vector of float)
+0:?           '@entryPointOutput' (out 4-component vector of float Position)
+0:8          add (temp 4-component vector of float)
+0:8            add (temp 4-component vector of float)
+0:8              add (temp 4-component vector of float)
+0:8                add (temp 4-component vector of float)
+0:8                  direct index (layout(location=1 ) temp 4-component vector of float)
+0:?                     'm' (layout(location=1 ) in 2-element array of 4-component vector of float)
+0:8                    Constant:
+0:8                      1 (const int)
+0:8                  direct index (layout(location=1 ) temp 4-component vector of float)
+0:?                     'm' (layout(location=1 ) in 2-element array of 4-component vector of float)
+0:8                    Constant:
+0:8                      0 (const int)
+0:8                Construct vec4 (temp 4-component vector of float)
+0:8                  Convert uint to float (temp float)
+0:8                    direct index (temp uint)
+0:?                       'coord' (layout(location=3 ) in 2-component vector of uint)
+0:8                      Constant:
+0:8                        0 (const int)
+0:8              'd' (layout(location=0 ) in 4-component vector of float)
+0:8            'e' (layout(location=4 ) in 4-component vector of float)
+0:8        Branch: Return
+0:?   Linker Objects
+
+
+Linked vertex stage:
+
+
+Shader version: 450
+0:? Sequence
+0:7  Function Definition: main(vf4;struct-VI-vf4[2]-vu21;vf4; (global 4-component vector of float Position)
+0:7    Function Parameters: 
+0:7      'd' (layout(location=0 ) in 4-component vector of float)
+0:7      'vi' (layout(location=1 ) in structure{temp 2-element array of 4-component vector of float m, temp 2-component vector of uint coord})
+0:7      'e' (layout(location=4 ) in 4-component vector of float)
+0:?     Sequence
+0:8      Sequence
+0:8        move second child to first child (temp 4-component vector of float)
+0:?           '@entryPointOutput' (out 4-component vector of float Position)
+0:8          add (temp 4-component vector of float)
+0:8            add (temp 4-component vector of float)
+0:8              add (temp 4-component vector of float)
+0:8                add (temp 4-component vector of float)
+0:8                  direct index (layout(location=1 ) temp 4-component vector of float)
+0:?                     'm' (layout(location=1 ) in 2-element array of 4-component vector of float)
+0:8                    Constant:
+0:8                      1 (const int)
+0:8                  direct index (layout(location=1 ) temp 4-component vector of float)
+0:?                     'm' (layout(location=1 ) in 2-element array of 4-component vector of float)
+0:8                    Constant:
+0:8                      0 (const int)
+0:8                Construct vec4 (temp 4-component vector of float)
+0:8                  Convert uint to float (temp float)
+0:8                    direct index (temp uint)
+0:?                       'coord' (layout(location=3 ) in 2-component vector of uint)
+0:8                      Constant:
+0:8                        0 (const int)
+0:8              'd' (layout(location=0 ) in 4-component vector of float)
+0:8            'e' (layout(location=4 ) in 4-component vector of float)
+0:8        Branch: Return
+0:?   Linker Objects
+
+// Module Version 10000
+// Generated by (magic number): 80001
+// Id's are bound by 41
+
+                              Capability Shader
+               1:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint Vertex 4  "main" 9 14 26 34 37
+                              Name 4  "main"
+                              Name 9  "@entryPointOutput"
+                              Name 14  "m"
+                              Name 26  "coord"
+                              Name 34  "d"
+                              Name 37  "e"
+                              Decorate 9(@entryPointOutput) BuiltIn Position
+                              Decorate 14(m) Location 1
+                              Decorate 26(coord) Location 3
+                              Decorate 34(d) Location 0
+                              Decorate 37(e) Location 4
+               2:             TypeVoid
+               3:             TypeFunction 2
+               6:             TypeFloat 32
+               7:             TypeVector 6(float) 4
+               8:             TypePointer Output 7(fvec4)
+9(@entryPointOutput):      8(ptr) Variable Output
+              10:             TypeInt 32 0
+              11:     10(int) Constant 2
+              12:             TypeArray 7(fvec4) 11
+              13:             TypePointer Input 12
+           14(m):     13(ptr) Variable Input
+              15:             TypeInt 32 1
+              16:     15(int) Constant 1
+              17:             TypePointer Input 7(fvec4)
+              20:     15(int) Constant 0
+              24:             TypeVector 10(int) 2
+              25:             TypePointer Input 24(ivec2)
+       26(coord):     25(ptr) Variable Input
+              27:     10(int) Constant 0
+              28:             TypePointer Input 10(int)
+           34(d):     17(ptr) Variable Input
+           37(e):     17(ptr) Variable Input
+         4(main):           2 Function None 3
+               5:             Label
+              18:     17(ptr) AccessChain 14(m) 16
+              19:    7(fvec4) Load 18
+              21:     17(ptr) AccessChain 14(m) 20
+              22:    7(fvec4) Load 21
+              23:    7(fvec4) FAdd 19 22
+              29:     28(ptr) AccessChain 26(coord) 27
+              30:     10(int) Load 29
+              31:    6(float) ConvertUToF 30
+              32:    7(fvec4) CompositeConstruct 31 31 31 31
+              33:    7(fvec4) FAdd 23 32
+              35:    7(fvec4) Load 34(d)
+              36:    7(fvec4) FAdd 33 35
+              38:    7(fvec4) Load 37(e)
+              39:    7(fvec4) FAdd 36 38
+                              Store 9(@entryPointOutput) 39
+                              Return
+                              FunctionEnd
diff --git a/Test/hlsl.structin.vert b/Test/hlsl.structin.vert
new file mode 100644 (file)
index 0000000..424624a
--- /dev/null
@@ -0,0 +1,9 @@
+struct VI {
+    float4 m[2];
+    uint2 coord;
+};
+
+float4 main(float4 d, VI vi, float4 e) : SV_POSITION
+{
+    return vi.m[1] + vi.m[0] + float4(vi.coord.x) + d + e;
+}
\ No newline at end of file
index 85fd262..41f9a70 100644 (file)
@@ -2,5 +2,5 @@
 // For the version, it uses the latest git tag followed by the number of commits.
 // For the date, it uses the current date (when then script is run).
 
-#define GLSLANG_REVISION "Overload400-PrecQual.1477"
-#define GLSLANG_DATE "09-Sep-2016"
+#define GLSLANG_REVISION "Overload400-PrecQual.1481"
+#define GLSLANG_DATE "10-Sep-2016"
index 5b42092..d4206af 100644 (file)
@@ -159,6 +159,7 @@ INSTANTIATE_TEST_CASE_P(
         {"hlsl.semicolons.frag", "main"},
         {"hlsl.shapeConv.frag", "main"},
         {"hlsl.stringtoken.frag", "main"},
+        {"hlsl.structin.vert", "main"},
         {"hlsl.intrinsics.vert", "VertexShaderFunction"},
         {"hlsl.matType.frag", "PixelShaderFunction"},
         {"hlsl.max.frag", "PixelShaderFunction"},
index ec2cc03..dbc2940 100755 (executable)
@@ -679,12 +679,16 @@ TIntermTyped* HlslParseContext::handleDotDereference(const TSourceLoc& loc, TInt
             }
         }
         if (fieldFound) {
-            if (base->getType().getQualifier().storage == EvqConst)
-                result = intermediate.foldDereference(base, member, loc);
+            if (base->getAsSymbolNode() && shouldFlatten(base->getType()))
+                result = flattenAccess(base, member);
             else {
-                TIntermTyped* index = intermediate.addConstantUnion(member, loc);
-                result = intermediate.addIndex(EOpIndexDirectStruct, base, index, loc);
-                result->setType(*(*fields)[member].type);
+                if (base->getType().getQualifier().storage == EvqConst)
+                    result = intermediate.foldDereference(base, member, loc);
+                else {
+                    TIntermTyped* index = intermediate.addConstantUnion(member, loc);
+                    result = intermediate.addIndex(EOpIndexDirectStruct, base, index, loc);
+                    result->setType(*(*fields)[member].type);
+                }
             }
         } else
             error(loc, "no such field in structure", field.c_str(), "");
@@ -694,6 +698,54 @@ TIntermTyped* HlslParseContext::handleDotDereference(const TSourceLoc& loc, TInt
     return result;
 }
 
+// Is this a structure that can't be passed down the stack?
+// E.g., pipeline inputs to the vertex stage and outputs from the fragment stage.
+bool HlslParseContext::shouldFlatten(const TType& type)
+{
+    const TStorageQualifier qualifier = type.getQualifier().storage;
+
+    return type.isStruct() &&
+           ((language == EShLangVertex   && qualifier == EvqVaryingIn) ||
+            (language == EShLangFragment && qualifier == EvqVaryingOut));
+}
+
+// Figure out mapping between a structures top members and an
+// equivalent set of individual variables.
+//
+// Assumes shouldFlatten() or equivalent was called first.
+//
+// TODO: generalize this to arbitrary nesting?
+void HlslParseContext::flattenStruct(const TVariable& variable)
+{
+    TVector<TVariable*> memberVariables;
+
+    auto members = *variable.getType().getStruct();
+    int location = variable.getType().getQualifier().layoutLocation;
+    for (int member = 0; member < (int)members.size(); ++member) {
+        TVariable* memberVariable = makeInternalVariable(members[member].type->getFieldName().c_str(), *members[member].type);
+        memberVariable->getWritableType().getQualifier() = variable.getType().getQualifier();
+        memberVariable->getWritableType().getQualifier().layoutLocation = location;
+        location += intermediate.computeTypeLocationSize(memberVariable->getType());
+        memberVariables.push_back(memberVariable);
+    }
+
+    flattenMap[variable.getUniqueId()] = memberVariables;
+}
+
+// Turn an access into structure that was flattened to instead be
+// an access to the individual variable the member was flattened to.
+// Assumes shouldFlatten() or equivalent was called first.
+TIntermTyped* HlslParseContext::flattenAccess(TIntermTyped* base, int member)
+{
+    const TIntermSymbol& symbolNode = *base->getAsSymbolNode();
+
+    if (flattenMap.find(symbolNode.getId()) == flattenMap.end())
+        return base;
+
+    const TVariable* memberVariable = flattenMap[symbolNode.getId()][member];
+    return intermediate.addSymbol(*memberVariable);
+}
+
 //
 // Handle seeing a function declarator in the grammar.  This is the precursor
 // to recognizing a function prototype or function definition.
@@ -800,6 +852,9 @@ TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& l
                 paramNodes = intermediate.growAggregate(paramNodes,
                     intermediate.addSymbol(*variable, loc),
                     loc);
+
+                if (shouldFlatten(*param.type))
+                    flattenStruct(*variable);
             }
         } else
             paramNodes = intermediate.growAggregate(paramNodes, intermediate.addSymbol(*param.type, loc), loc);
@@ -861,20 +916,21 @@ void HlslParseContext::remapEntrypointIO(TFunction& function)
 
     // parameters are actually shader-scoped inputs and outputs (in or out)
     for (int i = 0; i < function.getParamCount(); i++) {
-        if (function[i].type->getQualifier().isParamInput()) {
-            function[i].type->getQualifier().storage = EvqVaryingIn;
-            if (function[i].type->getQualifier().builtIn == EbvNone) {
-                function[i].type->getQualifier().layoutLocation = inCount;
+        TType& paramType = *function[i].type;
+        if (paramType.getQualifier().isParamInput()) {
+            paramType.getQualifier().storage = EvqVaryingIn;
+            if (paramType.getQualifier().builtIn == EbvNone) {
+                paramType.getQualifier().layoutLocation = inCount;
                 inCount += intermediate.computeTypeLocationSize(*function[i].type);
             }
         } else {
-            function[i].type->getQualifier().storage = EvqVaryingOut;
-            if (function[i].type->getQualifier().builtIn == EbvNone && language != EShLangFragment) {
-                function[i].type->getQualifier().layoutLocation = outCount;
+            paramType.getQualifier().storage = EvqVaryingOut;
+            if (paramType.getQualifier().builtIn == EbvNone) {
+                paramType.getQualifier().layoutLocation = outCount;
                 outCount += intermediate.computeTypeLocationSize(*function[i].type);
             }
         }
-        remapBuiltInType(*function[i].type);
+        remapBuiltInType(paramType);
     }
 }
 
index f422b3e..1e43dea 100755 (executable)
@@ -83,6 +83,9 @@ public:
     TIntermTyped* handleBinaryMath(const TSourceLoc&, const char* str, TOperator op, TIntermTyped* left, TIntermTyped* right);
     TIntermTyped* handleUnaryMath(const TSourceLoc&, const char* str, TOperator op, TIntermTyped* childNode);
     TIntermTyped* handleDotDereference(const TSourceLoc&, TIntermTyped* base, const TString& field);
+    bool shouldFlatten(const TType&);
+    void flattenStruct(const TVariable& variable);
+    TIntermTyped* flattenAccess(TIntermTyped* base, int member);
     TFunction& handleFunctionDeclarator(const TSourceLoc&, TFunction& function, bool prototype);
     TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&);
     void handleFunctionBody(const TSourceLoc&, TFunction&, TIntermNode* functionBody, TIntermNode*& node);
@@ -233,6 +236,8 @@ protected:
     //    array-sizing declarations
     //
     TVector<TSymbol*> ioArraySymbolResizeList;
+
+    TMap<int, TVector<TVariable*>> flattenMap;
 };
 
 } // end namespace glslang