summaryrefslogtreecommitdiffstats
path: root/source/slang/slang-parameter-binding.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/slang-parameter-binding.cpp')
-rw-r--r--source/slang/slang-parameter-binding.cpp675
1 files changed, 352 insertions, 323 deletions
diff --git a/source/slang/slang-parameter-binding.cpp b/source/slang/slang-parameter-binding.cpp
index 605e50d41..3c4c23a42 100644
--- a/source/slang/slang-parameter-binding.cpp
+++ b/source/slang/slang-parameter-binding.cpp
@@ -2205,386 +2205,413 @@ static RefPtr<TypeLayout> processEntryPointVaryingParameter(
varLayout->flags |= VarLayoutFlag::HasSemantic;
}
- // Scalar and vector types are treated as outputs directly
- if (auto basicType = as<BasicExpressionType>(type))
+ // We use a lambda here to process the parameter based on `type`.
+ // We need to be able to recurse on the lambda if need to translate/resolve
+ // `type` to something else, in that case we simply call the lambda recursively.
+ auto processParamOfType = [&](auto&& processParamOfTypeFunc, Type* type) -> RefPtr<TypeLayout>
{
- return processSimpleEntryPointParameter(context, basicType, state, varLayout);
- }
- else if (auto vectorType = as<VectorExpressionType>(type))
- {
- return processSimpleEntryPointParameter(context, vectorType, state, varLayout);
- }
- // A matrix is processed as if it was an array of rows
- else if (auto matrixType = as<MatrixExpressionType>(type))
- {
- auto foldedRowCountVal =
- context->getTargetProgram()->getProgram()->tryFoldIntVal(matrixType->getRowCount());
- IntegerLiteralValue rowCount = 0;
- if (!foldedRowCountVal)
+ // Scalar and vector types are treated as outputs directly
+ if (auto basicType = as<BasicExpressionType>(type))
{
- rowCount = getIntVal(foldedRowCountVal);
+ return processSimpleEntryPointParameter(context, basicType, state, varLayout);
}
- return processSimpleEntryPointParameter(
- context,
- matrixType,
- state,
- varLayout,
- (int)rowCount);
- }
- else if (auto arrayType = as<ArrayExpressionType>(type))
- {
- // Note: Bad Things will happen if we have an array input
- // without a semantic already being enforced.
- UInt elementCount = 0;
-
- if (!arrayType->isUnsized())
+ else if (auto vectorType = as<VectorExpressionType>(type))
{
- auto intVal = context->getTargetProgram()->getProgram()->tryFoldIntVal(
- arrayType->getElementCount());
- if (intVal)
- elementCount = (UInt)getIntVal(intVal);
+ return processSimpleEntryPointParameter(context, vectorType, state, varLayout);
}
-
- // We use the first element to derive the layout for the element type
- auto elementTypeLayout = processEntryPointVaryingParameter(
- context,
- arrayType->getElementType(),
- state,
- varLayout);
-
- // We still walk over subsequent elements to make sure they consume resources
- // as needed
- for (UInt ii = 1; ii < elementCount; ++ii)
+ // A matrix is processed as if it was an array of rows
+ else if (auto matrixType = as<MatrixExpressionType>(type))
{
- processEntryPointVaryingParameter(context, arrayType->getElementType(), state, nullptr);
+ auto foldedRowCountVal =
+ context->getTargetProgram()->getProgram()->tryFoldIntVal(matrixType->getRowCount());
+ IntegerLiteralValue rowCount = 0;
+ if (!foldedRowCountVal)
+ {
+ rowCount = getIntVal(foldedRowCountVal);
+ }
+ return processSimpleEntryPointParameter(
+ context,
+ matrixType,
+ state,
+ varLayout,
+ (int)rowCount);
}
-
- RefPtr<ArrayTypeLayout> arrayTypeLayout = new ArrayTypeLayout();
- arrayTypeLayout->elementTypeLayout = elementTypeLayout;
- arrayTypeLayout->type = arrayType;
-
- for (auto rr : elementTypeLayout->resourceInfos)
+ else if (auto arrayType = as<ArrayExpressionType>(type))
{
- arrayTypeLayout->findOrAddResourceInfo(rr.kind)->count = rr.count * elementCount;
- }
-
- return arrayTypeLayout;
- }
- else if (auto meshOutputType = as<MeshOutputType>(type))
- {
- // TODO: Ellie, revisit
- // Note: Bad Things will happen if we have an array input
- // without a semantic already being enforced.
+ // Note: Bad Things will happen if we have an array input
+ // without a semantic already being enforced.
+ UInt elementCount = 0;
- // We use the first element to derive the layout for the element type
- auto elementTypeLayout = processEntryPointVaryingParameter(
- context,
- meshOutputType->getElementType(),
- state,
- varLayout);
+ if (!arrayType->isUnsized())
+ {
+ auto intVal = context->getTargetProgram()->getProgram()->tryFoldIntVal(
+ arrayType->getElementCount());
+ if (intVal)
+ elementCount = (UInt)getIntVal(intVal);
+ }
- RefPtr<ArrayTypeLayout> arrayTypeLayout = new ArrayTypeLayout();
- arrayTypeLayout->elementTypeLayout = elementTypeLayout;
- arrayTypeLayout->type = arrayType;
+ // We use the first element to derive the layout for the element type
+ auto elementTypeLayout = processEntryPointVaryingParameter(
+ context,
+ arrayType->getElementType(),
+ state,
+ varLayout);
- // TODO: Ellie, this is probably not the right place to handle this
- // On GLSL the indices type is built in and as such doesn't consume
- // resources.
- if (!isKhronosTarget(context->getTargetRequest()) || !as<IndicesType>(type))
- {
- for (auto rr : elementTypeLayout->resourceInfos)
+ // We still walk over subsequent elements to make sure they consume resources
+ // as needed
+ for (UInt ii = 1; ii < elementCount; ++ii)
{
- // TODO: Ellie, explain why only one slot is consumed here
- arrayTypeLayout->findOrAddResourceInfo(rr.kind)->count = rr.count;
+ processEntryPointVaryingParameter(
+ context,
+ arrayType->getElementType(),
+ state,
+ nullptr);
}
- }
- return arrayTypeLayout;
- }
- else if (auto patchType = as<HLSLPatchType>(type))
- {
- // Similar to the MeshOutput case, a `InputPatch` or `OutputPatch` type is just like an
- // array.
- //
- auto elementTypeLayout = processEntryPointVaryingParameter(
- context,
- patchType->getElementType(),
- state,
- varLayout);
+ RefPtr<ArrayTypeLayout> arrayTypeLayout = new ArrayTypeLayout();
+ arrayTypeLayout->elementTypeLayout = elementTypeLayout;
+ arrayTypeLayout->type = arrayType;
- RefPtr<ArrayTypeLayout> arrayTypeLayout = new ArrayTypeLayout();
- arrayTypeLayout->elementTypeLayout = elementTypeLayout;
- arrayTypeLayout->type = arrayType;
+ for (auto rr : elementTypeLayout->resourceInfos)
+ {
+ arrayTypeLayout->findOrAddResourceInfo(rr.kind)->count = rr.count * elementCount;
+ }
- for (auto rr : elementTypeLayout->resourceInfos)
- {
- arrayTypeLayout->findOrAddResourceInfo(rr.kind)->count = rr.count;
+ return arrayTypeLayout;
}
-
- return arrayTypeLayout;
- }
- // Ignore a bunch of types that don't make sense here...
- else if (const auto subpassType = as<SubpassInputType>(type))
- {
- return nullptr;
- }
- else if (const auto textureType = as<TextureType>(type))
- {
- return nullptr;
- }
- else if (const auto samplerStateType = as<SamplerStateType>(type))
- {
- return nullptr;
- }
- else if (const auto constantBufferType = as<ConstantBufferType>(type))
- {
- return nullptr;
- }
- else if (auto ptrType = as<PtrType>(type))
- {
- SLANG_ASSERT(ptrType->astNodeType == ASTNodeType::PtrType);
-
- auto typeLayout = processSimpleEntryPointParameter(context, ptrType, state, varLayout);
- RefPtr<PointerTypeLayout> ptrTypeLayout = typeLayout.as<PointerTypeLayout>();
-
- // Work out the layout for the value/target type
- auto valueTypeLayout =
- processEntryPointVaryingParameter(context, ptrType->getValueType(), state, varLayout);
- ptrTypeLayout->valueTypeLayout = valueTypeLayout;
- return ptrTypeLayout;
- }
- else if (auto optionalType = as<OptionalType>(type))
- {
- Array<Type*, 2> types =
- makeArray(optionalType->getValueType(), context->getASTBuilder()->getBoolType());
- auto tupleType = context->getASTBuilder()->getTupleType(types.getView());
- return processEntryPointVaryingParameter(context, tupleType, state, varLayout);
- }
- else if (auto tupleType = as<TupleType>(type))
- {
- RefPtr<StructTypeLayout> structLayout = new StructTypeLayout();
- structLayout->type = type;
- for (Index i = 0; i < tupleType->getMemberCount(); i++)
+ else if (auto meshOutputType = as<MeshOutputType>(type))
{
- auto fieldType = tupleType->getMember(i);
- RefPtr<VarLayout> fieldVarLayout = new VarLayout();
-
- // We don't really have a "field" decl, so just use the tuple-typed decl
- // itself as the varDecl of the elements.
- auto fieldDecl = (VarDeclBase*)varLayout->varDecl.getDecl();
- fieldVarLayout->varDecl = fieldDecl;
+ // TODO: Ellie, revisit
+ // Note: Bad Things will happen if we have an array input
+ // without a semantic already being enforced.
- structLayout->fields.add(fieldVarLayout);
-
- auto fieldTypeLayout = processEntryPointVaryingParameterDecl(
+ // We use the first element to derive the layout for the element type
+ auto elementTypeLayout = processEntryPointVaryingParameter(
context,
- fieldDecl,
- fieldType,
+ meshOutputType->getElementType(),
state,
- fieldVarLayout);
+ varLayout);
+
+ RefPtr<ArrayTypeLayout> arrayTypeLayout = new ArrayTypeLayout();
+ arrayTypeLayout->elementTypeLayout = elementTypeLayout;
+ arrayTypeLayout->type = arrayType;
- if (!fieldTypeLayout)
+ // TODO: Ellie, this is probably not the right place to handle this
+ // On GLSL the indices type is built in and as such doesn't consume
+ // resources.
+ if (!isKhronosTarget(context->getTargetRequest()) || !as<IndicesType>(type))
{
- getSink(context)->diagnose(
- varLayout->varDecl,
- Diagnostics::notValidVaryingParameter,
- fieldType);
- continue;
+ for (auto rr : elementTypeLayout->resourceInfos)
+ {
+ // TODO: Ellie, explain why only one slot is consumed here
+ arrayTypeLayout->findOrAddResourceInfo(rr.kind)->count = rr.count;
+ }
}
- fieldVarLayout->typeLayout = fieldTypeLayout;
- // Assign offsets in var layout for each resource kind of the type.
- for (auto fieldTypeResInfo : fieldTypeLayout->resourceInfos)
+ return arrayTypeLayout;
+ }
+ else if (auto patchType = as<HLSLPatchType>(type))
+ {
+ // Similar to the MeshOutput case, a `InputPatch` or `OutputPatch` type is just like an
+ // array.
+ //
+ auto elementTypeLayout = processEntryPointVaryingParameter(
+ context,
+ patchType->getElementType(),
+ state,
+ varLayout);
+
+ RefPtr<ArrayTypeLayout> arrayTypeLayout = new ArrayTypeLayout();
+ arrayTypeLayout->elementTypeLayout = elementTypeLayout;
+ arrayTypeLayout->type = arrayType;
+
+ for (auto rr : elementTypeLayout->resourceInfos)
{
- auto kind = fieldTypeResInfo.kind;
- auto structTypeResInfo = structLayout->findOrAddResourceInfo(kind);
- auto fieldResInfo = fieldVarLayout->findOrAddResourceInfo(kind);
- fieldResInfo->index = structTypeResInfo->count.getFiniteValue();
- structTypeResInfo->count += fieldTypeResInfo.count;
+ arrayTypeLayout->findOrAddResourceInfo(rr.kind)->count = rr.count;
}
- }
- return structLayout;
- }
- // Catch declaration-reference types late in the sequence, since
- // otherwise they will include all of the above cases...
- else if (auto declRefType = as<DeclRefType>(type))
- {
- // If we are trying to get the layout of some extern type, do our best
- // to look it up in other loaded modules and generate the type layout
- // based on that.
- declRefType = context->layoutContext.lookupExternDeclRefType(declRefType);
- auto declRef = declRefType->getDeclRef();
+ return arrayTypeLayout;
+ }
+ // Ignore a bunch of types that don't make sense here...
+ else if (const auto subpassType = as<SubpassInputType>(type))
+ {
+ return nullptr;
+ }
+ else if (const auto textureType = as<TextureType>(type))
+ {
+ return nullptr;
+ }
+ else if (const auto samplerStateType = as<SamplerStateType>(type))
+ {
+ return nullptr;
+ }
+ else if (const auto constantBufferType = as<ConstantBufferType>(type))
+ {
+ return nullptr;
+ }
+ else if (auto ptrType = as<PtrType>(type))
+ {
+ SLANG_ASSERT(ptrType->astNodeType == ASTNodeType::PtrType);
+ auto typeLayout = processSimpleEntryPointParameter(context, ptrType, state, varLayout);
+ RefPtr<PointerTypeLayout> ptrTypeLayout = typeLayout.as<PointerTypeLayout>();
- if (auto structDeclRef = declRef.as<StructDecl>())
+ // Work out the layout for the value/target type
+ auto valueTypeLayout = processEntryPointVaryingParameter(
+ context,
+ ptrType->getValueType(),
+ state,
+ varLayout);
+ ptrTypeLayout->valueTypeLayout = valueTypeLayout;
+ return ptrTypeLayout;
+ }
+ else if (auto optionalType = as<OptionalType>(type))
+ {
+ Array<Type*, 2> types =
+ makeArray(optionalType->getValueType(), context->getASTBuilder()->getBoolType());
+ auto tupleType = context->getASTBuilder()->getTupleType(types.getView());
+ return processEntryPointVaryingParameter(context, tupleType, state, varLayout);
+ }
+ else if (auto tupleType = as<TupleType>(type))
{
RefPtr<StructTypeLayout> structLayout = new StructTypeLayout();
- structLayout->type = declRefType;
-
- // We will recursively walk the fields of a `struct` type
- // to compute layouts for those fields.
- //
- // Along the way, we may find fields with explicit layout
- // annotations, along with fields that have no explicit
- // layout. We will consider it an error to have a mix of
- // the two.
- //
- // TODO: We could support a mix of implicit and explicit
- // layout by performing layout on fields in two passes,
- // much like is done for the global scope. This would
- // complicate layout significantly for little practical
- // benefit, so it is very much a "nice to have" rather
- // than a "must have" feature.
- //
- Decl* firstExplicit = nullptr;
- Decl* firstImplicit = nullptr;
- for (auto field :
- getFields(context->getASTBuilder(), structDeclRef, MemberFilterStyle::Instance))
+ structLayout->type = type;
+ for (Index i = 0; i < tupleType->getMemberCount(); i++)
{
+ auto fieldType = tupleType->getMember(i);
RefPtr<VarLayout> fieldVarLayout = new VarLayout();
- fieldVarLayout->varDecl = field;
+
+ // We don't really have a "field" decl, so just use the tuple-typed decl
+ // itself as the varDecl of the elements.
+ auto fieldDecl = (VarDeclBase*)varLayout->varDecl.getDecl();
+ fieldVarLayout->varDecl = fieldDecl;
structLayout->fields.add(fieldVarLayout);
- structLayout->mapVarToLayout.add(field.getDecl(), fieldVarLayout);
auto fieldTypeLayout = processEntryPointVaryingParameterDecl(
context,
- field.getDecl(),
- getType(context->getASTBuilder(), field),
+ fieldDecl,
+ fieldType,
state,
fieldVarLayout);
if (!fieldTypeLayout)
{
- getSink(context)->diagnose(field, Diagnostics::notValidVaryingParameter, field);
+ getSink(context)->diagnose(
+ varLayout->varDecl,
+ Diagnostics::notValidVaryingParameter,
+ fieldType);
continue;
}
fieldVarLayout->typeLayout = fieldTypeLayout;
- // The field needs to have offset information stored
- // in `fieldVarLayout` for every kind of resource
- // consumed by `fieldTypeLayout`.
- //
+ // Assign offsets in var layout for each resource kind of the type.
for (auto fieldTypeResInfo : fieldTypeLayout->resourceInfos)
{
- // If the field is a Conditional<T, false> type, then it could have 0 size.
- // We should skip this field if it has no use of layout units.
- if (fieldTypeResInfo.count == 0)
- continue;
-
auto kind = fieldTypeResInfo.kind;
-
auto structTypeResInfo = structLayout->findOrAddResourceInfo(kind);
+ auto fieldResInfo = fieldVarLayout->findOrAddResourceInfo(kind);
+ fieldResInfo->index = structTypeResInfo->count.getFiniteValue();
+ structTypeResInfo->count += fieldTypeResInfo.count;
+ }
+ }
+ return structLayout;
+ }
+ // Catch declaration-reference types late in the sequence, since
+ // otherwise they will include all of the above cases...
+ else if (auto declRefType = as<DeclRefType>(type))
+ {
+ // If we are trying to get the layout of some extern type, do our best
+ // to look it up in other loaded modules and generate the type layout
+ // based on that.
+ auto lookedUpType = context->layoutContext.lookupExternDeclRefType(declRefType);
+
+ // If the link-time type resolved to something concrete, process the param as if it is
+ // of the concrete type by recursively calling this lambda.
+ if (type != lookedUpType)
+ return processParamOfTypeFunc(_Move(processParamOfTypeFunc), lookedUpType);
+
+ auto declRef = declRefType->getDeclRef();
+
+ if (auto structDeclRef = declRef.as<StructDecl>())
+ {
+ RefPtr<StructTypeLayout> structLayout = new StructTypeLayout();
+ structLayout->type = declRefType;
+
+ // We will recursively walk the fields of a `struct` type
+ // to compute layouts for those fields.
+ //
+ // Along the way, we may find fields with explicit layout
+ // annotations, along with fields that have no explicit
+ // layout. We will consider it an error to have a mix of
+ // the two.
+ //
+ // TODO: We could support a mix of implicit and explicit
+ // layout by performing layout on fields in two passes,
+ // much like is done for the global scope. This would
+ // complicate layout significantly for little practical
+ // benefit, so it is very much a "nice to have" rather
+ // than a "must have" feature.
+ //
+ Decl* firstExplicit = nullptr;
+ Decl* firstImplicit = nullptr;
+ for (auto field : getFields(
+ context->getASTBuilder(),
+ structDeclRef,
+ MemberFilterStyle::Instance))
+ {
+ RefPtr<VarLayout> fieldVarLayout = new VarLayout();
+ fieldVarLayout->varDecl = field;
+
+ structLayout->fields.add(fieldVarLayout);
+ structLayout->mapVarToLayout.add(field.getDecl(), fieldVarLayout);
+
+ auto fieldTypeLayout = processEntryPointVaryingParameterDecl(
+ context,
+ field.getDecl(),
+ getType(context->getASTBuilder(), field),
+ state,
+ fieldVarLayout);
- auto fieldResInfo = fieldVarLayout->FindResourceInfo(kind);
- if (!fieldResInfo)
+ if (!fieldTypeLayout)
{
- if (!firstImplicit)
- firstImplicit = field.getDecl();
-
- // In the implicit-layout case, we assign the field
- // the next available offset after the fields that
- // have preceded it.
- //
- fieldResInfo = fieldVarLayout->findOrAddResourceInfo(kind);
- fieldResInfo->index = structTypeResInfo->count.getFiniteValue();
- structTypeResInfo->count += fieldTypeResInfo.count;
+ getSink(context)->diagnose(
+ field,
+ Diagnostics::notValidVaryingParameter,
+ field);
+ continue;
}
- else
+ fieldVarLayout->typeLayout = fieldTypeLayout;
+
+ // The field needs to have offset information stored
+ // in `fieldVarLayout` for every kind of resource
+ // consumed by `fieldTypeLayout`.
+ //
+ for (auto fieldTypeResInfo : fieldTypeLayout->resourceInfos)
{
- if (!firstExplicit)
- firstExplicit = field.getDecl();
-
- // In the explicit case, the field already has offset
- // information, and we just need to update the computed
- // size of the `struct` type to account for the field.
- //
- auto fieldEndOffset = fieldResInfo->index + fieldTypeResInfo.count;
- structTypeResInfo->count =
- maximum(structTypeResInfo->count, fieldEndOffset);
+ // If the field is a Conditional<T, false> type, then it could have 0 size.
+ // We should skip this field if it has no use of layout units.
+ if (fieldTypeResInfo.count == 0)
+ continue;
+
+ auto kind = fieldTypeResInfo.kind;
+
+ auto structTypeResInfo = structLayout->findOrAddResourceInfo(kind);
+
+ auto fieldResInfo = fieldVarLayout->FindResourceInfo(kind);
+ if (!fieldResInfo)
+ {
+ if (!firstImplicit)
+ firstImplicit = field.getDecl();
+
+ // In the implicit-layout case, we assign the field
+ // the next available offset after the fields that
+ // have preceded it.
+ //
+ fieldResInfo = fieldVarLayout->findOrAddResourceInfo(kind);
+ fieldResInfo->index = structTypeResInfo->count.getFiniteValue();
+ structTypeResInfo->count += fieldTypeResInfo.count;
+ }
+ else
+ {
+ if (!firstExplicit)
+ firstExplicit = field.getDecl();
+
+ // In the explicit case, the field already has offset
+ // information, and we just need to update the computed
+ // size of the `struct` type to account for the field.
+ //
+ auto fieldEndOffset = fieldResInfo->index + fieldTypeResInfo.count;
+ structTypeResInfo->count =
+ maximum(structTypeResInfo->count, fieldEndOffset);
+ }
}
}
+ if (firstImplicit && firstExplicit)
+ {
+ getSink(context)->diagnose(
+ firstImplicit,
+ Diagnostics::mixingImplicitAndExplicitBindingForVaryingParams,
+ firstImplicit->getName(),
+ firstExplicit->getName());
+ }
+
+ return structLayout;
}
- if (firstImplicit && firstExplicit)
+ else if (auto globalGenericParamDecl = declRef.as<GlobalGenericParamDecl>())
{
- getSink(context)->diagnose(
- firstImplicit,
- Diagnostics::mixingImplicitAndExplicitBindingForVaryingParams,
- firstImplicit->getName(),
- firstExplicit->getName());
- }
-
- return structLayout;
- }
- else if (auto globalGenericParamDecl = declRef.as<GlobalGenericParamDecl>())
- {
- auto& layoutContext = context->layoutContext;
+ auto& layoutContext = context->layoutContext;
- if (auto concreteType = findGlobalGenericSpecializationArg(
- layoutContext,
- globalGenericParamDecl.getDecl()))
+ if (auto concreteType = findGlobalGenericSpecializationArg(
+ layoutContext,
+ globalGenericParamDecl.getDecl()))
+ {
+ // If we know what concrete type has been used to specialize
+ // the global generic type parameter, then we should use
+ // the concrete type instead.
+ //
+ // Note: it should be illegal for the user to use a generic
+ // type parameter in a varying parameter list without giving
+ // it an explicit user-defined semantic. Otherwise, it would be possible
+ // that the concrete type that gets plugged in is a user-defined
+ // `struct` that uses some `SV_` semantics in its definition,
+ // so that any static information about what system values
+ // the entry point uses would be incorrect.
+ //
+ return processEntryPointVaryingParameter(
+ context,
+ concreteType,
+ state,
+ varLayout);
+ }
+ else
+ {
+ // If we don't know a concrete type, then we aren't generating final
+ // code, so the reflection information should show the generic
+ // type parameter.
+ //
+ // We don't make any attempt to assign varying parameter resources
+ // to the generic type, since we can't know how many "slots"
+ // of varying input/output it would consume.
+ //
+ return createTypeLayoutForGlobalGenericTypeParam(
+ layoutContext,
+ type,
+ globalGenericParamDecl.getDecl());
+ }
+ }
+ else if (auto enumDeclRef = declRef.as<EnumDecl>())
{
- // If we know what concrete type has been used to specialize
- // the global generic type parameter, then we should use
- // the concrete type instead.
+ // We handle an enumeration type as its tag type for varying parameters.
+ // This allows enums to be used in vertex output/input similar to their
+ // underlying integer types.
//
- // Note: it should be illegal for the user to use a generic
- // type parameter in a varying parameter list without giving
- // it an explicit user-defined semantic. Otherwise, it would be possible
- // that the concrete type that gets plugged in is a user-defined
- // `struct` that uses some `SV_` semantics in its definition,
- // so that any static information about what system values
- // the entry point uses would be incorrect.
- //
- return processEntryPointVaryingParameter(context, concreteType, state, varLayout);
+ auto tagType = enumDeclRef.getDecl()->tagType;
+ SLANG_ASSERT(tagType);
+ return processEntryPointVaryingParameter(context, tagType, state, varLayout);
+ }
+ else if (auto associatedTypeParam = declRef.as<AssocTypeDecl>())
+ {
+ RefPtr<TypeLayout> assocTypeLayout = new TypeLayout();
+ assocTypeLayout->type = type;
+ return assocTypeLayout;
}
else
{
- // If we don't know a concrete type, then we aren't generating final
- // code, so the reflection information should show the generic
- // type parameter.
- //
- // We don't make any attempt to assign varying parameter resources
- // to the generic type, since we can't know how many "slots"
- // of varying input/output it would consume.
- //
- return createTypeLayoutForGlobalGenericTypeParam(
- layoutContext,
- type,
- globalGenericParamDecl.getDecl());
+ SLANG_UNEXPECTED("unhandled type kind");
}
}
- else if (auto enumDeclRef = declRef.as<EnumDecl>())
- {
- // We handle an enumeration type as its tag type for varying parameters.
- // This allows enums to be used in vertex output/input similar to their
- // underlying integer types.
- //
- auto tagType = enumDeclRef.getDecl()->tagType;
- SLANG_ASSERT(tagType);
- return processEntryPointVaryingParameter(context, tagType, state, varLayout);
- }
- else if (auto associatedTypeParam = declRef.as<AssocTypeDecl>())
- {
- RefPtr<TypeLayout> assocTypeLayout = new TypeLayout();
- assocTypeLayout->type = type;
- return assocTypeLayout;
- }
- else
+
+ // If we ran into an error in checking the user's code, then skip this parameter
+ else if (const auto errorType = as<ErrorType>(type))
{
- SLANG_UNEXPECTED("unhandled type kind");
+ return nullptr;
}
- }
- // If we ran into an error in checking the user's code, then skip this parameter
- else if (const auto errorType = as<ErrorType>(type))
- {
- return nullptr;
- }
-
- SLANG_UNEXPECTED("unhandled type kind");
- UNREACHABLE_RETURN(nullptr);
+ SLANG_UNEXPECTED("unhandled type kind");
+ UNREACHABLE_RETURN(nullptr);
+ };
+ return processParamOfType(_Move(processParamOfType), type);
}
/// Compute the type layout for a parameter declared directly on an entry point.
@@ -2606,8 +2633,8 @@ static RefPtr<TypeLayout> computeEntryPointParameterTypeLayout(
LayoutRulesImpl* layoutRules = nullptr;
if (isKhronosTarget(context->getTargetRequest()))
{
- // For Vulkan, entry point uniform parameters are laid out using push constant buffer
- // rules (defaults to std430).
+ // For Vulkan, entry point uniform parameters are laid out using push constant
+ // buffer rules (defaults to std430).
layoutRules = context->getRulesFamily()->getShaderStorageBufferRules(
context->getTargetProgram()->getOptionSet());
}
@@ -3559,15 +3586,16 @@ static void collectParameters(ParameterBindingContext* inContext, ComponentType*
/// Emit a diagnostic about a uniform/ordinary parameter at global scope.
void diagnoseGlobalUniform(SharedParameterBindingContext* sharedContext, VarDeclBase* varDecl)
{
- // Don't emit the implicit global shader parameter warning if the variable is explicitly marked
- // as uniform
+ // Don't emit the implicit global shader parameter warning if the variable is explicitly
+ // marked as uniform
if (!varDecl->hasModifier<HLSLUniformModifier>())
{
getSink(sharedContext)
->diagnose(varDecl, Diagnostics::globalUniformNotExpected, varDecl->getName());
}
- // Always check and warn about binding attributes being ignored, regardless of uniform modifier
+ // Always check and warn about binding attributes being ignored, regardless of uniform
+ // modifier
if (varDecl->findModifier<GLSLBindingAttribute>())
{
sharedContext->m_sink->diagnose(
@@ -3635,7 +3663,8 @@ struct ParameterBindingVisitorCounters
Index globalParamCounter = 0;
};
-/// Recursive routine to "complete" all binding for parameters and entry points in `componentType`.
+/// Recursive routine to "complete" all binding for parameters and entry points in
+/// `componentType`.
///
/// This includes allocation of as-yet-unused register/binding ranges to parameters (which
/// will then affect the ranges of registers/bindings that are available to subsequent
@@ -3973,8 +4002,8 @@ static bool _calcNeedsDefaultSpace(SharedParameterBindingContext& sharedContext)
continue;
case LayoutResourceKind::Uniform:
{
- // If it's uniform, but we have globals binding defined, we don't need a default
- // space for it as it will go in the global binding specified
+ // If it's uniform, but we have globals binding defined, we don't need a
+ // default space for it as it will go in the global binding specified
if (auto hlslToVulkanOptions =
sharedContext.getTargetProgram()->getHLSLToVulkanLayoutOptions())
{
@@ -4070,8 +4099,8 @@ static void _maybeApplyHLSLToVulkanShifts(
return;
}
- // If the user specified -fvk-b-shift for the default space but not -fvk-bind-global, we want to
- // apply the shift to the global constant buffer.
+ // If the user specified -fvk-b-shift for the default space but not -fvk-bind-global, we
+ // want to apply the shift to the global constant buffer.
if (!vulkanOptions->hasGlobalsBinding())
{
auto globalCBufferShift = vulkanOptions->getShift(
@@ -4117,10 +4146,10 @@ static void _maybeApplyHLSLToVulkanShifts(
// In essence we need to look for HLSL kinds which have inferance.
// We assume all map to Descriptor, and look for descriptor overlaps
- // We know there can't be a clash of HLSL layout kinds previously, otherwise that
- // would have already produced an a warning. We also know the only change is either
- // *all* of a set is shifted or none. That means post a shift there still can't be
- // clash between HLSL types.
+ // We know there can't be a clash of HLSL layout kinds previously, otherwise
+ // that would have already produced an a warning. We also know the only change
+ // is either *all* of a set is shifted or none. That means post a shift there
+ // still can't be clash between HLSL types.
// So clashes can only be between HLSL types and other bindings (regardless)