summaryrefslogtreecommitdiffstats
path: root/source/slang/slang-type-layout.cpp
diff options
context:
space:
mode:
authorEllie Hermaszewska <ellieh@nvidia.com>2022-11-16 09:49:06 +0800
committerGitHub <noreply@github.com>2022-11-16 09:49:06 +0800
commit1643471da0d6239177d11b0301c26d1adf95c0fb (patch)
tree9b8fddf92a5f817541e055a2657f9b0a00f90069 /source/slang/slang-type-layout.cpp
parent4917d71100aafcc38a81cd99d2a44a4cb3a89a0c (diff)
Mesh shader support (#2464)
* Add gdb generated files to .gitignore * Switch to c++17 TODO: Ellie update coding style doc * WIP mesh shaders * Add MeshOutputType and mesh output decorations * Lift array type layout creation out of _createTypeLayout in preparation for sharing it elsewhere * Initial pass at GLSL legalization for mesh shaders * Create output types for builtin mesh outputs This should be rendered as an out paramter block * Handle writes to member fields in mesh shader output * Per primitive output from mesh shaders * Add mesh shader tests * Redeclare mesh output builtins * Remove unused instruction * Emit explicit mesh output max max size * Add unimplemented warning for array members in mesh output * Implement mesh output splitting for GLSL in terms of getSubscriptVal * Allow HLSL syntax for mesh output modifiers * Improve error messages for mesh output * Add test for HLSL style mesh output syntax * Emit explicit mesh output indices max size * HLSL generation support for mesh shaders * Better errors for mesh shader misuse * Neaten comments * Regenerate vs2019 project files * Fix build on vs2019 * Retreat on c++17 Will make the change in a separate PR * slang-glslang binary dep 11.10.0 -> 11.12.0-32 * Fixes for msvc compiler * Update msvc project
Diffstat (limited to 'source/slang/slang-type-layout.cpp')
-rw-r--r--source/slang/slang-type-layout.cpp319
1 files changed, 166 insertions, 153 deletions
diff --git a/source/slang/slang-type-layout.cpp b/source/slang/slang-type-layout.cpp
index c77aadd68..45bacaa44 100644
--- a/source/slang/slang-type-layout.cpp
+++ b/source/slang/slang-type-layout.cpp
@@ -3240,6 +3240,171 @@ RefPtr<TypeLayout> createTypeLayoutForGlobalGenericTypeParam(
return _createTypeLayoutForGlobalGenericTypeParam(context, type, globalGenericParamDecl).layout;
}
+static TypeLayoutResult createArrayLikeTypeLayout(
+ TypeLayoutContext const& context,
+ Type* type,
+ Type* baseType,
+ IntVal* arrayLength
+ )
+{
+ auto rules = context.rules;
+
+ auto elementResult = _createTypeLayout(
+ context,
+ baseType);
+ auto elementInfo = elementResult.info;
+ auto elementTypeLayout = elementResult.layout;
+
+ // To a first approximation, an array will usually be laid out
+ // by taking the element's type layout and laying out `elementCount`
+ // copies of it. There are of course many details that make
+ // this simplistic version of things not quite work.
+ //
+ // An important complication to deal with is the possibility of
+ // having "unbounded" arrays, which don't specify a size.'
+ // The layout rules for these vary heavily by resource kind and API.
+ //
+
+ auto elementCount = GetElementCount(arrayLength);
+
+ //
+ // We can compute the uniform storage layout of an array using
+ // the rules for the target API.
+ //
+ // TODO: ensure that this does something reasonable with the unbounded
+ // case, or else issue an error message that the target doesn't
+ // support unbounded types.
+ //
+
+ auto arrayUniformInfo = rules->GetArrayLayout(
+ elementInfo,
+ elementCount).getUniformLayout();
+
+ RefPtr<ArrayTypeLayout> typeLayout = new ArrayTypeLayout();
+
+ // Some parts of the array type layout object are easy to fill in:
+ typeLayout->type = type;
+ typeLayout->rules = rules;
+ typeLayout->originalElementTypeLayout = elementTypeLayout;
+ typeLayout->uniformAlignment = arrayUniformInfo.alignment;
+ typeLayout->uniformStride = arrayUniformInfo.elementStride;
+
+ typeLayout->addResourceUsage(LayoutResourceKind::Uniform, arrayUniformInfo.size);
+
+ //
+ // The tricky part in constructing an array type layout comes when
+ // the element type is (or nests) a structure with resource-type
+ // fields, because in that case we need to perform AoS-to-SoA
+ // conversion as part of computing the final type layout, and
+ // we also need to pre-compute an "adjusted" element type
+ // layout that accounts for the striding that happens with
+ // resource-type contents.
+ //
+ // This complication is only made worse when we have to deal with
+ // unbounded-size arrays over such element types, since those
+ // resource-type fields will each end up consuming a full space
+ // in the resulting layout.
+ //
+ // The `maybeAdjustLayoutForArrayElementType` computes an "adjusted"
+ // type layout for the element type which takes the array stride into
+ // account. If it returns the same type layout that was passed in,
+ // then that means no adjustement took place.
+ //
+ // The `additionalSpacesNeededForAdjustedElementType` variable counts
+ // the number of additional register spaces that were consumed,
+ // in the case of an unbounded array.
+ //
+ UInt additionalSpacesNeededForAdjustedElementType = 0;
+ RefPtr<TypeLayout> adjustedElementTypeLayout = maybeAdjustLayoutForArrayElementType(
+ elementTypeLayout,
+ elementCount,
+ additionalSpacesNeededForAdjustedElementType);
+
+ typeLayout->elementTypeLayout = adjustedElementTypeLayout;
+
+ // We will now iterate over the resources consumed by the element
+ // type to compute how they contribute to the resource usage
+ // of the overall array type.
+ //
+ for( auto elementResourceInfo : elementTypeLayout->resourceInfos )
+ {
+ // The uniform case was already handled above
+ if( elementResourceInfo.kind == LayoutResourceKind::Uniform )
+ continue;
+
+ LayoutSize arrayResourceCount = 0;
+
+ // In almost all cases, the resources consumed by an array
+ // will be its element count times the resources consumed
+ // by its element type.
+ //
+ // The first exception to this is arrays of resources when
+ // compiling to GLSL for Vulkan, where an entire array
+ // only consumes a single descriptor-table slot.
+ //
+ if (elementResourceInfo.kind == LayoutResourceKind::DescriptorTableSlot)
+ {
+ arrayResourceCount = elementResourceInfo.count;
+ }
+ // The second exception to this is arrays of an existential type
+ // where the entire array should be specialized to a single concrete type.
+ //
+ else if (elementResourceInfo.kind == LayoutResourceKind::ExistentialTypeParam)
+ {
+ arrayResourceCount = elementResourceInfo.count;
+ }
+ //
+ // The next big exception is when we are forming an unbounded-size
+ // array and the element type got "adjusted," because that means
+ // the array type will need to allocate full spaces for any resource-type
+ // fields in the element type.
+ //
+ // Note: we carefully carve things out so that the case of a simple
+ // array of resources does *not* lead to the element type being adjusted,
+ // so that this logic doesn't trigger and we instead handle it with
+ // the default logic below.
+ //
+ else if(
+ elementCount.isInfinite()
+ && adjustedElementTypeLayout != elementTypeLayout
+ && doesResourceRequireAdjustmentForArrayOfStructs(elementResourceInfo.kind) )
+ {
+ // We want to ignore resource types consumed by the element type
+ // that need adjustement if the array size is infinite, since
+ // we will be allocating whole spaces for that part of the
+ // element's resource usage.
+ }
+ else
+ {
+ arrayResourceCount = elementResourceInfo.count * elementCount;
+ }
+
+ // Now that we've computed how the resource usage of the element type
+ // should contribute to the resource usage of the array, we can
+ // add in that resource usage.
+ //
+ typeLayout->addResourceUsage(
+ elementResourceInfo.kind,
+ arrayResourceCount);
+ }
+
+ // The loop above to compute the resource usage of the array from its
+ // element type ignored any resource-type fields in an unbounded-size
+ // array if they would have been allocated as full register spaces.
+ // Those same fields were counted in `additionalSpacesNeededForAdjustedElementType`,
+ // and need to be added into the total resource usage for the array
+ // if we skipped them as part of the loop (which happens when
+ // we detect that the element type layout had been "adjusted").
+ //
+ if( adjustedElementTypeLayout != elementTypeLayout )
+ {
+ typeLayout->addResourceUsage(LayoutResourceKind::RegisterSpace, additionalSpacesNeededForAdjustedElementType);
+ }
+
+ return TypeLayoutResult(typeLayout, arrayUniformInfo);
+}
+
+
static TypeLayoutResult _createTypeLayout(
TypeLayoutContext const& context,
Type* type)
@@ -3504,159 +3669,7 @@ static TypeLayoutResult _createTypeLayout(
}
else if (auto arrayType = as<ArrayExpressionType>(type))
{
- auto elementResult = _createTypeLayout(
- context,
- arrayType->baseType);
- auto elementInfo = elementResult.info;
- auto elementTypeLayout = elementResult.layout;
-
- // To a first approximation, an array will usually be laid out
- // by taking the element's type layout and laying out `elementCount`
- // copies of it. There are of course many details that make
- // this simplistic version of things not quite work.
- //
- // An important complication to deal with is the possibility of
- // having "unbounded" arrays, which don't specify a size.'
- // The layout rules for these vary heavily by resource kind and API.
- //
-
- auto elementCount = GetElementCount(arrayType->arrayLength);
-
- //
- // We can compute the uniform storage layout of an array using
- // the rules for the target API.
- //
- // TODO: ensure that this does something reasonable with the unbounded
- // case, or else issue an error message that the target doesn't
- // support unbounded types.
- //
-
- auto arrayUniformInfo = rules->GetArrayLayout(
- elementInfo,
- elementCount).getUniformLayout();
-
- RefPtr<ArrayTypeLayout> typeLayout = new ArrayTypeLayout();
-
- // Some parts of the array type layout object are easy to fill in:
- typeLayout->type = type;
- typeLayout->rules = rules;
- typeLayout->originalElementTypeLayout = elementTypeLayout;
- typeLayout->uniformAlignment = arrayUniformInfo.alignment;
- typeLayout->uniformStride = arrayUniformInfo.elementStride;
-
- typeLayout->addResourceUsage(LayoutResourceKind::Uniform, arrayUniformInfo.size);
-
- //
- // The tricky part in constructing an array type layout comes when
- // the element type is (or nests) a structure with resource-type
- // fields, because in that case we need to perform AoS-to-SoA
- // conversion as part of computing the final type layout, and
- // we also need to pre-compute an "adjusted" element type
- // layout that accounts for the striding that happens with
- // resource-type contents.
- //
- // This complication is only made worse when we have to deal with
- // unbounded-size arrays over such element types, since those
- // resource-type fields will each end up consuming a full space
- // in the resulting layout.
- //
- // The `maybeAdjustLayoutForArrayElementType` computes an "adjusted"
- // type layout for the element type which takes the array stride into
- // account. If it returns the same type layout that was passed in,
- // then that means no adjustement took place.
- //
- // The `additionalSpacesNeededForAdjustedElementType` variable counts
- // the number of additional register spaces that were consumed,
- // in the case of an unbounded array.
- //
- UInt additionalSpacesNeededForAdjustedElementType = 0;
- RefPtr<TypeLayout> adjustedElementTypeLayout = maybeAdjustLayoutForArrayElementType(
- elementTypeLayout,
- elementCount,
- additionalSpacesNeededForAdjustedElementType);
-
- typeLayout->elementTypeLayout = adjustedElementTypeLayout;
-
- // We will now iterate over the resources consumed by the element
- // type to compute how they contribute to the resource usage
- // of the overall array type.
- //
- for( auto elementResourceInfo : elementTypeLayout->resourceInfos )
- {
- // The uniform case was already handled above
- if( elementResourceInfo.kind == LayoutResourceKind::Uniform )
- continue;
-
- LayoutSize arrayResourceCount = 0;
-
- // In almost all cases, the resources consumed by an array
- // will be its element count times the resources consumed
- // by its element type.
- //
- // The first exception to this is arrays of resources when
- // compiling to GLSL for Vulkan, where an entire array
- // only consumes a single descriptor-table slot.
- //
- if (elementResourceInfo.kind == LayoutResourceKind::DescriptorTableSlot)
- {
- arrayResourceCount = elementResourceInfo.count;
- }
- // The second exception to this is arrays of an existential type
- // where the entire array should be specialized to a single concrete type.
- //
- else if (elementResourceInfo.kind == LayoutResourceKind::ExistentialTypeParam)
- {
- arrayResourceCount = elementResourceInfo.count;
- }
- //
- // The next big exception is when we are forming an unbounded-size
- // array and the element type got "adjusted," because that means
- // the array type will need to allocate full spaces for any resource-type
- // fields in the element type.
- //
- // Note: we carefully carve things out so that the case of a simple
- // array of resources does *not* lead to the element type being adjusted,
- // so that this logic doesn't trigger and we instead handle it with
- // the default logic below.
- //
- else if(
- elementCount.isInfinite()
- && adjustedElementTypeLayout != elementTypeLayout
- && doesResourceRequireAdjustmentForArrayOfStructs(elementResourceInfo.kind) )
- {
- // We want to ignore resource types consumed by the element type
- // that need adjustement if the array size is infinite, since
- // we will be allocating whole spaces for that part of the
- // element's resource usage.
- }
- else
- {
- arrayResourceCount = elementResourceInfo.count * elementCount;
- }
-
- // Now that we've computed how the resource usage of the element type
- // should contribute to the resource usage of the array, we can
- // add in that resource usage.
- //
- typeLayout->addResourceUsage(
- elementResourceInfo.kind,
- arrayResourceCount);
- }
-
- // The loop above to compute the resource usage of the array from its
- // element type ignored any resource-type fields in an unbounded-size
- // array if they would have been allocated as full register spaces.
- // Those same fields were counted in `additionalSpacesNeededForAdjustedElementType`,
- // and need to be added into the total resource usage for the array
- // if we skipped them as part of the loop (which happens when
- // we detect that the element type layout had been "adjusted").
- //
- if( adjustedElementTypeLayout != elementTypeLayout )
- {
- typeLayout->addResourceUsage(LayoutResourceKind::RegisterSpace, additionalSpacesNeededForAdjustedElementType);
- }
-
- return TypeLayoutResult(typeLayout, arrayUniformInfo);
+ return createArrayLikeTypeLayout(context, arrayType, arrayType->baseType, arrayType->arrayLength);
}
else if (auto declRefType = as<DeclRefType>(type))
{