summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/slang/slang-diagnostic-defs.h2
-rw-r--r--source/slang/slang-hlsl-to-vulkan-layout-options.cpp56
-rw-r--r--source/slang/slang-hlsl-to-vulkan-layout-options.h38
-rw-r--r--source/slang/slang-parameter-binding.cpp307
-rw-r--r--source/slang/slang-type-layout.cpp132
-rw-r--r--source/slang/slang-type-layout.h14
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(); }