diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/slang/slang-diagnostic-defs.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-hlsl-to-vulkan-layout-options.cpp | 56 | ||||
| -rw-r--r-- | source/slang/slang-hlsl-to-vulkan-layout-options.h | 38 | ||||
| -rw-r--r-- | source/slang/slang-parameter-binding.cpp | 307 | ||||
| -rw-r--r-- | source/slang/slang-type-layout.cpp | 132 | ||||
| -rw-r--r-- | source/slang/slang-type-layout.h | 14 |
6 files changed, 420 insertions, 129 deletions
diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index 463c6f525..286551716 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -582,6 +582,8 @@ DIAGNOSTIC(39023, Error, mixingImplicitAndExplicitBindingForVaryingParams, "mixi DIAGNOSTIC(39024, Warning, cannotInferVulkanBindingWithoutRegisterModifier, "shader parameter '$0' doesn't have a 'register' specified, automatic layout will be used") +DIAGNOSTIC(39025, Error, conflictingVulkanInferredBindingForParameter, "conflicting vulkan inferred binding for parameter '$0' overlap is $1 and $2") + // // 4xxxx - IL code generation. diff --git a/source/slang/slang-hlsl-to-vulkan-layout-options.cpp b/source/slang/slang-hlsl-to-vulkan-layout-options.cpp index 1033c0f56..74a3313da 100644 --- a/source/slang/slang-hlsl-to-vulkan-layout-options.cpp +++ b/source/slang/slang-hlsl-to-vulkan-layout-options.cpp @@ -29,7 +29,12 @@ static NamesDescriptionValue s_vulkanShiftKinds[] = HLSLToVulkanLayoutOptions::HLSLToVulkanLayoutOptions() { - reset(); + // Clear the all shifts + for (auto& shift : m_allShifts) + { + shift = kInvalidShift; + } + SLANG_ASSERT(isReset()); } @@ -40,6 +45,8 @@ void HLSLToVulkanLayoutOptions::setGlobalsBinding(const Binding& binding) void HLSLToVulkanLayoutOptions::reset() { + m_kindShiftEnabledFlags = 0; + for (auto& shift : m_allShifts) { shift = kInvalidShift; @@ -50,25 +57,10 @@ void HLSLToVulkanLayoutOptions::reset() void HLSLToVulkanLayoutOptions::setAllShift(Kind kind, Index shift) { - // We try to follow the convention, of the *last* entry set is the one used. - // If there a "all" set, we remove everything for the kind. - - // Find all the entries for the kind - List<Key> keys; - for (auto& pair : m_shifts) - { - if (pair.key.kind == kind) - { - keys.add(pair.key); - } - } - // Remove them all - for (auto& key : keys) - { - m_shifts.remove(key); - } + SLANG_ASSERT(shift != kInvalidShift); m_allShifts[Index(kind)] = shift; + _enableShiftForKind(kind); } void HLSLToVulkanLayoutOptions::setShift(Kind kind, Index set, Index shift) @@ -76,31 +68,25 @@ void HLSLToVulkanLayoutOptions::setShift(Kind kind, Index set, Index shift) SLANG_ASSERT(shift != kInvalidShift); Key key{ kind, set }; - m_shifts.add(key, shift); + m_shifts.set(key, shift); + _enableShiftForKind(kind); } Index HLSLToVulkanLayoutOptions::getShift(Kind kind, Index set) const { - if (auto ptr = m_shifts.tryGetValue(Key{ kind, set })) + if (canInferBindingForKind(kind)) { - return *ptr; - } - - return m_allShifts[Index(kind)]; -} - -bool HLSLToVulkanLayoutOptions::canInferBindings() const -{ - // If any all shift is set it's not default - for (auto shift : m_allShifts) - { - if (shift != kInvalidShift) + // We lookup a shift for a set first as this shift is "more specific" and + // is seen as taken precedent over the "all" scenario + if (auto ptr = m_shifts.tryGetValue(Key{ kind, set })) { - return true; + return *ptr; } - } - return m_shifts.getCount() > 0; + // Must have an `all` shift + return m_allShifts[Index(kind)]; + } + return kInvalidShift; } bool HLSLToVulkanLayoutOptions::hasState() const diff --git a/source/slang/slang-hlsl-to-vulkan-layout-options.h b/source/slang/slang-hlsl-to-vulkan-layout-options.h index b9eb3046d..e16989810 100644 --- a/source/slang/slang-hlsl-to-vulkan-layout-options.h +++ b/source/slang/slang-hlsl-to-vulkan-layout-options.h @@ -44,7 +44,7 @@ public: /// Append/ConsumeStructuredBuffer /// RWBuffer /// RWTextureXD/Array - UnorderedAccess, + UnorderedAccess = 0, /// Sampler (s) /// @@ -66,6 +66,22 @@ public: CountOf, }; + // A flag for each kind + typedef uint32_t KindFlags; + struct KindFlag + { + enum Enum : KindFlags + { + UnorderedAccess = KindFlags(1) << Index(Kind::UnorderedAccess), + Sampler = KindFlags(1) << Index(Kind::Sampler), + ShaderResource = KindFlags(1) << Index(Kind::ShaderResource), + ConstantBuffer = KindFlags(1) << Index(Kind::ConstantBuffer), + }; + }; + + /// Get a kind flag from a kind + SLANG_FORCE_INLINE static KindFlag::Enum getKindFlag(Kind kind) { SLANG_ASSERT(kind != Kind::Invalid); return KindFlag::Enum(KindFlags(1) << Index(kind)); } + struct Key { typedef Key ThisType; @@ -79,7 +95,7 @@ public: Index set; ///< The set this shift is associated with }; - /// Set the the all option for the kind + /// Set the the all option for the kind. void setAllShift(Kind kind, Index shift); /// Set the shift for kind/set @@ -92,12 +108,21 @@ public: bool hasGlobalsBinding() const { return m_globalsBinding.isSet(); } /// True if holds state such that vulkan bindings can be inferred from HLSL bindings - bool canInferBindings() const; + bool canInferBindings() const { return m_kindShiftEnabledFlags != 0; } + + /// True if the kind/set can be inferred + bool canInfer(Kind kind, Index set) const { return getShift(kind, set) != kInvalidShift; } + + /// True if can infer a binding for a kind + bool canInferBindingForKind(Kind kind) const { return (m_kindShiftEnabledFlags & getKindFlag(kind)) != 0; } /// Given an kind and a binding infer the vulkan binding. /// Will return an invalid binding if one is not found Binding inferBinding(Kind kind, const Binding& inBinding) const; + /// Returns flags indicating for each kind if there is shift inference + KindFlags getKindShiftEnabledFlags() const { return m_kindShiftEnabledFlags; } + /// Reset state such that all options are set to their default. The same state as when /// originally constructed void reset(); @@ -125,10 +150,17 @@ public: static Kind getKind(slang::ParameterCategory param); protected: + /// Marks that a shift is enabled for the kind + void _enableShiftForKind(Kind kind) { m_kindShiftEnabledFlags |= getKindFlag(kind); } + Binding m_globalsBinding; + /// The `all` shifts Index m_allShifts[Count(Kind::CountOf)]; + /// Holds a bit for each kind that has a shift enabled + KindFlags m_kindShiftEnabledFlags = 0; + /// Maps a key to the amount of shift Dictionary<Key, Index> m_shifts; }; diff --git a/source/slang/slang-parameter-binding.cpp b/source/slang/slang-parameter-binding.cpp index 1d38bc2f0..51279b605 100644 --- a/source/slang/slang-parameter-binding.cpp +++ b/source/slang/slang-parameter-binding.cpp @@ -232,22 +232,70 @@ struct UsedRanges return Add(range); } - bool contains(UInt index) + /// Finds the range that contains the index + /// Returns -1 if not found + Index findRangeContaining(UInt index) const { - for (auto rr : ranges) + const auto rangeCount = ranges.getCount(); + for (Index i = 0; i < rangeCount; ++i) { - if (index < rr.begin) - return false; + const auto& rr = ranges[i]; + if (index >= rr.begin && index < rr.end) + { + return index; + } + } + return -1; + } + /// Finds the range index that contains the range passed in. + /// Returns -1 if not found + Index findRangeContaining(UInt index, UInt count) const + { + const auto start = index; + const auto end = index + count; - if (index >= rr.end) - continue; + const auto rangeCount = ranges.getCount(); + for (Index i = 0; i < rangeCount; ++i) + { + const auto& rr = ranges[i]; - return true; + if (!(end <= rr.begin || start >= rr.end)) + { + return i; + } } + return -1; + } - return false; + Index findRangeContaining(UInt index, LayoutSize size) const + { + if (size.isFinite()) + { + const auto count = size.getFiniteValue(); + if (count > 0) + { + return (count == 1) ? + findRangeContaining(index) : + findRangeContaining(index, count); + } + } + else + { + // The size is infinite... + const auto rangeCount = ranges.getCount(); + for (Index i = 0; i < rangeCount; ++i) + { + // If the range end is part start index it's a hit + if (ranges[i].end > index) + { + return i; + } + } + } + return -1; } + bool contains(UInt index) const { return findRangeContaining(index) >= 0; } // Try to find space for `count` entries UInt Allocate(VarLayout* param, UInt count) @@ -285,7 +333,7 @@ struct ParameterBindingInfo { size_t space = 0; size_t index = 0; - LayoutSize count; + LayoutSize count = 0; }; struct ParameterBindingAndKindInfo : ParameterBindingInfo @@ -312,18 +360,6 @@ struct ParameterInfo : RefObject RefPtr<VarLayout> varLayout; ParameterBindingInfo bindingInfo[kLayoutResourceKindCount]; - - // The translation unit this parameter is specific to, if any -// TranslationUnitRequest* translationUnit = nullptr; - - ParameterInfo() - { - // Make sure we aren't claiming any resources yet - for( int ii = 0; ii < kLayoutResourceKindCount; ++ii ) - { - bindingInfo[ii].count = 0; - } - } }; struct EntryPointParameterBindingContext @@ -766,17 +802,31 @@ static void collectGlobalScopeParameter( parameterInfo->varLayout = varLayout; } -static RefPtr<UsedRangeSet> findUsedRangeSetForSpace( +static UsedRangeSet* _getOrCreateUsedRangeSetForSpace( ParameterBindingContext* context, UInt space) { - RefPtr<UsedRangeSet> usedRangeSet; - if (context->shared->globalSpaceUsedRangeSets.tryGetValue(space, usedRangeSet)) - return usedRangeSet; + auto& globalSpaceUsedRangeSets = context->shared->globalSpaceUsedRangeSets; - usedRangeSet = new UsedRangeSet(); - context->shared->globalSpaceUsedRangeSets.add(space, usedRangeSet); - return usedRangeSet; + auto& value = globalSpaceUsedRangeSets.getOrAddValue(space, RefPtr<UsedRangeSet>()); + if (!value) + { + value = new UsedRangeSet(); + } + return value; +} + +static UsedRangeSet* _getUsedRangeSetForSpace( + ParameterBindingContext* context, + UInt space) +{ + auto& globalSpaceUsedRangeSets = context->shared->globalSpaceUsedRangeSets; + + if (auto usedRangeSetPtr = globalSpaceUsedRangeSets.tryGetValue(space)) + { + return *usedRangeSetPtr; + } + return nullptr; } // Record that a particular register space (or set, in the GLSL case) @@ -860,7 +910,7 @@ static void addExplicitParameterBinding( } else { - auto usedRangeSet = findUsedRangeSetForSpace(context, semanticInfo.space); + auto usedRangeSet = _getOrCreateUsedRangeSetForSpace(context, semanticInfo.space); // Record that the particular binding space was // used by an explicit binding, so that we don't @@ -1065,50 +1115,51 @@ static void addExplicitParameterBindings_GLSL( // We need an HLSL register semantic to to infer from auto hlslRegSemantic = varDecl.getDecl()->findModifier<HLSLRegisterSemantic>(); - if (hlslRegSemantic == nullptr) + if (!hlslRegSemantic) { - // We don't have a HLSL binding, so no inferance can occur, issue a warning - // - // TODO(JS): I suppose there is some ambiguity here, because if we did a semantic lookup, and it didn't have a vulkanKind - // or didn't parse correctly we wouldn't issue this message. - getSink(context)->diagnose(varDecl.getDecl(), Diagnostics::cannotInferVulkanBindingWithoutRegisterModifier, varDecl); + // We'll use inference from the HLSL like layout that will happen elsewhere return; } - - // Get the HLSL binding info + + const auto hlslInfo = _extractLayoutSemanticInfo(context, hlslRegSemantic); if (hlslInfo.kind == LayoutResourceKind::None) { - // Is no hlsl resource binding + // Doesn't have an HLSL resource consumption, so we are done return; } - // We need to map to the GLSL binding types - HLSLToVulkanLayoutOptions::Kind vulkanKind = HLSLToVulkanLayoutOptions::getKind(hlslInfo.kind); - if (vulkanKind == HLSLToVulkanLayoutOptions::Kind::Invalid) + // We can't infer TextureSampler from HLSL (it's not an HLSL concept) + // So use default layout + auto varType = varDecl.getDecl()->getType(); + if (as<TextureSamplerType>(varType)) { - // The binding is not "inferable" so we are done return; } - - const auto hlslBinding = HLSLToVulkanLayoutOptions::Binding{ Index(hlslInfo.space), Index(hlslInfo.index) }; - const auto vulkanBinding = hlslToVulkanLayoutOptions->inferBinding(vulkanKind, hlslBinding); - if (vulkanBinding.isInvalid()) + // Can we map to a Vulkan kind in principal? + const HLSLToVulkanLayoutOptions::Kind vulkanKind = HLSLToVulkanLayoutOptions::getKind(hlslInfo.kind); + if (vulkanKind == HLSLToVulkanLayoutOptions::Kind::Invalid) { - // If we made it here, there are shift options, but there isn't one for the space/kind specified - // That could be a problem and unexpected, so issue a warning - getSink(context)->diagnose(varDecl.getDecl(), Diagnostics::hlslToVulkanMappingNotFound, varDecl); + // If we can't use inference, for the kind we'll use other mechanisms so we are done return; } - // Add for descriptor slot - resInfo = typeLayout->findOrAddResourceInfo(LayoutResourceKind::DescriptorTableSlot); + // If inference is not enabled for this kind, we can issue a warning + if (!hlslToVulkanLayoutOptions->canInfer(vulkanKind, hlslInfo.space)) + { + _maybeDiagnoseMissingVulkanLayoutModifier(context, varDecl); + return; + } + // We use the HLSL binding directly (even though this notionally for GLSL/Vulkan) + // We'll do the shifting at later later point in _maybeApplyHLSLToVulkanShifts + resInfo = typeLayout->findOrAddResourceInfo(hlslInfo.kind); + semanticInfo.kind = resInfo->kind; - semanticInfo.index = UInt(vulkanBinding.index); - semanticInfo.space = UInt(vulkanBinding.set); - + semanticInfo.index = UInt(hlslInfo.index); + semanticInfo.space = UInt(hlslInfo.space); + const LayoutSize count = resInfo->count; addExplicitParameterBinding(context, parameterInfo, varDecl.getDecl(), semanticInfo, count); @@ -1116,7 +1167,7 @@ static void addExplicitParameterBindings_GLSL( // Given a single parameter, collect whatever information we have on // how it has been explicitly bound, which may come from multiple declarations -void generateParameterBindings( +void _generateParameterBindings( ParameterBindingContext* context, RefPtr<ParameterInfo> parameterInfo) { @@ -1330,7 +1381,7 @@ static void completeBindingsForParameterImpl( // space. UInt space = context->shared->defaultSpace; - RefPtr<UsedRangeSet> usedRangeSet = findUsedRangeSetForSpace(context, space); + RefPtr<UsedRangeSet> usedRangeSet = _getOrCreateUsedRangeSetForSpace(context, space); bindingInfo.count = count; bindingInfo.index = usedRangeSet->usedResourceRanges[(int)kind].Allocate(firstVarLayout, count.getFiniteValue()); @@ -1518,7 +1569,7 @@ static RefPtr<TypeLayout> processSimpleEntryPointParameter( // TODO: construct a `ParameterInfo` we can use here so that // overlapped layout errors get reported nicely. // - auto usedResourceSet = findUsedRangeSetForSpace(context, 0); + auto usedResourceSet = _getOrCreateUsedRangeSetForSpace(context, 0); usedResourceSet->usedResourceRanges[int(LayoutResourceKind::UnorderedAccess)].Add(nullptr, semanticIndex, semanticIndex + semanticSlotCount); } } @@ -2528,11 +2579,11 @@ static ParameterBindingAndKindInfo _allocateConstantBufferBinding( ParameterBindingContext* context) { UInt space = context->shared->defaultSpace; - auto usedRangeSet = findUsedRangeSetForSpace(context, space); + auto usedRangeSet = _getOrCreateUsedRangeSetForSpace(context, space); auto layoutInfo = context->getRulesFamily() ->getConstantBufferRules(context->getTargetRequest()) - ->GetObjectLayout(ShaderParameterKind::ConstantBuffer); + ->GetObjectLayout(ShaderParameterKind::ConstantBuffer, context->layoutContext.objectLayoutOptions); ParameterBindingAndKindInfo info; info.kind = layoutInfo.kind; @@ -2548,11 +2599,11 @@ static ParameterBindingAndKindInfo _assignConstantBufferBinding( UInt space, UInt index) { - auto usedRangeSet = findUsedRangeSetForSpace(context, space); + auto usedRangeSet = _getOrCreateUsedRangeSetForSpace(context, space); auto layoutInfo = context->getRulesFamily() ->getConstantBufferRules(context->getTargetRequest()) - ->GetObjectLayout(ShaderParameterKind::ConstantBuffer); + ->GetObjectLayout(ShaderParameterKind::ConstantBuffer, context->layoutContext.objectLayoutOptions); const Index count = Index(layoutInfo.size.getFiniteValue()); @@ -3561,6 +3612,133 @@ static bool _calcNeedsDefaultSpace(SharedParameterBindingContext& sharedContext) return false; } +static void _appendRange(Index start, LayoutSize size, StringBuilder& ioBuf) +{ + if (size == 1) + { + // If it's in effect a single index, just append like that. + ioBuf << start; + } + else + { + ioBuf << "[ " << start << " ... "; + if (size.isFinite()) + { + ioBuf << start + size.getFiniteValue() << ")"; + } + else + { + ioBuf << "inf )"; + } + } +} + +static void _maybeApplyHLSLToVulkanShifts( + ParameterBindingContext* paramContext, + TargetRequest* targetReq, + DiagnosticSink* sink) +{ + SLANG_UNUSED(sink); + + SharedParameterBindingContext& sharedContext = *paramContext->shared; + + // We may need to finally do any shifting if we have HLSLToVulkanLayoutOptions + auto vulkanOptions = targetReq->getHLSLToVulkanLayoutOptions(); + if (!vulkanOptions) + { + return; + } + + // We only need to do this if there is some inferance + if (!vulkanOptions->canInferBindings()) + { + return; + } + + for (ParameterInfo* parameterInfo : sharedContext.parameters) + { + auto varLayout = parameterInfo->varLayout; + SLANG_RELEASE_ASSERT(varLayout); + + // Iterate over all of the resourceInfos + for (auto& resourceInfo : varLayout->resourceInfos) + { + // Get the hlslToVulkanKind, and apply if valid + auto hlslToVulkanKind = HLSLToVulkanLayoutOptions::getKind(resourceInfo.kind); + if (hlslToVulkanKind != HLSLToVulkanLayoutOptions::Kind::Invalid) + { + auto& bindingInfo = parameterInfo->bindingInfo[Index(resourceInfo.kind)]; + + // Lookup the shift for the kind/space + const auto shift = vulkanOptions->getShift(hlslToVulkanKind, resourceInfo.space); + // If the shift is valid.. + if (shift != HLSLToVulkanLayoutOptions::kInvalidShift) + { + // Apply the shift + resourceInfo.index += shift; + + // Fix the parameter binding info + bindingInfo.index += shift; + + // Presumably they should both match + SLANG_ASSERT(bindingInfo.index == resourceInfo.index); + SLANG_ASSERT(bindingInfo.space == resourceInfo.space); + } + + // We should go looking for overlaps. + // In essence we need to look for HLSL kinds which have inferance. + // We assume all map to Descriptor, and look for descriptor overlaps + + // We know there can't be a clash of HLSL layout kinds previously, otherwise that would have already produced an a warning. + // We also know the only change is either *all* of a set is shifted or none. + // That means post a shift there still can't be clash between HLSL types. + + // So clashes can only be between HLSL types and other bindings (regardless) + + + auto usedSpace = _getUsedRangeSetForSpace(paramContext, bindingInfo.space); + + // The space must exist, because we are already consuming resources on it + SLANG_ASSERT(usedSpace); + + const auto& usedRanges = usedSpace->usedResourceRanges; + + // All the HLSL like bindings, we in actuality be DescriptorSlots on Vulkan + const auto& usedRange = usedRanges[Index(LayoutResourceKind::DescriptorTableSlot)]; + + // We need to get the count for the amount of slots consumed for this type + auto typeLayout = varLayout->getTypeLayout(); + + if (auto resInfo = typeLayout->FindResourceInfo(resourceInfo.kind)) + { + const auto rangeIndex = usedRange.findRangeContaining(bindingInfo.index, resInfo->count); + if (rangeIndex >= 0) + { + // We found a clash. + + const auto& clashRange = usedRange.ranges[rangeIndex]; + + // Get the var we are clashing with + auto clashingVarLayout = clashRange.parameter; + + // Get the var that we are currently looking at + auto curVar = parameterInfo->varLayout->getVariable(); + + StringBuilder curRangeBuf; + _appendRange(bindingInfo.index, resInfo->count, curRangeBuf); + + StringBuilder clashRangeBuf; + _appendRange(clashRange.begin, LayoutSize(clashRange.end), clashRangeBuf); + + // Report the clash. + sink->diagnose(curVar, Diagnostics::conflictingVulkanInferredBindingForParameter, getReflectionName(clashingVarLayout->getVariable()), curRangeBuf, clashRangeBuf); + } + } + } + } + } +} + RefPtr<ProgramLayout> generateParameterBindings( TargetProgram* targetProgram, DiagnosticSink* sink) @@ -3644,7 +3822,7 @@ RefPtr<ProgramLayout> generateParameterBindings( // for( auto& parameter : sharedContext.parameters ) { - generateParameterBindings(&context, parameter); + _generateParameterBindings(&context, parameter); } // It is possible that code has specified an explicit location @@ -3714,7 +3892,7 @@ RefPtr<ProgramLayout> generateParameterBindings( // kind of a mess, but also seems to be the best possible // answer given the constraints. // - auto usedRangeSet = findUsedRangeSetForSpace(&context, info.space); + auto usedRangeSet = _getOrCreateUsedRangeSetForSpace(&context, info.space); markSpaceUsed(&context, nullptr, info.space); usedRangeSet->usedResourceRanges[(int)kind].Add( nullptr, @@ -3856,6 +4034,9 @@ RefPtr<ProgramLayout> generateParameterBindings( // _completeBindings(&context, program); + // We may need to finally do any shifting if we have HLSLToVulkanLayoutOptions + _maybeApplyHLSLToVulkanShifts(&context, targetReq, sink); + // Next we need to create a type layout to reflect the information // we have collected, and we will use the `ScopeLayoutBuilder` // to encapsulate the logic that can be shared with the entry-point diff --git a/source/slang/slang-type-layout.cpp b/source/slang/slang-type-layout.cpp index c933c5bb5..5cf8d2350 100644 --- a/source/slang/slang-type-layout.cpp +++ b/source/slang/slang-type-layout.cpp @@ -696,12 +696,60 @@ struct GLSLSpecializationConstantLayoutRulesImpl : DefaultLayoutRulesImpl GLSLSpecializationConstantLayoutRulesImpl kGLSLSpecializationConstantLayoutRulesImpl; -// +// Given a ShaderParamKind returns the equivalent LayoutResourceKind/ParameterCategory/SlangParameterCategory +static LayoutResourceKind _getHLSLLayoutResourceKind(ShaderParameterKind kind) +{ + switch (kind) + { + case ShaderParameterKind::ConstantBuffer: + return LayoutResourceKind::ConstantBuffer; + + case ShaderParameterKind::TextureUniformBuffer: + case ShaderParameterKind::StructuredBuffer: + case ShaderParameterKind::RawBuffer: + case ShaderParameterKind::Buffer: + case ShaderParameterKind::Texture: + return LayoutResourceKind::ShaderResource; + + case ShaderParameterKind::MutableStructuredBuffer: + case ShaderParameterKind::MutableRawBuffer: + case ShaderParameterKind::MutableBuffer: + case ShaderParameterKind::MutableTexture: + return LayoutResourceKind::UnorderedAccess; + + case ShaderParameterKind::SamplerState: + return LayoutResourceKind::SamplerState; + default: + return LayoutResourceKind::None; + } +} struct GLSLObjectLayoutRulesImpl : ObjectLayoutRulesImpl { - virtual SimpleLayoutInfo GetObjectLayout(ShaderParameterKind) override + virtual SimpleLayoutInfo GetObjectLayout(ShaderParameterKind kind, const Options& options) override { + if (options.hlslToVulkanKindFlags) + { + // Is this an HLSL kind that might be shifted + + // Get as hlslLayoutKind + const auto hlslLayoutKind = _getHLSLLayoutResourceKind(kind); + + // Get as hlslToVulkanKind + const auto hlslToVulkanKind = HLSLToVulkanLayoutOptions::getKind(hlslLayoutKind); + + if (hlslToVulkanKind != HLSLToVulkanLayoutOptions::Kind::Invalid) + { + // Is this kind enabled for shift? + if (options.hlslToVulkanKindFlags & HLSLToVulkanLayoutOptions::getKindFlag(hlslToVulkanKind)) + { + // We are going to consume a HLSL layout kind + // Later we will do shifting as necessary + return SimpleLayoutInfo(hlslLayoutKind, 1); + } + } + } + // In Vulkan GLSL, pretty much every object is just a descriptor-table slot. // We can refine this method once we support a case where this isn't true. return SimpleLayoutInfo(LayoutResourceKind::DescriptorTableSlot, 1); @@ -711,7 +759,7 @@ GLSLObjectLayoutRulesImpl kGLSLObjectLayoutRulesImpl; struct GLSLPushConstantBufferObjectLayoutRulesImpl : GLSLObjectLayoutRulesImpl { - virtual SimpleLayoutInfo GetObjectLayout(ShaderParameterKind /*kind*/) override + virtual SimpleLayoutInfo GetObjectLayout(ShaderParameterKind /*kind*/, const Options& /* options */) override { // Special-case the layout for a constant-buffer, because we don't // want it to allocate a descriptor-table slot @@ -722,7 +770,7 @@ GLSLPushConstantBufferObjectLayoutRulesImpl kGLSLPushConstantBufferObjectLayoutR struct GLSLShaderRecordConstantBufferObjectLayoutRulesImpl : GLSLObjectLayoutRulesImpl { - virtual SimpleLayoutInfo GetObjectLayout(ShaderParameterKind /*kind*/) override + virtual SimpleLayoutInfo GetObjectLayout(ShaderParameterKind /*kind*/, const Options& /* options */) override { // Special-case the layout for a constant-buffer, because we don't // want it to allocate a descriptor-table slot @@ -733,7 +781,7 @@ GLSLShaderRecordConstantBufferObjectLayoutRulesImpl kGLSLShaderRecordConstantBuf struct HLSLObjectLayoutRulesImpl : ObjectLayoutRulesImpl { - virtual SimpleLayoutInfo GetObjectLayout(ShaderParameterKind kind) override + virtual SimpleLayoutInfo GetObjectLayout(ShaderParameterKind kind, const Options& /* options */) override { switch( kind ) { @@ -910,7 +958,7 @@ CUDALayoutRulesFamilyImpl kCUDALayoutRulesFamilyImpl; struct CPUObjectLayoutRulesImpl : ObjectLayoutRulesImpl { - virtual SimpleLayoutInfo GetObjectLayout(ShaderParameterKind kind) override + virtual SimpleLayoutInfo GetObjectLayout(ShaderParameterKind kind, const Options& /* options */) override { switch (kind) { @@ -962,7 +1010,7 @@ struct CUDAObjectLayoutRulesImpl : CPUObjectLayoutRulesImpl // of opaque handle (as opposed to a pointer) such as CUsurfObject, CUtexObject typedef unsigned long long ObjectHandle; - virtual SimpleLayoutInfo GetObjectLayout(ShaderParameterKind kind) override + virtual SimpleLayoutInfo GetObjectLayout(ShaderParameterKind kind, const Options & /* options */) override { switch (kind) { @@ -1501,6 +1549,11 @@ TypeLayoutContext getInitialLayoutContextForTarget(TargetRequest* targetReq, Pro context.rules = nullptr; context.matrixLayoutMode = targetReq->getDefaultMatrixLayoutMode(); + if (auto hlslToVulkanLayoutOptions = targetReq->getHLSLToVulkanLayoutOptions()) + { + context.objectLayoutOptions.hlslToVulkanKindFlags = hlslToVulkanLayoutOptions->getKindShiftEnabledFlags(); + } + if( rulesFamily ) { context.rules = rulesFamily->getConstantBufferRules(targetReq); @@ -1586,21 +1639,22 @@ static TypeLayoutResult createSimpleTypeLayout( return TypeLayoutResult(typeLayout, info); } -static SimpleLayoutInfo getParameterGroupLayoutInfo( - ParameterGroupType* type, - LayoutRulesImpl* rules) +static SimpleLayoutInfo _getParameterGroupLayoutInfo( + TypeLayoutContext const& context, + ParameterGroupType* type, + LayoutRulesImpl* rules) { if( as<ConstantBufferType>(type) ) { - return rules->GetObjectLayout(ShaderParameterKind::ConstantBuffer); + return rules->GetObjectLayout(ShaderParameterKind::ConstantBuffer, context.objectLayoutOptions); } else if( as<TextureBufferType>(type) ) { - return rules->GetObjectLayout(ShaderParameterKind::TextureUniformBuffer); + return rules->GetObjectLayout(ShaderParameterKind::TextureUniformBuffer, context.objectLayoutOptions); } else if( as<GLSLShaderStorageBufferType>(type) ) { - return rules->GetObjectLayout(ShaderParameterKind::ShaderStorageBuffer); + return rules->GetObjectLayout(ShaderParameterKind::ShaderStorageBuffer, context.objectLayoutOptions); } else if (as<ParameterBlockType>(type)) { @@ -2270,7 +2324,7 @@ static RefPtr<TypeLayout> _createParameterGroupTypeLayout( // allocate a constant buffer regiser/binding into // the overall layout, to account for it. // - auto cbUsage = parameterGroupRules->GetObjectLayout(ShaderParameterKind::ConstantBuffer); + auto cbUsage = parameterGroupRules->GetObjectLayout(ShaderParameterKind::ConstantBuffer, context.objectLayoutOptions); containerTypeLayout->addResourceUsage(cbUsage.kind, cbUsage.size); } @@ -2730,7 +2784,7 @@ createStructuredBufferTypeLayout( RefPtr<TypeLayout> elementTypeLayout) { auto rules = context.rules; - auto info = rules->GetObjectLayout(kind); + auto info = rules->GetObjectLayout(kind, context.objectLayoutOptions); auto typeLayout = new StructuredBufferTypeLayout(); @@ -3378,6 +3432,26 @@ RefPtr<TypeLayout> createTypeLayoutForGlobalGenericTypeParam( return _createTypeLayoutForGlobalGenericTypeParam(context, type, globalGenericParamDecl).layout; } +static bool _isDescriptorSlotLike( + TypeLayoutContext const& context, + LayoutResourceKind kind) +{ + if (kind == LayoutResourceKind::DescriptorTableSlot) + { + return true; + } + + if (context.objectLayoutOptions.hlslToVulkanKindFlags) + { + const auto hlslToVulkanKind = HLSLToVulkanLayoutOptions::getKind(kind); + // If it maps to a kind and it is enabled it is 'in effect' a Descriptor slot + return hlslToVulkanKind != HLSLToVulkanLayoutOptions::Kind::Invalid && + (context.objectLayoutOptions.hlslToVulkanKindFlags & HLSLToVulkanLayoutOptions::getKindFlag(hlslToVulkanKind)); + } + + return false; +} + static TypeLayoutResult createArrayLikeTypeLayout( TypeLayoutContext const& context, Type* type, @@ -3472,6 +3546,13 @@ static TypeLayoutResult createArrayLikeTypeLayout( LayoutSize arrayResourceCount = 0; + // We copy because if the element is *actually* DescriptorSlot like, + // we'll change the type. + // NOTE! That as it stands this will change the resource type from an HLSL type + // to Descriptor slot. This scenario happens when we have HLSLToVulkanLayoutOptions + // enabled, we layout with some HLSL types. + auto elementResourceKind = elementResourceInfo.kind; + // In almost all cases, the resources consumed by an array // will be its element count times the resources consumed // by its element type. @@ -3480,14 +3561,15 @@ static TypeLayoutResult createArrayLikeTypeLayout( // compiling to GLSL for Vulkan, where an entire array // only consumes a single descriptor-table slot. // - if (elementResourceInfo.kind == LayoutResourceKind::DescriptorTableSlot) + if (_isDescriptorSlotLike(context, elementResourceKind)) { arrayResourceCount = elementResourceInfo.count; + elementResourceKind = LayoutResourceKind::DescriptorTableSlot; } // The second exception to this is arrays of an existential type // where the entire array should be specialized to a single concrete type. // - else if (elementResourceInfo.kind == LayoutResourceKind::ExistentialTypeParam) + else if (elementResourceKind == LayoutResourceKind::ExistentialTypeParam) { arrayResourceCount = elementResourceInfo.count; } @@ -3505,7 +3587,7 @@ static TypeLayoutResult createArrayLikeTypeLayout( else if( elementCount.isInfinite() && adjustedElementTypeLayout != elementTypeLayout - && doesResourceRequireAdjustmentForArrayOfStructs(elementResourceInfo.kind) ) + && doesResourceRequireAdjustmentForArrayOfStructs(elementResourceKind) ) { // We want to ignore resource types consumed by the element type // that need adjustement if the array size is infinite, since @@ -3611,7 +3693,7 @@ static TypeLayoutResult _createTypeLayout( // different from a `Texture2D<U>` in terms of how it // should be handled as a member of a container. // - auto info = getParameterGroupLayoutInfo(parameterGroupType, rules); + auto info = _getParameterGroupLayoutInfo(context, parameterGroupType, rules); // The more interesting case, though, is when the user // is requesting us to actually create a `TypeLayout`, @@ -3633,7 +3715,7 @@ static TypeLayoutResult _createTypeLayout( else if (const auto samplerStateType = as<SamplerStateType>(type)) { return createSimpleTypeLayout( - rules->GetObjectLayout(ShaderParameterKind::SamplerState), + rules->GetObjectLayout(ShaderParameterKind::SamplerState, context.objectLayoutOptions), type, rules); } @@ -3654,7 +3736,7 @@ static TypeLayoutResult _createTypeLayout( } return createSimpleTypeLayout( - rules->GetObjectLayout(kind), + rules->GetObjectLayout(kind, context.objectLayoutOptions), type, rules); } @@ -3675,7 +3757,7 @@ static TypeLayoutResult _createTypeLayout( } return createSimpleTypeLayout( - rules->GetObjectLayout(kind), + rules->GetObjectLayout(kind, context.objectLayoutOptions), type, rules); } @@ -3696,7 +3778,7 @@ static TypeLayoutResult _createTypeLayout( } return createSimpleTypeLayout( - rules->GetObjectLayout(kind), + rules->GetObjectLayout(kind, context.objectLayoutOptions), type, rules); } @@ -3704,7 +3786,7 @@ static TypeLayoutResult _createTypeLayout( // TODO: need a better way to handle this stuff... #define CASE(TYPE, KIND) \ else if(auto type_##TYPE = as<TYPE>(type)) do { \ - auto info = rules->GetObjectLayout(ShaderParameterKind::KIND); \ + auto info = rules->GetObjectLayout(ShaderParameterKind::KIND, context.objectLayoutOptions); \ auto typeLayout = createStructuredBufferTypeLayout( \ context, \ ShaderParameterKind::KIND, \ @@ -3726,7 +3808,7 @@ static TypeLayoutResult _createTypeLayout( #define CASE(TYPE, KIND) \ else if(as<TYPE>(type)) do { \ return createSimpleTypeLayout( \ - rules->GetObjectLayout(ShaderParameterKind::KIND), \ + rules->GetObjectLayout(ShaderParameterKind::KIND, context.objectLayoutOptions), \ type, rules); \ } while(0) diff --git a/source/slang/slang-type-layout.h b/source/slang/slang-type-layout.h index a80f6afdd..dc769d1c7 100644 --- a/source/slang/slang-type-layout.h +++ b/source/slang/slang-type-layout.h @@ -947,8 +947,13 @@ struct SimpleLayoutRulesImpl struct ObjectLayoutRulesImpl { + struct Options + { + HLSLToVulkanLayoutOptions::KindFlags hlslToVulkanKindFlags = 0; + }; + // Compute layout info for an object type - virtual SimpleLayoutInfo GetObjectLayout(ShaderParameterKind kind) = 0; + virtual SimpleLayoutInfo GetObjectLayout(ShaderParameterKind kind, const Options& options) = 0; }; struct LayoutRulesImpl @@ -999,9 +1004,9 @@ struct LayoutRulesImpl // Forward `ObjectLayoutRulesImpl` interface - SimpleLayoutInfo GetObjectLayout(ShaderParameterKind kind) + SimpleLayoutInfo GetObjectLayout(ShaderParameterKind kind, const ObjectLayoutRulesImpl::Options& options) { - return objectRules->GetObjectLayout(kind); + return objectRules->GetObjectLayout(kind, options); } // @@ -1084,6 +1089,9 @@ struct TypeLayoutContext // Map types to their type layout Dictionary<Type*, TypeLayoutResult> layoutMap; + // Options passed to object layout + ObjectLayoutRulesImpl::Options objectLayoutOptions; + LayoutRulesImpl* getRules() { return rules; } LayoutRulesFamilyImpl* getRulesFamily() const { return rules->getLayoutRulesFamily(); } |
