summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Foley <tfoleyNV@users.noreply.github.com>2017-11-29 11:45:15 -0800
committerGitHub <noreply@github.com>2017-11-29 11:45:15 -0800
commitb487516880f56fd69ff76bf7cb3f0f1711bc356d (patch)
tree0f1464a22ac7f52053ab4f8f768967c1383c597c
parent713938038a87b9e4a69f198f09f1bf231be6f72f (diff)
Add API to query stage of varying parameter (#302)
Fixes #301 The problem here is that if you have input GLSL code like: ```glsl // example.vs in vec3 pos; ``` and: ```glsl // example.fs in vec3 worldPos; ``` Then both `pos` and `worldPos` are reflected as global variables (parameters of the *program*), which both get bound to "varying input" resources, but there is no way to tell through the API that `pos` is a vertex parameter while `worldPos` is a fragment one. The original request in issue #301 was to expose parameters like this not as a global variables, but rather as parameters of the entry point in their specific file. That is, treat it as if the user had written, e.g.: ```glsl // example.vs void vsMain(in vec3 pos) { ... } ``` Doing that would unify the GLSL and HLSL/Slang cases a bit, but would require the Slang reflection API to lie about the structure of code the user wrote. At a more basic level, that would have been hard to implement because the current reflection API just exposes the underlying AST, and the AST *needs* to leave `pos` at the global scope so that when we go and spit GLSL back out we retain the original structure. This PR implements a more simplistic solution, where the user is allowed to query the stage that a varying parameter "belongs" to. For right now I'm only enabling this to work for varying parameters (but it doesn't care if they are entry-point or global-scope varyings). Despite what I said on #301, this should work for both the top-level parameter's variable layout, *and* any variable layouts for fields within its type reflection. In terms of implementation, I took the simple but wasteful route: every `VarLayout` now has a `stage` field that is by default initialized to `SLANG_STAGE_NONE`. When collecting varying parameters, I take advantage of the fact that everything bottlenecks through `processEntryPointParameter()` which takes an `EntryPointParameterState` so that I can set the `VarLayout::stage` field for any varying parameter in one place. While I was making this change, I also did a bit of cleanup so that the "official" names for the varying parameter categories are `VARYING_INPUT` and `VARYING_OUTPUT`, with `VERTEX_INPUT` and `FRAGMENT_OUTPUT` being "deprecated" in principle. I didn't do the bulk rename inside the codebase yet.
-rw-r--r--slang.h33
-rw-r--r--source/slang/ast-legalize.cpp1
-rw-r--r--source/slang/ir-legalize-types.cpp2
-rw-r--r--source/slang/parameter-binding.cpp10
-rw-r--r--source/slang/reflection.cpp30
-rw-r--r--source/slang/type-layout.h6
-rw-r--r--tests/reflection/sample-rate-input.glsl.expected6
-rw-r--r--tests/reflection/vertex-input-semantics.hlsl.expected33
-rw-r--r--tools/slang-reflection-test/main.cpp26
9 files changed, 127 insertions, 20 deletions
diff --git a/slang.h b/slang.h
index 82e0aab22..9d0e5fb27 100644
--- a/slang.h
+++ b/slang.h
@@ -589,8 +589,8 @@ extern "C"
SLANG_PARAMETER_CATEGORY_CONSTANT_BUFFER,
SLANG_PARAMETER_CATEGORY_SHADER_RESOURCE,
SLANG_PARAMETER_CATEGORY_UNORDERED_ACCESS,
- SLANG_PARAMETER_CATEGORY_VERTEX_INPUT,
- SLANG_PARAMETER_CATEGORY_FRAGMENT_OUTPUT,
+ SLANG_PARAMETER_CATEGORY_VARYING_INPUT,
+ SLANG_PARAMETER_CATEGORY_VARYING_OUTPUT,
SLANG_PARAMETER_CATEGORY_SAMPLER_STATE,
SLANG_PARAMETER_CATEGORY_UNIFORM,
SLANG_PARAMETER_CATEGORY_DESCRIPTOR_TABLE_SLOT,
@@ -605,6 +605,11 @@ extern "C"
//
SLANG_PARAMETER_CATEGORY_COUNT,
+
+
+ // DEPRECATED:
+ SLANG_PARAMETER_CATEGORY_VERTEX_INPUT = SLANG_PARAMETER_CATEGORY_VARYING_INPUT,
+ SLANG_PARAMETER_CATEGORY_FRAGMENT_OUTPUT = SLANG_PARAMETER_CATEGORY_VARYING_OUTPUT,
};
typedef SlangUInt32 SlangStage;
@@ -618,6 +623,7 @@ extern "C"
SLANG_STAGE_FRAGMENT,
SLANG_STAGE_COMPUTE,
+ // alias:
SLANG_STAGE_PIXEL = SLANG_STAGE_FRAGMENT,
};
@@ -672,6 +678,16 @@ extern "C"
SLANG_API char const* spReflectionVariableLayout_GetSemanticName(SlangReflectionVariableLayout* var);
SLANG_API size_t spReflectionVariableLayout_GetSemanticIndex(SlangReflectionVariableLayout* var);
+ /** Get the stage that a variable belongs to (if any).
+
+ A variable "belongs" to a specific stage when it is a varying input/output
+ parameter either defined as part of the parameter list for an entry
+ point *or* at the global scope of a stage-specific GLSL code file (e.g.,
+ an `in` parameter in a GLSL `.vs` file belongs to the vertex stage).
+ */
+ SLANG_API SlangStage spReflectionVariableLayout_getStage(
+ SlangReflectionVariableLayout* var);
+
// Shader Parameter Reflection
typedef SlangReflectionVariableLayout SlangReflectionParameter;
@@ -857,8 +873,8 @@ namespace slang
ConstantBuffer = SLANG_PARAMETER_CATEGORY_CONSTANT_BUFFER,
ShaderResource = SLANG_PARAMETER_CATEGORY_SHADER_RESOURCE,
UnorderedAccess = SLANG_PARAMETER_CATEGORY_UNORDERED_ACCESS,
- VertexInput = SLANG_PARAMETER_CATEGORY_VERTEX_INPUT,
- FragmentOutput = SLANG_PARAMETER_CATEGORY_FRAGMENT_OUTPUT,
+ VaryingInput = SLANG_PARAMETER_CATEGORY_VARYING_INPUT,
+ VaryingOutput = SLANG_PARAMETER_CATEGORY_VARYING_OUTPUT,
SamplerState = SLANG_PARAMETER_CATEGORY_SAMPLER_STATE,
Uniform = SLANG_PARAMETER_CATEGORY_UNIFORM,
DescriptorTableSlot = SLANG_PARAMETER_CATEGORY_DESCRIPTOR_TABLE_SLOT,
@@ -866,6 +882,10 @@ namespace slang
PushConstantBuffer = SLANG_PARAMETER_CATEGORY_PUSH_CONSTANT_BUFFER,
RegisterSpace = SLANG_PARAMETER_CATEGORY_REGISTER_SPACE,
GenericResource = SLANG_PARAMETER_CATEGORY_GENERIC,
+
+ // DEPRECATED:
+ VertexInput = SLANG_PARAMETER_CATEGORY_VERTEX_INPUT,
+ FragmentOutput = SLANG_PARAMETER_CATEGORY_FRAGMENT_OUTPUT,
};
struct TypeLayoutReflection
@@ -1057,6 +1077,11 @@ namespace slang
{
return spReflectionVariableLayout_GetSemanticIndex((SlangReflectionVariableLayout*) this);
}
+
+ SlangStage getStage()
+ {
+ return spReflectionVariableLayout_getStage((SlangReflectionVariableLayout*) this);
+ }
};
struct EntryPointReflection
diff --git a/source/slang/ast-legalize.cpp b/source/slang/ast-legalize.cpp
index afc8b31c8..1b045cbc9 100644
--- a/source/slang/ast-legalize.cpp
+++ b/source/slang/ast-legalize.cpp
@@ -3309,6 +3309,7 @@ struct LoweringVisitor
RefPtr<VarLayout> newFieldLayout = new VarLayout();
newFieldLayout->typeLayout = fieldLayout->typeLayout;
newFieldLayout->flags = fieldLayout->flags;
+ newFieldLayout->stage = fieldLayout->stage;
newFieldLayout->varDecl = fieldLayout->varDecl;
newFieldLayout->systemValueSemantic = fieldLayout->systemValueSemantic;
newFieldLayout->systemValueSemanticIndex = fieldLayout->systemValueSemanticIndex;
diff --git a/source/slang/ir-legalize-types.cpp b/source/slang/ir-legalize-types.cpp
index 37df5f698..7fad2ccc5 100644
--- a/source/slang/ir-legalize-types.cpp
+++ b/source/slang/ir-legalize-types.cpp
@@ -1620,6 +1620,8 @@ static LegalVal declareSimpleVar(
// well as all the offset information that has accumulated
// along the chain of parent variables.
+ // TODO: this logic needs to propagate through semantics...
+
varLayout = new VarLayout();
varLayout->typeLayout = typeLayout;
diff --git a/source/slang/parameter-binding.cpp b/source/slang/parameter-binding.cpp
index b97c174fc..66f7d437c 100644
--- a/source/slang/parameter-binding.cpp
+++ b/source/slang/parameter-binding.cpp
@@ -627,6 +627,7 @@ struct EntryPointParameterState
int* ioSemanticIndex = nullptr;
EntryPointParameterDirectionMask directionMask;
int semanticSlotCount;
+ Stage stage = Stage::Unknown;
};
@@ -639,7 +640,7 @@ static RefPtr<TypeLayout> processEntryPointParameter(
static void collectGlobalScopeGLSLVaryingParameter(
ParameterBindingContext* context,
RefPtr<VarDeclBase> varDecl,
- RefPtr<Type> effectiveType,
+ RefPtr<Type> effectiveType,
EntryPointParameterDirection direction)
{
int defaultSemanticIndex = 0;
@@ -647,6 +648,7 @@ static void collectGlobalScopeGLSLVaryingParameter(
EntryPointParameterState state;
state.directionMask = direction;
state.ioSemanticIndex = &defaultSemanticIndex;
+ state.stage = context->stage;
RefPtr<VarLayout> varLayout = new VarLayout();
varLayout->varDecl = makeDeclRef(varDecl.Ptr());
@@ -1333,6 +1335,10 @@ static RefPtr<TypeLayout> processEntryPointParameter(
varLayout->flags |= VarLayoutFlag::HasSemantic;
}
+ if (varLayout)
+ {
+ varLayout->stage = state.stage;
+ }
// Scalar and vector types are treated as outputs directly
if(auto basicType = type->As<BasicExpressionType>())
@@ -1485,6 +1491,7 @@ static void collectEntryPointParameters(
state.ioSemanticIndex = &defaultSemanticIndex;
state.optSemanticName = nullptr;
state.semanticSlotCount = 0;
+ state.stage = entryPoint->profile.GetStage();
for( auto m : entryPointFuncDecl->Members )
{
@@ -2020,6 +2027,7 @@ RefPtr<ProgramLayout> specializeProgramLayout(
RefPtr<VarLayout> newVarLayout = new VarLayout();
RefPtr<ParameterInfo> paramInfo = new ParameterInfo();
newVarLayout->varDecl = varLayout->varDecl;
+ newVarLayout->stage = varLayout->stage;
newVarLayout->typeLayout = newTypeLayout;
paramInfo->varLayouts.Add(newVarLayout);
completeBindingsForParameter(&context, paramInfo);
diff --git a/source/slang/reflection.cpp b/source/slang/reflection.cpp
index 14199f126..a1ea3ff72 100644
--- a/source/slang/reflection.cpp
+++ b/source/slang/reflection.cpp
@@ -666,6 +666,36 @@ SLANG_API size_t spReflectionVariableLayout_GetSemanticIndex(SlangReflectionVari
return varLayout->semanticIndex;
}
+SLANG_API SlangStage spReflectionVariableLayout_getStage(
+ SlangReflectionVariableLayout* inVarLayout)
+{
+ auto varLayout = convert(inVarLayout);
+ if(!varLayout) return SLANG_STAGE_NONE;
+
+ // A parameter that is not a varying input or output is
+ // not considered to belong to a single stage.
+ //
+ // TODO: We might need to reconsider this for, e.g., entry
+ // point parameters, where they might be stage-specific even
+ // if they are uniform.
+ if (!varLayout->FindResourceInfo(Slang::LayoutResourceKind::VaryingInput)
+ && !varLayout->FindResourceInfo(Slang::LayoutResourceKind::VaryingOutput))
+ {
+ return SLANG_STAGE_NONE;
+ }
+
+ // TODO: We should find the stage for a variable layout by
+ // walking up the tree of layout information, until we find
+ // something that has a definitive stage attached to it (e.g.,
+ // either an entry point or a GLSL translation unit).
+ //
+ // We don't currently have parent links in the reflection layout
+ // information, so doing that walk would be tricky right now, so
+ // it is easier to just bloat the representation and store yet another
+ // field on every variable layout.
+ return (SlangStage) varLayout->stage;
+}
+
// Shader Parameter Reflection
diff --git a/source/slang/type-layout.h b/source/slang/type-layout.h
index 07530bdfc..66763c8a7 100644
--- a/source/slang/type-layout.h
+++ b/source/slang/type-layout.h
@@ -251,6 +251,12 @@ public:
String semanticName;
int semanticIndex;
+ // The stage this variable belongs to, in case it is
+ // stage-specific.
+ // TODO: This is wasteful to be storing on every single
+ // variable layout.
+ Stage stage = Stage::Unknown;
+
// The start register(s) for any resources
struct ResourceInfo
{
diff --git a/tests/reflection/sample-rate-input.glsl.expected b/tests/reflection/sample-rate-input.glsl.expected
index 5800a3630..53e0b6e17 100644
--- a/tests/reflection/sample-rate-input.glsl.expected
+++ b/tests/reflection/sample-rate-input.glsl.expected
@@ -21,7 +21,8 @@ standard output = {
},
{
"name": "uv",
- "binding": {"kind": "vertexInput", "index": 0},
+ "stage": "fragment",
+ "binding": {"kind": "varyingInput", "index": 0},
"type": {
"kind": "vector",
"elementCount": 2,
@@ -33,7 +34,8 @@ standard output = {
},
{
"name": "c",
- "binding": {"kind": "fragmentOutput", "index": 0},
+ "stage": "fragment",
+ "binding": {"kind": "varyingOutput", "index": 0},
"type": {
"kind": "vector",
"elementCount": 4,
diff --git a/tests/reflection/vertex-input-semantics.hlsl.expected b/tests/reflection/vertex-input-semantics.hlsl.expected
index a3747a86a..06b7bc95a 100644
--- a/tests/reflection/vertex-input-semantics.hlsl.expected
+++ b/tests/reflection/vertex-input-semantics.hlsl.expected
@@ -13,7 +13,8 @@ standard output = {
"parameters": [
{
"name": "a",
- "binding": {"kind": "vertexInput", "index": 0},
+ "stage": "vertex",
+ "binding": {"kind": "varyingInput", "index": 0},
"semanticName": "A",
"type": {
"kind": "vector",
@@ -26,7 +27,8 @@ standard output = {
},
{
"name": "b",
- "binding": {"kind": "vertexInput", "index": 1, "count": 3},
+ "stage": "vertex",
+ "binding": {"kind": "varyingInput", "index": 1, "count": 3},
"semanticName": "B",
"type": {
"kind": "struct",
@@ -42,7 +44,8 @@ standard output = {
"scalarType": "int32"
}
},
- "binding": {"kind": "vertexInput", "index": 0},
+ "stage": "vertex",
+ "binding": {"kind": "varyingInput", "index": 0},
"semanticName": "B"
},
{
@@ -61,7 +64,8 @@ standard output = {
"scalarType": "float32"
}
},
- "binding": {"kind": "vertexInput", "index": 0},
+ "stage": "vertex",
+ "binding": {"kind": "varyingInput", "index": 0},
"semanticName": "B",
"semanticIndex": 1
},
@@ -75,13 +79,15 @@ standard output = {
"scalarType": "float32"
}
},
- "binding": {"kind": "vertexInput", "index": 1},
+ "stage": "vertex",
+ "binding": {"kind": "varyingInput", "index": 1},
"semanticName": "B",
"semanticIndex": 2
}
]
},
- "binding": {"kind": "vertexInput", "index": 1, "count": 2},
+ "stage": "vertex",
+ "binding": {"kind": "varyingInput", "index": 1, "count": 2},
"semanticName": "B",
"semanticIndex": 1
}
@@ -90,7 +96,8 @@ standard output = {
},
{
"name": "c",
- "binding": {"kind": "vertexInput", "index": 4, "count": 3},
+ "stage": "vertex",
+ "binding": {"kind": "varyingInput", "index": 4, "count": 3},
"type": {
"kind": "struct",
"name": "C",
@@ -111,7 +118,8 @@ standard output = {
"scalarType": "float32"
}
},
- "binding": {"kind": "vertexInput", "index": 0},
+ "stage": "vertex",
+ "binding": {"kind": "varyingInput", "index": 0},
"semanticName": "CX"
},
{
@@ -124,13 +132,15 @@ standard output = {
"scalarType": "float32"
}
},
- "binding": {"kind": "vertexInput", "index": 1},
+ "stage": "vertex",
+ "binding": {"kind": "varyingInput", "index": 1},
"semanticName": "CX",
"semanticIndex": 1
}
]
},
- "binding": {"kind": "vertexInput", "index": 0, "count": 2},
+ "stage": "vertex",
+ "binding": {"kind": "varyingInput", "index": 0, "count": 2},
"semanticName": "CX"
},
{
@@ -143,7 +153,8 @@ standard output = {
"scalarType": "int32"
}
},
- "binding": {"kind": "vertexInput", "index": 2},
+ "stage": "vertex",
+ "binding": {"kind": "varyingInput", "index": 2},
"semanticName": "CY"
}
]
diff --git a/tools/slang-reflection-test/main.cpp b/tools/slang-reflection-test/main.cpp
index b0d970ba3..219acbc76 100644
--- a/tools/slang-reflection-test/main.cpp
+++ b/tools/slang-reflection-test/main.cpp
@@ -109,8 +109,8 @@ static void emitReflectionVarBindingInfoJSON(
CASE(CONSTANT_BUFFER, constantBuffer);
CASE(SHADER_RESOURCE, shaderResource);
CASE(UNORDERED_ACCESS, unorderedAccess);
- CASE(VERTEX_INPUT, vertexInput);
- CASE(FRAGMENT_OUTPUT, fragmentOutput);
+ CASE(VARYING_INPUT, varyingInput);
+ CASE(VARYING_OUTPUT, varyingOutput);
CASE(SAMPLER_STATE, samplerState);
CASE(UNIFORM, uniform);
CASE(DESCRIPTOR_TABLE_SLOT, descriptorTableSlot);
@@ -146,6 +146,28 @@ static void emitReflectionVarBindingInfoJSON(
PrettyWriter& writer,
slang::VariableLayoutReflection* var)
{
+ auto stage = var->getStage();
+ if (stage != SLANG_STAGE_NONE)
+ {
+ char const* stageName = "UNKNOWN";
+ switch (stage)
+ {
+ case SLANG_STAGE_VERTEX: stageName = "vertex"; break;
+ case SLANG_STAGE_HULL: stageName = "hull"; break;
+ case SLANG_STAGE_DOMAIN: stageName = "domain"; break;
+ case SLANG_STAGE_GEOMETRY: stageName = "geometry"; break;
+ case SLANG_STAGE_FRAGMENT: stageName = "fragment"; break;
+ case SLANG_STAGE_COMPUTE: stageName = "compute"; break;
+
+ default:
+ break;
+ }
+
+ write(writer, "\"stage\": \"");
+ write(writer, stageName);
+ write(writer, "\",\n");
+ }
+
auto typeLayout = var->getTypeLayout();
auto categoryCount = var->getCategoryCount();