From 46b68ed41daecfaf1761e299cf040156e0f65ac0 Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Fri, 15 Dec 2017 14:26:58 -0800 Subject: Add sample-rate-input detection for HLSL. (#312) * Add sample-rate-input detection for HLSL. In the HLSL case, it is possible to do this detection entirely based on declared signatures (it doesn't have a dependency on code generation like the GLSL case does). I've added test cases for the two main ways that a shader can become sample rate: 1. Qualify a fragment input with `sample` 2. Accept an input with the `SV_SampleIndex` semantic In each case I nested the input inside a `struct` to try to match common HLSL idiom, and to make sure that we handle the nested case. This code is *not* robust against shaders that declare such an input and then never use it, but that is to be expected given the goals for Slang. * Fixup: add missing test output files --- source/slang/parameter-binding.cpp | 64 ++++++++++++++++++----- tests/reflection/sample-index-input.hlsl | 15 ++++++ tests/reflection/sample-index-input.hlsl.expected | 52 ++++++++++++++++++ tests/reflection/sample-rate-input.hlsl | 15 ++++++ tests/reflection/sample-rate-input.hlsl.expected | 58 ++++++++++++++++++++ 5 files changed, 190 insertions(+), 14 deletions(-) create mode 100644 tests/reflection/sample-index-input.hlsl create mode 100644 tests/reflection/sample-index-input.hlsl.expected create mode 100644 tests/reflection/sample-rate-input.hlsl create mode 100644 tests/reflection/sample-rate-input.hlsl.expected diff --git a/source/slang/parameter-binding.cpp b/source/slang/parameter-binding.cpp index 4eb1cf6ee..4ec4f6fd5 100644 --- a/source/slang/parameter-binding.cpp +++ b/source/slang/parameter-binding.cpp @@ -263,6 +263,9 @@ struct ParameterBindingContext // What stage (if any) are we compiling for? Stage stage; + // The entry point that is being processed right now. + EntryPointLayout* entryPointLayout = nullptr; + // The source language we are trying to use SourceLanguage sourceLanguage; @@ -647,6 +650,7 @@ struct EntryPointParameterState EntryPointParameterDirectionMask directionMask; int semanticSlotCount; Stage stage = Stage::Unknown; + bool isSampleRate = false; }; @@ -1276,6 +1280,14 @@ static RefPtr processSimpleEntryPointParameter( } } + if (state.directionMask & kEntryPointParameterDirection_Input) + { + if (sn == "sv_sampleindex") + { + state.isSampleRate = true; + } + } + // Remember the system-value semantic so that we can query it later if (varLayout) { @@ -1308,33 +1320,53 @@ static RefPtr processSimpleEntryPointParameter( } } + if (state.isSampleRate + && (state.directionMask & kEntryPointParameterDirection_Input) + && (context->stage == Stage::Fragment)) + { + if (auto entryPointLayout = context->entryPointLayout) + { + entryPointLayout->flags |= EntryPointLayout::Flag::usesAnySampleRateInput; + } + } + *state.ioSemanticIndex += state.semanticSlotCount; typeLayout->type = type; return typeLayout; } -static RefPtr processEntryPointParameterWithPossibleSemantic( +static RefPtr processEntryPointParameterDecl( ParameterBindingContext* context, - Decl* declForSemantic, - RefPtr type, - EntryPointParameterState const& state, + Decl* decl, + RefPtr type, + EntryPointParameterState const& inState, RefPtr varLayout) { + SimpleSemanticInfo semanticInfo; + int semanticIndex = 0; + + EntryPointParameterState state = inState; + // If there is no explicit semantic already in effect, *and* we find an explicit // semantic on the associated declaration, then we'll use it. if( !state.optSemanticName ) { - if( auto semantic = declForSemantic->FindModifier() ) + if( auto semantic = decl->FindModifier() ) { - auto semanticInfo = decomposeSimpleSemantic(semantic); - int semanticIndex = semanticInfo.index; + semanticInfo = decomposeSimpleSemantic(semantic); + semanticIndex = semanticInfo.index; - EntryPointParameterState subState = state; - subState.optSemanticName = &semanticInfo.name; - subState.ioSemanticIndex = &semanticIndex; + state.optSemanticName = &semanticInfo.name; + state.ioSemanticIndex = &semanticIndex; + } + } - return processEntryPointParameter(context, type, subState, varLayout); + if (decl) + { + if (decl->FindModifier()) + { + state.isSampleRate = true; } } @@ -1441,7 +1473,7 @@ static RefPtr processEntryPointParameter( RefPtr fieldVarLayout = new VarLayout(); fieldVarLayout->varDecl = field; - auto fieldTypeLayout = processEntryPointParameterWithPossibleSemantic( + auto fieldTypeLayout = processEntryPointParameterDecl( context, field.getDecl(), GetType(field), @@ -1512,6 +1544,8 @@ static void collectEntryPointParameters( entryPointLayout->profile = entryPoint->profile; entryPointLayout->entryPoint = entryPointFuncDecl; + context->entryPointLayout = entryPointLayout; + context->shared->programLayout->entryPoints.Add(entryPointLayout); @@ -1559,7 +1593,7 @@ static void collectEntryPointParameters( RefPtr paramVarLayout = new VarLayout(); paramVarLayout->varDecl = makeDeclRef(paramDecl.Ptr()); - auto paramTypeLayout = processEntryPointParameterWithPossibleSemantic( + auto paramTypeLayout = processEntryPointParameterDecl( context, paramDecl.Ptr(), paramDecl->type.type->Substitute(typeSubst).As(), @@ -1591,7 +1625,7 @@ static void collectEntryPointParameters( RefPtr resultLayout = new VarLayout(); - auto resultTypeLayout = processEntryPointParameterWithPossibleSemantic( + auto resultTypeLayout = processEntryPointParameterDecl( context, entryPointFuncDecl, resultType->Substitute(typeSubst).As(), @@ -1689,6 +1723,7 @@ static void collectParameters( context->stage = entryPoint->profile.GetStage(); collectEntryPointParameters(context, entryPoint.Ptr(), nullptr); } + context->entryPointLayout = nullptr; } // Now collect parameters from loaded modules @@ -2065,6 +2100,7 @@ RefPtr specializeProgramLayout( { collectEntryPointParameters(&context, entryPoint, typeSubst); } + context.entryPointLayout = nullptr; } auto constantBufferRules = context.getRulesFamily()->getConstantBufferRules(); diff --git a/tests/reflection/sample-index-input.hlsl b/tests/reflection/sample-index-input.hlsl new file mode 100644 index 000000000..edb0690d6 --- /dev/null +++ b/tests/reflection/sample-index-input.hlsl @@ -0,0 +1,15 @@ +//TEST:REFLECTION:-profile ps_5_0 -target hlsl + +// Confirm that we register a shader as sample-rate when +// it declares `SV_SampleIndex` as an input. + +struct PSInput +{ + float4 color : COLOR; + uint sampleIndex : SV_SampleIndex; +}; + +float4 main(PSInput input) : SV_Target +{ + return input.color; +} \ No newline at end of file diff --git a/tests/reflection/sample-index-input.hlsl.expected b/tests/reflection/sample-index-input.hlsl.expected new file mode 100644 index 000000000..5bf5f297e --- /dev/null +++ b/tests/reflection/sample-index-input.hlsl.expected @@ -0,0 +1,52 @@ +result code = 0 +standard error = { +} +standard output = { +{ + "parameters": [ + + ], + "entryPoints": [ + { + "name": "main", + "stage:": "fragment", + "parameters": [ + { + "name": "input", + "stage": "fragment", + "binding": {"kind": "varyingInput", "index": 0}, + "type": { + "kind": "struct", + "name": "PSInput", + "fields": [ + { + "name": "color", + "type": { + "kind": "vector", + "elementCount": 4, + "elementType": { + "kind": "scalar", + "scalarType": "float32" + } + }, + "stage": "fragment", + "binding": {"kind": "varyingInput", "index": 0}, + "semanticName": "COLOR" + }, + { + "name": "sampleIndex", + "type": { + "kind": "scalar", + "scalarType": "uint32" + }, + "semanticName": "SV_SAMPLEINDEX" + } + ] + } + } + ], + "usesAnySampleRateInput": true + } + ] +} +} diff --git a/tests/reflection/sample-rate-input.hlsl b/tests/reflection/sample-rate-input.hlsl new file mode 100644 index 000000000..0545afb02 --- /dev/null +++ b/tests/reflection/sample-rate-input.hlsl @@ -0,0 +1,15 @@ +//TEST:REFLECTION:-profile ps_5_0 -target hlsl + +// Confirm that we register a shader as sample-rate when +// it declares (not necessarly *uses*) a `sample` qualified input + +struct PSInput +{ + float4 extra : EXTRA; + sample float4 color : COLOR; +}; + +float4 main(PSInput input) : SV_Target +{ + return input.extra + input.color; +} \ No newline at end of file diff --git a/tests/reflection/sample-rate-input.hlsl.expected b/tests/reflection/sample-rate-input.hlsl.expected new file mode 100644 index 000000000..0c86ebecb --- /dev/null +++ b/tests/reflection/sample-rate-input.hlsl.expected @@ -0,0 +1,58 @@ +result code = 0 +standard error = { +} +standard output = { +{ + "parameters": [ + + ], + "entryPoints": [ + { + "name": "main", + "stage:": "fragment", + "parameters": [ + { + "name": "input", + "stage": "fragment", + "binding": {"kind": "varyingInput", "index": 0, "count": 2}, + "type": { + "kind": "struct", + "name": "PSInput", + "fields": [ + { + "name": "extra", + "type": { + "kind": "vector", + "elementCount": 4, + "elementType": { + "kind": "scalar", + "scalarType": "float32" + } + }, + "stage": "fragment", + "binding": {"kind": "varyingInput", "index": 0}, + "semanticName": "EXTRA" + }, + { + "name": "color", + "type": { + "kind": "vector", + "elementCount": 4, + "elementType": { + "kind": "scalar", + "scalarType": "float32" + } + }, + "stage": "fragment", + "binding": {"kind": "varyingInput", "index": 1}, + "semanticName": "COLOR" + } + ] + } + } + ], + "usesAnySampleRateInput": true + } + ] +} +} -- cgit v1.2.3