summaryrefslogtreecommitdiffstats
path: root/source/slang/slang-reflection-api.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/slang-reflection-api.cpp')
-rw-r--r--source/slang/slang-reflection-api.cpp214
1 files changed, 170 insertions, 44 deletions
diff --git a/source/slang/slang-reflection-api.cpp b/source/slang/slang-reflection-api.cpp
index e68efde06..d75920fdb 100644
--- a/source/slang/slang-reflection-api.cpp
+++ b/source/slang/slang-reflection-api.cpp
@@ -1056,22 +1056,104 @@ SLANG_API SlangReflectionVariableLayout* spReflectionTypeLayout_getSpecializedTy
}
}
+SLANG_API SlangInt spReflectionType_getSpecializedTypeArgCount(SlangReflectionType* inType)
+{
+ auto type = convert(inType);
+ if(!type) return 0;
+
+ auto specializedType = as<ExistentialSpecializedType>(type);
+ if(!specializedType) return 0;
+
+ return specializedType->args.getCount();
+}
+
+SLANG_API SlangReflectionType* spReflectionType_getSpecializedTypeArgType(SlangReflectionType* inType, SlangInt index)
+{
+ auto type = convert(inType);
+ if(!type) return nullptr;
+
+ auto specializedType = as<ExistentialSpecializedType>(type);
+ if(!specializedType) return nullptr;
+
+ if(index < 0) return nullptr;
+ if(index >= specializedType->args.getCount()) return nullptr;
+
+ auto argType = as<Type>(specializedType->args[index].val);
+ return convert(argType);
+}
+
namespace Slang
{
+ /// A link in a chain of `VarLayout`s that can be used to compute offset information for a nested field
struct BindingRangePathLink
{
+ BindingRangePathLink()
+ {}
+
BindingRangePathLink(
BindingRangePathLink* parent,
VarLayout* var)
- : parent(parent)
- , var(var)
+ : var(var)
+ , parent(parent)
{}
- BindingRangePathLink* parent;
- VarLayout* var;
+ /// The inner-most variable that contributes to the offset along this path
+ VarLayout* var = nullptr;
+
+ /// The next outer link along the path
+ BindingRangePathLink* parent = nullptr;
+ };
+
+ /// A path leading to some nested field, with both parimary and "pending" data offsets
+ struct BindingRangePath
+ {
+
+ /// The chain of variables that defines the "primary" offset of a nested field
+ BindingRangePathLink* primary = nullptr;
+
+ /// The chain of variables that defines the offset for "pending" data of a nested field
+ BindingRangePathLink* pending = nullptr;
};
+ /// A helper type to construct a `BindingRangePath` that extends an existing path
+ struct ExtendedBindingRangePath : BindingRangePath
+ {
+ /// Construct a path that extends `parent` with offset information from `varLayout`
+ ExtendedBindingRangePath(
+ BindingRangePath const& parent,
+ VarLayout* varLayout)
+ {
+ SLANG_ASSERT(varLayout);
+
+ // We always add another link to the primary chain.
+ //
+ primaryLink = BindingRangePathLink(parent.primary, varLayout);
+ primary = &primaryLink;
+
+ // If the `varLayout` provided has any offset information
+ // for pending data, then we also add a link to the pending
+ // chain, but otherwise we re-use the pending chain from
+ // the parent path.
+ //
+ if(auto pendingLayout = varLayout->pendingVarLayout)
+ {
+ pendingLink = BindingRangePathLink(parent.pending, pendingLayout);
+ pending = &pendingLink;
+ }
+ else
+ {
+ pending = parent.pending;
+ }
+ }
+
+ /// Storage for a link in the primary chain, if needed
+ BindingRangePathLink primaryLink;
+
+ /// Storage for a link in the pending chain, if needed
+ BindingRangePathLink pendingLink;
+ };
+ /// Calculate the offset for resources of the given `kind` in the `path`.
Int _calcIndexOffset(BindingRangePathLink* path, LayoutResourceKind kind)
{
Int result = 0;
@@ -1085,6 +1167,7 @@ namespace Slang
return result;
}
+ /// Calculate the regsiter space / set for resources of the given `kind` in the `path`.
Int _calcSpaceOffset(BindingRangePathLink* path, LayoutResourceKind kind)
{
Int result = 0;
@@ -1208,12 +1291,24 @@ namespace Slang
}
}
-
-
SlangBindingType _calcBindingType(
Slang::TypeLayout* typeLayout,
LayoutResourceKind kind)
{
+ // At the type level, a push-constant buffer and a regular constant
+ // buffer are currently not distinct, so we need to detect push
+ // constant buffers/ranges before we inspect the `typeLayout` to
+ // avoid reflecting them all as ordinary constant buffers.
+ //
+ switch(kind)
+ {
+ default:
+ break;
+
+ case LayoutResourceKind::PushConstantBuffer:
+ return SLANG_BINDING_TYPE_PUSH_CONSTANT;
+ }
+
// If the type or type layout implies a specific binding type
// (e.g., a `Texture2D` implies a texture binding), then we
// will always favor the binding type implied.
@@ -1267,7 +1362,42 @@ namespace Slang
return index;
}
- void addRangesRec(TypeLayout* typeLayout, BindingRangePathLink* path, LayoutSize multiplier)
+ /// Create a single `VarLayout` for `typeLayout` that summarizes all of the offset information in `path`.
+ ///
+ /// Note: This function does not handle "pending" layout information.
+ RefPtr<VarLayout> _createSimpleOffsetVarLayout(TypeLayout* typeLayout, BindingRangePathLink* path)
+ {
+ SLANG_ASSERT(typeLayout);
+
+ RefPtr<VarLayout> varLayout = new VarLayout();
+ varLayout->typeLayout = typeLayout;
+
+ for(auto typeResInfo : typeLayout->resourceInfos)
+ {
+ auto kind = typeResInfo.kind;
+ auto varResInfo = varLayout->findOrAddResourceInfo(kind);
+ varResInfo->index = _calcIndexOffset(path, kind);
+ varResInfo->space = _calcSpaceOffset(path, kind);
+ }
+
+ return varLayout;
+ }
+
+ /// Create a single `VarLayout` for `typeLayout` that summarizes all of the offset information in `path`.
+ RefPtr<VarLayout> createOffsetVarLayout(TypeLayout* typeLayout, BindingRangePath const& path)
+ {
+ auto primaryVarLayout = _createSimpleOffsetVarLayout(typeLayout, path.primary);
+ SLANG_ASSERT(primaryVarLayout);
+
+ if(auto pendingDataTypeLayout = typeLayout->pendingDataTypeLayout)
+ {
+ primaryVarLayout->pendingVarLayout = _createSimpleOffsetVarLayout(pendingDataTypeLayout, path.pending);
+ }
+
+ return primaryVarLayout;
+ }
+
+ void addRangesRec(TypeLayout* typeLayout, BindingRangePath const& path, LayoutSize multiplier)
{
if( auto structTypeLayout = as<StructTypeLayout>(typeLayout) )
{
@@ -1287,9 +1417,8 @@ namespace Slang
auto fieldTypeLayout = fieldVarLayout->getTypeLayout();
-
- BindingRangePathLink fieldLink(path, fieldVarLayout);
- addRangesRec(fieldTypeLayout, &fieldLink, multiplier);
+ ExtendedBindingRangePath fieldPath(path, fieldVarLayout);
+ addRangesRec(fieldTypeLayout, fieldPath, multiplier);
}
return;
}
@@ -1336,7 +1465,7 @@ namespace Slang
{
if( spaceOffset == -1 )
{
- spaceOffset = _calcSpaceOffset(path, kind);
+ spaceOffset = _calcSpaceOffset(path.primary, kind);
}
kind = resInfo.kind;
@@ -1382,24 +1511,17 @@ namespace Slang
bindingRange.firstDescriptorRangeIndex = 0;
bindingRange.descriptorRangeCount = 0;
- if( kind == LayoutResourceKind::PushConstantBuffer )
- {
- if(auto resInfo = parameterGroupTypeLayout->elementVarLayout->typeLayout->FindResourceInfo(LayoutResourceKind::Uniform))
- {
- bindingRange.count *= resInfo->count;
- }
- }
-
// Every parameter group will introduce a sub-object range,
// which will include bindings based on the type of data
// inside the sub-object.
//
TypeLayout::ExtendedInfo::SubObjectRangeInfo subObjectRange;
subObjectRange.bindingRangeIndex = bindingRangeIndex;
+ subObjectRange.offsetVarLayout = createOffsetVarLayout(typeLayout, path);
subObjectRange.spaceOffset = 0;
- if (kind == LayoutResourceKind::RegisterSpace && path)
+ if (kind == LayoutResourceKind::RegisterSpace && path.primary)
{
- auto resInfo = path->var->FindResourceInfo(LayoutResourceKind::RegisterSpace);
+ auto resInfo = path.primary->var->FindResourceInfo(LayoutResourceKind::RegisterSpace);
subObjectRange.spaceOffset = resInfo->index;
}
// It is possible that the sub-object has descriptor ranges
@@ -1488,16 +1610,7 @@ namespace Slang
descriptorRange.kind = resInfo.kind;
descriptorRange.bindingType = _calcBindingType(typeLayout, resInfo.kind);
descriptorRange.count = multiplier;
- descriptorRange.indexOffset = _calcIndexOffset(path, resInfo.kind);
-
- if( resInfo.kind == LayoutResourceKind::PushConstantBuffer )
- {
- if(auto uniformResInfo = parameterGroupTypeLayout->elementVarLayout->typeLayout->FindResourceInfo(LayoutResourceKind::Uniform))
- {
- descriptorRange.count *= uniformResInfo->count;
- }
- }
-
+ descriptorRange.indexOffset = _calcIndexOffset(path.primary, resInfo.kind);
descriptorSet->descriptorRanges.add(descriptorRange);
}
}
@@ -1548,12 +1661,12 @@ namespace Slang
// up binding information, to ensure that the descriptor ranges
// that get enumerated here have correct register/binding offsets.
//
- BindingRangePathLink elementPath(path, parameterGroupTypeLayout->elementVarLayout);
+ ExtendedBindingRangePath elementPath(path, parameterGroupTypeLayout->elementVarLayout);
Index bindingRangeCountBefore = m_extendedInfo->m_bindingRanges.getCount();
Index subObjectRangeCountBefore = m_extendedInfo->m_subObjectRanges.getCount();
- addRangesRec(parameterGroupTypeLayout->elementVarLayout->typeLayout, &elementPath, multiplier);
+ addRangesRec(parameterGroupTypeLayout->elementVarLayout->typeLayout, elementPath, multiplier);
m_extendedInfo->m_bindingRanges.setCount(bindingRangeCountBefore);
m_extendedInfo->m_subObjectRanges.setCount(subObjectRangeCountBefore);
@@ -1576,10 +1689,6 @@ namespace Slang
// An `interface` type should introduce a binding range and a matching
// sub-object range.
//
- // We currently do *not* allocate any descriptor ranges to represent
- // an interface-type field, since the only direct storage required
- // is all uniform/ordinary data.
- //
TypeLayout::ExtendedInfo::BindingRangeInfo bindingRange;
bindingRange.leafTypeLayout = typeLayout;
bindingRange.bindingType = SLANG_BINDING_TYPE_EXISTENTIAL_VALUE;
@@ -1590,10 +1699,7 @@ namespace Slang
TypeLayout::ExtendedInfo::SubObjectRangeInfo subObjectRange;
subObjectRange.bindingRangeIndex = m_extendedInfo->m_bindingRanges.getCount();
-
- // TODO: if we have "pending" layout information that tells us where
- // data for the sub-object range has been allocated, then we need
- // a way to reference that data here.
+ subObjectRange.offsetVarLayout = createOffsetVarLayout(typeLayout, path);
m_extendedInfo->m_bindingRanges.add(bindingRange);
m_extendedInfo->m_subObjectRanges.add(subObjectRange);
@@ -1730,8 +1836,8 @@ namespace Slang
// `resInfo` representing resouce usage.
//
auto count = resInfo.count * multiplier;
- auto indexOffset = _calcIndexOffset(path, kind);
- auto spaceOffset = _calcSpaceOffset(path, kind);
+ auto indexOffset = _calcIndexOffset(path.primary, kind);
+ auto spaceOffset = _calcSpaceOffset(path.primary, kind);
TypeLayout::ExtendedInfo::DescriptorRangeInfo descriptorRange;
descriptorRange.kind = kind;
@@ -1767,7 +1873,8 @@ namespace Slang
context.m_typeLayout = typeLayout;
context.m_extendedInfo = extendedInfo;
- context.addRangesRec(typeLayout, nullptr, 1);
+ BindingRangePath rootPath;
+ context.addRangesRec(typeLayout, rootPath, 1);
typeLayout->m_extendedInfo = extendedInfo;
}
@@ -2033,6 +2140,25 @@ SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeSpaceOffset(
return extTypeLayout->m_subObjectRanges[subObjectRangeIndex].spaceOffset;
}
+SLANG_API SlangReflectionVariableLayout* spReflectionTypeLayout_getSubObjectRangeOffset(
+ SlangReflectionTypeLayout* inTypeLayout,
+ SlangInt subObjectRangeIndex)
+{
+ auto typeLayout = convert(inTypeLayout);
+ if (!typeLayout)
+ return 0;
+
+ auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout);
+
+ if (subObjectRangeIndex < 0)
+ return 0;
+ if (subObjectRangeIndex >= extTypeLayout->m_subObjectRanges.getCount())
+ return 0;
+
+ return convert(extTypeLayout->m_subObjectRanges[subObjectRangeIndex].offsetVarLayout);
+}
+
+
#if 0
SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeSubObjectRangeIndex(SlangReflectionTypeLayout* inTypeLayout, SlangInt index)