summaryrefslogtreecommitdiffstats
path: root/source/slang/slang-parameter-binding.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/slang-parameter-binding.cpp')
-rw-r--r--source/slang/slang-parameter-binding.cpp359
1 files changed, 240 insertions, 119 deletions
diff --git a/source/slang/slang-parameter-binding.cpp b/source/slang/slang-parameter-binding.cpp
index 721d4204d..fbd11c7d0 100644
--- a/source/slang/slang-parameter-binding.cpp
+++ b/source/slang/slang-parameter-binding.cpp
@@ -332,6 +332,7 @@ struct EntryPointParameterBindingContext
UsedRangeSet usedRangeSet;
};
+
// State that is shared during parameter binding,
// across all translation units
struct SharedParameterBindingContext
@@ -476,7 +477,7 @@ LayoutResourceKind findRegisterClassFromName(UnownedStringSlice const& registerC
break;
case 5:
- if( registerClassName == "space" )
+ if( registerClassName == toSlice("space") )
{
return LayoutResourceKind::RegisterSpace;
}
@@ -963,7 +964,7 @@ static void addExplicitParameterBindings_HLSL(
}
}
-static void maybeDiagnoseMissingVulkanLayoutModifier(
+static void _maybeDiagnoseMissingVulkanLayoutModifier(
ParameterBindingContext* context,
DeclRef<VarDeclBase> const& varDecl)
{
@@ -981,7 +982,6 @@ static void addExplicitParameterBindings_GLSL(
RefPtr<ParameterInfo> parameterInfo,
RefPtr<VarLayout> varLayout)
{
-
// We only want to apply GLSL-style layout modifers
// when compiling for a Khronos-related target.
//
@@ -1002,36 +1002,35 @@ static void addExplicitParameterBindings_GLSL(
//
TypeLayout::ResourceInfo* resInfo = nullptr;
+ TypeLayout::ResourceInfo* foundResInfo = nullptr;
+
LayoutSemanticInfo semanticInfo;
semanticInfo.index = 0;
semanticInfo.space = 0;
- if( (resInfo = typeLayout->FindResourceInfo(LayoutResourceKind::DescriptorTableSlot)) != nullptr )
+
+ if( (foundResInfo = typeLayout->FindResourceInfo(LayoutResourceKind::DescriptorTableSlot)) != nullptr )
{
// Try to find `binding` and `set`
- auto attr = varDecl.getDecl()->findModifier<GLSLBindingAttribute>();
- if (!attr)
+ if (auto attr = varDecl.getDecl()->findModifier<GLSLBindingAttribute>())
{
- maybeDiagnoseMissingVulkanLayoutModifier(context, varDecl);
- return;
+ resInfo = foundResInfo;
+ semanticInfo.index = attr->binding;
+ semanticInfo.space = attr->set;
}
- semanticInfo.index = attr->binding;
- semanticInfo.space = attr->set;
}
- else if( (resInfo = typeLayout->FindResourceInfo(LayoutResourceKind::RegisterSpace)) != nullptr )
+ else if( (foundResInfo = typeLayout->FindResourceInfo(LayoutResourceKind::RegisterSpace)) != nullptr )
{
// Try to find `set`
- auto attr = varDecl.getDecl()->findModifier<GLSLBindingAttribute>();
- if (!attr)
+ if (auto attr = varDecl.getDecl()->findModifier<GLSLBindingAttribute>())
{
- maybeDiagnoseMissingVulkanLayoutModifier(context, varDecl);
- return;
- }
- if( attr->binding != 0)
- {
- getSink(context)->diagnose(attr, Diagnostics::wholeSpaceParameterRequiresZeroBinding, varDecl.getName(), attr->binding);
+ resInfo = foundResInfo;
+ if (attr->binding != 0)
+ {
+ getSink(context)->diagnose(attr, Diagnostics::wholeSpaceParameterRequiresZeroBinding, varDecl.getName(), attr->binding);
+ }
+ semanticInfo.index = attr->set;
+ semanticInfo.space = 0;
}
- semanticInfo.index = attr->set;
- semanticInfo.space = 0;
}
else if( (resInfo = typeLayout->FindResourceInfo(LayoutResourceKind::SpecializationConstant)) != nullptr )
{
@@ -1042,15 +1041,64 @@ static void addExplicitParameterBindings_GLSL(
return;
}
- // If we didn't find any matches, then bail
- if(!resInfo)
+ // if we found resInfo, we add the explicit binding
+ if (resInfo)
+ {
+ auto kind = resInfo->kind;
+ auto count = resInfo->count;
+ semanticInfo.kind = kind;
+
+ addExplicitParameterBinding(context, parameterInfo, varDecl, semanticInfo, count);
+ return;
+ }
+
+ // See if we can infer vulkan binding from HLSL if we have such options set
+ auto hlslToVulkanLayoutOptions = context->getTargetRequest()->getHLSLToVulkanLayoutOptions();
+
+ if (!hlslToVulkanLayoutOptions)
+ {
+ _maybeDiagnoseMissingVulkanLayoutModifier(context, varDecl);
+ return;
+ }
+
+ // Do we have any vulkan shift settings
+ auto hlslRegSemantic = varDecl.getDecl()->findModifier<HLSLRegisterSemantic>();
+
+ if (hlslRegSemantic == nullptr)
+ {
+ // We don't have a HLSL binding, so we can't infer, so we can't assign an infered explicit binding
return;
+ }
+
+ // Get the HLSL binding info
+ const auto hlslInfo = ExtractLayoutSemanticInfo(context, hlslRegSemantic);
+ if (hlslInfo.kind != LayoutResourceKind::None)
+ {
+ // We need to map to the GLSL binding types
+ HLSLToVulkanLayoutOptions::Kind vulkanKind = HLSLToVulkanLayoutOptions::getKind(hlslInfo.kind);
+ if (vulkanKind != HLSLToVulkanLayoutOptions::Kind::Invalid)
+ {
+ const auto shift = hlslToVulkanLayoutOptions->getShift(vulkanKind, Index(hlslInfo.space));
+ if (shift != HLSLToVulkanLayoutOptions::kInvalidShift)
+ {
+ const Index bindingIndex = Index(hlslInfo.index) + shift;
- auto kind = resInfo->kind;
- auto count = resInfo->count;
- semanticInfo.kind = kind;
+ if (bindingIndex >= 0)
+ {
+ // Add for descriptor slot
+ resInfo = typeLayout->findOrAddResourceInfo(LayoutResourceKind::DescriptorTableSlot);
+
+ semanticInfo.kind = resInfo->kind;
+ semanticInfo.index = UInt(bindingIndex);
+ semanticInfo.space = hlslInfo.space;
+
+ const LayoutSize count = resInfo->count;
- addExplicitParameterBinding(context, parameterInfo, varDecl, semanticInfo, count);
+ addExplicitParameterBinding(context, parameterInfo, varDecl, semanticInfo, count);
+ }
+ }
+ }
+ }
}
// Given a single parameter, collect whatever information we have on
@@ -2281,7 +2329,7 @@ struct ScopeLayoutBuilder
}
- RefPtr<VarLayout> endLayout()
+ RefPtr<VarLayout> endLayout(VarLayout* inVarLayout = nullptr)
{
// Finish computing the layout for the ordindary data (if any).
//
@@ -2307,7 +2355,12 @@ struct ScopeLayoutBuilder
// We now have a bunch of layout information, which we should
// record into a suitable object that represents the scope
- RefPtr<VarLayout> scopeVarLayout = new VarLayout();
+ RefPtr<VarLayout> scopeVarLayout = inVarLayout;
+ if (!scopeVarLayout)
+ {
+ scopeVarLayout = new VarLayout();
+ }
+
scopeVarLayout->typeLayout = scopeTypeLayout;
if( auto pendingTypeLayout = scopeTypeLayout->pendingDataTypeLayout )
@@ -2445,19 +2498,15 @@ struct SimpleScopeLayoutBuilder : ScopeLayoutBuilder
/// the resources required for a constant buffer in the appropriate
/// target-specific fashion.
///
-static ParameterBindingAndKindInfo maybeAllocateConstantBufferBinding(
- ParameterBindingContext* context,
- bool needConstantBuffer)
+static ParameterBindingAndKindInfo _allocateConstantBufferBinding(
+ ParameterBindingContext* context)
{
- if( !needConstantBuffer ) return ParameterBindingAndKindInfo();
-
UInt space = context->shared->defaultSpace;
auto usedRangeSet = findUsedRangeSetForSpace(context, space);
auto layoutInfo = context->getRulesFamily()
->getConstantBufferRules(context->getTargetRequest())
- ->GetObjectLayout(
- ShaderParameterKind::ConstantBuffer);
+ ->GetObjectLayout(ShaderParameterKind::ConstantBuffer);
ParameterBindingAndKindInfo info;
info.kind = layoutInfo.kind;
@@ -2467,6 +2516,32 @@ static ParameterBindingAndKindInfo maybeAllocateConstantBufferBinding(
return info;
}
+static ParameterBindingAndKindInfo _assignConstantBufferBinding(
+ ParameterBindingContext* context,
+ VarLayout* varLayout,
+ UInt space,
+ UInt index)
+{
+ auto usedRangeSet = findUsedRangeSetForSpace(context, space);
+
+ auto layoutInfo = context->getRulesFamily()
+ ->getConstantBufferRules(context->getTargetRequest())
+ ->GetObjectLayout(ShaderParameterKind::ConstantBuffer);
+
+ const Index count = Index(layoutInfo.size.getFiniteValue());
+
+ auto existingParam = usedRangeSet->usedResourceRanges[(int)layoutInfo.kind].Add(varLayout, index, index + count);
+ SLANG_UNUSED(existingParam);
+ SLANG_ASSERT(existingParam == nullptr);
+
+ ParameterBindingAndKindInfo info;
+ info.kind = layoutInfo.kind;
+ info.count = count;
+ info.index = index;
+ info.space = space;
+ return info;
+}
+
/// Remove resource usage from `typeLayout` that should only be stored per-entry-point.
///
/// This is used when constructing the overall layout for an entry point, to make sure
@@ -3374,6 +3449,92 @@ static void _completeBindings(
_completeBindings(context, program, &counters);
}
+static bool _calcNeedsDefaultSpace(SharedParameterBindingContext& sharedContext)
+{
+ // Next we will look at the global-scope parameters and see if
+ // any of them requires a `register` or `binding` that will
+ // thus need to land in a default space.
+ //
+ for (auto& parameterInfo : sharedContext.parameters)
+ {
+ auto varLayout = parameterInfo->varLayout;
+ SLANG_RELEASE_ASSERT(varLayout);
+
+ // For each parameter, we will look at each resource it consumes.
+ //
+ for (auto resInfo : varLayout->typeLayout->resourceInfos)
+ {
+ // We don't want to consider resource kinds for which
+ // the variable already has an (explicit) binding, since
+ // the space from the explicit binding will be used, so
+ // that a default space isn't needed.
+ //
+ if (parameterInfo->bindingInfo[resInfo.kind].count != 0)
+ continue;
+
+ // We also want to exclude certain resource kinds from
+ // consideration, since parameters using those resource
+ // kinds wouldn't be allocated into the default space
+ // anyway.
+ //
+ switch (resInfo.kind)
+ {
+ case LayoutResourceKind::RegisterSpace:
+ case LayoutResourceKind::PushConstantBuffer:
+ continue;
+ case LayoutResourceKind::Uniform:
+ {
+ // If it's uniform, but we have globals binding defined, we don't need a default space for it
+ // as it will go in the global binding specified
+ if (auto hlslToVulkanOptions = sharedContext.getTargetRequest()->getHLSLToVulkanLayoutOptions())
+ {
+ if (hlslToVulkanOptions->hasGlobalsBinding())
+ {
+ continue;
+ }
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ // Otherwise, we have a shader parameter that will need
+ // a default space or set to live in.
+ //
+ return true;
+ }
+ }
+
+ // We also need a default space for any entry-point parameters
+ // that consume appropriate resource kinds.
+ //
+ for (auto& entryPoint : sharedContext.programLayout->entryPoints)
+ {
+ auto paramsLayout = entryPoint->parametersLayout;
+ for (auto resInfo : paramsLayout->resourceInfos)
+ {
+ switch (resInfo.kind)
+ {
+ default:
+ break;
+
+ case LayoutResourceKind::RegisterSpace:
+ case LayoutResourceKind::VaryingInput:
+ case LayoutResourceKind::VaryingOutput:
+ case LayoutResourceKind::HitAttributes:
+ case LayoutResourceKind::RayPayload:
+ continue;
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
RefPtr<ProgramLayout> generateParameterBindings(
TargetProgram* targetProgram,
DiagnosticSink* sink)
@@ -3536,6 +3697,31 @@ RefPtr<ProgramLayout> generateParameterBindings(
}
}
+ // Global constant buffer binding.
+ // It's initially invalid. (kind = None).
+ ParameterBindingAndKindInfo globalConstantBufferBinding;
+
+ // We define this variable early, such that we can create and use when specifying
+ // a HLSLToVulkan based binding. It can if setup be used on endLayout, called later
+ RefPtr<VarLayout> globalScopeVarLayout;
+
+ // If we have a space/binding assigned for use for globals in Vulkan,
+ // we can't use *that* as the default space, so we allocate if
+ if (auto vulkanOptions = targetReq->getHLSLToVulkanLayoutOptions())
+ {
+ if (vulkanOptions->hasGlobalsBinding())
+ {
+ // Create VarLayout which will be associated with the binding, and setup later
+ globalScopeVarLayout = new VarLayout;
+
+ // Allocate the set
+ markSpaceUsed(&context, nullptr, vulkanOptions->m_globalsBindingSet);
+
+ // Mark the use of this binding
+ globalConstantBufferBinding = _assignConstantBufferBinding(&context, globalScopeVarLayout, vulkanOptions->m_globalsBindingSet, vulkanOptions->m_globalsBinding);
+ }
+ }
+
// Once we have a canonical list of all the parameters, we can
// detect if there are any global-scope parameters that make use
// of `LayoutResourceKind::Uniform`, since such parameters would
@@ -3550,10 +3736,14 @@ RefPtr<ProgramLayout> generateParameterBindings(
//
bool needDefaultConstantBuffer = false;
+ // If we have already setup a global constant buffer binding, we don't need a default one
+ //
// On a CPU target, it's okay to have global scope parameters that use Uniform resources (because on CPU
// all resources are 'Uniform')
// TODO(JS): We'll just assume the same with CUDA target for now..
- if (!_isCPUTarget(targetReq->getTarget()) && !_isPTXTarget(targetReq->getTarget()))
+ if (globalConstantBufferBinding.kind == LayoutResourceKind::None &&
+ !_isCPUTarget(targetReq->getTarget()) &&
+ !_isPTXTarget(targetReq->getTarget()))
{
for( auto& parameterInfo : sharedContext.parameters )
{
@@ -3577,81 +3767,9 @@ RefPtr<ProgramLayout> generateParameterBindings(
// As a starting point, we will definitely need a "default" space if
// we are creating a default constant buffer, since it should get
// a binding in that "default" space.
- //
- bool needDefaultSpace = needDefaultConstantBuffer;
- if (!needDefaultSpace)
- {
- // Next we will look at the global-scope parameters and see if
- // any of them requires a `register` or `binding` that will
- // thus need to land in a default space.
- //
- for (auto& parameterInfo : sharedContext.parameters)
- {
- auto varLayout = parameterInfo->varLayout;
- SLANG_RELEASE_ASSERT(varLayout);
-
- // For each parameter, we will look at each resource it consumes.
- //
- for (auto resInfo : varLayout->typeLayout->resourceInfos)
- {
- // We don't want to consider resource kinds for which
- // the variable already has an (explicit) binding, since
- // the space from the explicit binding will be used, so
- // that a default space isn't needed.
- //
- if( parameterInfo->bindingInfo[resInfo.kind].count != 0 )
- continue;
-
- // We also want to exclude certain resource kinds from
- // consideration, since parameters using those resource
- // kinds wouldn't be allocated into the default space
- // anyway.
- //
- switch( resInfo.kind )
- {
- case LayoutResourceKind::RegisterSpace:
- case LayoutResourceKind::PushConstantBuffer:
- continue;
-
- default:
- break;
- }
-
- // Otherwise, we have a shader parameter that will need
- // a default space or set to live in.
- //
- needDefaultSpace = true;
- break;
- }
- }
-
- // We also need a default space for any entry-point parameters
- // that consume appropriate resource kinds.
- //
- for(auto& entryPoint : sharedContext.programLayout->entryPoints)
- {
- auto paramsLayout = entryPoint->parametersLayout;
- for(auto resInfo : paramsLayout->resourceInfos )
- {
- switch(resInfo.kind)
- {
- default:
- break;
-
- case LayoutResourceKind::RegisterSpace:
- case LayoutResourceKind::VaryingInput:
- case LayoutResourceKind::VaryingOutput:
- case LayoutResourceKind::HitAttributes:
- case LayoutResourceKind::RayPayload:
- continue;
- }
-
- needDefaultSpace = true;
- break;
- }
- }
- }
-
+
+ const bool needDefaultSpace = needDefaultConstantBuffer || _calcNeedsDefaultSpace(sharedContext);
+
// If we need a space for default bindings, then allocate it here.
if (needDefaultSpace)
{
@@ -3694,12 +3812,13 @@ RefPtr<ProgramLayout> generateParameterBindings(
}
// If there are any global-scope uniforms, then we need to
- // allocate a constant-buffer binding for them here.
- //
- ParameterBindingAndKindInfo globalConstantBufferBinding = maybeAllocateConstantBufferBinding(
- &context,
- needDefaultConstantBuffer);
-
+ // allocate a constant-buffer binding for them here, if hasn't already been
+ // assigned
+ if (globalConstantBufferBinding.kind == LayoutResourceKind::None && needDefaultConstantBuffer)
+ {
+ globalConstantBufferBinding = _allocateConstantBufferBinding(&context);
+ }
+
// Now that all of the explicit bindings have been dealt with
// and we've also allocate any space/buffer that is required
// for global-scope parameters, we will go through the
@@ -3721,10 +3840,12 @@ RefPtr<ProgramLayout> generateParameterBindings(
globalScopeLayoutBuilder.addParameter(parameterInfo);
}
- auto globalScopeVarLayout = globalScopeLayoutBuilder.endLayout();
+ globalScopeVarLayout = globalScopeLayoutBuilder.endLayout(globalScopeVarLayout);
+
if( globalConstantBufferBinding.count != 0 )
{
auto cbInfo = globalScopeVarLayout->findOrAddResourceInfo(globalConstantBufferBinding.kind);
+
cbInfo->space = globalConstantBufferBinding.space;
cbInfo->index = globalConstantBufferBinding.index;
}