diff options
Diffstat (limited to 'source/slang/slang-parameter-binding.cpp')
| -rw-r--r-- | source/slang/slang-parameter-binding.cpp | 359 |
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; } |
