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:
steve-lunarg 2016-11-17 15:04:20 -07:00
parent fabe7d6a61
commit f49cdf4183
13 changed files with 531 additions and 39 deletions

View 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
View 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();
}

View File

@ -621,6 +621,10 @@ enum TOperator {
EOpMethodGatherCmpGreen, // ... EOpMethodGatherCmpGreen, // ...
EOpMethodGatherCmpBlue, // ... EOpMethodGatherCmpBlue, // ...
EOpMethodGatherCmpAlpha, // ... EOpMethodGatherCmpAlpha, // ...
// geometry methods
EOpMethodAppend, // Geometry shader methods
EOpMethodRestartStrip, // ...
}; };
class TIntermTraverser; class TIntermTraverser;

View File

@ -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"},

View File

@ -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

View File

@ -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,
}; };
} }

View File

@ -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: // ...

View File

@ -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&);

View File

@ -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));
} }

View File

@ -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;

View File

@ -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);
} }
// //

View File

@ -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:

View File

@ -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,