diff options
| author | Tim Foley <tfoleyNV@users.noreply.github.com> | 2017-11-29 11:45:15 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-11-29 11:45:15 -0800 |
| commit | b487516880f56fd69ff76bf7cb3f0f1711bc356d (patch) | |
| tree | 0f1464a22ac7f52053ab4f8f768967c1383c597c | |
| parent | 713938038a87b9e4a69f198f09f1bf231be6f72f (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.h | 33 | ||||
| -rw-r--r-- | source/slang/ast-legalize.cpp | 1 | ||||
| -rw-r--r-- | source/slang/ir-legalize-types.cpp | 2 | ||||
| -rw-r--r-- | source/slang/parameter-binding.cpp | 10 | ||||
| -rw-r--r-- | source/slang/reflection.cpp | 30 | ||||
| -rw-r--r-- | source/slang/type-layout.h | 6 | ||||
| -rw-r--r-- | tests/reflection/sample-rate-input.glsl.expected | 6 | ||||
| -rw-r--r-- | tests/reflection/vertex-input-semantics.hlsl.expected | 33 | ||||
| -rw-r--r-- | tools/slang-reflection-test/main.cpp | 26 |
9 files changed, 127 insertions, 20 deletions
@@ -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(); |
