Commit e741249b by steve-lunarg

HLSL: pass tessellation execution modes through to SPIR-V

The SPIR-V generator had assumed tessellation modes such as primitive type and vertex order would only appear in tess eval (domain) shaders. SPIR-V allows either, and HLSL allows and possibly requires them to be in the hull shader. This change: 1. Passes them through for either tessellation stage, and, 2. Does not set up defaults in the domain stage for HLSl compilation, to avoid conflicting definitions.
parent e752f463
......@@ -869,14 +869,20 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* gls
builder.addCapability(spv::CapabilityShader);
break;
case EShLangTessEvaluation:
case EShLangTessControl:
builder.addCapability(spv::CapabilityTessellation);
builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices());
break;
case EShLangTessEvaluation:
builder.addCapability(spv::CapabilityTessellation);
switch (glslangIntermediate->getInputPrimitive()) {
glslang::TLayoutGeometry primitive;
if (glslangIntermediate->getStage() == EShLangTessControl) {
builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices());
primitive = glslangIntermediate->getOutputPrimitive();
} else {
primitive = glslangIntermediate->getInputPrimitive();
}
switch (primitive) {
case glslang::ElgTriangles: mode = spv::ExecutionModeTriangles; break;
case glslang::ElgQuads: mode = spv::ExecutionModeQuads; break;
case glslang::ElgIsolines: mode = spv::ExecutionModeIsolines; break;
......
hlsl.hull.1.tesc
Shader version: 450
vertices = 4
vertex spacing = equal_spacing
0:? Sequence
0:26 Function Definition: @main(struct-VS_OUT-vf31[4];u1; ( temp structure{ temp 3-component vector of float cpoint})
0:26 Function Parameters:
......@@ -115,6 +116,7 @@ Linked tessellation control stage:
Shader version: 450
vertices = 4
vertex spacing = equal_spacing
0:? Sequence
0:26 Function Definition: @main(struct-VS_OUT-vf31[4];u1; ( temp structure{ temp 3-component vector of float cpoint})
0:26 Function Parameters:
......@@ -232,6 +234,8 @@ vertices = 4
MemoryModel Logical GLSL450
EntryPoint TessellationControl 4 "main" 40 44 48 66 72 92
ExecutionMode 4 OutputVertices 4
ExecutionMode 4 Isolines
ExecutionMode 4 SpacingEqual
Name 4 "main"
Name 8 "VS_OUT"
MemberName 8(VS_OUT) 0 "cpoint"
......
hlsl.hull.2.tesc
Shader version: 450
vertices = 4
vertex spacing = equal_spacing
0:? Sequence
0:26 Function Definition: @main(struct-VS_OUT-vf31[4]; ( temp structure{ temp 3-component vector of float cpoint})
0:26 Function Parameters:
......@@ -113,6 +114,7 @@ Linked tessellation control stage:
Shader version: 450
vertices = 4
vertex spacing = equal_spacing
0:? Sequence
0:26 Function Definition: @main(struct-VS_OUT-vf31[4]; ( temp structure{ temp 3-component vector of float cpoint})
0:26 Function Parameters:
......@@ -228,6 +230,8 @@ vertices = 4
MemoryModel Logical GLSL450
EntryPoint TessellationControl 4 "main" 42 46 48 64 66 74 94
ExecutionMode 4 OutputVertices 4
ExecutionMode 4 Isolines
ExecutionMode 4 SpacingEqual
Name 4 "main"
Name 8 "VS_OUT"
MemberName 8(VS_OUT) 0 "cpoint"
......
hlsl.hull.ctrlpt-1.tesc
Shader version: 450
vertices = 3
vertex spacing = fractional_odd_spacing
triangle order = cw
0:? Sequence
0:27 Function Definition: @main(struct-hs_in_t-vf31[3];u1; ( temp structure{ temp 3-component vector of float val})
0:27 Function Parameters:
......@@ -200,6 +202,8 @@ Linked tessellation control stage:
Shader version: 450
vertices = 3
vertex spacing = fractional_odd_spacing
triangle order = cw
0:? Sequence
0:27 Function Definition: @main(struct-hs_in_t-vf31[3];u1; ( temp structure{ temp 3-component vector of float val})
0:27 Function Parameters:
......@@ -402,6 +406,9 @@ vertices = 3
MemoryModel Logical GLSL450
EntryPoint TessellationControl 4 "main" 41 45 48 94 108 126
ExecutionMode 4 OutputVertices 3
ExecutionMode 4 Triangles
ExecutionMode 4 SpacingFractionalOdd
ExecutionMode 4 VertexOrderCw
Name 4 "main"
Name 8 "hs_in_t"
MemberName 8(hs_in_t) 0 "val"
......
hlsl.hull.void.tesc
Shader version: 450
vertices = 3
vertex spacing = fractional_even_spacing
0:? Sequence
0:26 Function Definition: @main(struct-VS_OUT-vf31[3]; ( temp structure{ temp 3-component vector of float cpoint})
0:26 Function Parameters:
......@@ -55,6 +56,7 @@ Linked tessellation control stage:
Shader version: 450
vertices = 3
vertex spacing = fractional_even_spacing
0:? Sequence
0:26 Function Definition: @main(struct-VS_OUT-vf31[3]; ( temp structure{ temp 3-component vector of float cpoint})
0:26 Function Parameters:
......@@ -112,6 +114,8 @@ vertices = 3
MemoryModel Logical GLSL450
EntryPoint TessellationControl 4 "main" 33 37 39
ExecutionMode 4 OutputVertices 3
ExecutionMode 4 Triangles
ExecutionMode 4 SpacingFractionalEven
Name 4 "main"
Name 8 "VS_OUT"
MemberName 8(VS_OUT) 0 "cpoint"
......
struct ds_in_t
{
float4 pos : POSITION;
float3 norm : TEXCOORD0;
};
struct pcf_in_t
{
float flTessFactor [3] : SV_TessFactor;
float flInsideTessFactor : SV_InsideTessFactor;
};
struct gs_in_t
{
float4 pos : POSITION;
float3 norm : TEXCOORD0;
};
[domain ( "tri" )]
gs_in_t main (const OutputPatch <ds_in_t, 3> i, float3 tesscoord : SV_DomainLocation, pcf_in_t pcf_data )
{
gs_in_t o;
o.pos = i[0].pos + tesscoord.x;
o.norm = i[0].norm + tesscoord.y;
tesscoord.z;
return o;
}
......@@ -884,6 +884,13 @@ void TIntermediate::output(TInfoSink& infoSink, bool tree)
case EShLangTessControl:
infoSink.debug << "vertices = " << vertices << "\n";
if (inputPrimitive != ElgNone)
infoSink.debug << "input primitive = " << TQualifier::getGeometryString(inputPrimitive) << "\n";
if (vertexSpacing != EvsNone)
infoSink.debug << "vertex spacing = " << TQualifier::getVertexSpacingString(vertexSpacing) << "\n";
if (vertexOrder != EvoNone)
infoSink.debug << "triangle order = " << TQualifier::getVertexOrderString(vertexOrder) << "\n";
break;
case EShLangTessEvaluation:
......
......@@ -461,10 +461,12 @@ void TIntermediate::finalCheck(TInfoSink& infoSink, bool keepUncalled)
case EShLangTessEvaluation:
if (inputPrimitive == ElgNone)
error(infoSink, "At least one shader must specify an input layout primitive");
if (vertexSpacing == EvsNone)
vertexSpacing = EvsEqual;
if (vertexOrder == EvoNone)
vertexOrder = EvoCcw;
if (source == EShSourceGlsl) {
if (vertexSpacing == EvsNone)
vertexSpacing = EvsEqual;
if (vertexOrder == EvoNone)
vertexOrder = EvoCcw;
}
break;
case EShLangGeometry:
if (inputPrimitive == ElgNone)
......
......@@ -122,6 +122,7 @@ INSTANTIATE_TEST_CASE_P(
{"hlsl.getdimensions.rw.dx10.frag", "main"},
{"hlsl.getdimensions.dx10.vert", "main"},
{"hlsl.getsampleposition.dx10.frag", "main"},
{"hlsl.domain.1.tese", "main"},
{"hlsl.hull.1.tesc", "main"},
{"hlsl.hull.2.tesc", "main"},
{"hlsl.hull.void.tesc", "main"},
......
......@@ -1386,7 +1386,7 @@ void HlslParseContext::trackLinkage(TSymbol& symbol)
// Some types require fixed array sizes in SPIR-V, but can be scalars or
// arrays of sizes SPIR-V doesn't allow. For example, tessellation factors.
// This creates the right size. A conversion is performed when the internal
// type is copied to or from the external
// type is copied to or from the external type.
void HlslParseContext::fixBuiltInArrayType(TType& type)
{
int requiredSize = 0;
......@@ -1600,7 +1600,7 @@ TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& l
// Handle all [attrib] attribute for the shader entry point
void HlslParseContext::handleEntryPointAttributes(const TSourceLoc& loc, TFunction& userFunction, const TAttributeMap& attributes)
void HlslParseContext::handleEntryPointAttributes(const TSourceLoc& loc, const TAttributeMap& attributes)
{
// Handle entry-point function attributes
const TIntermAggregate* numThreads = attributes[EatNumThreads];
......@@ -1779,7 +1779,7 @@ TIntermNode* HlslParseContext::transformEntryPoint(const TSourceLoc& loc, TFunct
entryPointFunction = &userFunction; // needed in finish()
// Handle entry point attributes
handleEntryPointAttributes(loc, userFunction, attributes);
handleEntryPointAttributes(loc, attributes);
// entry point logic...
......@@ -1853,6 +1853,9 @@ TIntermNode* HlslParseContext::transformEntryPoint(const TSourceLoc& loc, TFunct
if (entryPointOutput) {
TIntermTyped* returnAssign;
// For hull shaders, the wrapped entry point return value is written to
// an array element as indexed by invocation ID, which we might have to make up.
// This is required to match SPIR-V semantics.
if (language == EShLangTessControl) {
TIntermSymbol* invocationIdSym = findLinkageSymbol(EbvInvocationId);
......
......@@ -80,7 +80,7 @@ public:
void handleFunctionDeclarator(const TSourceLoc&, TFunction& function, bool prototype);
TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&, const TAttributeMap&, TIntermNode*& entryPointTree);
TIntermNode* transformEntryPoint(const TSourceLoc&, TFunction&, const TAttributeMap&);
void handleEntryPointAttributes(const TSourceLoc&, TFunction&, const TAttributeMap&);
void handleEntryPointAttributes(const TSourceLoc&, const TAttributeMap&);
void handleFunctionBody(const TSourceLoc&, TFunction&, TIntermNode* functionBody, TIntermNode*& node);
void remapEntryPointIO(TFunction& function, TVariable*& returnValue, TVector<TVariable*>& inputs, TVector<TVariable*>& outputs);
void remapNonEntryPointIO(TFunction& function);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment