diff options
Diffstat (limited to 'source/slang/slang-reflection-api.cpp')
| -rw-r--r-- | source/slang/slang-reflection-api.cpp | 214 |
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) |
