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 +++++++++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 14 deletions(-) (limited to 'source') 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(); -- cgit v1.2.3