summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/slang/slang-type-layout.cpp210
1 files changed, 111 insertions, 99 deletions
diff --git a/source/slang/slang-type-layout.cpp b/source/slang/slang-type-layout.cpp
index f8c2bd377..bc6ed13a2 100644
--- a/source/slang/slang-type-layout.cpp
+++ b/source/slang/slang-type-layout.cpp
@@ -1797,6 +1797,11 @@ static bool _usesOrdinaryData(RefPtr<TypeLayout> typeLayout)
return _usesResourceKind(typeLayout, LayoutResourceKind::Uniform);
}
+static bool _usesExistentialData(RefPtr<TypeLayout> typeLayout)
+{
+ return _usesResourceKind(typeLayout, LayoutResourceKind::ExistentialObjectParam);
+}
+
/// Add resource usage from `srcTypeLayout` to `dstTypeLayout` unless it would be "masked."
///
/// This function is appropriate for applying resource usage from an element type
@@ -1918,9 +1923,32 @@ static RefPtr<TypeLayout> _createParameterGroupTypeLayout(
//
// To determine if we actually need a constant-buffer binding,
// we will inspect the element type and see if it contains
- // any ordinary/uniform data.
+ // any ordinary/uniform data *or* any interface/existential-type
+ // slots.
+ //
+ // The latter detail might sound surprising, because it means
+ // that for a declaration like:
//
- bool wantConstantBuffer = _usesOrdinaryData(rawElementTypeLayout);
+ // cbuffer U { IThing gThing; }
+ //
+ // we will allocate a constant-buffer binding for `U` whether
+ // or not it turns out that the concrete type plugged in for
+ // `IThing gThing` has any ordinary/uniform data at all (that is,
+ // if the user plugs in a type that only holds a `Texture2D`,
+ // we will still have allocated the constant buffer binding/register,
+ // and waste it on an empty buffer).
+ //
+ // The reason for this choice is that it greatly simplifies
+ // logic for clients of Slang: a given `ConstantBuffer<>` or
+ // `cbuffer` variable can be statically determined to either
+ // need a constant buffer binding or not, based on its declared
+ // element type, and *nothing* that happens later can change
+ // that (e.g., plugging in a new value/object for `gThing`
+ // can't retroactively change whether or not `U` needed
+ // a constant buffer).
+ //
+ bool wantConstantBuffer = _usesOrdinaryData(rawElementTypeLayout)
+ || _usesExistentialData(rawElementTypeLayout);
if( wantConstantBuffer )
{
// If there is any ordinary data, then we'll need to
@@ -1932,10 +1960,8 @@ static RefPtr<TypeLayout> _createParameterGroupTypeLayout(
}
// Similarly to how we only need a constant buffer to be allocated
- // if the contents of the group actually had ordinary/uniform data,
- // we also only want to allocate a `space` or `set` if that is really
- // required.
- //
+ // if the contents of the group actually call for it, we also only
+ // want to allocate a `space` or `set` if that is really required.
//
bool canUseSpaceOrSet = false;
//
@@ -1970,9 +1996,11 @@ static RefPtr<TypeLayout> _createParameterGroupTypeLayout(
if( canUseSpaceOrSet )
{
// Note that if we are allocating a constant buffer to hold
- // some ordinary/uniform data then we definitely want a space/set,
- // but we don't need to special-case that because the loop
- // here will also detect the `LayoutResourceKind::Uniform` usage.
+ // some ordinary/uniform (or existential) data then we
+ // definitely want a space/set (because we will need it for
+ // the constant buffer we allocated above) but we don't need
+ // to special-case that because the loop here will also detect
+ // the `LayoutResourceKind::Uniform` usage.
for( auto elementResourceInfo : rawElementTypeLayout->resourceInfos )
{
@@ -2080,89 +2108,27 @@ static RefPtr<TypeLayout> _createParameterGroupTypeLayout(
{
auto rules = rawElementTypeLayout->rules;
- // One really annoying complication we need to deal with here
- // its that it is possible that the original parameter group
- // declaration didn't need a constant buffer or `space`/`set`
- // to be allocated, but once we consider the "pending" data
- // we need to have a constant buffer and/or space.
+ // Note that because we conservatively allocated both
+ // a constant buffer `register`/`binding` and a `space`/`set`
+ // for the container in cases where the element type
+ // might need it (which included interface/existential types),
+ // there is no need to worry about a case where `pendingElementType`
+ // could require a constant buffer `register`/`binding` or
+ // as `space`/`set` to be allocated but we didn't already
+ // allocate one in the non-pending layout.
+ //
+ // Out focus here is then on setting up the representation
+ // of the "pending" data for the element type, and in
+ // particular on dealing with any data that needs to
+ // "bleed through" to the resource usage of the overall
+ // parameter group.
//
- // We will compute whether the pending data create a demand
- // for a constant buffer and/or a space/set, so that we know
- // if we are in the tricky case.
- //
- bool pendingDataWantsConstantBuffer = _usesOrdinaryData(pendingElementTypeLayout);
- bool pendingDataWantsSpaceOrSet = false;
- if( canUseSpaceOrSet )
- {
- for( auto resInfo : pendingElementTypeLayout->resourceInfos )
- {
- if( resInfo.kind != LayoutResourceKind::RegisterSpace )
- {
- pendingDataWantsSpaceOrSet = true;
- break;
- }
- }
- }
-
- // We will use a few different variables to track resource
- // usage for the pending data, with roles similar to the
- // umbrella type layout, container layout, and element layout
- // that already came up for the main part of the parameter group type.
-
-
- RefPtr<TypeLayout> pendingContainerTypeLayout = new TypeLayout();
- pendingContainerTypeLayout->type = parameterGroupType;
- pendingContainerTypeLayout->rules = parameterGroupRules;
-
- containerTypeLayout->pendingDataTypeLayout = pendingContainerTypeLayout;
-
- RefPtr<VarLayout> pendingContainerVarLayout = new VarLayout();
- pendingContainerVarLayout->typeLayout = pendingContainerTypeLayout;
-
- containerVarLayout->pendingVarLayout = pendingContainerVarLayout;
-
-
RefPtr<VarLayout> pendingElementVarLayout = new VarLayout();
pendingElementVarLayout->typeLayout = pendingElementTypeLayout;
elementVarLayout->pendingVarLayout = pendingElementVarLayout;
- // If we need a space/set for the pending data, and don't already
- // have one, then we will allocate it now, as part of the
- // "full" data type.
- //
- if( pendingDataWantsSpaceOrSet && !wantSpaceOrSet )
- {
- pendingContainerTypeLayout->addResourceUsage(LayoutResourceKind::RegisterSpace, 1);
-
- // From here on, we know we have access to a register space,
- // and we can mask any registers/bindings appropriately.
- //
- wantSpaceOrSet = true;
- }
-
- // If we need a constant buffer for laying out ordinary
- // data, and didn't have one allocated before, we will create
- // one.
- //
- if( pendingDataWantsConstantBuffer && !wantConstantBuffer )
- {
- auto cbUsage = rules->GetObjectLayout(ShaderParameterKind::ConstantBuffer);
- pendingContainerTypeLayout->addResourceUsage(cbUsage.kind, cbUsage.size);
-
- wantConstantBuffer = true;
- }
-
- for( auto resInfo : pendingContainerTypeLayout->resourceInfos )
- {
- pendingContainerVarLayout->findOrAddResourceInfo(resInfo.kind);
- }
-
- // Now that we've added in the resource usage for any CB or set/space
- // we needed to allocate just for the pending data, we can safely
- // lay out the pending data itself.
- //
- // The ordinary/uniform part of things wil always be "masked" and
+ // Any ordinary/uniform part of the pending data wil always be "masked" and
// needs to come after any uniform data from the original element type.
//
// To kick things off we will initialize state for `struct` type layout,
@@ -2183,8 +2149,8 @@ static RefPtr<TypeLayout> _createParameterGroupTypeLayout(
if( resInfo.kind == LayoutResourceKind::Uniform )
{
// For the ordinary/uniform resource kind, we will add the resource
- // usage as a structure field, and then write the resulting offset
- // into the variable layout for the pending data.
+ // usage as if it was a structure field, and then write the resulting
+ // offset into the variable layout for the pending data.
//
auto offset = rules->AddStructField(
&uniformLayout,
@@ -2195,16 +2161,11 @@ static RefPtr<TypeLayout> _createParameterGroupTypeLayout(
}
else
{
- // For all other resource kinds, we will set the offset in
- // the variable layout based on the total resources of that
- // kind seen so far (including the "container" if any),
- // and then bump the count for total resource usage.
+ // For all other resource kinds, we simply need to add an
+ // entry to the pending layout to represent the resource
+ // usage of the pending data.
//
- auto elementVarResInfo = pendingElementVarLayout->findOrAddResourceInfo(resInfo.kind);
- if( auto containerTypeInfo = pendingContainerTypeLayout->FindResourceInfo(resInfo.kind) )
- {
- elementVarResInfo->index = containerTypeInfo->count.getFiniteValue();
- }
+ pendingElementVarLayout->findOrAddResourceInfo(resInfo.kind);
}
}
rules->EndStructLayout(&uniformLayout);
@@ -2218,7 +2179,6 @@ static RefPtr<TypeLayout> _createParameterGroupTypeLayout(
// up the hierarchy.
//
RefPtr<TypeLayout> unmaskedPendingDataTypeLayout = new TypeLayout();
- _addUnmaskedResourceUsage(true, unmaskedPendingDataTypeLayout, pendingContainerTypeLayout, wantSpaceOrSet);
_addUnmaskedResourceUsage(false, unmaskedPendingDataTypeLayout, pendingElementTypeLayout, wantSpaceOrSet);
// TODO: we should probably optimize for the case where there is no unmasked
@@ -2228,6 +2188,58 @@ static RefPtr<TypeLayout> _createParameterGroupTypeLayout(
//
typeLayout->pendingDataTypeLayout = unmaskedPendingDataTypeLayout;
+ // We will now attempt to compute reasonable offset information for
+ // (non-uniform) pending data in the element type. There are basically
+ // two cases here:
+ //
+ // 1. If the resource kind is one that is "masked" by the container,
+ // then the pending data can be statically placed at an offset fater
+ // the diret (non-pending) element data.
+ //
+ // 2. If the resource kind is one that "bleeds through" to the container,
+ // then its offset will always be relative to the location that
+ // gets allocated for pending data in the container, which means it
+ // is always zero.
+ //
+ // Because the offsets are currently all set to zero, we only
+ // need to check for case (1).
+ //
+ for( auto pendingVarResInfo : pendingElementVarLayout->resourceInfos )
+ {
+ auto kind = pendingVarResInfo.kind;
+
+ // If we are looking at uniform resource usage, we already
+ // handled it easlier.
+ //
+ if(kind == LayoutResourceKind::Uniform)
+ continue;
+
+ // If the usage is unmasked, the nwe are in case (2) and should
+ // skip out.
+ //
+ if(unmaskedPendingDataTypeLayout->FindResourceInfo(kind))
+ continue;
+
+ // Okay, we have resource info for somethign that is going
+ // to be "masked" by the container, in which case we
+ // can compute a fixed offset, after any existing data
+ // of the same kind.
+ //
+ auto existingVarResInfo = elementVarLayout->FindResourceInfo(kind);
+ if(!existingVarResInfo)
+ continue;
+
+ auto existingTypeResInfo = elementVarLayout->typeLayout->FindResourceInfo(kind);
+ if(!existingTypeResInfo)
+ continue;
+
+ // TODO: We need a more robust solution than just calling
+ // `getFiniteValue` here.
+ //
+ pendingVarResInfo.index = existingVarResInfo->index
+ + existingTypeResInfo->count.getFiniteValue();
+ }
+
// TODO: we should probably adjust the size reported by the element type
// to include any "pending" data that was allocated into the group, so
// that it can be easier for client code to allocate their instances.
@@ -3025,7 +3037,7 @@ static TypeLayoutResult _createTypeLayout(
// buffer, including offsets, etc.
//
// 2. Compute information about any object types inside
- // the constant buffer, which need to be surfaces out
+ // the constant buffer, which need to be surfaced out
// to the top level.
//
auto typeLayout = createParameterGroupTypeLayout(