aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsteve-lunarg <steve_gh@khasekhemwy.net>2016-11-17 15:04:20 -0700
committersteve-lunarg <steve_gh@khasekhemwy.net>2016-11-21 18:25:08 -0700
commitf49cdf41831c2332bcb70469d6baca339a6c6d1a (patch)
tree31f03e16edd07e6f262151e6423874d55410d127
parentfabe7d6a613782d49becaef86aa0161ed7d3c4d7 (diff)
downloadglslang-f49cdf41831c2332bcb70469d6baca339a6c6d1a.tar.gz
WIP: HLSL: Add GS support
This PR adds: [maxvertexcount(n)] attributes point/line/triangle/lineadj/triangleadj qualifiers PointStream/LineStream/TriangleStream templatized types Append method on above template types RestartStrip method on above template types.
-rw-r--r--Test/baseResults/hlsl.basic.geom.out201
-rw-r--r--Test/hlsl.basic.geom25
-rw-r--r--glslang/Include/intermediate.h4
-rw-r--r--gtests/Hlsl.FromFile.cpp1
-rw-r--r--hlsl/hlslAttributes.cpp18
-rw-r--r--hlsl/hlslAttributes.h17
-rwxr-xr-xhlsl/hlslGrammar.cpp106
-rwxr-xr-xhlsl/hlslGrammar.h4
-rwxr-xr-xhlsl/hlslParseHelper.cpp144
-rwxr-xr-xhlsl/hlslParseHelper.h4
-rwxr-xr-xhlsl/hlslParseables.cpp9
-rwxr-xr-xhlsl/hlslScanContext.cpp25
-rwxr-xr-xhlsl/hlslTokens.h12
13 files changed, 531 insertions, 39 deletions
diff --git a/Test/baseResults/hlsl.basic.geom.out b/Test/baseResults/hlsl.basic.geom.out
new file mode 100644
index 00000000..2c20b439
--- /dev/null
+++ b/Test/baseResults/hlsl.basic.geom.out
@@ -0,0 +1,201 @@
+hlsl.basic.geom
+Shader version: 450
+invocations = -1
+max_vertices = 4
+input primitive = triangles
+output primitive = line_strip
+0:? Sequence
+0:16 Function Definition: main(u1[3];u1[3];struct-PSInput-f1-i11; (temp void)
+0:16 Function Parameters:
+0:16 'VertexID' (layout(location=0 ) in 3-element array of uint)
+0:16 'test' (layout(location=3 ) in 3-element array of uint)
+0:16 'OutputStream' (out structure{temp float myfloat, temp int something})
+0:? Sequence
+0:19 move second child to first child (temp float)
+0:19 myfloat: direct index for structure (temp float)
+0:19 'Vert' (temp structure{temp float myfloat, temp int something})
+0:19 Constant:
+0:19 0 (const int)
+0:19 Convert uint to float (temp float)
+0:19 add (temp uint)
+0:19 add (temp uint)
+0:19 direct index (layout(location=3 ) temp uint)
+0:19 'test' (layout(location=3 ) in 3-element array of uint)
+0:19 Constant:
+0:19 0 (const int)
+0:19 direct index (layout(location=3 ) temp uint)
+0:19 'test' (layout(location=3 ) in 3-element array of uint)
+0:19 Constant:
+0:19 1 (const int)
+0:19 direct index (layout(location=3 ) temp uint)
+0:19 'test' (layout(location=3 ) in 3-element array of uint)
+0:19 Constant:
+0:19 2 (const int)
+0:20 move second child to first child (temp int)
+0:20 something: direct index for structure (temp int)
+0:20 'Vert' (temp structure{temp float myfloat, temp int something})
+0:20 Constant:
+0:20 1 (const int)
+0:20 Convert uint to int (temp int)
+0:20 direct index (layout(location=0 ) temp uint)
+0:20 'VertexID' (layout(location=0 ) in 3-element array of uint)
+0:20 Constant:
+0:20 0 (const int)
+0:22 Sequence
+0:22 move second child to first child (temp structure{temp float myfloat, temp int something})
+0:22 'OutputStream' (out structure{temp float myfloat, temp int something})
+0:22 'Vert' (temp structure{temp float myfloat, temp int something})
+0:22 EmitVertex (temp void)
+0:23 Sequence
+0:23 move second child to first child (temp structure{temp float myfloat, temp int something})
+0:23 'OutputStream' (out structure{temp float myfloat, temp int something})
+0:23 'Vert' (temp structure{temp float myfloat, temp int something})
+0:23 EmitVertex (temp void)
+0:24 EndPrimitive (temp void)
+0:? Linker Objects
+0:? 'VertexID' (layout(location=0 ) in 3-element array of uint)
+0:? 'test' (layout(location=3 ) in 3-element array of uint)
+0:? 'myfloat' (layout(location=0 ) out float)
+0:? 'something' (layout(location=1 ) out int)
+
+
+Linked geometry stage:
+
+
+Shader version: 450
+invocations = 1
+max_vertices = 4
+input primitive = triangles
+output primitive = line_strip
+0:? Sequence
+0:16 Function Definition: main(u1[3];u1[3];struct-PSInput-f1-i11; (temp void)
+0:16 Function Parameters:
+0:16 'VertexID' (layout(location=0 ) in 3-element array of uint)
+0:16 'test' (layout(location=3 ) in 3-element array of uint)
+0:16 'OutputStream' (out structure{temp float myfloat, temp int something})
+0:? Sequence
+0:19 move second child to first child (temp float)
+0:19 myfloat: direct index for structure (temp float)
+0:19 'Vert' (temp structure{temp float myfloat, temp int something})
+0:19 Constant:
+0:19 0 (const int)
+0:19 Convert uint to float (temp float)
+0:19 add (temp uint)
+0:19 add (temp uint)
+0:19 direct index (layout(location=3 ) temp uint)
+0:19 'test' (layout(location=3 ) in 3-element array of uint)
+0:19 Constant:
+0:19 0 (const int)
+0:19 direct index (layout(location=3 ) temp uint)
+0:19 'test' (layout(location=3 ) in 3-element array of uint)
+0:19 Constant:
+0:19 1 (const int)
+0:19 direct index (layout(location=3 ) temp uint)
+0:19 'test' (layout(location=3 ) in 3-element array of uint)
+0:19 Constant:
+0:19 2 (const int)
+0:20 move second child to first child (temp int)
+0:20 something: direct index for structure (temp int)
+0:20 'Vert' (temp structure{temp float myfloat, temp int something})
+0:20 Constant:
+0:20 1 (const int)
+0:20 Convert uint to int (temp int)
+0:20 direct index (layout(location=0 ) temp uint)
+0:20 'VertexID' (layout(location=0 ) in 3-element array of uint)
+0:20 Constant:
+0:20 0 (const int)
+0:22 Sequence
+0:22 move second child to first child (temp structure{temp float myfloat, temp int something})
+0:22 'OutputStream' (out structure{temp float myfloat, temp int something})
+0:22 'Vert' (temp structure{temp float myfloat, temp int something})
+0:22 EmitVertex (temp void)
+0:23 Sequence
+0:23 move second child to first child (temp structure{temp float myfloat, temp int something})
+0:23 'OutputStream' (out structure{temp float myfloat, temp int something})
+0:23 'Vert' (temp structure{temp float myfloat, temp int something})
+0:23 EmitVertex (temp void)
+0:24 EndPrimitive (temp void)
+0:? Linker Objects
+0:? 'VertexID' (layout(location=0 ) in 3-element array of uint)
+0:? 'test' (layout(location=3 ) in 3-element array of uint)
+0:? 'myfloat' (layout(location=0 ) out float)
+0:? 'something' (layout(location=1 ) out int)
+
+// Module Version 10000
+// Generated by (magic number): 80001
+// Id's are bound by 45
+
+ Capability Geometry
+ 1: ExtInstImport "GLSL.std.450"
+ MemoryModel Logical GLSL450
+ EntryPoint Geometry 4 "main" 16 31 38 42 44
+ ExecutionMode 4 Triangles
+ ExecutionMode 4 Invocations 1
+ ExecutionMode 4 OutputLineStrip
+ ExecutionMode 4 OutputVertices 4
+ Name 4 "main"
+ Name 8 "PSInput"
+ MemberName 8(PSInput) 0 "myfloat"
+ MemberName 8(PSInput) 1 "something"
+ Name 10 "Vert"
+ Name 16 "test"
+ Name 31 "VertexID"
+ Name 38 "OutputStream"
+ Name 42 "myfloat"
+ Name 44 "something"
+ Decorate 16(test) Location 3
+ Decorate 31(VertexID) Location 0
+ Decorate 42(myfloat) Location 0
+ Decorate 44(something) Location 1
+ 2: TypeVoid
+ 3: TypeFunction 2
+ 6: TypeFloat 32
+ 7: TypeInt 32 1
+ 8(PSInput): TypeStruct 6(float) 7(int)
+ 9: TypePointer Function 8(PSInput)
+ 11: 7(int) Constant 0
+ 12: TypeInt 32 0
+ 13: 12(int) Constant 3
+ 14: TypeArray 12(int) 13
+ 15: TypePointer Input 14
+ 16(test): 15(ptr) Variable Input
+ 17: TypePointer Input 12(int)
+ 20: 7(int) Constant 1
+ 24: 7(int) Constant 2
+ 29: TypePointer Function 6(float)
+ 31(VertexID): 15(ptr) Variable Input
+ 35: TypePointer Function 7(int)
+ 37: TypePointer Output 8(PSInput)
+38(OutputStream): 37(ptr) Variable Output
+ 41: TypePointer Output 6(float)
+ 42(myfloat): 41(ptr) Variable Output
+ 43: TypePointer Output 7(int)
+ 44(something): 43(ptr) Variable Output
+ 4(main): 2 Function None 3
+ 5: Label
+ 10(Vert): 9(ptr) Variable Function
+ 18: 17(ptr) AccessChain 16(test) 11
+ 19: 12(int) Load 18
+ 21: 17(ptr) AccessChain 16(test) 20
+ 22: 12(int) Load 21
+ 23: 12(int) IAdd 19 22
+ 25: 17(ptr) AccessChain 16(test) 24
+ 26: 12(int) Load 25
+ 27: 12(int) IAdd 23 26
+ 28: 6(float) ConvertUToF 27
+ 30: 29(ptr) AccessChain 10(Vert) 11
+ Store 30 28
+ 32: 17(ptr) AccessChain 31(VertexID) 11
+ 33: 12(int) Load 32
+ 34: 7(int) Bitcast 33
+ 36: 35(ptr) AccessChain 10(Vert) 20
+ Store 36 34
+ 39: 8(PSInput) Load 10(Vert)
+ Store 38(OutputStream) 39
+ EmitVertex
+ 40: 8(PSInput) Load 10(Vert)
+ Store 38(OutputStream) 40
+ EmitVertex
+ EndPrimitive
+ Return
+ FunctionEnd
diff --git a/Test/hlsl.basic.geom b/Test/hlsl.basic.geom
new file mode 100644
index 00000000..79b061ee
--- /dev/null
+++ b/Test/hlsl.basic.geom
@@ -0,0 +1,25 @@
+struct PSInput
+{
+ float myfloat : SOME_SEMANTIC;
+ int something : ANOTHER_SEMANTIC;
+};
+
+struct nametest {
+ int Append; // these are valid names even though they are also method names.
+ int RestartStrip; // ...
+};
+
+[maxvertexcount(4)]
+void main(triangle in uint VertexID[3] : VertexID,
+ triangle uint test[3] : FOO,
+ inout LineStream<PSInput> OutputStream)
+{
+ PSInput Vert;
+
+ Vert.myfloat = test[0] + test[1] + test[2];
+ Vert.something = VertexID[0];
+
+ OutputStream.Append(Vert);
+ OutputStream.Append(Vert);
+ OutputStream.RestartStrip();
+}
diff --git a/glslang/Include/intermediate.h b/glslang/Include/intermediate.h
index db61b750..8f7ffcc0 100644
--- a/glslang/Include/intermediate.h
+++ b/glslang/Include/intermediate.h
@@ -621,6 +621,10 @@ enum TOperator {
EOpMethodGatherCmpGreen, // ...
EOpMethodGatherCmpBlue, // ...
EOpMethodGatherCmpAlpha, // ...
+
+ // geometry methods
+ EOpMethodAppend, // Geometry shader methods
+ EOpMethodRestartStrip, // ...
};
class TIntermTraverser;
diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp
index 5487fb98..2867140e 100644
--- a/gtests/Hlsl.FromFile.cpp
+++ b/gtests/Hlsl.FromFile.cpp
@@ -88,6 +88,7 @@ INSTANTIATE_TEST_CASE_P(
{"hlsl.attribute.frag", "PixelShaderFunction"},
{"hlsl.attribute.expression.comp", "main"},
{"hlsl.basic.comp", "main"},
+ {"hlsl.basic.geom", "main"},
{"hlsl.buffer.frag", "PixelShaderFunction"},
{"hlsl.calculatelod.dx10.frag", "main"},
{"hlsl.calculatelodunclamped.dx10.frag", "main"},
diff --git a/hlsl/hlslAttributes.cpp b/hlsl/hlslAttributes.cpp
index 957f282e..966ff352 100644
--- a/hlsl/hlslAttributes.cpp
+++ b/hlsl/hlslAttributes.cpp
@@ -55,27 +55,29 @@ namespace glslang {
else if (lowername == "domain")
return EatDomain;
else if (lowername == "earlydepthstencil")
- return EatEarlydepthstencil;
+ return EatEarlyDepthStencil;
else if (lowername == "fastopt")
- return EatFastopt;
+ return EatFastOpt;
else if (lowername == "flatten")
return EatFlatten;
else if (lowername == "forcecase")
- return EatForcecase;
+ return EatForceCase;
else if (lowername == "instance")
return EatInstance;
else if (lowername == "maxtessfactor")
- return EatMaxtessfactor;
+ return EatMaxTessFactor;
+ else if (lowername == "maxvertexcount")
+ return EatMaxVertexCount;
else if (lowername == "numthreads")
- return EatNumthreads;
+ return EatNumThreads;
else if (lowername == "outputcontrolpoints")
- return EatOutputcontrolpoints;
+ return EatOutputControlPoints;
else if (lowername == "outputtopology")
- return EatOutputtopology;
+ return EatOutputTopology;
else if (lowername == "partitioning")
return EatPartitioning;
else if (lowername == "patchconstantfunc")
- return EatPatchconstantfunc;
+ return EatPatchConstantFunc;
else if (lowername == "unroll")
return EatUnroll;
else
diff --git a/hlsl/hlslAttributes.h b/hlsl/hlslAttributes.h
index da5ee5ef..312a4564 100644
--- a/hlsl/hlslAttributes.h
+++ b/hlsl/hlslAttributes.h
@@ -48,17 +48,18 @@ namespace glslang {
EatBranch,
EatCall,
EatDomain,
- EatEarlydepthstencil,
- EatFastopt,
+ EatEarlyDepthStencil,
+ EatFastOpt,
EatFlatten,
- EatForcecase,
+ EatForceCase,
EatInstance,
- EatMaxtessfactor,
- EatNumthreads,
- EatOutputcontrolpoints,
- EatOutputtopology,
+ EatMaxTessFactor,
+ EatNumThreads,
+ EatMaxVertexCount,
+ EatOutputControlPoints,
+ EatOutputTopology,
EatPartitioning,
- EatPatchconstantfunc,
+ EatPatchConstantFunc,
EatUnroll,
};
}
diff --git a/hlsl/hlslGrammar.cpp b/hlsl/hlslGrammar.cpp
index e6f4b603..b2715eda 100755
--- a/hlsl/hlslGrammar.cpp
+++ b/hlsl/hlslGrammar.cpp
@@ -469,9 +469,14 @@ bool HlslGrammar::acceptFullySpecifiedType(TType& type)
// Some qualifiers are set when parsing the type. Merge those with
// whatever comes from acceptQualifier.
assert(qualifier.layoutFormat == ElfNone);
+
qualifier.layoutFormat = type.getQualifier().layoutFormat;
qualifier.precision = type.getQualifier().precision;
- type.getQualifier() = qualifier;
+
+ if (type.getQualifier().storage == EvqVaryingOut)
+ qualifier.storage = type.getQualifier().storage;
+
+ type.getQualifier() = qualifier;
}
return true;
@@ -544,6 +549,35 @@ bool HlslGrammar::acceptQualifier(TQualifier& qualifier)
if (! acceptLayoutQualifierList(qualifier))
return false;
continue;
+
+ // GS geometries: these are specified on stage input variables, and are an error (not verified here)
+ // for output variables.
+ case EHTokPoint:
+ qualifier.storage = EvqIn;
+ if (!parseContext.handleInputGeometry(token.loc, ElgPoints))
+ return false;
+ break;
+ case EHTokLine:
+ qualifier.storage = EvqIn;
+ if (!parseContext.handleInputGeometry(token.loc, ElgLines))
+ return false;
+ break;
+ case EHTokTriangle:
+ qualifier.storage = EvqIn;
+ if (!parseContext.handleInputGeometry(token.loc, ElgTriangles))
+ return false;
+ break;
+ case EHTokLineAdj:
+ qualifier.storage = EvqIn;
+ if (!parseContext.handleInputGeometry(token.loc, ElgLinesAdjacency))
+ return false;
+ break;
+ case EHTokTriangleAdj:
+ qualifier.storage = EvqIn;
+ if (!parseContext.handleInputGeometry(token.loc, ElgTrianglesAdjacency))
+ return false;
+ break;
+
default:
return true;
}
@@ -608,7 +642,7 @@ bool HlslGrammar::acceptLayoutQualifierList(TQualifier& qualifier)
// | UINT
// | BOOL
//
-bool HlslGrammar::acceptTemplateType(TBasicType& basicType)
+bool HlslGrammar::acceptTemplateVecMatBasicType(TBasicType& basicType)
{
switch (peek()) {
case EHTokFloat:
@@ -652,7 +686,7 @@ bool HlslGrammar::acceptVectorTemplateType(TType& type)
}
TBasicType basicType;
- if (! acceptTemplateType(basicType)) {
+ if (! acceptTemplateVecMatBasicType(basicType)) {
expected("scalar type");
return false;
}
@@ -704,7 +738,7 @@ bool HlslGrammar::acceptMatrixTemplateType(TType& type)
}
TBasicType basicType;
- if (! acceptTemplateType(basicType)) {
+ if (! acceptTemplateVecMatBasicType(basicType)) {
expected("scalar type");
return false;
}
@@ -753,6 +787,56 @@ bool HlslGrammar::acceptMatrixTemplateType(TType& type)
return true;
}
+// layout_geometry
+// : LINESTREAM
+// | POINTSTREAM
+// | TRIANGLESTREAM
+//
+bool HlslGrammar::acceptOutputPrimitiveGeometry(TLayoutGeometry& geometry)
+{
+ // read geometry type
+ const EHlslTokenClass geometryType = peek();
+
+ switch (geometryType) {
+ case EHTokPointStream: geometry = ElgPoints; break;
+ case EHTokLineStream: geometry = ElgLineStrip; break;
+ case EHTokTriangleStream: geometry = ElgTriangleStrip; break;
+ default:
+ return false; // not a layout geometry
+ }
+
+ advanceToken(); // consume the layout keyword
+ return true;
+}
+
+// stream_out_template_type
+// : output_primitive_geometry_type LEFT_ANGLE type RIGHT_ANGLE
+//
+bool HlslGrammar::acceptStreamOutTemplateType(TType& type, TLayoutGeometry& geometry)
+{
+ geometry = ElgNone;
+
+ if (! acceptOutputPrimitiveGeometry(geometry))
+ return false;
+
+ if (! acceptTokenClass(EHTokLeftAngle))
+ return false;
+
+ if (! acceptType(type)) {
+ expected("stream output type");
+ return false;
+ }
+
+ type.getQualifier().storage = EvqVaryingOut;
+
+ if (! acceptTokenClass(EHTokRightAngle)) {
+ expected("right angle bracket");
+ return false;
+ }
+
+ return true;
+}
+
// annotations
// : LEFT_ANGLE declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
//
@@ -989,6 +1073,20 @@ bool HlslGrammar::acceptType(TType& type)
return acceptMatrixTemplateType(type);
break;
+ case EHTokPointStream: // fall through
+ case EHTokLineStream: // ...
+ case EHTokTriangleStream: // ...
+ {
+ TLayoutGeometry geometry;
+ if (! acceptStreamOutTemplateType(type, geometry))
+ return false;
+
+ if (! parseContext.handleOutputGeometry(token.loc, geometry))
+ return false;
+
+ return true;
+ }
+
case EHTokSampler: // fall through
case EHTokSampler1d: // ...
case EHTokSampler2d: // ...
diff --git a/hlsl/hlslGrammar.h b/hlsl/hlslGrammar.h
index c3e42f67..8804b217 100755
--- a/hlsl/hlslGrammar.h
+++ b/hlsl/hlslGrammar.h
@@ -72,9 +72,11 @@ namespace glslang {
bool acceptQualifier(TQualifier&);
bool acceptLayoutQualifierList(TQualifier&);
bool acceptType(TType&);
- bool acceptTemplateType(TBasicType&);
+ bool acceptTemplateVecMatBasicType(TBasicType&);
bool acceptVectorTemplateType(TType&);
bool acceptMatrixTemplateType(TType&);
+ bool acceptStreamOutTemplateType(TType&, TLayoutGeometry&);
+ bool acceptOutputPrimitiveGeometry(TLayoutGeometry&);
bool acceptAnnotations(TQualifier&);
bool acceptSamplerType(TType&);
bool acceptTextureType(TType&);
diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp
index ff2c3014..49577677 100755
--- a/hlsl/hlslParseHelper.cpp
+++ b/hlsl/hlslParseHelper.cpp
@@ -758,6 +758,13 @@ TIntermTyped* HlslParseContext::handleDotDereference(const TSourceLoc& loc, TInt
return intermediate.addMethod(base, TType(sampler.type, EvqTemporary, vecSize), &field, loc);
}
}
+ } else if (field == "Append" ||
+ field == "RestartStrip") {
+ // These methods only valid on stage in variables
+ // TODO: ... which are stream out types, if there's any way to test that here.
+ if (base->getType().getQualifier().storage == EvqVaryingOut) {
+ return intermediate.addMethod(base, TType(EbtVoid), &field, loc);
+ }
}
// It's not .length() if we get to here.
@@ -1137,12 +1144,19 @@ TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& l
postMainReturn = false;
// Handle function attributes
- const TIntermAggregate* numThreadliterals = attributes[EatNumthreads];
- if (numThreadliterals != nullptr && inEntryPoint) {
- const TIntermSequence& sequence = numThreadliterals->getSequence();
+ if (inEntryPoint) {
+ const TIntermAggregate* numThreads = attributes[EatNumThreads];
+ if (numThreads != nullptr) {
+ const TIntermSequence& sequence = numThreads->getSequence();
- for (int lid = 0; lid < int(sequence.size()); ++lid)
- intermediate.setLocalSize(lid, sequence[lid]->getAsConstantUnion()->getConstArray()[0].getIConst());
+ for (int lid = 0; lid < int(sequence.size()); ++lid)
+ intermediate.setLocalSize(lid, sequence[lid]->getAsConstantUnion()->getConstArray()[0].getIConst());
+ }
+
+ const TIntermAggregate* maxVertexCount = attributes[EatMaxVertexCount];
+ if (maxVertexCount != nullptr) {
+ intermediate.setVertices(maxVertexCount->getSequence()[0]->getAsConstantUnion()->getConstArray()[0].getIConst());
+ }
}
return paramNodes;
@@ -2064,6 +2078,55 @@ void HlslParseContext::decomposeSampleMethods(const TSourceLoc& loc, TIntermType
}
//
+// Decompose geometry shader methods
+//
+void HlslParseContext::decomposeGeometryMethods(const TSourceLoc& loc, TIntermTyped*& node, TIntermNode* arguments)
+{
+ if (!node || !node->getAsOperator())
+ return;
+
+ const TOperator op = node->getAsOperator()->getOp();
+ const TIntermAggregate* argAggregate = arguments ? arguments->getAsAggregate() : nullptr;
+
+ switch (op) {
+ case EOpMethodAppend:
+ if (argAggregate) {
+ TIntermAggregate* sequence = nullptr;
+ TIntermAggregate* emit = new TIntermAggregate(EOpEmitVertex);
+
+ emit->setLoc(loc);
+ emit->setType(TType(EbtVoid));
+
+ sequence = intermediate.growAggregate(sequence,
+ intermediate.addAssign(EOpAssign,
+ argAggregate->getSequence()[0]->getAsTyped(),
+ argAggregate->getSequence()[1]->getAsTyped(), loc),
+ loc);
+
+ sequence = intermediate.growAggregate(sequence, emit);
+
+ sequence->setOperator(EOpSequence);
+ sequence->setLoc(loc);
+ sequence->setType(TType(EbtVoid));
+ node = sequence;
+ }
+ break;
+
+ case EOpMethodRestartStrip:
+ {
+ TIntermAggregate* cut = new TIntermAggregate(EOpEndPrimitive);
+ cut->setLoc(loc);
+ cut->setType(TType(EbtVoid));
+ node = cut;
+ }
+ break;
+
+ default:
+ break; // most pass through unchanged
+ }
+}
+
+//
// Optionally decompose intrinsics to AST opcodes.
//
void HlslParseContext::decomposeIntrinsic(const TSourceLoc& loc, TIntermTyped*& node, TIntermNode* arguments)
@@ -2546,8 +2609,9 @@ TIntermTyped* HlslParseContext::handleFunctionCall(const TSourceLoc& loc, TFunct
result = addOutputArgumentConversions(*fnCandidate, *result->getAsAggregate());
}
- decomposeIntrinsic(loc, result, arguments); // HLSL->AST intrinsic decompositions
- decomposeSampleMethods(loc, result, arguments); // HLSL->AST sample method decompositions
+ decomposeIntrinsic(loc, result, arguments); // HLSL->AST intrinsic decompositions
+ decomposeSampleMethods(loc, result, arguments); // HLSL->AST sample method decompositions
+ decomposeGeometryMethods(loc, result, arguments); // HLSL->AST geometry method decompositions
}
}
@@ -4295,6 +4359,14 @@ const TFunction* HlslParseContext::findFunction(const TSourceLoc& loc, const TFu
TVector<const TFunction*> candidateList;
symbolTable.findFunctionNameList(call.getMangledName(), candidateList, builtIn);
+ // These builtin ops can accept any type, so we bypass the argument selection
+ if (candidateList.size() == 1 && builtIn &&
+ (candidateList[0]->getBuiltInOp() == EOpMethodAppend ||
+ candidateList[0]->getBuiltInOp() == EOpMethodRestartStrip)) {
+
+ return candidateList[0];
+ }
+
// can 'from' convert to 'to'?
const auto convertible = [this](const TType& from, const TType& to) -> bool {
if (from == to)
@@ -5203,6 +5275,53 @@ void HlslParseContext::addQualifierToExisting(const TSourceLoc& loc, TQualifier
}
//
+// Update the intermediate for the given input geometry
+//
+bool HlslParseContext::handleInputGeometry(const TSourceLoc& loc, const TLayoutGeometry& geometry)
+{
+ switch (geometry) {
+ case ElgPoints: // fall through
+ case ElgLines: // ...
+ case ElgTriangles: // ...
+ case ElgLinesAdjacency: // ...
+ case ElgTrianglesAdjacency: // ...
+ if (! intermediate.setInputPrimitive(geometry)) {
+ error(loc, "input primitive geometry redefinition", TQualifier::getGeometryString(geometry), "");
+ return false;
+ }
+ break;
+
+ default:
+ error(loc, "cannot apply to 'in'", TQualifier::getGeometryString(geometry), "");
+ return false;
+ }
+
+ return true;
+}
+
+//
+// Update the intermediate for the given output geometry
+//
+bool HlslParseContext::handleOutputGeometry(const TSourceLoc& loc, const TLayoutGeometry& geometry)
+{
+ switch (geometry) {
+ case ElgPoints:
+ case ElgLineStrip:
+ case ElgTriangleStrip:
+ if (! intermediate.setOutputPrimitive(geometry)) {
+ error(loc, "output primitive geometry redefinition", TQualifier::getGeometryString(geometry), "");
+ return false;
+ }
+ break;
+ default:
+ error(loc, "cannot apply to 'out'", TQualifier::getGeometryString(geometry), "");
+ return false;
+ }
+
+ return true;
+}
+
+//
// Updating default qualifier for the case of a declaration with just a qualifier,
// no type, block, or identifier.
//
@@ -5231,16 +5350,7 @@ void HlslParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc,
error(loc, "cannot apply to input", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), "");
}
} else if (publicType.qualifier.storage == EvqVaryingOut) {
- switch (publicType.shaderQualifiers.geometry) {
- case ElgPoints:
- case ElgLineStrip:
- case ElgTriangleStrip:
- if (! intermediate.setOutputPrimitive(publicType.shaderQualifiers.geometry))
- error(loc, "cannot change previously set output primitive", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), "");
- break;
- default:
- error(loc, "cannot apply to 'out'", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), "");
- }
+ handleOutputGeometry(loc, publicType.shaderQualifiers.geometry);
} else
error(loc, "cannot apply to:", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), GetStorageQualifierString(publicType.qualifier.storage));
}
diff --git a/hlsl/hlslParseHelper.h b/hlsl/hlslParseHelper.h
index 9a7285f9..3862c10f 100755
--- a/hlsl/hlslParseHelper.h
+++ b/hlsl/hlslParseHelper.h
@@ -81,6 +81,7 @@ public:
TIntermTyped* handleFunctionCall(const TSourceLoc&, TFunction*, TIntermNode*);
void decomposeIntrinsic(const TSourceLoc&, TIntermTyped*& node, TIntermNode* arguments);
void decomposeSampleMethods(const TSourceLoc&, TIntermTyped*& node, TIntermNode* arguments);
+ void decomposeGeometryMethods(const TSourceLoc&, TIntermTyped*& node, TIntermNode* arguments);
TIntermTyped* handleLengthMethod(const TSourceLoc&, TFunction*, TIntermNode*);
void addInputArgumentConversions(const TFunction&, TIntermNode*&) const;
TIntermTyped* addOutputArgumentConversions(const TFunction&, TIntermAggregate&);
@@ -160,6 +161,9 @@ public:
TLayoutFormat getLayoutFromTxType(const TSourceLoc&, const TType&);
+ bool handleOutputGeometry(const TSourceLoc&, const TLayoutGeometry& geometry);
+ bool handleInputGeometry(const TSourceLoc&, const TLayoutGeometry& geometry);
+
protected:
void inheritGlobalDefaults(TQualifier& dst) const;
TVariable* makeInternalVariable(const char* name, const TType&) const;
diff --git a/hlsl/hlslParseables.cpp b/hlsl/hlslParseables.cpp
index 7ab159dc..f8fed0d8 100755
--- a/hlsl/hlslParseables.cpp
+++ b/hlsl/hlslParseables.cpp
@@ -502,6 +502,7 @@ void TBuiltInParseablesHlsl::initialize(int /*version*/, EProfile /*profile*/, c
static const EShLanguageMask EShLangCS = EShLangAll;
static const EShLanguageMask EShLangPS = EShLangAll;
static const EShLanguageMask EShLangHS = EShLangAll;
+ static const EShLanguageMask EShLangGS = EShLangAll;
// This structure encodes the prototype information for each HLSL intrinsic.
// Because explicit enumeration would be cumbersome, it's procedurally generated.
@@ -831,6 +832,10 @@ void TBuiltInParseablesHlsl::initialize(int /*version*/, EProfile /*profile*/, c
{ "GatherCmpAlpha", /* O-4 */ "V4", nullptr, "%@,S,V,S,V,,,", "FIU,s,F,,I,,,", EShLangAll },
{ "GatherCmpAlpha", /* O-4, status */"V4", nullptr, "%@,S,V,S,V,,,,S","FIU,s,F,,I,,,,U",EShLangAll },
+ // geometry methods
+ { "Append", "-", "-", "-", "-", EShLangGS },
+ { "RestartStrip", "-", "-", "-", "-", EShLangGS },
+
// Mark end of list, since we want to avoid a range-based for, as some compilers don't handle it yet.
{ nullptr, nullptr, nullptr, nullptr, nullptr, 0 },
};
@@ -1140,6 +1145,10 @@ void TBuiltInParseablesHlsl::identifyBuiltIns(int /*version*/, EProfile /*profil
symbolTable.relateToOperator("GatherCmpGreen", EOpMethodGatherCmpGreen);
symbolTable.relateToOperator("GatherCmpBlue", EOpMethodGatherCmpBlue);
symbolTable.relateToOperator("GatherCmpAlpha", EOpMethodGatherCmpAlpha);
+
+ // GS methods
+ symbolTable.relateToOperator("Append", EOpMethodAppend);
+ symbolTable.relateToOperator("RestartStrip", EOpMethodRestartStrip);
}
//
diff --git a/hlsl/hlslScanContext.cpp b/hlsl/hlslScanContext.cpp
index e7cd1fcf..2c45b3ff 100755
--- a/hlsl/hlslScanContext.cpp
+++ b/hlsl/hlslScanContext.cpp
@@ -119,6 +119,16 @@ void HlslScanContext::fillInKeywordMap()
(*KeywordMap)["inout"] = EHTokInOut;
(*KeywordMap)["layout"] = EHTokLayout;
+ (*KeywordMap)["point"] = EHTokPoint;
+ (*KeywordMap)["line"] = EHTokLine;
+ (*KeywordMap)["triangle"] = EHTokTriangle;
+ (*KeywordMap)["lineadj"] = EHTokLineAdj;
+ (*KeywordMap)["triangleadj"] = EHTokTriangleAdj;
+
+ (*KeywordMap)["PointStream"] = EHTokPointStream;
+ (*KeywordMap)["LineStream"] = EHTokLineStream;
+ (*KeywordMap)["TriangleStream"] = EHTokTriangleStream;
+
(*KeywordMap)["Buffer"] = EHTokBuffer;
(*KeywordMap)["vector"] = EHTokVector;
(*KeywordMap)["matrix"] = EHTokMatrix;
@@ -496,7 +506,20 @@ EHlslTokenClass HlslScanContext::tokenizeIdentifier()
case EHTokLayout:
return keyword;
- // template types
+ // primitive types
+ case EHTokPoint:
+ case EHTokLine:
+ case EHTokTriangle:
+ case EHTokLineAdj:
+ case EHTokTriangleAdj:
+ return keyword;
+
+ // stream out types
+ case EHTokPointStream:
+ case EHTokLineStream:
+ case EHTokTriangleStream:
+ return keyword;
+
case EHTokBuffer:
case EHTokVector:
case EHTokMatrix:
diff --git a/hlsl/hlslTokens.h b/hlsl/hlslTokens.h
index d634c8ee..6902070c 100755
--- a/hlsl/hlslTokens.h
+++ b/hlsl/hlslTokens.h
@@ -66,6 +66,18 @@ enum EHlslTokenClass {
EHTokInOut,
EHTokLayout,
+ // primitive types
+ EHTokPoint,
+ EHTokLine,
+ EHTokTriangle,
+ EHTokLineAdj,
+ EHTokTriangleAdj,
+
+ // stream out types
+ EHTokPointStream,
+ EHTokLineStream,
+ EHTokTriangleStream,
+
// template types
EHTokBuffer,
EHTokVector,