mirror of
https://github.com/KhronosGroup/glslang
synced 2024-11-09 12:00:05 +00:00
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.
This commit is contained in:
parent
fabe7d6a61
commit
f49cdf4183
201
Test/baseResults/hlsl.basic.geom.out
Normal file
201
Test/baseResults/hlsl.basic.geom.out
Normal file
@ -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
|
25
Test/hlsl.basic.geom
Normal file
25
Test/hlsl.basic.geom
Normal file
@ -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();
|
||||||
|
}
|
@ -621,6 +621,10 @@ enum TOperator {
|
|||||||
EOpMethodGatherCmpGreen, // ...
|
EOpMethodGatherCmpGreen, // ...
|
||||||
EOpMethodGatherCmpBlue, // ...
|
EOpMethodGatherCmpBlue, // ...
|
||||||
EOpMethodGatherCmpAlpha, // ...
|
EOpMethodGatherCmpAlpha, // ...
|
||||||
|
|
||||||
|
// geometry methods
|
||||||
|
EOpMethodAppend, // Geometry shader methods
|
||||||
|
EOpMethodRestartStrip, // ...
|
||||||
};
|
};
|
||||||
|
|
||||||
class TIntermTraverser;
|
class TIntermTraverser;
|
||||||
|
@ -88,6 +88,7 @@ INSTANTIATE_TEST_CASE_P(
|
|||||||
{"hlsl.attribute.frag", "PixelShaderFunction"},
|
{"hlsl.attribute.frag", "PixelShaderFunction"},
|
||||||
{"hlsl.attribute.expression.comp", "main"},
|
{"hlsl.attribute.expression.comp", "main"},
|
||||||
{"hlsl.basic.comp", "main"},
|
{"hlsl.basic.comp", "main"},
|
||||||
|
{"hlsl.basic.geom", "main"},
|
||||||
{"hlsl.buffer.frag", "PixelShaderFunction"},
|
{"hlsl.buffer.frag", "PixelShaderFunction"},
|
||||||
{"hlsl.calculatelod.dx10.frag", "main"},
|
{"hlsl.calculatelod.dx10.frag", "main"},
|
||||||
{"hlsl.calculatelodunclamped.dx10.frag", "main"},
|
{"hlsl.calculatelodunclamped.dx10.frag", "main"},
|
||||||
|
@ -55,27 +55,29 @@ namespace glslang {
|
|||||||
else if (lowername == "domain")
|
else if (lowername == "domain")
|
||||||
return EatDomain;
|
return EatDomain;
|
||||||
else if (lowername == "earlydepthstencil")
|
else if (lowername == "earlydepthstencil")
|
||||||
return EatEarlydepthstencil;
|
return EatEarlyDepthStencil;
|
||||||
else if (lowername == "fastopt")
|
else if (lowername == "fastopt")
|
||||||
return EatFastopt;
|
return EatFastOpt;
|
||||||
else if (lowername == "flatten")
|
else if (lowername == "flatten")
|
||||||
return EatFlatten;
|
return EatFlatten;
|
||||||
else if (lowername == "forcecase")
|
else if (lowername == "forcecase")
|
||||||
return EatForcecase;
|
return EatForceCase;
|
||||||
else if (lowername == "instance")
|
else if (lowername == "instance")
|
||||||
return EatInstance;
|
return EatInstance;
|
||||||
else if (lowername == "maxtessfactor")
|
else if (lowername == "maxtessfactor")
|
||||||
return EatMaxtessfactor;
|
return EatMaxTessFactor;
|
||||||
|
else if (lowername == "maxvertexcount")
|
||||||
|
return EatMaxVertexCount;
|
||||||
else if (lowername == "numthreads")
|
else if (lowername == "numthreads")
|
||||||
return EatNumthreads;
|
return EatNumThreads;
|
||||||
else if (lowername == "outputcontrolpoints")
|
else if (lowername == "outputcontrolpoints")
|
||||||
return EatOutputcontrolpoints;
|
return EatOutputControlPoints;
|
||||||
else if (lowername == "outputtopology")
|
else if (lowername == "outputtopology")
|
||||||
return EatOutputtopology;
|
return EatOutputTopology;
|
||||||
else if (lowername == "partitioning")
|
else if (lowername == "partitioning")
|
||||||
return EatPartitioning;
|
return EatPartitioning;
|
||||||
else if (lowername == "patchconstantfunc")
|
else if (lowername == "patchconstantfunc")
|
||||||
return EatPatchconstantfunc;
|
return EatPatchConstantFunc;
|
||||||
else if (lowername == "unroll")
|
else if (lowername == "unroll")
|
||||||
return EatUnroll;
|
return EatUnroll;
|
||||||
else
|
else
|
||||||
|
@ -48,17 +48,18 @@ namespace glslang {
|
|||||||
EatBranch,
|
EatBranch,
|
||||||
EatCall,
|
EatCall,
|
||||||
EatDomain,
|
EatDomain,
|
||||||
EatEarlydepthstencil,
|
EatEarlyDepthStencil,
|
||||||
EatFastopt,
|
EatFastOpt,
|
||||||
EatFlatten,
|
EatFlatten,
|
||||||
EatForcecase,
|
EatForceCase,
|
||||||
EatInstance,
|
EatInstance,
|
||||||
EatMaxtessfactor,
|
EatMaxTessFactor,
|
||||||
EatNumthreads,
|
EatNumThreads,
|
||||||
EatOutputcontrolpoints,
|
EatMaxVertexCount,
|
||||||
EatOutputtopology,
|
EatOutputControlPoints,
|
||||||
|
EatOutputTopology,
|
||||||
EatPartitioning,
|
EatPartitioning,
|
||||||
EatPatchconstantfunc,
|
EatPatchConstantFunc,
|
||||||
EatUnroll,
|
EatUnroll,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -469,9 +469,14 @@ bool HlslGrammar::acceptFullySpecifiedType(TType& type)
|
|||||||
// Some qualifiers are set when parsing the type. Merge those with
|
// Some qualifiers are set when parsing the type. Merge those with
|
||||||
// whatever comes from acceptQualifier.
|
// whatever comes from acceptQualifier.
|
||||||
assert(qualifier.layoutFormat == ElfNone);
|
assert(qualifier.layoutFormat == ElfNone);
|
||||||
|
|
||||||
qualifier.layoutFormat = type.getQualifier().layoutFormat;
|
qualifier.layoutFormat = type.getQualifier().layoutFormat;
|
||||||
qualifier.precision = type.getQualifier().precision;
|
qualifier.precision = type.getQualifier().precision;
|
||||||
type.getQualifier() = qualifier;
|
|
||||||
|
if (type.getQualifier().storage == EvqVaryingOut)
|
||||||
|
qualifier.storage = type.getQualifier().storage;
|
||||||
|
|
||||||
|
type.getQualifier() = qualifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -544,6 +549,35 @@ bool HlslGrammar::acceptQualifier(TQualifier& qualifier)
|
|||||||
if (! acceptLayoutQualifierList(qualifier))
|
if (! acceptLayoutQualifierList(qualifier))
|
||||||
return false;
|
return false;
|
||||||
continue;
|
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:
|
default:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -608,7 +642,7 @@ bool HlslGrammar::acceptLayoutQualifierList(TQualifier& qualifier)
|
|||||||
// | UINT
|
// | UINT
|
||||||
// | BOOL
|
// | BOOL
|
||||||
//
|
//
|
||||||
bool HlslGrammar::acceptTemplateType(TBasicType& basicType)
|
bool HlslGrammar::acceptTemplateVecMatBasicType(TBasicType& basicType)
|
||||||
{
|
{
|
||||||
switch (peek()) {
|
switch (peek()) {
|
||||||
case EHTokFloat:
|
case EHTokFloat:
|
||||||
@ -652,7 +686,7 @@ bool HlslGrammar::acceptVectorTemplateType(TType& type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
TBasicType basicType;
|
TBasicType basicType;
|
||||||
if (! acceptTemplateType(basicType)) {
|
if (! acceptTemplateVecMatBasicType(basicType)) {
|
||||||
expected("scalar type");
|
expected("scalar type");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -704,7 +738,7 @@ bool HlslGrammar::acceptMatrixTemplateType(TType& type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
TBasicType basicType;
|
TBasicType basicType;
|
||||||
if (! acceptTemplateType(basicType)) {
|
if (! acceptTemplateVecMatBasicType(basicType)) {
|
||||||
expected("scalar type");
|
expected("scalar type");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -753,6 +787,56 @@ bool HlslGrammar::acceptMatrixTemplateType(TType& type)
|
|||||||
return true;
|
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
|
// annotations
|
||||||
// : LEFT_ANGLE declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
|
// : LEFT_ANGLE declaration SEMI_COLON ... declaration SEMICOLON RIGHT_ANGLE
|
||||||
//
|
//
|
||||||
@ -989,6 +1073,20 @@ bool HlslGrammar::acceptType(TType& type)
|
|||||||
return acceptMatrixTemplateType(type);
|
return acceptMatrixTemplateType(type);
|
||||||
break;
|
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 EHTokSampler: // fall through
|
||||||
case EHTokSampler1d: // ...
|
case EHTokSampler1d: // ...
|
||||||
case EHTokSampler2d: // ...
|
case EHTokSampler2d: // ...
|
||||||
|
@ -72,9 +72,11 @@ namespace glslang {
|
|||||||
bool acceptQualifier(TQualifier&);
|
bool acceptQualifier(TQualifier&);
|
||||||
bool acceptLayoutQualifierList(TQualifier&);
|
bool acceptLayoutQualifierList(TQualifier&);
|
||||||
bool acceptType(TType&);
|
bool acceptType(TType&);
|
||||||
bool acceptTemplateType(TBasicType&);
|
bool acceptTemplateVecMatBasicType(TBasicType&);
|
||||||
bool acceptVectorTemplateType(TType&);
|
bool acceptVectorTemplateType(TType&);
|
||||||
bool acceptMatrixTemplateType(TType&);
|
bool acceptMatrixTemplateType(TType&);
|
||||||
|
bool acceptStreamOutTemplateType(TType&, TLayoutGeometry&);
|
||||||
|
bool acceptOutputPrimitiveGeometry(TLayoutGeometry&);
|
||||||
bool acceptAnnotations(TQualifier&);
|
bool acceptAnnotations(TQualifier&);
|
||||||
bool acceptSamplerType(TType&);
|
bool acceptSamplerType(TType&);
|
||||||
bool acceptTextureType(TType&);
|
bool acceptTextureType(TType&);
|
||||||
|
@ -758,6 +758,13 @@ TIntermTyped* HlslParseContext::handleDotDereference(const TSourceLoc& loc, TInt
|
|||||||
return intermediate.addMethod(base, TType(sampler.type, EvqTemporary, vecSize), &field, loc);
|
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.
|
// It's not .length() if we get to here.
|
||||||
@ -1137,12 +1144,19 @@ TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& l
|
|||||||
postMainReturn = false;
|
postMainReturn = false;
|
||||||
|
|
||||||
// Handle function attributes
|
// Handle function attributes
|
||||||
const TIntermAggregate* numThreadliterals = attributes[EatNumthreads];
|
if (inEntryPoint) {
|
||||||
if (numThreadliterals != nullptr && inEntryPoint) {
|
const TIntermAggregate* numThreads = attributes[EatNumThreads];
|
||||||
const TIntermSequence& sequence = numThreadliterals->getSequence();
|
if (numThreads != nullptr) {
|
||||||
|
const TIntermSequence& sequence = numThreads->getSequence();
|
||||||
|
|
||||||
for (int lid = 0; lid < int(sequence.size()); ++lid)
|
for (int lid = 0; lid < int(sequence.size()); ++lid)
|
||||||
intermediate.setLocalSize(lid, sequence[lid]->getAsConstantUnion()->getConstArray()[0].getIConst());
|
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;
|
return paramNodes;
|
||||||
@ -2063,6 +2077,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.
|
// Optionally decompose intrinsics to AST opcodes.
|
||||||
//
|
//
|
||||||
@ -2546,8 +2609,9 @@ TIntermTyped* HlslParseContext::handleFunctionCall(const TSourceLoc& loc, TFunct
|
|||||||
result = addOutputArgumentConversions(*fnCandidate, *result->getAsAggregate());
|
result = addOutputArgumentConversions(*fnCandidate, *result->getAsAggregate());
|
||||||
}
|
}
|
||||||
|
|
||||||
decomposeIntrinsic(loc, result, arguments); // HLSL->AST intrinsic decompositions
|
decomposeIntrinsic(loc, result, arguments); // HLSL->AST intrinsic decompositions
|
||||||
decomposeSampleMethods(loc, result, arguments); // HLSL->AST sample method 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;
|
TVector<const TFunction*> candidateList;
|
||||||
symbolTable.findFunctionNameList(call.getMangledName(), candidateList, builtIn);
|
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'?
|
// can 'from' convert to 'to'?
|
||||||
const auto convertible = [this](const TType& from, const TType& to) -> bool {
|
const auto convertible = [this](const TType& from, const TType& to) -> bool {
|
||||||
if (from == to)
|
if (from == to)
|
||||||
@ -5202,6 +5274,53 @@ void HlslParseContext::addQualifierToExisting(const TSourceLoc& loc, TQualifier
|
|||||||
addQualifierToExisting(loc, qualifier, *identifiers[i]);
|
addQualifierToExisting(loc, qualifier, *identifiers[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// 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,
|
// Updating default qualifier for the case of a declaration with just a qualifier,
|
||||||
// no type, block, or identifier.
|
// 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), "");
|
error(loc, "cannot apply to input", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), "");
|
||||||
}
|
}
|
||||||
} else if (publicType.qualifier.storage == EvqVaryingOut) {
|
} else if (publicType.qualifier.storage == EvqVaryingOut) {
|
||||||
switch (publicType.shaderQualifiers.geometry) {
|
handleOutputGeometry(loc, 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), "");
|
|
||||||
}
|
|
||||||
} else
|
} else
|
||||||
error(loc, "cannot apply to:", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), GetStorageQualifierString(publicType.qualifier.storage));
|
error(loc, "cannot apply to:", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), GetStorageQualifierString(publicType.qualifier.storage));
|
||||||
}
|
}
|
||||||
|
@ -81,6 +81,7 @@ public:
|
|||||||
TIntermTyped* handleFunctionCall(const TSourceLoc&, TFunction*, TIntermNode*);
|
TIntermTyped* handleFunctionCall(const TSourceLoc&, TFunction*, TIntermNode*);
|
||||||
void decomposeIntrinsic(const TSourceLoc&, TIntermTyped*& node, TIntermNode* arguments);
|
void decomposeIntrinsic(const TSourceLoc&, TIntermTyped*& node, TIntermNode* arguments);
|
||||||
void decomposeSampleMethods(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*);
|
TIntermTyped* handleLengthMethod(const TSourceLoc&, TFunction*, TIntermNode*);
|
||||||
void addInputArgumentConversions(const TFunction&, TIntermNode*&) const;
|
void addInputArgumentConversions(const TFunction&, TIntermNode*&) const;
|
||||||
TIntermTyped* addOutputArgumentConversions(const TFunction&, TIntermAggregate&);
|
TIntermTyped* addOutputArgumentConversions(const TFunction&, TIntermAggregate&);
|
||||||
@ -160,6 +161,9 @@ public:
|
|||||||
|
|
||||||
TLayoutFormat getLayoutFromTxType(const TSourceLoc&, const TType&);
|
TLayoutFormat getLayoutFromTxType(const TSourceLoc&, const TType&);
|
||||||
|
|
||||||
|
bool handleOutputGeometry(const TSourceLoc&, const TLayoutGeometry& geometry);
|
||||||
|
bool handleInputGeometry(const TSourceLoc&, const TLayoutGeometry& geometry);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void inheritGlobalDefaults(TQualifier& dst) const;
|
void inheritGlobalDefaults(TQualifier& dst) const;
|
||||||
TVariable* makeInternalVariable(const char* name, const TType&) const;
|
TVariable* makeInternalVariable(const char* name, const TType&) const;
|
||||||
|
@ -502,6 +502,7 @@ void TBuiltInParseablesHlsl::initialize(int /*version*/, EProfile /*profile*/, c
|
|||||||
static const EShLanguageMask EShLangCS = EShLangAll;
|
static const EShLanguageMask EShLangCS = EShLangAll;
|
||||||
static const EShLanguageMask EShLangPS = EShLangAll;
|
static const EShLanguageMask EShLangPS = EShLangAll;
|
||||||
static const EShLanguageMask EShLangHS = EShLangAll;
|
static const EShLanguageMask EShLangHS = EShLangAll;
|
||||||
|
static const EShLanguageMask EShLangGS = EShLangAll;
|
||||||
|
|
||||||
// This structure encodes the prototype information for each HLSL intrinsic.
|
// This structure encodes the prototype information for each HLSL intrinsic.
|
||||||
// Because explicit enumeration would be cumbersome, it's procedurally generated.
|
// 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 */ "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 },
|
{ "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.
|
// 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 },
|
{ nullptr, nullptr, nullptr, nullptr, nullptr, 0 },
|
||||||
};
|
};
|
||||||
@ -1140,6 +1145,10 @@ void TBuiltInParseablesHlsl::identifyBuiltIns(int /*version*/, EProfile /*profil
|
|||||||
symbolTable.relateToOperator("GatherCmpGreen", EOpMethodGatherCmpGreen);
|
symbolTable.relateToOperator("GatherCmpGreen", EOpMethodGatherCmpGreen);
|
||||||
symbolTable.relateToOperator("GatherCmpBlue", EOpMethodGatherCmpBlue);
|
symbolTable.relateToOperator("GatherCmpBlue", EOpMethodGatherCmpBlue);
|
||||||
symbolTable.relateToOperator("GatherCmpAlpha", EOpMethodGatherCmpAlpha);
|
symbolTable.relateToOperator("GatherCmpAlpha", EOpMethodGatherCmpAlpha);
|
||||||
|
|
||||||
|
// GS methods
|
||||||
|
symbolTable.relateToOperator("Append", EOpMethodAppend);
|
||||||
|
symbolTable.relateToOperator("RestartStrip", EOpMethodRestartStrip);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -119,6 +119,16 @@ void HlslScanContext::fillInKeywordMap()
|
|||||||
(*KeywordMap)["inout"] = EHTokInOut;
|
(*KeywordMap)["inout"] = EHTokInOut;
|
||||||
(*KeywordMap)["layout"] = EHTokLayout;
|
(*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)["Buffer"] = EHTokBuffer;
|
||||||
(*KeywordMap)["vector"] = EHTokVector;
|
(*KeywordMap)["vector"] = EHTokVector;
|
||||||
(*KeywordMap)["matrix"] = EHTokMatrix;
|
(*KeywordMap)["matrix"] = EHTokMatrix;
|
||||||
@ -496,7 +506,20 @@ EHlslTokenClass HlslScanContext::tokenizeIdentifier()
|
|||||||
case EHTokLayout:
|
case EHTokLayout:
|
||||||
return keyword;
|
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 EHTokBuffer:
|
||||||
case EHTokVector:
|
case EHTokVector:
|
||||||
case EHTokMatrix:
|
case EHTokMatrix:
|
||||||
|
@ -66,6 +66,18 @@ enum EHlslTokenClass {
|
|||||||
EHTokInOut,
|
EHTokInOut,
|
||||||
EHTokLayout,
|
EHTokLayout,
|
||||||
|
|
||||||
|
// primitive types
|
||||||
|
EHTokPoint,
|
||||||
|
EHTokLine,
|
||||||
|
EHTokTriangle,
|
||||||
|
EHTokLineAdj,
|
||||||
|
EHTokTriangleAdj,
|
||||||
|
|
||||||
|
// stream out types
|
||||||
|
EHTokPointStream,
|
||||||
|
EHTokLineStream,
|
||||||
|
EHTokTriangleStream,
|
||||||
|
|
||||||
// template types
|
// template types
|
||||||
EHTokBuffer,
|
EHTokBuffer,
|
||||||
EHTokVector,
|
EHTokVector,
|
||||||
|
Loading…
Reference in New Issue
Block a user