summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/slang/ast-legalize.cpp2
-rw-r--r--source/slang/emit.cpp100
-rw-r--r--source/slang/legalize-types.cpp49
-rw-r--r--source/slang/reflection.cpp142
-rw-r--r--source/slang/type-layout.cpp294
-rw-r--r--source/slang/type-layout.h19
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