diff options
Diffstat (limited to 'source/slang/type-layout.cpp')
| -rw-r--r-- | source/slang/type-layout.cpp | 294 |
1 files changed, 190 insertions, 104 deletions
diff --git a/source/slang/type-layout.cpp b/source/slang/type-layout.cpp index 30b2ee01a..da1337778 100644 --- a/source/slang/type-layout.cpp +++ b/source/slang/type-layout.cpp @@ -758,8 +758,7 @@ static SimpleLayoutInfo getParameterGroupLayoutInfo( RefPtr<TypeLayout> createTypeLayout( TypeLayoutContext const& context, - Type* type, - SimpleLayoutInfo offset); + Type* type); static bool isOpenGLTarget(TargetRequest*) { @@ -860,21 +859,110 @@ static bool shouldAllocateRegisterSpaceForParameterBlock( return false; } +// Given an existing type layout `oldTypeLayout`, apply offsets +// to any contained fields based on the resource infos in `offsetTypeLayout` +// *and* the usage implied by `offsetLayout` +RefPtr<TypeLayout> applyOffsetToTypeLayout( + RefPtr<TypeLayout> oldTypeLayout, + RefPtr<TypeLayout> offsetTypeLayout) +{ + // There is no need to apply offsets if the old type and the offset + // don't share any resource infos in common. + bool anyHit = false; + for (auto oldResInfo : oldTypeLayout->resourceInfos) + { + if (auto offsetResInfo = offsetTypeLayout->FindResourceInfo(oldResInfo.kind)) + { + anyHit = true; + break; + } + } + + if (!anyHit) + return oldTypeLayout; + + RefPtr<TypeLayout> newTypeLayout; + if (auto oldStructTypeLayout = oldTypeLayout.As<StructTypeLayout>()) + { + RefPtr<StructTypeLayout> newStructTypeLayout = new StructTypeLayout(); + newStructTypeLayout->type = oldStructTypeLayout->type; + newStructTypeLayout->uniformAlignment = oldStructTypeLayout->uniformAlignment; + + Dictionary<VarLayout*, VarLayout*> mapOldFieldToNew; + + for (auto oldField : oldStructTypeLayout->fields) + { + RefPtr<VarLayout> newField = new VarLayout(); + newField->varDecl = oldField->varDecl; + newField->typeLayout = oldField->typeLayout; + newField->flags = oldField->flags; + newField->semanticIndex = oldField->semanticIndex; + newField->semanticName = oldField->semanticName; + newField->stage = oldField->stage; + newField->systemValueSemantic = oldField->systemValueSemantic; + newField->systemValueSemanticIndex = oldField->systemValueSemanticIndex; + + + for (auto oldResInfo : oldField->resourceInfos) + { + auto newResInfo = newField->findOrAddResourceInfo(oldResInfo.kind); + newResInfo->index = oldResInfo.index; + newResInfo->space = oldResInfo.space; + if (auto offsetResInfo = offsetTypeLayout->FindResourceInfo(oldResInfo.kind)) + { + newResInfo->index += offsetResInfo->count; + } + } + + newStructTypeLayout->fields.Add(newField); + + mapOldFieldToNew.Add(oldField.Ptr(), newField.Ptr()); + } + + for (auto entry : oldStructTypeLayout->mapVarToLayout) + { + VarLayout* newFieldLayout = nullptr; + if (mapOldFieldToNew.TryGetValue(entry.Value.Ptr(), newFieldLayout)) + { + newStructTypeLayout->mapVarToLayout.Add(entry.Key, newFieldLayout); + } + } + + newTypeLayout = newStructTypeLayout; + } + else + { + // TODO: need to handle other cases here + return oldTypeLayout; + } + + // No matter what replacement we plug in for the element type, we need to copy + // over its resource usage: + for (auto oldResInfo : oldTypeLayout->resourceInfos) + { + auto newResInfo = newTypeLayout->findOrAddResourceInfo(oldResInfo.kind); + newResInfo->count = oldResInfo.count; + } + + return newTypeLayout; +} + RefPtr<ParameterGroupTypeLayout> createParameterGroupTypeLayout( TypeLayoutContext const& context, RefPtr<ParameterGroupType> parameterGroupType, SimpleLayoutInfo parameterGroupInfo, - RefPtr<TypeLayout> elementTypeLayout) + RefPtr<TypeLayout> rawElementTypeLayout) { auto parameterGroupRules = context.rules; - auto typeLayout = new ParameterGroupTypeLayout(); - + RefPtr<ParameterGroupTypeLayout> typeLayout = new ParameterGroupTypeLayout(); typeLayout->type = parameterGroupType; typeLayout->rules = parameterGroupRules; - typeLayout->elementTypeLayout = elementTypeLayout; + RefPtr<TypeLayout> containerTypeLayout = new TypeLayout(); + containerTypeLayout->type = parameterGroupType; + containerTypeLayout->rules = parameterGroupRules; // The layout of the constant buffer if it gets stored // in another constant buffer is just what we computed @@ -883,6 +971,7 @@ createParameterGroupTypeLayout( // SLANG_RELEASE_ASSERT(parameterGroupInfo.kind != LayoutResourceKind::Uniform); typeLayout->uniformAlignment = 1; + containerTypeLayout->uniformAlignment = 1; // TODO(tfoley): There is a subtle question here of whether // a constant buffer declaration that then contains zero @@ -896,7 +985,7 @@ createParameterGroupTypeLayout( // parameter block itself. if( parameterGroupInfo.size ) { - typeLayout->addResourceUsage( + containerTypeLayout->addResourceUsage( parameterGroupInfo.kind, parameterGroupInfo.size); } @@ -916,35 +1005,22 @@ createParameterGroupTypeLayout( bool ownRegisterSpace = false; if (parameterBlockType) { + // Should we allocate this block its own regsiter space? if( shouldAllocateRegisterSpaceForParameterBlock(context) ) { ownRegisterSpace = true; } - // If the parameter block contains any uniform data, then we - // had better allocate a constant buffer for it. - bool anyUniformData = false; - if(auto elementUniformInfo = elementTypeLayout->FindResourceInfo(LayoutResourceKind::Uniform) ) - { - if( elementUniformInfo->count != 0 ) - { - // We have a non-zero number of bytes of uniform data here. - anyUniformData = true; - } - } - - if( anyUniformData ) - { - typeLayout->addResourceUsage(LayoutResourceKind::ConstantBuffer, 1); - } - - // Next, if we are going to allocate whole register space(s) to the - // parameter block, check if it actually needs one (it might be empty, - // or only contain other parameter blocks). + // If we need a register space, then maybe allocate one. if( ownRegisterSpace ) { + // The basic logic here is that if the parameter block only + // contains other parameter blocks (which themselves have + // their own register spaces), then we don't need to + // allocate *yet another* register space for the block. + bool needsARegisterSpace = false; - for( auto elementResourceInfo : elementTypeLayout->resourceInfos ) + for( auto elementResourceInfo : rawElementTypeLayout->resourceInfos ) { if(elementResourceInfo.kind != LayoutResourceKind::RegisterSpace) { @@ -953,11 +1029,31 @@ createParameterGroupTypeLayout( } } + // If we determine that a register space is needed, then add one here. if( needsARegisterSpace ) { typeLayout->addResourceUsage(LayoutResourceKind::RegisterSpace, 1); } } + + // Next, we check if the parameter block has any uniform data, since + // that means we need to allocate a constant-buffer binding for it. + bool anyUniformData = false; + if(auto elementUniformInfo = rawElementTypeLayout->FindResourceInfo(LayoutResourceKind::Uniform) ) + { + if( elementUniformInfo->count != 0 ) + { + // We have a non-zero number of bytes of uniform data here. + anyUniformData = true; + } + } + if( anyUniformData ) + { + // We need to ensure that the block itself consumes at least one "register" for its + // constant buffer part. + auto cbUsage = parameterGroupRules->GetObjectLayout(ShaderParameterKind::ConstantBuffer); + containerTypeLayout->addResourceUsage(cbUsage.kind, cbUsage.size); + } } // The layout for the element type was computed without any knowledge @@ -965,45 +1061,73 @@ createParameterGroupTypeLayout( // need to go through and offset that any starting locations (e.g., // in nested `StructTypeLayout`s) based on what we allocated to // the parent. + // + // Note: at the moment, constant buffers apply their own offsetting + // logic elsewhere, so we need to only do this logic for parameter blocks + RefPtr<TypeLayout> offsetTypeLayout = applyOffsetToTypeLayout(rawElementTypeLayout, containerTypeLayout); + + typeLayout->containerTypeLayout = containerTypeLayout; + typeLayout->offsetElementTypeLayout = offsetTypeLayout; + + // We will construct a dummy variable layout to represent the offsettting + // that needs to be applied to the element type to put it after the + // container. + RefPtr<VarLayout> elementVarLayout = new VarLayout(); + elementVarLayout->typeLayout = rawElementTypeLayout; + for (auto containerResourceInfo : containerTypeLayout->resourceInfos) + { + auto kind = containerResourceInfo.kind; + if (auto elementResourceInfo = rawElementTypeLayout->FindResourceInfo(kind)) + { + auto varResourceInfo = elementVarLayout->findOrAddResourceInfo(kind); + varResourceInfo->index += containerResourceInfo.count; + } + } + typeLayout->elementVarLayout = elementVarLayout; - // TODO(tfoley): actually implement that! - - - // Now we will (possibly) accumulate the resources used by the element - // type into the resources used by the parameter group. The reason - // this is "possibly" is because, e.g., a `ConstantBuffer<Foo>` should - // not report itself as consuming `sizeof(Foo)` bytes of uniform data, - // or else it would mess up layout for any type that contains the - // constant buffer. Similarly, a parameter block that consumes whole - // register `space`s shouldn't report its fine-grained resource - // usage inside those spces. - for( auto elementResourceInfo : elementTypeLayout->resourceInfos ) + if (ownRegisterSpace) { - switch( elementResourceInfo.kind ) + // A parameter block type that gets its own register space will only + // include resource usage from the element type when it itself consumes + // while register spaces. + if (auto elementResInfo = rawElementTypeLayout->FindResourceInfo(LayoutResourceKind::RegisterSpace)) { - case LayoutResourceKind::RegisterSpace: - // Register spaces consumed by the element type should be - // reflected in the resource usage of the parent type. - typeLayout->addResourceUsage(elementResourceInfo); - break; + typeLayout->addResourceUsage(*elementResInfo); + } + } + else + { + // If the parameter block is *not* getting its own regsiter space, then + // it needs to include the resource usage from the "container" type, plus + // any relevant resource usage for the element type. - case LayoutResourceKind::Uniform: - // Uniform resource usages will always be hidden. - break; + // We start by accumulating any resource usage from the container. + for (auto containerResourceInfo : containerTypeLayout->resourceInfos) + { + typeLayout->addResourceUsage(containerResourceInfo); + } - default: - // All other register types should be hidden *if* we - // are allocating a whole register space, and exposed - // otherwise. - if( ownRegisterSpace ) - { - // don't expose internal register/binding use outside - } - else + // Now we will (possibly) accumulate the resources used by the element + // type into the resources used by the parameter group. The reason + // this is "possibly" is because, e.g., a `ConstantBuffer<Foo>` should + // not report itself as consuming `sizeof(Foo)` bytes of uniform data, + // or else it would mess up layout for any type that contains the + // constant buffer. + for( auto elementResourceInfo : rawElementTypeLayout->resourceInfos ) + { + switch( elementResourceInfo.kind ) { + case LayoutResourceKind::Uniform: + // Uniform resource usages will always be hidden. + break; + + default: + // All other register types will not be hidden, + // since we aren't in the case where the parameter group + // gets its own register space. typeLayout->addResourceUsage(elementResourceInfo); + break; } - break; } } @@ -1059,8 +1183,7 @@ createParameterGroupTypeLayout( auto elementTypeLayout = createTypeLayout( context.with(elementTypeRules), - elementType, - info); + elementType); return createParameterGroupTypeLayout( context, @@ -1188,16 +1311,7 @@ createStructuredBufferTypeLayout( SimpleLayoutInfo GetLayoutImpl( TypeLayoutContext const& context, Type* type, - RefPtr<TypeLayout>* outTypeLayout, - SimpleLayoutInfo offset); - -SimpleLayoutInfo GetLayoutImpl( - TypeLayoutContext const& context, - Type* type, - RefPtr<TypeLayout>* outTypeLayout) -{ - return GetLayoutImpl(context, type, outTypeLayout, SimpleLayoutInfo()); -} + RefPtr<TypeLayout>* outTypeLayout); SimpleLayoutInfo GetLayoutImpl( TypeLayoutContext const& context, @@ -1219,7 +1333,7 @@ SimpleLayoutInfo GetLayoutImpl( // layout, such as GLSL `std140`. } - return GetLayoutImpl(subContext, type, outTypeLayout, SimpleLayoutInfo()); + return GetLayoutImpl(subContext, type, outTypeLayout); } int findGenericParam(List<RefPtr<GenericParamLayout>> & genericParameters, GlobalGenericParamDecl * decl) @@ -1230,8 +1344,7 @@ int findGenericParam(List<RefPtr<GenericParamLayout>> & genericParameters, Globa SimpleLayoutInfo GetLayoutImpl( TypeLayoutContext const& context, Type* type, - RefPtr<TypeLayout>* outTypeLayout, - SimpleLayoutInfo offset) + RefPtr<TypeLayout>* outTypeLayout) { auto rules = context.rules; @@ -1583,15 +1696,6 @@ 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; - } - } } } @@ -1657,40 +1761,22 @@ SimpleLayoutInfo GetLayout( RefPtr<TypeLayout> createTypeLayout( TypeLayoutContext const& context, - Type* type, - SimpleLayoutInfo offset) -{ - RefPtr<TypeLayout> typeLayout; - GetLayoutImpl(context, type, &typeLayout, offset); - return typeLayout; -} - -RefPtr<TypeLayout> createTypeLayout( - TypeLayoutContext const& context, Type* type) { RefPtr<TypeLayout> typeLayout; - GetLayoutImpl(context, type, &typeLayout, SimpleLayoutInfo()); + GetLayoutImpl(context, type, &typeLayout); return typeLayout; } RefPtr<TypeLayout> CreateTypeLayout( TypeLayoutContext const& context, - Type* type, - SimpleLayoutInfo offset) + Type* type) { RefPtr<TypeLayout> typeLayout; - GetLayoutImpl(context, type, &typeLayout, offset); + GetLayoutImpl(context, type, &typeLayout); return typeLayout; } -RefPtr<TypeLayout> CreateTypeLayout( - TypeLayoutContext const& context, - Type* type) -{ - return CreateTypeLayout(context, type, SimpleLayoutInfo()); -} - RefPtr<GlobalGenericParamDecl> GenericParamTypeLayout::getGlobalGenericParamDecl() { auto declRefType = type->AsDeclRefType(); |
