Merge pull request #1379 from LoopDawg/groupid-fix
HLSL: various SPIR-V compute shader IDs must be 3-vectors of integers
diff --git a/Test/baseResults/hlsl.tristream-append.geom.out b/Test/baseResults/hlsl.tristream-append.geom.out
new file mode 100644
index 0000000..2444cfb
--- /dev/null
+++ b/Test/baseResults/hlsl.tristream-append.geom.out
@@ -0,0 +1,212 @@
+hlsl.tristream-append.geom
+Shader version: 500
+invocations = -1
+max_vertices = 3
+input primitive = triangles
+output primitive = triangle_strip
+0:? Sequence
+0:8 Function Definition: EmitVertex(struct-GSPS_INPUT1;struct-GSPS_INPUT1; ( temp void)
+0:8 Function Parameters:
+0:8 'output' ( in structure{})
+0:8 'TriStream' ( out structure{})
+0:? Sequence
+0:9 Sequence
+0:9 Sequence
+0:9 move second child to first child ( temp structure{})
+0:9 'TriStream' ( out structure{})
+0:9 'output' ( in structure{})
+0:9 EmitVertex ( temp void)
+0:14 Function Definition: @main(struct-GSPS_INPUT1[3];struct-GSPS_INPUT1; ( temp void)
+0:14 Function Parameters:
+0:14 'input' ( in 3-element array of structure{})
+0:14 'TriStream' ( out structure{})
+0:? Sequence
+0:15 Function Call: EmitVertex(struct-GSPS_INPUT1;struct-GSPS_INPUT1; ( temp void)
+0:15 direct index ( temp structure{})
+0:15 'input' ( in 3-element array of structure{})
+0:15 Constant:
+0:15 0 (const int)
+0:15 'TriStream' ( out structure{})
+0:16 Function Call: EmitVertex(struct-GSPS_INPUT1;struct-GSPS_INPUT1; ( temp void)
+0:16 direct index ( temp structure{})
+0:16 'input' ( in 3-element array of structure{})
+0:16 Constant:
+0:16 1 (const int)
+0:16 'TriStream' ( out structure{})
+0:17 Function Call: EmitVertex(struct-GSPS_INPUT1;struct-GSPS_INPUT1; ( temp void)
+0:17 direct index ( temp structure{})
+0:17 'input' ( in 3-element array of structure{})
+0:17 Constant:
+0:17 2 (const int)
+0:17 'TriStream' ( out structure{})
+0:14 Function Definition: main( ( temp void)
+0:14 Function Parameters:
+0:? Sequence
+0:14 move second child to first child ( temp 3-element array of structure{})
+0:? 'input' ( temp 3-element array of structure{})
+0:? 'input' ( in 3-element array of structure{})
+0:14 Function Call: @main(struct-GSPS_INPUT1[3];struct-GSPS_INPUT1; ( temp void)
+0:? 'input' ( temp 3-element array of structure{})
+0:? 'TriStream' ( temp structure{})
+0:? Linker Objects
+
+
+Linked geometry stage:
+
+
+Shader version: 500
+invocations = 1
+max_vertices = 3
+input primitive = triangles
+output primitive = triangle_strip
+0:? Sequence
+0:8 Function Definition: EmitVertex(struct-GSPS_INPUT1;struct-GSPS_INPUT1; ( temp void)
+0:8 Function Parameters:
+0:8 'output' ( in structure{})
+0:8 'TriStream' ( out structure{})
+0:? Sequence
+0:9 Sequence
+0:9 Sequence
+0:9 move second child to first child ( temp structure{})
+0:9 'TriStream' ( out structure{})
+0:9 'output' ( in structure{})
+0:9 EmitVertex ( temp void)
+0:14 Function Definition: @main(struct-GSPS_INPUT1[3];struct-GSPS_INPUT1; ( temp void)
+0:14 Function Parameters:
+0:14 'input' ( in 3-element array of structure{})
+0:14 'TriStream' ( out structure{})
+0:? Sequence
+0:15 Function Call: EmitVertex(struct-GSPS_INPUT1;struct-GSPS_INPUT1; ( temp void)
+0:15 direct index ( temp structure{})
+0:15 'input' ( in 3-element array of structure{})
+0:15 Constant:
+0:15 0 (const int)
+0:15 'TriStream' ( out structure{})
+0:16 Function Call: EmitVertex(struct-GSPS_INPUT1;struct-GSPS_INPUT1; ( temp void)
+0:16 direct index ( temp structure{})
+0:16 'input' ( in 3-element array of structure{})
+0:16 Constant:
+0:16 1 (const int)
+0:16 'TriStream' ( out structure{})
+0:17 Function Call: EmitVertex(struct-GSPS_INPUT1;struct-GSPS_INPUT1; ( temp void)
+0:17 direct index ( temp structure{})
+0:17 'input' ( in 3-element array of structure{})
+0:17 Constant:
+0:17 2 (const int)
+0:17 'TriStream' ( out structure{})
+0:14 Function Definition: main( ( temp void)
+0:14 Function Parameters:
+0:? Sequence
+0:14 move second child to first child ( temp 3-element array of structure{})
+0:? 'input' ( temp 3-element array of structure{})
+0:? 'input' ( in 3-element array of structure{})
+0:14 Function Call: @main(struct-GSPS_INPUT1[3];struct-GSPS_INPUT1; ( temp void)
+0:? 'input' ( temp 3-element array of structure{})
+0:? 'TriStream' ( temp structure{})
+0:? Linker Objects
+
+// Module Version 10000
+// Generated by (magic number): 80006
+// Id's are bound by 57
+
+ Capability Geometry
+ 1: ExtInstImport "GLSL.std.450"
+ MemoryModel Logical GLSL450
+ EntryPoint Geometry 4 "main"
+ ExecutionMode 4 Triangles
+ ExecutionMode 4 Invocations 1
+ ExecutionMode 4 OutputTriangleStrip
+ ExecutionMode 4 OutputVertices 3
+ Source HLSL 500
+ Name 4 "main"
+ Name 6 "GSPS_INPUT"
+ Name 11 "EmitVertex(struct-GSPS_INPUT1;struct-GSPS_INPUT1;"
+ Name 9 "output"
+ Name 10 "TriStream"
+ Name 20 "@main(struct-GSPS_INPUT1[3];struct-GSPS_INPUT1;"
+ Name 18 "input"
+ Name 19 "TriStream"
+ Name 23 "TriStream"
+ Name 27 "param"
+ Name 30 "param"
+ Name 34 "param"
+ Name 37 "param"
+ Name 41 "param"
+ Name 44 "param"
+ Name 47 "input"
+ Name 49 "input"
+ Name 51 "TriStream"
+ Name 52 "param"
+ Name 54 "param"
+ 2: TypeVoid
+ 3: TypeFunction 2
+ 6(GSPS_INPUT): TypeStruct
+ 7: TypePointer Function 6(GSPS_INPUT)
+ 8: TypeFunction 2 7(ptr) 7(ptr)
+ 13: TypeInt 32 0
+ 14: 13(int) Constant 3
+ 15: TypeArray 6(GSPS_INPUT) 14
+ 16: TypePointer Function 15
+ 17: TypeFunction 2 16(ptr) 7(ptr)
+ 22: TypePointer Output 6(GSPS_INPUT)
+ 23(TriStream): 22(ptr) Variable Output
+ 25: TypeInt 32 1
+ 26: 25(int) Constant 0
+ 33: 25(int) Constant 1
+ 40: 25(int) Constant 2
+ 48: TypePointer Input 15
+ 49(input): 48(ptr) Variable Input
+ 4(main): 2 Function None 3
+ 5: Label
+ 47(input): 16(ptr) Variable Function
+ 51(TriStream): 7(ptr) Variable Function
+ 52(param): 16(ptr) Variable Function
+ 54(param): 7(ptr) Variable Function
+ 50: 15 Load 49(input)
+ Store 47(input) 50
+ 53: 15 Load 47(input)
+ Store 52(param) 53
+ 55: 2 FunctionCall 20(@main(struct-GSPS_INPUT1[3];struct-GSPS_INPUT1;) 52(param) 54(param)
+ 56:6(GSPS_INPUT) Load 54(param)
+ Store 51(TriStream) 56
+ Return
+ FunctionEnd
+11(EmitVertex(struct-GSPS_INPUT1;struct-GSPS_INPUT1;): 2 Function None 8
+ 9(output): 7(ptr) FunctionParameter
+ 10(TriStream): 7(ptr) FunctionParameter
+ 12: Label
+ 24:6(GSPS_INPUT) Load 9(output)
+ Store 23(TriStream) 24
+ EmitVertex
+ Return
+ FunctionEnd
+20(@main(struct-GSPS_INPUT1[3];struct-GSPS_INPUT1;): 2 Function None 17
+ 18(input): 16(ptr) FunctionParameter
+ 19(TriStream): 7(ptr) FunctionParameter
+ 21: Label
+ 27(param): 7(ptr) Variable Function
+ 30(param): 7(ptr) Variable Function
+ 34(param): 7(ptr) Variable Function
+ 37(param): 7(ptr) Variable Function
+ 41(param): 7(ptr) Variable Function
+ 44(param): 7(ptr) Variable Function
+ 28: 7(ptr) AccessChain 18(input) 26
+ 29:6(GSPS_INPUT) Load 28
+ Store 27(param) 29
+ 31: 2 FunctionCall 11(EmitVertex(struct-GSPS_INPUT1;struct-GSPS_INPUT1;) 27(param) 30(param)
+ 32:6(GSPS_INPUT) Load 30(param)
+ Store 19(TriStream) 32
+ 35: 7(ptr) AccessChain 18(input) 33
+ 36:6(GSPS_INPUT) Load 35
+ Store 34(param) 36
+ 38: 2 FunctionCall 11(EmitVertex(struct-GSPS_INPUT1;struct-GSPS_INPUT1;) 34(param) 37(param)
+ 39:6(GSPS_INPUT) Load 37(param)
+ Store 19(TriStream) 39
+ 42: 7(ptr) AccessChain 18(input) 40
+ 43:6(GSPS_INPUT) Load 42
+ Store 41(param) 43
+ 45: 2 FunctionCall 11(EmitVertex(struct-GSPS_INPUT1;struct-GSPS_INPUT1;) 41(param) 44(param)
+ 46:6(GSPS_INPUT) Load 44(param)
+ Store 19(TriStream) 46
+ Return
+ FunctionEnd
diff --git a/Test/hlsl.tristream-append.geom b/Test/hlsl.tristream-append.geom
new file mode 100644
index 0000000..208607d
--- /dev/null
+++ b/Test/hlsl.tristream-append.geom
@@ -0,0 +1,18 @@
+struct GSPS_INPUT
+{
+};
+
+// Test Append() method appearing before declaration of entry point's stream output.
+
+void EmitVertex(in GSPS_INPUT output, inout TriangleStream<GSPS_INPUT> TriStream)
+{
+ TriStream.Append( output );
+}
+
+[maxvertexcount(3)]
+void main( triangle GSPS_INPUT input[3], inout TriangleStream<GSPS_INPUT> TriStream )
+{
+ EmitVertex(input[0], TriStream);
+ EmitVertex(input[1], TriStream);
+ EmitVertex(input[2], TriStream);
+}
diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp
index ad76cf3..7cf1cbf 100644
--- a/gtests/Hlsl.FromFile.cpp
+++ b/gtests/Hlsl.FromFile.cpp
@@ -371,6 +371,7 @@
{"hlsl.targetStruct1.frag", "main"},
{"hlsl.targetStruct2.frag", "main"},
{"hlsl.templatetypes.frag", "PixelShaderFunction"},
+ {"hlsl.tristream-append.geom", "main"},
{"hlsl.tx.bracket.frag", "main"},
{"hlsl.tx.overload.frag", "main"},
{"hlsl.type.half.frag", "main"},
diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp
index b776278..e6d29ea 100755
--- a/hlsl/hlslParseHelper.cpp
+++ b/hlsl/hlslParseHelper.cpp
@@ -4490,23 +4490,18 @@
emit->setLoc(loc);
emit->setType(TType(EbtVoid));
- // find the matching output
- if (gsStreamOutput == nullptr) {
- error(loc, "unable to find output symbol for Append()", "", "");
- return;
- }
+ TIntermTyped* data = argAggregate->getSequence()[1]->getAsTyped();
- sequence = intermediate.growAggregate(sequence,
- handleAssign(loc, EOpAssign,
- intermediate.addSymbol(*gsStreamOutput, loc),
- argAggregate->getSequence()[1]->getAsTyped()),
- loc);
-
+ // This will be patched in finalization during finalizeAppendMethods()
+ sequence = intermediate.growAggregate(sequence, data, loc);
sequence = intermediate.growAggregate(sequence, emit);
sequence->setOperator(EOpSequence);
sequence->setLoc(loc);
sequence->setType(TType(EbtVoid));
+
+ gsAppends.push_back({sequence, loc});
+
node = sequence;
}
break;
@@ -9922,6 +9917,31 @@
}
}
+// Finalization step: patch append methods to use proper stream output, which isn't known until
+// main is parsed, which could happen after the append method is parsed.
+void HlslParseContext::finalizeAppendMethods()
+{
+ TSourceLoc loc;
+ loc.init();
+
+ // Nothing to do: bypass test for valid stream output.
+ if (gsAppends.empty())
+ return;
+
+ if (gsStreamOutput == nullptr) {
+ error(loc, "unable to find output symbol for Append()", "", "");
+ return;
+ }
+
+ // Patch append sequences, now that we know the stream output symbol.
+ for (auto append = gsAppends.begin(); append != gsAppends.end(); ++append) {
+ append->node->getSequence()[0] =
+ handleAssign(append->loc, EOpAssign,
+ intermediate.addSymbol(*gsStreamOutput, append->loc),
+ append->node->getSequence()[0]->getAsTyped());
+ }
+}
+
// post-processing
void HlslParseContext::finish()
{
@@ -9934,6 +9954,7 @@
removeUnusedStructBufferCounters();
addPatchConstantInvocation();
fixTextureShadowModes();
+ finalizeAppendMethods();
// Communicate out (esp. for command line) that we formed AST that will make
// illegal AST SPIR-V and it needs transforms to legalize it.
diff --git a/hlsl/hlslParseHelper.h b/hlsl/hlslParseHelper.h
index b16a8c2..32a1923 100755
--- a/hlsl/hlslParseHelper.h
+++ b/hlsl/hlslParseHelper.h
@@ -266,6 +266,7 @@
TVariable* getSplitNonIoVar(int id) const;
void addPatchConstantInvocation();
void fixTextureShadowModes();
+ void finalizeAppendMethods();
TIntermTyped* makeIntegerIndex(TIntermTyped*);
void fixBuiltInIoType(TType&);
@@ -460,6 +461,17 @@
TVector<tMipsOperatorData> mipsOperatorMipArg;
+ // The geometry output stream is not copied out from the entry point as a typical output variable
+ // is. It's written via EmitVertex (hlsl=Append), which may happen in arbitrary control flow.
+ // For this we need the real output symbol. Since it may not be known at the time and Append()
+ // method is parsed, the sequence will be patched during finalization.
+ struct tGsAppendData {
+ TIntermAggregate* node;
+ TSourceLoc loc;
+ };
+
+ TVector<tGsAppendData> gsAppends;
+
// A texture object may be used with shadow and non-shadow samplers, but both may not be
// alive post-DCE in the same shader. We do not know at compilation time which are alive: that's
// only known post-DCE. If a texture is used both ways, we create two textures, and