diff options
| author | Tim Foley <tfoley@nvidia.com> | 2017-07-14 12:00:29 -0700 |
|---|---|---|
| committer | Tim Foley <tfoley@nvidia.com> | 2017-07-14 12:00:29 -0700 |
| commit | f4ac13d6718d6433f69eb21311110c8225a95aee (patch) | |
| tree | fb6ab85174f2f630dd49910bc69bb23309f9eee0 /source/slang/type-layout.cpp | |
| parent | d9366db8993c566fbb0af780c13db438dbf74022 (diff) | |
Adjust type layout when parameter block constains member using the same resource
If we have something like to following in HLSL:
cbuffer C { Texture2D t; ... }
and we are compiling to GLSL, then both `C` and `C.t` consume the same kind of resource (a descriptor-table slot).
The way reflection was working right now, querying the index of `C` would return its binding (let's say it is `4` just to be concrete) and then a query on `C::t` would give its offset, which was being computed as `0` because it is the first field in the logical `struct` type.
That obviously leads to bad math and requires some subtle `+1`s in cases to get things right (e.g., when scalaring during lowering, I had to carefully add one in some cases).
It is unreasonable to expect users to deal with this.
This commit changes it so that the offset of field `C::t` is `1` so that hopefully more things Just Work.
The special-case logic in lowering is now gone.
One important catch here is that this pretty much only works in the case where the element type of a parameter block is a `struct` type (which is really all that makes sense right now).
If we ever want to generalize this in the future, then it will probably be necessary to change the `TypeLayout` case for parameter blocks to store a `VarLayout` for the element, rather than just a `TypeLayout`.
Diffstat (limited to 'source/slang/type-layout.cpp')
| -rw-r--r-- | source/slang/type-layout.cpp | 121 |
1 files changed, 88 insertions, 33 deletions
diff --git a/source/slang/type-layout.cpp b/source/slang/type-layout.cpp index 2e0f3035a..6ca2d68fb 100644 --- a/source/slang/type-layout.cpp +++ b/source/slang/type-layout.cpp @@ -681,28 +681,14 @@ static SimpleLayoutInfo getParameterBlockLayoutInfo( RefPtr<ParameterBlockTypeLayout> createParameterBlockTypeLayout( RefPtr<ParameterBlockType> parameterBlockType, - RefPtr<TypeLayout> elementTypeLayout, - LayoutRulesImpl* rules) + LayoutRulesImpl* parameterBlockRules, + SimpleLayoutInfo parameterBlockInfo, + RefPtr<TypeLayout> elementTypeLayout) { - SimpleLayoutInfo info; - if (parameterBlockType) - { - info = getParameterBlockLayoutInfo( - parameterBlockType, - rules); - } - else - { - // If there is no concrete type, then it seems like we are - // being asked to compute layout for the global scope - info = rules->GetObjectLayout(ShaderParameterKind::ConstantBuffer); - } - - auto typeLayout = new ParameterBlockTypeLayout(); typeLayout->type = parameterBlockType; - typeLayout->rules = rules; + typeLayout->rules = parameterBlockRules; typeLayout->elementTypeLayout = elementTypeLayout; @@ -711,7 +697,7 @@ createParameterBlockTypeLayout( // originally (which should be a single binding "slot" // and hence no uniform data). // - typeLayout->uniformAlignment = info.alignment; + typeLayout->uniformAlignment = parameterBlockInfo.alignment; assert(!typeLayout->FindResourceInfo(LayoutResourceKind::Uniform)); assert(typeLayout->uniformAlignment == 1); @@ -725,11 +711,11 @@ createParameterBlockTypeLayout( // Make sure that we allocate resource usage for the // parameter block itself. - if( info.size ) + if( parameterBlockInfo.size ) { typeLayout->addResourceUsage( - info.kind, - info.size); + parameterBlockInfo.kind, + parameterBlockInfo.size); } // Now, if the element type itself had any resources, then @@ -749,6 +735,48 @@ createParameterBlockTypeLayout( return typeLayout; } +RefPtr<ParameterBlockTypeLayout> +createParameterBlockTypeLayout( + RefPtr<ParameterBlockType> parameterBlockType, + LayoutRulesImpl* parameterBlockRules, + RefPtr<ExpressionType> elementType, + LayoutRulesImpl* elementTypeRules) +{ + // First compute resource usage of the block itself. + // For now we assume that the layout of the block can + // always be described in a `SimpleLayoutInfo` (only + // a single resource kind consumed). + SimpleLayoutInfo info; + if (parameterBlockType) + { + info = getParameterBlockLayoutInfo( + parameterBlockType, + parameterBlockRules); + } + else + { + // If there is no concrete type, then it seems like we are + // being asked to compute layout for the global scope + info = parameterBlockRules->GetObjectLayout(ShaderParameterKind::ConstantBuffer); + } + + // Now compute a layout for the elements of the parameter block. + // Note that we need to be careful and deal with the case where + // the elements of the block use the same resource kind consumed + // by the block itself. + + auto elementTypeLayout = CreateTypeLayout( + elementType, + elementTypeRules, + info); + + return createParameterBlockTypeLayout( + parameterBlockType, + parameterBlockRules, + info, + elementTypeLayout); +} + LayoutRulesImpl* getParameterBufferElementTypeLayoutRules( RefPtr<ParameterBlockType> parameterBlockType, LayoutRulesImpl* rules) @@ -783,22 +811,20 @@ LayoutRulesImpl* getParameterBufferElementTypeLayoutRules( RefPtr<ParameterBlockTypeLayout> createParameterBlockTypeLayout( RefPtr<ParameterBlockType> parameterBlockType, - LayoutRulesImpl* rules) + LayoutRulesImpl* parameterBlockRules) { // Determine the layout rules to use for the contents of the block - auto parameterBlockLayoutRules = getParameterBufferElementTypeLayoutRules( + auto elementTypeRules = getParameterBufferElementTypeLayoutRules( parameterBlockType, - rules); + parameterBlockRules); - // Create and save type layout for the buffer contents. - auto elementTypeLayout = CreateTypeLayout( - parameterBlockType->elementType.Ptr(), - parameterBlockLayoutRules); + auto elementType = parameterBlockType->elementType; return createParameterBlockTypeLayout( parameterBlockType, - elementTypeLayout, - rules); + parameterBlockRules, + elementType, + elementTypeRules); } // Create a type layout for a structured buffer type. @@ -863,8 +889,23 @@ createStructuredBufferTypeLayout( SimpleLayoutInfo GetLayoutImpl( ExpressionType* type, LayoutRulesImpl* rules, + RefPtr<TypeLayout>* outTypeLayout, + SimpleLayoutInfo offset); + +SimpleLayoutInfo GetLayoutImpl( + ExpressionType* type, + LayoutRulesImpl* rules, RefPtr<TypeLayout>* outTypeLayout) { + return GetLayoutImpl(type, rules, outTypeLayout, SimpleLayoutInfo()); +} + +SimpleLayoutInfo GetLayoutImpl( + ExpressionType* type, + LayoutRulesImpl* rules, + RefPtr<TypeLayout>* outTypeLayout, + SimpleLayoutInfo offset) +{ if (auto parameterBlockType = type->As<ParameterBlockType>()) { // If the user is just interested in uniform layout info, @@ -1184,6 +1225,15 @@ SimpleLayoutInfo GetLayoutImpl( fieldResourceInfo->index = structTypeResourceInfo->count; structTypeResourceInfo->count += fieldTypeResourceInfo.count; } + + // If the user passed in offset info, then apply it here + if (offset.size) + { + if (auto fieldResInfo = fieldLayout->FindResourceInfo(offset.kind)) + { + fieldResInfo->index += offset.size; + } + } } } @@ -1226,13 +1276,18 @@ SimpleLayoutInfo GetLayout(ExpressionType* inType, LayoutRulesImpl* rules) return GetLayoutImpl(inType, rules, nullptr); } -RefPtr<TypeLayout> CreateTypeLayout(ExpressionType* type, LayoutRulesImpl* rules) +RefPtr<TypeLayout> CreateTypeLayout(ExpressionType* type, LayoutRulesImpl* rules, SimpleLayoutInfo offset) { RefPtr<TypeLayout> typeLayout; - GetLayoutImpl(type, rules, &typeLayout); + GetLayoutImpl(type, rules, &typeLayout, offset); return typeLayout; } +RefPtr<TypeLayout> CreateTypeLayout(ExpressionType* type, LayoutRulesImpl* rules) +{ + return CreateTypeLayout(type, rules, SimpleLayoutInfo()); +} + SimpleLayoutInfo GetLayout(ExpressionType* type, LayoutRule rule) { LayoutRulesImpl* rulesImpl = GetLayoutRulesImpl(rule); |
