diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/slang/ast-legalize.cpp | 2 | ||||
| -rw-r--r-- | source/slang/emit.cpp | 100 | ||||
| -rw-r--r-- | source/slang/legalize-types.cpp | 49 | ||||
| -rw-r--r-- | source/slang/reflection.cpp | 142 | ||||
| -rw-r--r-- | source/slang/type-layout.cpp | 294 | ||||
| -rw-r--r-- | source/slang/type-layout.h | 19 |
6 files changed, 435 insertions, 171 deletions
diff --git a/source/slang/ast-legalize.cpp b/source/slang/ast-legalize.cpp index 0c9d6154e..144277301 100644 --- a/source/slang/ast-legalize.cpp +++ b/source/slang/ast-legalize.cpp @@ -3129,7 +3129,7 @@ struct LoweringVisitor while (auto parameterGroupTypeLayout = typeLayout.As<ParameterGroupTypeLayout>()) { - typeLayout = parameterGroupTypeLayout->elementTypeLayout; + typeLayout = parameterGroupTypeLayout->offsetElementTypeLayout; } while (auto arrayTypeLayout = typeLayout.As<ArrayTypeLayout>()) diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp index 09d209f6e..33fd46bdb 100644 --- a/source/slang/emit.cpp +++ b/source/slang/emit.cpp @@ -3454,10 +3454,13 @@ struct EmitVisitor // Emit a single `regsiter` semantic, as appropriate for a given resource-type-specific layout info void emitHLSLRegisterSemantic( VarLayout::ResourceInfo const& info, + UInt spaceOffset, // Keyword to use in the uniform case (`register` for globals, `packoffset` inside a `cbuffer`) char const* uniformSemanticSpelling = "register") { + UInt space = info.space + spaceOffset; + switch(info.kind) { case LayoutResourceKind::Uniform: @@ -3529,10 +3532,10 @@ struct EmitVisitor break; } Emit(info.index); - if(info.space) + if(space) { Emit(", space"); - Emit(info.space); + Emit(space); } Emit(")"); } @@ -3557,7 +3560,7 @@ struct EmitVisitor for( auto rr : layout->resourceInfos ) { - emitHLSLRegisterSemantic(rr, uniformSemanticSpelling); + emitHLSLRegisterSemantic(rr, getSpaceOffset(layout), uniformSemanticSpelling); } } @@ -3590,6 +3593,7 @@ struct EmitVisitor auto offsetResource = rr; + UInt spaceOffset = 0; if(layout && kind != LayoutResourceKind::Uniform) { @@ -3607,9 +3611,11 @@ struct EmitVisitor offsetResource.index += cbufferResource->index; offsetResource.space += cbufferResource->space; } + + spaceOffset = getSpaceOffset(layout); } - emitHLSLRegisterSemantic(offsetResource, "packoffset"); + emitHLSLRegisterSemantic(offsetResource, spaceOffset, "packoffset"); } } @@ -3634,7 +3640,7 @@ struct EmitVisitor auto info = layout->FindResourceInfo(LayoutResourceKind::ConstantBuffer); SLANG_RELEASE_ASSERT(info); - emitHLSLRegisterSemantic(*info); + emitHLSLRegisterSemantic(*info, getSpaceOffset(layout)); Emit("\n{\n"); @@ -3648,7 +3654,7 @@ struct EmitVisitor // RefPtr<Type> elementType = parameterBlockType->elementType; - RefPtr<TypeLayout> elementTypeLayout = bufferLayout->elementTypeLayout; + RefPtr<TypeLayout> elementTypeLayout = bufferLayout->offsetElementTypeLayout; EmitType(elementType, varDecl->getName()); @@ -3690,7 +3696,7 @@ struct EmitVisitor RefPtr<ParameterGroupTypeLayout> bufferLayout = layout->typeLayout.As<ParameterGroupTypeLayout>(); SLANG_RELEASE_ASSERT(bufferLayout); - RefPtr<StructTypeLayout> structTypeLayout = bufferLayout->elementTypeLayout.As<StructTypeLayout>(); + RefPtr<StructTypeLayout> structTypeLayout = bufferLayout->offsetElementTypeLayout.As<StructTypeLayout>(); SLANG_RELEASE_ASSERT(structTypeLayout); @@ -3708,7 +3714,7 @@ struct EmitVisitor auto info = layout->FindResourceInfo(LayoutResourceKind::ConstantBuffer); SLANG_RELEASE_ASSERT(info); - emitHLSLRegisterSemantic(*info); + emitHLSLRegisterSemantic(*info, getSpaceOffset(layout)); Emit("\n{\n"); @@ -3757,8 +3763,10 @@ struct EmitVisitor } void emitGLSLLayoutQualifier( - VarLayout::ResourceInfo const& info) + VarLayout::ResourceInfo const& info, + UInt spaceOffset) { + UInt space = info.space + spaceOffset; switch(info.kind) { case LayoutResourceKind::Uniform: @@ -3812,10 +3820,10 @@ struct EmitVisitor case LayoutResourceKind::DescriptorTableSlot: Emit("layout(binding = "); Emit(info.index); - if(info.space) + if(space) { Emit(", set = "); - Emit(info.space); + Emit(space); } Emit(")\n"); break; @@ -3827,6 +3835,13 @@ struct EmitVisitor } } + UInt getSpaceOffset(VarLayout* layout) + { + if (auto resInfo = layout->FindResourceInfo(LayoutResourceKind::RegisterSpace)) + return resInfo->index; + return 0; + } + void emitGLSLLayoutQualifiers( RefPtr<VarLayout> layout, LayoutResourceKind filter = LayoutResourceKind::None) @@ -3842,6 +3857,8 @@ struct EmitVisitor break; } + UInt spaceOffset = getSpaceOffset(layout); + for( auto info : layout->resourceInfos ) { // Skip info that doesn't match our filter @@ -3851,15 +3868,46 @@ struct EmitVisitor continue; } - emitGLSLLayoutQualifier(info); + emitGLSLLayoutQualifier(info, spaceOffset); } } + void emitGLSLParameterBlockDecl( + RefPtr<VarDeclBase> varDecl, + RefPtr<ParameterBlockType> parameterBlockType, + RefPtr<VarLayout> layout) + { + EmitModifiers(varDecl); + emitGLSLLayoutQualifiers(layout); + Emit("uniform "); + + emitName(varDecl); + + Emit("\n{\n"); + + RefPtr<ParameterGroupTypeLayout> bufferLayout = layout->typeLayout.As<ParameterGroupTypeLayout>(); + SLANG_RELEASE_ASSERT(bufferLayout); + + RefPtr<Type> elementType = parameterBlockType->elementType; + RefPtr<TypeLayout> elementTypeLayout = bufferLayout->offsetElementTypeLayout; + + EmitType(elementType, varDecl->getName()); + Emit(";\n"); + + Emit("};\n"); + } + void emitGLSLParameterGroupDecl( RefPtr<VarDeclBase> varDecl, RefPtr<ParameterGroupType> parameterGroupType, RefPtr<VarLayout> layout) { + if( auto parameterBlockType = parameterGroupType->As<ParameterBlockType>()) + { + emitGLSLParameterBlockDecl(varDecl, parameterBlockType, layout); + return; + } + // The data type that describes where stuff in the constant buffer should go RefPtr<Type> dataType = parameterGroupType->elementType; @@ -3871,7 +3919,7 @@ struct EmitVisitor auto typeLayout = layout->typeLayout; if (auto bufferLayout = typeLayout.As<ParameterGroupTypeLayout>()) { - typeLayout = bufferLayout->elementTypeLayout; + typeLayout = bufferLayout->offsetElementTypeLayout; } structTypeLayout = typeLayout.As<StructTypeLayout>(); @@ -3884,7 +3932,13 @@ struct EmitVisitor EmitModifiers(varDecl); // Emit an apprpriate declaration keyword based on the kind of block - if (parameterGroupType->As<ConstantBufferType>()) + if (parameterGroupType->As<GLSLShaderStorageBufferType>()) + { + Emit("buffer"); + } + // Note: tested `buffer` case before `uniform`, since `GLSLShaderStorageBufferType` + // is also a subclass of `UniformParameterGroupType`. + else if (parameterGroupType->As<UniformParameterGroupType>()) { Emit("uniform"); } @@ -3896,10 +3950,6 @@ struct EmitVisitor { Emit("out"); } - else if (parameterGroupType->As<GLSLShaderStorageBufferType>()) - { - Emit("buffer"); - } else { SLANG_DIAGNOSE_UNEXPECTED(getSink(), varDecl, "unhandled GLSL shader parameter kind"); @@ -6391,7 +6441,7 @@ emitDeclImpl(decl, nullptr); auto info = layout->FindResourceInfo(LayoutResourceKind::ConstantBuffer); SLANG_RELEASE_ASSERT(info); - emitHLSLRegisterSemantic(*info); + emitHLSLRegisterSemantic(*info, getSpaceOffset(layout)); emit("\n{\n"); @@ -6400,7 +6450,7 @@ emitDeclImpl(decl, nullptr); auto typeLayout = layout->typeLayout; if( auto parameterGroupTypeLayout = typeLayout.As<ParameterGroupTypeLayout>() ) { - typeLayout = parameterGroupTypeLayout->elementTypeLayout; + typeLayout = parameterGroupTypeLayout->offsetElementTypeLayout; } emitIRType(ctx, elementType, getIRName(varDecl)); @@ -6430,7 +6480,7 @@ emitDeclImpl(decl, nullptr); auto info = layout->FindResourceInfo(LayoutResourceKind::ConstantBuffer); SLANG_RELEASE_ASSERT(info); - emitHLSLRegisterSemantic(*info); + emitHLSLRegisterSemantic(*info, getSpaceOffset(layout)); emit("\n{\n"); @@ -6439,7 +6489,7 @@ emitDeclImpl(decl, nullptr); auto typeLayout = layout->typeLayout; if( auto parameterGroupTypeLayout = typeLayout.As<ParameterGroupTypeLayout>() ) { - typeLayout = parameterGroupTypeLayout->elementTypeLayout; + typeLayout = parameterGroupTypeLayout->offsetElementTypeLayout; } if(auto declRefType = elementType->As<DeclRefType>()) @@ -6497,7 +6547,7 @@ emitDeclImpl(decl, nullptr); auto info = layout->FindResourceInfo(LayoutResourceKind::DescriptorTableSlot); if (info) { - emitGLSLLayoutQualifier(*info); + emitGLSLLayoutQualifier(*info, getSpaceOffset(layout)); } if(type->As<GLSLShaderStorageBufferType>()) @@ -6519,7 +6569,7 @@ emitDeclImpl(decl, nullptr); auto typeLayout = layout->typeLayout; if( auto parameterGroupTypeLayout = typeLayout.As<ParameterGroupTypeLayout>() ) { - typeLayout = parameterGroupTypeLayout->elementTypeLayout; + typeLayout = parameterGroupTypeLayout->offsetElementTypeLayout; } if(auto declRefType = elementType->As<DeclRefType>()) @@ -6969,7 +7019,7 @@ StructTypeLayout* getGlobalStructLayout( // and hope that the global-scope block (`$Globals`) gets auto-assigned // the same location that we manually asigned it. - auto elementTypeLayout = globalConstantBufferLayout->elementTypeLayout; + auto elementTypeLayout = globalConstantBufferLayout->offsetElementTypeLayout; auto elementTypeStructLayout = elementTypeLayout.As<StructTypeLayout>(); // We expect all constant buffers to contain `struct` types for now diff --git a/source/slang/legalize-types.cpp b/source/slang/legalize-types.cpp index fb9c70c97..1264201a2 100644 --- a/source/slang/legalize-types.cpp +++ b/source/slang/legalize-types.cpp @@ -972,7 +972,7 @@ RefPtr<TypeLayout> getDerefTypeLayout( if (auto parameterGroupTypeLayout = dynamic_cast<ParameterGroupTypeLayout*>(typeLayout)) { - return parameterGroupTypeLayout->elementTypeLayout; + return parameterGroupTypeLayout->offsetElementTypeLayout; } return typeLayout; @@ -993,7 +993,7 @@ RefPtr<VarLayout> getFieldLayout( } else if(auto parameterGroupTypeLayotu = dynamic_cast<ParameterGroupTypeLayout*>(typeLayout)) { - typeLayout = parameterGroupTypeLayotu->elementTypeLayout; + typeLayout = parameterGroupTypeLayotu->offsetElementTypeLayout; } else { @@ -1029,6 +1029,19 @@ RefPtr<VarLayout> createVarLayout( RefPtr<VarLayout> varLayout = new VarLayout(); varLayout->typeLayout = typeLayout; + // For most resource kinds, the register index/space to use should + // be the sum along the entire chain of variables. + // + // For example, if we had input: + // + // struct S { Texture2D a; Texture2D b; }; + // S s : register(t10); + // + // And we were generating a stand-alone variable for `s.b`, then + // we'd need to add the offset for `b` (1 texture register), to + // the offset for `s` (10 texture registers) to get the final + // binding to apply. + // for (auto rr : typeLayout->resourceInfos) { auto resInfo = varLayout->findOrAddResourceInfo(rr.kind); @@ -1043,28 +1056,30 @@ RefPtr<VarLayout> createVarLayout( } } - // Some of the parent variables might actually contain offsets - // to the `space` or `set` of the field, and we need to apply - // those to all the nested resource infos. - for (auto vv = varChain; vv; vv = vv->next) + // As a special case, if the leaf variable doesn't hold an entry for + // `RegisterSpace`, but at least one declaration in the chain *does*, + // then we want to make sure that we add such an entry. + if (!varLayout->FindResourceInfo(LayoutResourceKind::RegisterSpace)) { - auto parentSpaceInfo = vv->varLayout->FindResourceInfo(LayoutResourceKind::RegisterSpace); - if (!parentSpaceInfo) - continue; - - for (auto& rr : varLayout->resourceInfos) + // Sum up contributions from all parents. + UInt space = 0; + for (auto vv = varChain; vv; vv = vv->next) { - if (rr.kind == LayoutResourceKind::RegisterSpace) - { - rr.index += parentSpaceInfo->index; - } - else + if (auto parentResInfo = vv->varLayout->FindResourceInfo(LayoutResourceKind::RegisterSpace)) { - rr.space += parentSpaceInfo->index; + space += parentResInfo->index; } } + + // If there were non-zero contributions, then add an entry to represent them. + if (space) + { + varLayout->findOrAddResourceInfo(LayoutResourceKind::RegisterSpace)->index = space; + } } + + return varLayout; } diff --git a/source/slang/reflection.cpp b/source/slang/reflection.cpp index 5962bce96..7068ecea4 100644 --- a/source/slang/reflection.cpp +++ b/source/slang/reflection.cpp @@ -529,7 +529,7 @@ SLANG_API SlangReflectionTypeLayout* spReflectionTypeLayout_GetElementTypeLayout } else if( auto constantBufferTypeLayout = dynamic_cast<ParameterGroupTypeLayout*>(typeLayout)) { - return convert(constantBufferTypeLayout->elementTypeLayout.Ptr()); + return convert(constantBufferTypeLayout->offsetElementTypeLayout.Ptr()); } else if( auto structuredBufferTypeLayout = dynamic_cast<StructuredBufferTypeLayout*>(typeLayout)) { @@ -539,6 +539,19 @@ SLANG_API SlangReflectionTypeLayout* spReflectionTypeLayout_GetElementTypeLayout return nullptr; } +SLANG_API SlangReflectionVariableLayout* spReflectionTypeLayout_GetElementVarLayout(SlangReflectionTypeLayout* inTypeLayout) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return nullptr; + + if( auto constantBufferTypeLayout = dynamic_cast<ParameterGroupTypeLayout*>(typeLayout)) + { + return convert(constantBufferTypeLayout->elementVarLayout.Ptr()); + } + + return nullptr; +} + static SlangParameterCategory getParameterCategory( LayoutResourceKind kind) { @@ -566,6 +579,11 @@ SLANG_API SlangParameterCategory spReflectionTypeLayout_GetParameterCategory(Sla auto typeLayout = convert(inTypeLayout); if(!typeLayout) return SLANG_PARAMETER_CATEGORY_NONE; + if (auto parameterGroupTypeLayout = dynamic_cast<ParameterGroupTypeLayout*>(typeLayout)) + { + typeLayout = parameterGroupTypeLayout->containerTypeLayout; + } + return getParameterCategory(typeLayout); } @@ -574,6 +592,11 @@ SLANG_API unsigned spReflectionTypeLayout_GetCategoryCount(SlangReflectionTypeLa auto typeLayout = convert(inTypeLayout); if(!typeLayout) return 0; + if (auto parameterGroupTypeLayout = dynamic_cast<ParameterGroupTypeLayout*>(typeLayout)) + { + typeLayout = parameterGroupTypeLayout->containerTypeLayout; + } + return (unsigned) typeLayout->resourceInfos.Count(); } @@ -582,6 +605,11 @@ SLANG_API SlangParameterCategory spReflectionTypeLayout_GetCategoryByIndex(Slang auto typeLayout = convert(inTypeLayout); if(!typeLayout) return SLANG_PARAMETER_CATEGORY_NONE; + if (auto parameterGroupTypeLayout = dynamic_cast<ParameterGroupTypeLayout*>(typeLayout)) + { + typeLayout = parameterGroupTypeLayout->containerTypeLayout; + } + return typeLayout->resourceInfos[index].kind; } @@ -626,12 +654,68 @@ SLANG_API SlangReflectionTypeLayout* spReflectionVariableLayout_GetTypeLayout(Sl return convert(varLayout->getTypeLayout()); } +namespace Slang +{ + // Attempt "do what I mean" remapping from the parameter category the user asked about, + // over to a parameter category that they might have meant. + static SlangParameterCategory maybeRemapParameterCategory( + TypeLayout* typeLayout, + SlangParameterCategory category) + { + // Do we have an entry for the category they asked about? Then use that. + if (typeLayout->FindResourceInfo(LayoutResourceKind(category))) + return category; + + // Do we have an entry for the `DescriptorTableSlot` category? + if (typeLayout->FindResourceInfo(LayoutResourceKind::DescriptorTableSlot)) + { + // Is the category they were asking about one that makes sense for the type + // of this variable? + Type* type = typeLayout->getType(); + while (auto arrayType = type->As<ArrayExpressionType>()) + type = arrayType->baseType; + switch (spReflectionType_GetKind(convert(type))) + { + case SLANG_TYPE_KIND_CONSTANT_BUFFER: + if(category == SLANG_PARAMETER_CATEGORY_CONSTANT_BUFFER) + return SLANG_PARAMETER_CATEGORY_DESCRIPTOR_TABLE_SLOT; + break; + + case SLANG_TYPE_KIND_RESOURCE: + if(category == SLANG_PARAMETER_CATEGORY_SHADER_RESOURCE) + return SLANG_PARAMETER_CATEGORY_DESCRIPTOR_TABLE_SLOT; + break; + + case SLANG_TYPE_KIND_SAMPLER_STATE: + if(category == SLANG_PARAMETER_CATEGORY_SAMPLER_STATE) + return SLANG_PARAMETER_CATEGORY_DESCRIPTOR_TABLE_SLOT; + break; + + // TODO: implement more helpers here + + default: + break; + } + } + + return category; + } +} + SLANG_API size_t spReflectionVariableLayout_GetOffset(SlangReflectionVariableLayout* inVarLayout, SlangParameterCategory category) { auto varLayout = convert(inVarLayout); if(!varLayout) return 0; auto info = varLayout->FindResourceInfo(LayoutResourceKind(category)); + + if (!info) + { + // No match with requested category? Try again with one they might have meant... + category = maybeRemapParameterCategory(varLayout->getTypeLayout(), category); + info = varLayout->FindResourceInfo(LayoutResourceKind(category)); + } + if(!info) return 0; return info->index; @@ -642,10 +726,30 @@ SLANG_API size_t spReflectionVariableLayout_GetSpace(SlangReflectionVariableLayo auto varLayout = convert(inVarLayout); if(!varLayout) return 0; + auto info = varLayout->FindResourceInfo(LayoutResourceKind(category)); - if(!info) return 0; + if (!info) + { + // No match with requested category? Try again with one they might have meant... + category = maybeRemapParameterCategory(varLayout->getTypeLayout(), category); + info = varLayout->FindResourceInfo(LayoutResourceKind(category)); + } + + UInt space = 0; + + // First, deal with any offset applied to the specific resource kind specified + if (info) + { + space += info->space; + } + + // Next, deal with any dedicated register-space offset applied to, e.g., a parameter block + if (auto spaceInfo = varLayout->FindResourceInfo(LayoutResourceKind::RegisterSpace)) + { + space += spaceInfo->index; + } - return info->space; + return space; } SLANG_API char const* spReflectionVariableLayout_GetSemanticName(SlangReflectionVariableLayout* inVarLayout) @@ -705,28 +809,20 @@ SLANG_API SlangStage spReflectionVariableLayout_getStage( SLANG_API unsigned spReflectionParameter_GetBindingIndex(SlangReflectionParameter* inVarLayout) { - auto varLayout = convert(inVarLayout); - if(!varLayout) return 0; - - if(varLayout->resourceInfos.Count() > 0) - { - return (unsigned) varLayout->resourceInfos[0].index; - } - - return 0; + SlangReflectionVariableLayout* varLayout = (SlangReflectionVariableLayout*)inVarLayout; + return (unsigned) spReflectionVariableLayout_GetOffset( + varLayout, + spReflectionTypeLayout_GetParameterCategory( + spReflectionVariableLayout_GetTypeLayout(varLayout))); } SLANG_API unsigned spReflectionParameter_GetBindingSpace(SlangReflectionParameter* inVarLayout) { - auto varLayout = convert(inVarLayout); - if(!varLayout) return 0; - - if(varLayout->resourceInfos.Count() > 0) - { - return (unsigned) varLayout->resourceInfos[0].space; - } - - return 0; + SlangReflectionVariableLayout* varLayout = (SlangReflectionVariableLayout*)inVarLayout; + return (unsigned) spReflectionVariableLayout_GetSpace( + varLayout, + spReflectionTypeLayout_GetParameterCategory( + spReflectionVariableLayout_GetTypeLayout(varLayout))); } // Helpers for getting parameter count @@ -737,7 +833,7 @@ namespace Slang { if(auto parameterGroupLayout = typeLayout.As<ParameterGroupTypeLayout>()) { - typeLayout = parameterGroupLayout->elementTypeLayout; + typeLayout = parameterGroupLayout->offsetElementTypeLayout; } if(auto structLayout = typeLayout.As<StructTypeLayout>()) @@ -752,7 +848,7 @@ namespace Slang { if(auto parameterGroupLayout = typeLayout.As<ParameterGroupTypeLayout>()) { - typeLayout = parameterGroupLayout->elementTypeLayout; + typeLayout = parameterGroupLayout->offsetElementTypeLayout; } if(auto structLayout = typeLayout.As<StructTypeLayout>()) 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(); diff --git a/source/slang/type-layout.h b/source/slang/type-layout.h index 66763c8a7..fc2007437 100644 --- a/source/slang/type-layout.h +++ b/source/slang/type-layout.h @@ -307,7 +307,24 @@ public: class ParameterGroupTypeLayout : public TypeLayout { public: - RefPtr<TypeLayout> elementTypeLayout; + // The layout of the "container" type itself. + // E.g., for a constant buffer, this would reflect + // the resource usage of the container, without + // the element type factored in. + RefPtr<TypeLayout> containerTypeLayout; + + // A variable layout for the element of the container. + // The offsets of the variable layout will reflect + // the offsets that need to applied to get past the + // container types resource usage, while the actual + // type layout won't have offsets applied (unlike + // `offsetElementTypeLayout` below). + RefPtr<VarLayout> elementVarLayout; + + // The layout of the element type, with offsets applied + // so that any fields (if the element type is a `struct`) + // will be offset by the resource usage of the container. + RefPtr<TypeLayout> offsetElementTypeLayout; }; // type layout for a variable that has a constant-buffer type |
