diff options
| author | Tim Foley <tfoleyNV@users.noreply.github.com> | 2017-10-19 11:49:16 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-10-19 11:49:16 -0700 |
| commit | 88023aea669f258d66e53eab10215337a7f72853 (patch) | |
| tree | 630d2f89a201283307ebc3ae1ccd3ce3d28876bb | |
| parent | 5995b7a47b2b65025410b9d558dfe1820e4c42e0 (diff) | |
Reflection: allow querying of semantics on varying input/output (#224)
This is functionality required to support a Falcor bug fix.
Most of the code to compute the right semantic name/index for a parameter was already present.
This change adds:
- Storage for semantic name/index on every `VarLayout`
- Note: this is wasteful and should be optimized later
- A public API to query the semantic name/index
- The contract is that this API returns `NULL` if the parameter had no semantic
- A bit of work in `parameter-binding.cpp` to attach semantics to varying input/output when traversing varying parameters.
- Note: this is intentionally set up so that it associates semantics even with non-leaf parameters, so that an API user can query the semantic of a `struct` parameter and know that its members will be assigned sequential semantic indices from its starting value.
- Support for dumping this information in reflection tests
One notable thing that I did *not* change here is that the reflection test fixture doesn't report information on the output of an entry point, even though it really should. That should be fixed in a separate change, though, because it would affect many of the expected outputs.
| -rw-r--r-- | slang.h | 13 | ||||
| -rw-r--r-- | source/slang/lower.cpp | 2 | ||||
| -rw-r--r-- | source/slang/parameter-binding.cpp | 21 | ||||
| -rw-r--r-- | source/slang/reflection.cpp | 22 | ||||
| -rw-r--r-- | source/slang/type-layout.h | 8 | ||||
| -rw-r--r-- | tests/reflection/thread-group-size.hlsl.expected | 1 | ||||
| -rw-r--r-- | tests/reflection/vertex-input-semantics.hlsl | 33 | ||||
| -rw-r--r-- | tests/reflection/vertex-input-semantics.hlsl.expected | 152 | ||||
| -rw-r--r-- | tools/slang-reflection-test/main.cpp | 15 |
9 files changed, 267 insertions, 0 deletions
@@ -627,6 +627,9 @@ extern "C" SLANG_API size_t spReflectionVariableLayout_GetOffset(SlangReflectionVariableLayout* var, SlangParameterCategory category); SLANG_API size_t spReflectionVariableLayout_GetSpace(SlangReflectionVariableLayout* var, SlangParameterCategory category); + SLANG_API char const* spReflectionVariableLayout_GetSemanticName(SlangReflectionVariableLayout* var); + SLANG_API size_t spReflectionVariableLayout_GetSemanticIndex(SlangReflectionVariableLayout* var); + // Shader Parameter Reflection typedef SlangReflectionVariableLayout SlangReflectionParameter; @@ -989,6 +992,16 @@ namespace slang { return spReflectionVariableLayout_GetSpace((SlangReflectionVariableLayout*) this, category); } + + char const* getSemanticName() + { + return spReflectionVariableLayout_GetSemanticName((SlangReflectionVariableLayout*) this); + } + + size_t getSemanticIndex() + { + return spReflectionVariableLayout_GetSemanticIndex((SlangReflectionVariableLayout*) this); + } }; struct EntryPointReflection diff --git a/source/slang/lower.cpp b/source/slang/lower.cpp index 5708bab64..94738307b 100644 --- a/source/slang/lower.cpp +++ b/source/slang/lower.cpp @@ -3183,6 +3183,8 @@ struct LoweringVisitor newFieldLayout->varDecl = fieldLayout->varDecl; newFieldLayout->systemValueSemantic = fieldLayout->systemValueSemantic; newFieldLayout->systemValueSemanticIndex = fieldLayout->systemValueSemanticIndex; + newFieldLayout->semanticName = fieldLayout->semanticName; + newFieldLayout->semanticIndex = fieldLayout->semanticIndex; for (auto resInfo : fieldLayout->resourceInfos) { diff --git a/source/slang/parameter-binding.cpp b/source/slang/parameter-binding.cpp index 4fbec5652..fed838e6b 100644 --- a/source/slang/parameter-binding.cpp +++ b/source/slang/parameter-binding.cpp @@ -1190,6 +1190,27 @@ static RefPtr<TypeLayout> processEntryPointParameter( EntryPointParameterState const& state, RefPtr<VarLayout> varLayout) { + // If there is an available semantic name and index, + // then we should apply it to this parameter unconditionally + // (that is, not just if it is a leaf parameter). + auto optSemanticName = state.optSemanticName; + if (optSemanticName && varLayout) + { + // Always store semantics in upper-case for + // reflection information, since they are + // supposed to be case-insensitive and + // upper-case is the dominant convention. + String semanticName = *optSemanticName; + String sn = semanticName.ToUpper(); + + auto semanticIndex = *state.ioSemanticIndex; + + varLayout->semanticName = sn; + varLayout->semanticIndex = semanticIndex; + varLayout->flags |= VarLayoutFlag::HasSemantic; + } + + // Scalar and vector types are treated as outputs directly if(auto basicType = type->As<BasicExpressionType>()) { diff --git a/source/slang/reflection.cpp b/source/slang/reflection.cpp index 435b4db3f..d7e8820c0 100644 --- a/source/slang/reflection.cpp +++ b/source/slang/reflection.cpp @@ -623,6 +623,28 @@ SLANG_API size_t spReflectionVariableLayout_GetSpace(SlangReflectionVariableLayo return info->space; } +SLANG_API char const* spReflectionVariableLayout_GetSemanticName(SlangReflectionVariableLayout* inVarLayout) +{ + auto varLayout = convert(inVarLayout); + if(!varLayout) return 0; + + if (!(varLayout->flags & Slang::VarLayoutFlag::HasSemantic)) + return 0; + + return varLayout->semanticName.Buffer(); +} + +SLANG_API size_t spReflectionVariableLayout_GetSemanticIndex(SlangReflectionVariableLayout* inVarLayout) +{ + auto varLayout = convert(inVarLayout); + if(!varLayout) return 0; + + if (!(varLayout->flags & Slang::VarLayoutFlag::HasSemantic)) + return 0; + + return varLayout->semanticIndex; +} + // Shader Parameter Reflection diff --git a/source/slang/type-layout.h b/source/slang/type-layout.h index 971088aac..d078d9554 100644 --- a/source/slang/type-layout.h +++ b/source/slang/type-layout.h @@ -218,6 +218,7 @@ typedef unsigned int VarLayoutFlags; enum VarLayoutFlag : VarLayoutFlags { IsRedeclaration = 1 << 0, ///< This is a redeclaration of some shader parameter + HasSemantic = 1 << 1, }; // A reified layout for a particular variable, field, etc. @@ -241,6 +242,13 @@ public: String systemValueSemantic; int systemValueSemanticIndex; + // General cse semantic name and index + // TODO: this and the system-value field are redundant + // TODO: the `VarLayout` type is getting bloated; we need to not store this + // information unless actually required. + String semanticName; + int semanticIndex; + // The start register(s) for any resources struct ResourceInfo { diff --git a/tests/reflection/thread-group-size.hlsl.expected b/tests/reflection/thread-group-size.hlsl.expected index d139c5b64..a41c66248 100644 --- a/tests/reflection/thread-group-size.hlsl.expected +++ b/tests/reflection/thread-group-size.hlsl.expected @@ -24,6 +24,7 @@ standard output = { "bindings": [ ], + "semanticName": "SV_DISPATCHTHREADID", "type": { "kind": "vector", "elementCount": 3, diff --git a/tests/reflection/vertex-input-semantics.hlsl b/tests/reflection/vertex-input-semantics.hlsl new file mode 100644 index 000000000..87a8431bc --- /dev/null +++ b/tests/reflection/vertex-input-semantics.hlsl @@ -0,0 +1,33 @@ +//TEST:REFLECTION:-profile vs_4_0 -target hlsl + +// Confirm that we can generate reflection info for +// vertex shader input parameters, including those +// that have semantics, and including nesting +// via struct types. + +struct X +{ + float4 x0; + float4 x1; +}; + +struct B +{ + int4 b0; + X b1; +}; + +struct C +{ + X c0 : CX; + int4 c1 : CY; +}; + +float4 main( + float4 a : A, + B b : B, + C c) + : SV_Position +{ + return 0.0; +}
\ No newline at end of file diff --git a/tests/reflection/vertex-input-semantics.hlsl.expected b/tests/reflection/vertex-input-semantics.hlsl.expected new file mode 100644 index 000000000..014533fdb --- /dev/null +++ b/tests/reflection/vertex-input-semantics.hlsl.expected @@ -0,0 +1,152 @@ +result code = 0 +standard error = { +} +standard output = { +{ + "parameters": [ + + ], + "entryPoints": [ + { + "name": "main", + "stage:": "vertex", + "parameters": [ + { + "name": "a", + "binding": {"kind": "vertexInput", "index": 0}, + "semanticName": "A", + "type": { + "kind": "vector", + "elementCount": 4, + "elementType": { + "kind": "scalar", + "scalarType": "float32" + } + } + }, + { + "name": "b", + "binding": {"kind": "vertexInput", "index": 1, "count": 3}, + "semanticName": "B", + "type": { + "kind": "struct", + "fields": [ + { + "name": "b0", + "type": { + "kind": "vector", + "elementCount": 4, + "elementType": { + "kind": "scalar", + "scalarType": "int32" + } + }, + "binding": {"kind": "vertexInput", "index": 0}, + "semanticName": "B" + }, + { + "name": "b1", + "type": { + "kind": "struct", + "fields": [ + { + "name": "x0", + "type": { + "kind": "vector", + "elementCount": 4, + "elementType": { + "kind": "scalar", + "scalarType": "float32" + } + }, + "binding": {"kind": "vertexInput", "index": 0}, + "semanticName": "B", + "semanticIndex": 1 + }, + { + "name": "x1", + "type": { + "kind": "vector", + "elementCount": 4, + "elementType": { + "kind": "scalar", + "scalarType": "float32" + } + }, + "binding": {"kind": "vertexInput", "index": 1}, + "semanticName": "B", + "semanticIndex": 2 + } + ] + }, + "binding": {"kind": "vertexInput", "index": 1, "count": 2}, + "semanticName": "B", + "semanticIndex": 1 + } + ] + } + }, + { + "name": "c", + "binding": {"kind": "vertexInput", "index": 4, "count": 3}, + "type": { + "kind": "struct", + "fields": [ + { + "name": "c0", + "type": { + "kind": "struct", + "fields": [ + { + "name": "x0", + "type": { + "kind": "vector", + "elementCount": 4, + "elementType": { + "kind": "scalar", + "scalarType": "float32" + } + }, + "binding": {"kind": "vertexInput", "index": 0}, + "semanticName": "CX" + }, + { + "name": "x1", + "type": { + "kind": "vector", + "elementCount": 4, + "elementType": { + "kind": "scalar", + "scalarType": "float32" + } + }, + "binding": {"kind": "vertexInput", "index": 1}, + "semanticName": "CX", + "semanticIndex": 1 + } + ] + }, + "binding": {"kind": "vertexInput", "index": 0, "count": 2}, + "semanticName": "CX" + }, + { + "name": "c1", + "type": { + "kind": "vector", + "elementCount": 4, + "elementType": { + "kind": "scalar", + "scalarType": "int32" + } + }, + "binding": {"kind": "vertexInput", "index": 2}, + "semanticName": "CY" + } + ] + } + } + ] + } + ] +} +} diff --git a/tools/slang-reflection-test/main.cpp b/tools/slang-reflection-test/main.cpp index 9568dc3fe..f604ca1aa 100644 --- a/tools/slang-reflection-test/main.cpp +++ b/tools/slang-reflection-test/main.cpp @@ -183,6 +183,21 @@ static void emitReflectionVarBindingInfoJSON( { write(writer,"\n]"); } + + if (auto semanticName = var->getSemanticName()) + { + write(writer, ",\n"); + write(writer,"\"semanticName\": \""); + write(writer, semanticName); + write(writer, "\""); + + if (auto semanticIndex = var->getSemanticIndex()) + { + write(writer, ",\n"); + write(writer,"\"semanticIndex\": "); + write(writer, semanticIndex); + } + } } static void emitReflectionNameInfoJSON( |
