summaryrefslogtreecommitdiffstats
path: root/source/slang/parameter-binding.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/parameter-binding.cpp')
-rw-r--r--source/slang/parameter-binding.cpp239
1 files changed, 226 insertions, 13 deletions
diff --git a/source/slang/parameter-binding.cpp b/source/slang/parameter-binding.cpp
index fa015186b..836ed254f 100644
--- a/source/slang/parameter-binding.cpp
+++ b/source/slang/parameter-binding.cpp
@@ -667,6 +667,17 @@ static void collectGlobalScopeGLSLVaryingParameter(
}
// Collect a single declaration into our set of parameters
+static void collectGlobalGenericParameter(
+ ParameterBindingContext* context,
+ RefPtr<GlobalGenericParamDecl> paramDecl)
+{
+ RefPtr<GenericParamLayout> layout = new GenericParamLayout();
+ layout->decl = paramDecl;
+ layout->index = (int)context->shared->programLayout->globalGenericParams.Count();
+ context->shared->programLayout->globalGenericParams.Add(layout);
+}
+
+// Collect a single declaration into our set of parameters
static void collectGlobalScopeParameter(
ParameterBindingContext* context,
RefPtr<VarDeclBase> varDecl)
@@ -1037,7 +1048,13 @@ static void completeBindingsForParameter(
continue;
}
-
+ else if (kind == LayoutResourceKind::GenericResource)
+ {
+ bindingInfo.space = 0;
+ bindingInfo.count = 0;
+ bindingInfo.index = 0;
+ continue;
+ }
// For now we only auto-generate bindings in space zero
//
@@ -1065,6 +1082,11 @@ static void completeBindingsForParameter(
bindingInfo.space = space;
}
+ if (firstTypeLayout->FindResourceInfo(LayoutResourceKind::GenericResource))
+ {
+
+ }
+
// At this point we should have explicit binding locations chosen for
// all the relevant resource kinds, so we can apply these to the
// declarations:
@@ -1093,15 +1115,22 @@ static void collectGlobalScopeParameters(
ModuleDecl* program)
{
// First enumerate parameters at global scope
- for( auto decl : program->Members )
+ // We collect two things here:
+ // 1. A shader parameter, which is always a variable
+ // 2. A global entry-point generic parameter type (`__generic_param`),
+ // which is a GlobalGenericParamDecl
+ // We collect global generic type parameters in the first pass,
+ // So we can fill in the correct index into ordinary type layouts
+ // for generic types in the second pass.
+ for (auto decl : program->Members)
{
- // A shader parameter is always a variable,
- // so skip declarations that aren't variables.
- auto varDecl = decl.As<VarDeclBase>();
- if (!varDecl)
- continue;
-
- collectGlobalScopeParameter(context, varDecl);
+ if (auto genParamDecl = decl.As<GlobalGenericParamDecl>())
+ collectGlobalGenericParameter(context, genParamDecl);
+ }
+ for (auto decl : program->Members)
+ {
+ if (auto varDecl = decl.As<VarDeclBase>())
+ collectGlobalScopeParameter(context, varDecl);
}
// Next, we need to enumerate the parameters of
@@ -1665,7 +1694,8 @@ void generateParameterBindings(
if (!layoutContext.rules)
return;
- RefPtr<ProgramLayout> programLayout = new ProgramLayout;
+ RefPtr<ProgramLayout> programLayout = new ProgramLayout();
+ targetReq->layout = programLayout;
// Create a context to hold shared state during the process
// of generating parameter bindings
@@ -1680,7 +1710,6 @@ void generateParameterBindings(
context.shared = &sharedContext;
context.translationUnit = nullptr;
context.layoutContext = layoutContext;
-
// Walk through AST to discover all the parameters
collectParameters(&context, compileReq);
@@ -1707,6 +1736,7 @@ void generateParameterBindings(
// If there are any global-scope uniforms, then we need to
// allocate a constant-buffer binding for them here.
ParameterBindingInfo globalConstantBufferBinding;
+ globalConstantBufferBinding.index = 0;
if( anyGlobalUniforms )
{
// TODO: this logic is only correct for D3D targets, where
@@ -1838,8 +1868,191 @@ void generateParameterBindings(
// We now have a bunch of layout information, which we should
// record into a suitable object that represents the program
- programLayout->globalScopeLayout = globalScopeLayout;
- targetReq->layout = programLayout;
+ RefPtr<VarLayout> globalVarLayout = new VarLayout();
+ globalVarLayout->typeLayout = globalScopeLayout;
+ if (anyGlobalUniforms)
+ {
+ auto cbInfo = globalVarLayout->findOrAddResourceInfo(LayoutResourceKind::ConstantBuffer);
+ cbInfo->space = 0;
+ cbInfo->index = globalConstantBufferBinding.index;
+ }
+ programLayout->globalScopeLayout = globalVarLayout;
}
+StructTypeLayout* getGlobalStructLayout(
+ ProgramLayout* programLayout);
+
+RefPtr<ProgramLayout> specializeProgramLayout(
+ TargetRequest * targetReq,
+ ProgramLayout* programLayout,
+ Substitutions * typeSubst)
+{
+ RefPtr<ProgramLayout> newProgramLayout;
+ newProgramLayout = new ProgramLayout();
+ newProgramLayout->bindingForHackSampler = programLayout->bindingForHackSampler;
+ newProgramLayout->hackSamplerVar = programLayout->hackSamplerVar;
+ for (auto & entryPoint : programLayout->entryPoints)
+ {
+ RefPtr<EntryPointLayout> newEntryPoint = new EntryPointLayout(*entryPoint);
+ // TODO: for now just copy existing entry point layouts, but we eventually need to
+ // specialize these as well...
+ newProgramLayout->entryPoints.Add(newEntryPoint);
+ }
+
+ List<RefPtr<TypeLayout>> paramTypeLayouts;
+ auto globalStructLayout = getGlobalStructLayout(programLayout);
+ SLANG_ASSERT(globalStructLayout);
+ RefPtr<StructTypeLayout> structLayout = new StructTypeLayout();
+ RefPtr<TypeLayout> globalScopeLayout = structLayout;
+ structLayout->uniformAlignment = globalStructLayout->uniformAlignment;
+
+ // Try to find rules based on the selected code-generation target
+ auto layoutContext = getInitialLayoutContextForTarget(targetReq);
+
+ // If there was no target, or there are no rules for the target,
+ // then bail out here.
+ if (!layoutContext.rules)
+ return newProgramLayout;
+
+
+ // we need to initialize a layout context to mark used registers
+ SharedParameterBindingContext sharedContext;
+ sharedContext.compileRequest = targetReq->compileRequest;
+ sharedContext.defaultLayoutRules = layoutContext.getRulesFamily();
+ sharedContext.programLayout = programLayout;
+
+ // Create a sub-context to collect parameters that get
+ // declared into the global scope
+ ParameterBindingContext context;
+ context.shared = &sharedContext;
+ context.translationUnit = nullptr;
+ context.layoutContext = layoutContext;
+
+ auto constantBufferRules = context.getRulesFamily()->getConstantBufferRules();
+ structLayout->rules = constantBufferRules;
+
+ UniformLayoutInfo structLayoutInfo;
+ structLayoutInfo.alignment = globalStructLayout->uniformAlignment;
+ structLayoutInfo.size = 0;
+ bool anyUniforms = false;
+ Dictionary<RefPtr<VarLayout>, RefPtr<VarLayout>> varLayoutMapping;
+ for (auto & varLayout : globalStructLayout->fields)
+ {
+ // To recover layout context, we skip generic resources in the first pass
+ // If the var is a generic resource, its resourceInfos will be empty.
+ if (varLayout->resourceInfos.Count() == 0)
+ continue;
+ SLANG_ASSERT(varLayout->resourceInfos.Count() == varLayout->typeLayout->resourceInfos.Count());
+ auto uniformInfo = varLayout->FindResourceInfo(LayoutResourceKind::Uniform);
+ auto tUniformInfo = varLayout->typeLayout->FindResourceInfo(LayoutResourceKind::Uniform);
+ if (uniformInfo)
+ {
+ anyUniforms = true;
+ SLANG_ASSERT(tUniformInfo);
+ structLayoutInfo.size = Math::Max(structLayoutInfo.size, uniformInfo->index + tUniformInfo->count);
+ }
+ for (UInt i = 0; i < varLayout->resourceInfos.Count(); i++)
+ {
+ auto resInfo = varLayout->resourceInfos[i];
+ auto tresInfo = varLayout->typeLayout->resourceInfos[i];
+ SLANG_ASSERT(resInfo.kind == tresInfo.kind);
+ auto usedRangeSet = findUsedRangeSetForSpace(&context, resInfo.space);
+ markSpaceUsed(&context, resInfo.space);
+ usedRangeSet->usedResourceRanges[(int)resInfo.kind].Add(
+ nullptr, // we don't need to track parameter info here
+ resInfo.index,
+ resInfo.index + varLayout->typeLayout->resourceInfos[0].count);
+ }
+ structLayout->fields.Add(varLayout);
+ varLayoutMapping[varLayout] = varLayout;
+ }
+ auto originalGlobalCBufferInfo = programLayout->globalScopeLayout->FindResourceInfo(LayoutResourceKind::ConstantBuffer);
+ VarLayout::ResourceInfo globalCBufferInfo;
+ globalCBufferInfo.kind = LayoutResourceKind::None;
+ globalCBufferInfo.space = 0;
+ globalCBufferInfo.index = 0;
+ if (originalGlobalCBufferInfo)
+ {
+ globalCBufferInfo.kind = LayoutResourceKind::ConstantBuffer;
+ globalCBufferInfo.space = originalGlobalCBufferInfo->space;
+ globalCBufferInfo.index = originalGlobalCBufferInfo->index;
+ }
+ // we have the context restored, can continue to layout the generic variables now
+ for (auto & varLayout : globalStructLayout->fields)
+ {
+ if (varLayout->typeLayout->FindResourceInfo(LayoutResourceKind::GenericResource))
+ {
+ RefPtr<Type> newType = varLayout->typeLayout->type->Substitute(typeSubst).As<Type>();
+ RefPtr<TypeLayout> newTypeLayout = CreateTypeLayout(
+ layoutContext.with(constantBufferRules),
+ newType);
+ auto layoutInfo = newTypeLayout->FindResourceInfo(LayoutResourceKind::Uniform);
+ size_t uniformSize = layoutInfo ? layoutInfo->count : 0;
+ if (uniformSize)
+ {
+ if (globalCBufferInfo.kind == LayoutResourceKind::None)
+ {
+ // user defined a uniform via a global generic type argument
+ // but we have not reserved a binding for the global uniform buffer
+ UInt space = 0;
+ auto usedRangeSet = findUsedRangeSetForSpace(&context, space);
+ globalCBufferInfo.kind = LayoutResourceKind::ConstantBuffer;
+ globalCBufferInfo.index =
+ usedRangeSet->usedResourceRanges[
+ (int)LayoutResourceKind::ConstantBuffer].Allocate(nullptr, 1);
+ globalCBufferInfo.space = space;
+ }
+ }
+ RefPtr<VarLayout> newVarLayout = new VarLayout();
+ RefPtr<ParameterInfo> paramInfo = new ParameterInfo();
+ newVarLayout->varDecl = varLayout->varDecl;
+ newVarLayout->typeLayout = newTypeLayout;
+ paramInfo->varLayouts.Add(newVarLayout);
+ completeBindingsForParameter(&context, paramInfo);
+ // update uniform layout
+
+ if (uniformSize != 0)
+ {
+ // Make sure uniform fields get laid out properly...
+ UniformLayoutInfo fieldInfo(
+ uniformSize,
+ newTypeLayout->uniformAlignment);
+ size_t uniformOffset = layoutContext.getRulesFamily()->getConstantBufferRules()->AddStructField(
+ &structLayoutInfo,
+ fieldInfo);
+ newVarLayout->findOrAddResourceInfo(LayoutResourceKind::Uniform)->index = uniformOffset;
+ anyUniforms = true;
+ }
+ structLayout->fields.Add(newVarLayout);
+ varLayoutMapping[varLayout] = newVarLayout;
+ }
+ }
+ for (auto mapping : globalStructLayout->mapVarToLayout)
+ {
+ RefPtr<VarLayout> updatedVarLayout = mapping.Value;
+ varLayoutMapping.TryGetValue(updatedVarLayout, updatedVarLayout);
+ structLayout->mapVarToLayout[mapping.Key] = updatedVarLayout;
+ }
+
+ // If there are global-scope uniforms, then we need to wrap
+ // up a global constant buffer type layout to hold them
+ RefPtr<VarLayout> globalVarLayout = new VarLayout();
+ if (anyUniforms)
+ {
+ auto globalConstantBufferLayout = createParameterGroupTypeLayout(
+ layoutContext,
+ nullptr,
+ constantBufferRules,
+ constantBufferRules->GetObjectLayout(ShaderParameterKind::ConstantBuffer),
+ structLayout);
+
+ globalScopeLayout = globalConstantBufferLayout;
+ auto cbInfo = globalVarLayout->findOrAddResourceInfo(LayoutResourceKind::ConstantBuffer);
+ *cbInfo = globalCBufferInfo;
+ }
+ globalVarLayout->typeLayout = globalScopeLayout;
+ programLayout->globalScopeLayout = globalVarLayout;
+ newProgramLayout->globalScopeLayout = globalVarLayout;
+ return newProgramLayout;
+}
}