summaryrefslogtreecommitdiffstats
path: root/source/slang/emit.cpp
diff options
context:
space:
mode:
authorTim Foley <tfoleyNV@users.noreply.github.com>2017-12-13 15:48:29 -0800
committerGitHub <noreply@github.com>2017-12-13 15:48:29 -0800
commit6d6142122b15461d6c8cabdb31292b0de688ba35 (patch)
treee33d1d6f68fc5a37372c89b31edb059ab6373ec8 /source/slang/emit.cpp
parent0f55649cc1aa8ad3218b7f8ba7b1eabdd2ec6526 (diff)
Fix parameter block binding for Vulkan (#308)
Fixes #307 This ends up being a major overhaul over how type layout computation is structured and exposed. The big problems all arise around cases where both the "container" for a parameter block or CB, and the "element" type both use the same kind of resource. E.g., if you define a CB with a texture in it, then in Vulkan both the CB and the texture use the same kind of resource, and so if you query the CB's resource usage it will just tell you it uses two descriptor-table slots, but nothing more than that. Similar confusion still arises in the HLSL case, when a CB with a texture in it reports its parameter category as "mixed" so that a user might query for a category they didn't mean to. There were also cases in the existing code where a parameter block might expose *both* a register-space usage and another concrete resource type, which isn't right. The most important changes here are: - A `ParameterGroupTypeLayout` now has a more refined internal structure, consisting of: - A `containerTypeLayout`, which represents the resource usage of the buffer/block itself (e.g., if a constant buffer had to be allocated) - An `elementVarLayout` which stores the offsets that need to be applied to get from the `VarLayout` for an instance of this parameter-group type to the offsets of its elements. The `TypeLayout` for this variable layout should be the "raw" type of the block/CB element. - The `offsetElementTypeLayout` (formerly just `elementTypeLayout`) which represents the element type, but in the case of a `struct` element type, will have fields offset similar to the `elementVarLayout`. This is what all the old code used to use, so we need to keep it for compatibility. - When doing reflection on a `ParameterGroupTypeLayout`, we now only report the resource usage of the `containerTypeLayout`. This is technically a potentially breaking change in the public API, but I don't think Falcor will mind, since they actually want something closer to this behavior. - Add a new public API for querying the element variable layout of a parameter block of constant buffer. This could be used by savvy applications to fold the handling of CB element offsetting into some notion of a "reflection path." This would be required for applications that want to handle CBs or parameter blocks where the element type is *not* a `struct` type. - Remove old logic for applying an offset when creating a type layout for constant buffer element, and instead perform offsetting more uniformly later, by constructing the `offsetElementTypeLayout` from the `rawElementTypeLayout`. This is useful both because we want to keep both (the "raw" type layout becomes the type layout of the `elementVarLayout`), and also because we can decide later whether we even want to allocate a CB register for a buffer, based on whether it actually contains any uniform data. - Fix cases where we might end up with a parameter block type reporting both that it uses a whole register space (and thus should not expose the resource usage of the container/element type) *and* a constant-buffer register/slot. The latter should be hidden inside the regsiter space. - Clean up the `spReflectionParameter_GetBinding{Index,Space}` functions to just route to `spReflectionVariableLayout_Get{Offset,Space}`, using the "default" category of the parameter - Try to make the `GetSpace` query take into account cases where a variable also has an explicit `RegisterSpace` allocation. - This probably still needs some cleanup, since ideally we'd just move things into the `space` field on the `ReosurceInfo` and have an invariant that a variable *either* has a `RegisterSpace` allocation, or it has other resource infos, but never both... - Add some ad-hoc logic so that if the user queries for a binding index/space using a parameter category that doesn't actually apply (e.g., they query for a D3D `t` register when using Vulkan), we can optionally remap it to the resource type they "probably" meant. This is a mess of Do What I Mean code, but it is also what our users want right now. - Fix various bits of emit logic so that if a parameter block has a register space/set allocated to it, we properly output that as part of the binding information for it. - This is another thing that might be cleaned up if we rationale the way that things get split during legalization. - Add a GLSL case for emitting a parameter block variable as a `cbuffer`.
Diffstat (limited to 'source/slang/emit.cpp')
-rw-r--r--source/slang/emit.cpp100
1 files changed, 75 insertions, 25 deletions
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