diff options
| author | Tim Foley <tfoley@nvidia.com> | 2017-07-10 09:29:11 -0700 |
|---|---|---|
| committer | Tim Foley <tfoley@nvidia.com> | 2017-07-10 09:29:11 -0700 |
| commit | 5b7c254d24653fd1c19157e8d5ef68a7e787ff58 (patch) | |
| tree | df7d790f33f7e4c8adc1b9b747c7c908d8bab0d4 /source | |
| parent | 7af89d178736637cfad9c195f85f7f83e2f4ba99 (diff) | |
Start handling system-value semantics during lowering
I hadn't been lowering `SV_Position` outputs to `gl_Position`, and had somehow been relying on hidden driver behavior that I guess made things Just Work.
This change adds some infrastructure to handle `SV_` semantics during lowering of an entry point (currently only covering `SV_Position` and `SV_Target`, FWIW).
As a byproduct, this also means that a `VarLayout` stores semantic info, which could conceivably be exposed through reflection data now.
Diffstat (limited to 'source')
| -rw-r--r-- | source/slang/lower.cpp | 93 | ||||
| -rw-r--r-- | source/slang/parameter-binding.cpp | 53 | ||||
| -rw-r--r-- | source/slang/type-layout.h | 4 |
3 files changed, 113 insertions, 37 deletions
diff --git a/source/slang/lower.cpp b/source/slang/lower.cpp index 023c63591..165812fae 100644 --- a/source/slang/lower.cpp +++ b/source/slang/lower.cpp @@ -1545,38 +1545,93 @@ struct LoweringVisitor type = arrayType; } - // TODO: if we are declaring an SOA-ized array, - // this is where those array dimensions would need - // to be tacked on. + // We need to create a reference to the global-scope declaration + // of the proper GLSL input/output variable. This might + // be a user-defined input/output, or a system-defined `gl_` one. + RefPtr<ExpressionSyntaxNode> globalVarExpr; + + // Handle system-value inputs/outputs + assert(varLayout); + auto systemValueSemantic = varLayout->systemValueSemantic; + if (systemValueSemantic.Length() != 0) + { + auto ns = systemValueSemantic.ToLower(); - RefPtr<Variable> globalVarDecl = new Variable(); - globalVarDecl->Name.Content = info.name; - globalVarDecl->Type.type = type; + if (ns == "sv_target") + { + // Note: we do *not* need to generate some kind of `gl_` + // builtin for fragment-shader outputs: they are just + // ordinary `out` variables, with ordinary `location`s, + // as far as GLSL is concerned. + } + else if (ns == "sv_position") + { + RefPtr<VarExpressionSyntaxNode> globalVarRef = new VarExpressionSyntaxNode(); + globalVarRef->name = "gl_Position"; + globalVarExpr = globalVarRef; + } + else + { + assert(!"unhandled"); + } + } - ensureDeclHasAValidName(globalVarDecl); + // If we didn't match some kind of builtin input/output, + // then declare a user input/output variable instead + if (!globalVarExpr) + { + RefPtr<Variable> globalVarDecl = new Variable(); + globalVarDecl->Name.Content = info.name; + globalVarDecl->Type.type = type; - addMember(shared->loweredProgram, globalVarDecl); + ensureDeclHasAValidName(globalVarDecl); - // Add the layout information - RefPtr<ComputedLayoutModifier> modifier = new ComputedLayoutModifier(); - modifier->layout = varLayout; - addModifier(globalVarDecl, modifier); + addMember(shared->loweredProgram, globalVarDecl); - // Need to generate an assignment in the right direction. + // Add the layout information + RefPtr<ComputedLayoutModifier> modifier = new ComputedLayoutModifier(); + modifier->layout = varLayout; + addModifier(globalVarDecl, modifier); + + // Add appropriate in/out modifier + switch (info.direction) + { + case VaryingParameterDirection::Input: + addModifier(globalVarDecl, new InModifier()); + break; + + case VaryingParameterDirection::Output: + addModifier(globalVarDecl, new OutModifier()); + break; + } + + + RefPtr<VarExpressionSyntaxNode> globalVarRef = new VarExpressionSyntaxNode(); + globalVarRef->Position = globalVarDecl->Position; + globalVarRef->declRef = makeDeclRef(globalVarDecl.Ptr()); + globalVarRef->name = globalVarDecl->getName(); + + globalVarExpr = globalVarRef; + } + + // TODO: if we are declaring an SOA-ized array, + // this is where those array dimensions would need + // to be tacked on. // - // TODO: for now I am just dealing with input: + // That is, this logic should be getting collected into a loop, + // and so we need to have a loop variable we can use to + // index into the two different expressions. + + // Need to generate an assignment in the right direction. switch (info.direction) { case VaryingParameterDirection::Input: - addModifier(globalVarDecl, new InModifier()); - assign(varExpr, globalVarDecl); + assign(varExpr, globalVarExpr); break; case VaryingParameterDirection::Output: - addModifier(globalVarDecl, new OutModifier()); - - assign(globalVarDecl, varExpr); + assign(globalVarExpr, varExpr); break; } } diff --git a/source/slang/parameter-binding.cpp b/source/slang/parameter-binding.cpp index ec611f8b1..0683c7f8c 100644 --- a/source/slang/parameter-binding.cpp +++ b/source/slang/parameter-binding.cpp @@ -788,6 +788,7 @@ static RefPtr<TypeLayout> processSimpleEntryPointParameter( ParameterBindingContext* context, RefPtr<ExpressionType> type, EntryPointParameterState const& inState, + RefPtr<VarLayout> varLayout, int semanticSlotCount = 1) { EntryPointParameterState state = inState; @@ -817,6 +818,13 @@ static RefPtr<TypeLayout> processSimpleEntryPointParameter( } } + // Remember the system-value semantic so that we can query it later + if (varLayout) + { + varLayout->systemValueSemantic = semanticName; + varLayout->systemValueSemanticIndex = semanticIndex; + } + // TODO: add some kind of usage information for system input/output } else @@ -847,13 +855,15 @@ static RefPtr<TypeLayout> processSimpleEntryPointParameter( static RefPtr<TypeLayout> processEntryPointParameter( ParameterBindingContext* context, RefPtr<ExpressionType> type, - EntryPointParameterState const& state); + EntryPointParameterState const& state, + RefPtr<VarLayout> varLayout); static RefPtr<TypeLayout> processEntryPointParameterWithPossibleSemantic( ParameterBindingContext* context, Decl* declForSemantic, RefPtr<ExpressionType> type, - EntryPointParameterState const& state) + EntryPointParameterState const& state, + RefPtr<VarLayout> varLayout) { // If there is no explicit semantic already in effect, *and* we find an explicit // semantic on the associated declaration, then we'll use it. @@ -868,7 +878,7 @@ static RefPtr<TypeLayout> processEntryPointParameterWithPossibleSemantic( subState.optSemanticName = &semanticInfo.name; subState.ioSemanticIndex = &semanticIndex; - processEntryPointParameter(context, type, subState); + processEntryPointParameter(context, type, subState, varLayout); } } @@ -876,29 +886,30 @@ static RefPtr<TypeLayout> processEntryPointParameterWithPossibleSemantic( // *or* we couldn't find an explicit semantic to apply on the given // declaration, so we will just recursive with whatever we have at // the moment. - return processEntryPointParameter(context, type, state); + return processEntryPointParameter(context, type, state, varLayout); } static RefPtr<TypeLayout> processEntryPointParameter( ParameterBindingContext* context, RefPtr<ExpressionType> type, - EntryPointParameterState const& state) + EntryPointParameterState const& state, + RefPtr<VarLayout> varLayout) { // Scalar and vector types are treated as outputs directly if(auto basicType = type->As<BasicExpressionType>()) { - return processSimpleEntryPointParameter(context, basicType, state); + return processSimpleEntryPointParameter(context, basicType, state, varLayout); } else if(auto vectorType = type->As<VectorExpressionType>()) { - return processSimpleEntryPointParameter(context, vectorType, state); + return processSimpleEntryPointParameter(context, vectorType, state, varLayout); } // A matrix is processed as if it was an array of rows else if( auto matrixType = type->As<MatrixExpressionType>() ) { auto rowCount = GetIntVal(matrixType->getRowCount()); - return processSimpleEntryPointParameter(context, matrixType, state, (int) rowCount); + return processSimpleEntryPointParameter(context, matrixType, state, varLayout, (int) rowCount); } else if( auto arrayType = type->As<ArrayExpressionType>() ) { @@ -908,13 +919,13 @@ static RefPtr<TypeLayout> processEntryPointParameter( auto elementCount = (UInt) GetIntVal(arrayType->ArrayLength); // We use the first element to derive the layout for the element type - auto elementTypeLayout = processEntryPointParameter(context, arrayType->BaseType, state); + auto elementTypeLayout = processEntryPointParameter(context, arrayType->BaseType, state, varLayout); // We still walk over subsequent elements to make sure they consume resources // as needed for( UInt ii = 1; ii < elementCount; ++ii ) { - processEntryPointParameter(context, arrayType->BaseType, state); + processEntryPointParameter(context, arrayType->BaseType, state, nullptr); } RefPtr<ArrayTypeLayout> arrayTypeLayout = new ArrayTypeLayout(); @@ -946,14 +957,16 @@ static RefPtr<TypeLayout> processEntryPointParameter( // Need to recursively walk the fields of the structure now... for( auto field : GetFields(structDeclRef) ) { + RefPtr<VarLayout> fieldVarLayout = new VarLayout(); + fieldVarLayout->varDecl = field; + auto fieldTypeLayout = processEntryPointParameterWithPossibleSemantic( context, field.getDecl(), GetType(field), - state); + state, + fieldVarLayout); - RefPtr<VarLayout> fieldVarLayout = new VarLayout(); - fieldVarLayout->varDecl = field; fieldVarLayout->typeLayout = fieldTypeLayout; for (auto rr : fieldTypeLayout->resourceInfos) @@ -1062,14 +1075,16 @@ static void collectEntryPointParameters( state.directionMask |= kEntryPointParameterDirection_Output; } + RefPtr<VarLayout> paramVarLayout = new VarLayout(); + paramVarLayout->varDecl = makeDeclRef(paramDecl.Ptr()); + auto paramTypeLayout = processEntryPointParameterWithPossibleSemantic( context, paramDecl.Ptr(), paramDecl->Type.type, - state); + state, + paramVarLayout); - RefPtr<VarLayout> paramVarLayout = new VarLayout(); - paramVarLayout->varDecl = makeDeclRef(paramDecl.Ptr()); paramVarLayout->typeLayout = paramTypeLayout; for (auto rr : paramTypeLayout->resourceInfos) @@ -1089,13 +1104,15 @@ static void collectEntryPointParameters( { state.directionMask = kEntryPointParameterDirection_Output; + RefPtr<VarLayout> resultLayout = new VarLayout(); + auto resultTypeLayout = processEntryPointParameterWithPossibleSemantic( context, entryPointFuncDecl, resultType, - state); + state, + resultLayout); - RefPtr<VarLayout> resultLayout = new VarLayout(); resultLayout->typeLayout = resultTypeLayout; for (auto rr : resultTypeLayout->resourceInfos) diff --git a/source/slang/type-layout.h b/source/slang/type-layout.h index 3ee12656c..262a8c3b1 100644 --- a/source/slang/type-layout.h +++ b/source/slang/type-layout.h @@ -237,6 +237,10 @@ public: // Additional flags VarLayoutFlags flags = 0; + // System-value semantic (and index) if this is a system value + String systemValueSemantic; + int systemValueSemanticIndex; + // The start register(s) for any resources struct ResourceInfo { |
