summaryrefslogtreecommitdiffstats
path: root/source/slang/parameter-binding.cpp
diff options
context:
space:
mode:
authorTim Foley <tfoleyNV@users.noreply.github.com>2019-03-01 09:43:47 -0800
committerGitHub <noreply@github.com>2019-03-01 09:43:47 -0800
commit620af1c60a2e84bbbc0e74f11cb9bc6a6976d9e4 (patch)
treebba1e1d60c950f71506dd235ecc3309e6aa4880f /source/slang/parameter-binding.cpp
parentefca2bb38700847adb2385d311b8b801376659bb (diff)
Move enumeration of shader parameters to Program/EntryPoint (#870)
There's a certain amount of logic in `parameter-binding.cpp` that just has to do with the basic problem of enumerating the shader parameters of a `Program`. The main source of complexity is that for legacy/compatibility reasons we need to consider two shader parameters with the same name as being the "same" parameter for layout purposes, and then we need to do a bunch of validation to ensure that these parameters have compatible types. The biggest part of this change is moving that logic to `Program`, so that it builds up a list of its shader parameters during the front-end work, so that any errors related to bad redeclarations will now come up even if we aren't generated target-specific layouts/code. All of the code for `getReflectionName`, `StructuralTypeMatchStack`, etc. is pretty much copy-pasted from `parameter-binding.cpp` over to `check.cpp`, with the `ParameterBindingContext` replaced with a `DiagnosticSink`. The `Program::_collectShaderParameters` function (renamed from `_collectExistentialParams`) then deals with the enumeration and deduplication logic that used to happen in `collectGlobalScopeParameters()`. The new declarations in `compiler.h` reveal the underlying reason for this change: by letting `Program` and `EntryPoint` handle the canonical enumeration of parameters, we can associate each parameter with the range of existential type slots it uses, which will simplify certain work around interfaces (not in this change...). Moving the code out of parameter binding and into `check.cpp` revealed some unused GLSL-related code that I removed while I was at it. I also found that the `IsDeclaration` case of `VarLayoutFlag` wasn't actually being used, so I went ahead and removed it (we can easily re-add it if we ever find a need for it). Overall this isn't a big cleanup (mostly just code moving, rather than being eliminated), but it will facilitate other changes, and it seems cleaner overall to do this work once in target-independent logic, rather than per-target.
Diffstat (limited to 'source/slang/parameter-binding.cpp')
-rw-r--r--source/slang/parameter-binding.cpp644
1 files changed, 61 insertions, 583 deletions
diff --git a/source/slang/parameter-binding.cpp b/source/slang/parameter-binding.cpp
index dda3a8621..a472a9280 100644
--- a/source/slang/parameter-binding.cpp
+++ b/source/slang/parameter-binding.cpp
@@ -395,9 +395,6 @@ struct ParameterBindingContext
// the resource usage of shader parameters.
TypeLayoutContext layoutContext;
- // A dictionary to accelerate looking up parameters by name
- Dictionary<Name*, ParameterInfo*> mapNameToParameterInfo;
-
// What stage (if any) are we compiling for?
Stage stage;
@@ -573,424 +570,6 @@ LayoutSemanticInfo ExtractLayoutSemanticInfo(
return info;
}
-static Name* getReflectionName(VarDeclBase* varDecl)
-{
- if (auto reflectionNameModifier = varDecl->FindModifier<ParameterGroupReflectionName>())
- return reflectionNameModifier->nameAndLoc.name;
-
- return varDecl->getName();
-}
-
-// Information tracked when doing a structural
-// match of types.
-struct StructuralTypeMatchStack
-{
- DeclRef<VarDeclBase> leftDecl;
- DeclRef<VarDeclBase> rightDecl;
- StructuralTypeMatchStack* parent;
-};
-
-static void diagnoseParameterTypeMismatch(
- ParameterBindingContext* context,
- StructuralTypeMatchStack* inStack)
-{
- SLANG_ASSERT(inStack);
-
- // The bottom-most entry in the stack should represent
- // the shader parameters that kicked things off
- auto stack = inStack;
- while(stack->parent)
- stack = stack->parent;
-
- getSink(context)->diagnose(stack->leftDecl, Diagnostics::shaderParameterDeclarationsDontMatch, getReflectionName(stack->leftDecl));
- getSink(context)->diagnose(stack->rightDecl, Diagnostics::seeOtherDeclarationOf, getReflectionName(stack->rightDecl));
-}
-
-// Two types that were expected to match did not.
-// Inform the user with a suitable message.
-static void diagnoseTypeMismatch(
- ParameterBindingContext* context,
- StructuralTypeMatchStack* inStack)
-{
- auto stack = inStack;
- SLANG_ASSERT(stack);
- diagnoseParameterTypeMismatch(context, stack);
-
- auto leftType = GetType(stack->leftDecl);
- auto rightType = GetType(stack->rightDecl);
-
- if( stack->parent )
- {
- getSink(context)->diagnose(stack->leftDecl, Diagnostics::fieldTypeMisMatch, getReflectionName(stack->leftDecl), leftType, rightType);
- getSink(context)->diagnose(stack->rightDecl, Diagnostics::seeOtherDeclarationOf, getReflectionName(stack->rightDecl));
-
- stack = stack->parent;
- if( stack )
- {
- while( stack->parent )
- {
- getSink(context)->diagnose(stack->leftDecl, Diagnostics::usedInDeclarationOf, getReflectionName(stack->leftDecl));
- stack = stack->parent;
- }
- }
- }
- else
- {
- getSink(context)->diagnose(stack->leftDecl, Diagnostics::shaderParameterTypeMismatch, leftType, rightType);
- }
-}
-
-// Two types that were expected to match did not.
-// Inform the user with a suitable message.
-static void diagnoseTypeFieldsMismatch(
- ParameterBindingContext* context,
- DeclRef<Decl> const& left,
- DeclRef<Decl> const& right,
- StructuralTypeMatchStack* stack)
-{
- diagnoseParameterTypeMismatch(context, stack);
-
- getSink(context)->diagnose(left, Diagnostics::fieldDeclarationsDontMatch, left.GetName());
- getSink(context)->diagnose(right, Diagnostics::seeOtherDeclarationOf, right.GetName());
-
- if( stack )
- {
- while( stack->parent )
- {
- getSink(context)->diagnose(stack->leftDecl, Diagnostics::usedInDeclarationOf, getReflectionName(stack->leftDecl));
- stack = stack->parent;
- }
- }
-}
-
-static void collectFields(
- DeclRef<AggTypeDecl> declRef,
- List<DeclRef<VarDecl>>& outFields)
-{
- for( auto fieldDeclRef : getMembersOfType<VarDecl>(declRef) )
- {
- if(fieldDeclRef.getDecl()->HasModifier<HLSLStaticModifier>())
- continue;
-
- outFields.Add(fieldDeclRef);
- }
-}
-
-static bool validateTypesMatch(
- ParameterBindingContext* context,
- Type* left,
- Type* right,
- StructuralTypeMatchStack* stack);
-
-static bool validateIntValuesMatch(
- ParameterBindingContext* context,
- IntVal* left,
- IntVal* right,
- StructuralTypeMatchStack* stack)
-{
- if(left->EqualsVal(right))
- return true;
-
- // TODO: are there other cases we need to handle here?
-
- diagnoseTypeMismatch(context, stack);
- return false;
-}
-
-
-static bool validateValuesMatch(
- ParameterBindingContext* context,
- Val* left,
- Val* right,
- StructuralTypeMatchStack* stack)
-{
- if( auto leftType = dynamicCast<Type>(left) )
- {
- if( auto rightType = dynamicCast<Type>(right) )
- {
- return validateTypesMatch(context, leftType, rightType, stack);
- }
- }
-
- if( auto leftInt = dynamicCast<IntVal>(left) )
- {
- if( auto rightInt = dynamicCast<IntVal>(right) )
- {
- return validateIntValuesMatch(context, leftInt, rightInt, stack);
- }
- }
-
- if( auto leftWitness = dynamicCast<SubtypeWitness>(left) )
- {
- if( auto rightWitness = dynamicCast<SubtypeWitness>(right) )
- {
- return true;
- }
- }
-
- diagnoseTypeMismatch(context, stack);
- return false;
-}
-
-static bool validateGenericSubstitutionsMatch(
- ParameterBindingContext* context,
- GenericSubstitution* left,
- GenericSubstitution* right,
- StructuralTypeMatchStack* stack)
-{
- if( !left )
- {
- if( !right )
- {
- return true;
- }
-
- diagnoseTypeMismatch(context, stack);
- return false;
- }
-
-
-
- UInt argCount = left->args.Count();
- if( argCount != right->args.Count() )
- {
- diagnoseTypeMismatch(context, stack);
- return false;
- }
-
- for( UInt aa = 0; aa < argCount; ++aa )
- {
- auto leftArg = left->args[aa];
- auto rightArg = right->args[aa];
-
- if(!validateValuesMatch(context, leftArg, rightArg, stack))
- return false;
- }
-
- return true;
-}
-
-static bool validateThisTypeSubstitutionsMatch(
- ParameterBindingContext* /*context*/,
- ThisTypeSubstitution* /*left*/,
- ThisTypeSubstitution* /*right*/,
- StructuralTypeMatchStack* /*stack*/)
-{
- // TODO: actual checking.
- return true;
-}
-
-static bool validateSpecializationsMatch(
- ParameterBindingContext* context,
- SubstitutionSet left,
- SubstitutionSet right,
- StructuralTypeMatchStack* stack)
-{
- auto ll = left.substitutions;
- auto rr = right.substitutions;
- for(;;)
- {
- // Skip any global generic substitutions.
- if(auto leftGlobalGeneric = as<GlobalGenericParamSubstitution>(ll))
- {
- ll = leftGlobalGeneric->outer;
- continue;
- }
- if(auto rightGlobalGeneric = as<GlobalGenericParamSubstitution>(rr))
- {
- rr = rightGlobalGeneric->outer;
- continue;
- }
-
- // If either ran out, then we expect both to have run out.
- if(!ll || !rr)
- return !ll && !rr;
-
- auto leftSubst = ll;
- auto rightSubst = rr;
-
- ll = ll->outer;
- rr = rr->outer;
-
- if(auto leftGeneric = as<GenericSubstitution>(leftSubst))
- {
- if(auto rightGeneric = as<GenericSubstitution>(rightSubst))
- {
- if(validateGenericSubstitutionsMatch(context, leftGeneric, rightGeneric, stack))
- {
- continue;
- }
- }
- }
- else if(auto leftThisType = as<ThisTypeSubstitution>(leftSubst))
- {
- if(auto rightThisType = as<ThisTypeSubstitution>(rightSubst))
- {
- if(validateThisTypeSubstitutionsMatch(context, leftThisType, rightThisType, stack))
- {
- continue;
- }
- }
- }
-
- return false;
- }
-
- return true;
-}
-
-// Determine if two types "match" for the purposes of `cbuffer` layout rules.
-//
-static bool validateTypesMatch(
- ParameterBindingContext* context,
- Type* left,
- Type* right,
- StructuralTypeMatchStack* stack)
-{
- if(left->Equals(right))
- return true;
-
- // It is possible that the types don't match exactly, but
- // they *do* match structurally.
-
- // Note: the following code will lead to infinite recursion if there
- // are ever recursive types. We'd need a more refined system to
- // cache the matches we've already found.
-
- if( auto leftDeclRefType = as<DeclRefType>(left) )
- {
- if( auto rightDeclRefType = as<DeclRefType>(right) )
- {
- // Are they references to matching decl refs?
- auto leftDeclRef = leftDeclRefType->declRef;
- auto rightDeclRef = rightDeclRefType->declRef;
-
- // Do the reference the same declaration? Or declarations
- // with the same name?
- //
- // TODO: we should only consider the same-name case if the
- // declarations come from translation units being compiled
- // (and not an imported module).
- if( leftDeclRef.getDecl() == rightDeclRef.getDecl()
- || leftDeclRef.GetName() == rightDeclRef.GetName() )
- {
- // Check that any generic arguments match
- if( !validateSpecializationsMatch(
- context,
- leftDeclRef.substitutions,
- rightDeclRef.substitutions,
- stack) )
- {
- return false;
- }
-
- // Check that any declared fields match too.
- if( auto leftStructDeclRef = leftDeclRef.as<AggTypeDecl>() )
- {
- if( auto rightStructDeclRef = rightDeclRef.as<AggTypeDecl>() )
- {
- List<DeclRef<VarDecl>> leftFields;
- List<DeclRef<VarDecl>> rightFields;
-
- collectFields(leftStructDeclRef, leftFields);
- collectFields(rightStructDeclRef, rightFields);
-
- UInt leftFieldCount = leftFields.Count();
- UInt rightFieldCount = rightFields.Count();
-
- if( leftFieldCount != rightFieldCount )
- {
- diagnoseTypeFieldsMismatch(context, leftDeclRef, rightDeclRef, stack);
- return false;
- }
-
- for( UInt ii = 0; ii < leftFieldCount; ++ii )
- {
- auto leftField = leftFields[ii];
- auto rightField = rightFields[ii];
-
- if( leftField.GetName() != rightField.GetName() )
- {
- diagnoseTypeFieldsMismatch(context, leftDeclRef, rightDeclRef, stack);
- return false;
- }
-
- auto leftFieldType = GetType(leftField);
- auto rightFieldType = GetType(rightField);
-
- StructuralTypeMatchStack subStack;
- subStack.parent = stack;
- subStack.leftDecl = leftField;
- subStack.rightDecl = rightField;
-
- if(!validateTypesMatch(context, leftFieldType,rightFieldType, &subStack))
- return false;
- }
- }
- }
-
- // Everything seemed to match recursively.
- return true;
- }
- }
- }
-
- // If we are looking at `T[N]` and `U[M]` we want to check that
- // `T` is structurally equivalent to `U` and `N` is the same as `M`.
- else if( auto leftArrayType = as<ArrayExpressionType>(left) )
- {
- if( auto rightArrayType = as<ArrayExpressionType>(right) )
- {
- if(!validateTypesMatch(context, leftArrayType->baseType, rightArrayType->baseType, stack) )
- return false;
-
- if(!validateValuesMatch(context, leftArrayType->ArrayLength, rightArrayType->ArrayLength, stack))
- return false;
-
- return true;
- }
- }
-
- diagnoseTypeMismatch(context, stack);
- return false;
-}
-
-// This function is supposed to determine if two global shader
-// parameter declarations represent the same logical parameter
-// (so that they should get the exact same binding(s) allocated).
-//
-static bool doesParameterMatch(
- ParameterBindingContext* context,
- RefPtr<VarLayout> varLayout,
- ParameterInfo* parameterInfo)
-{
- // Any "varying" parameter should automatically be excluded
- //
- // Note that we use the `typeLayout` field rather than
- // looking at resource information on the variable directly,
- // because this may be called when binding hasn't been performed.
- for (auto rr : varLayout->typeLayout->resourceInfos)
- {
- switch (rr.kind)
- {
- case LayoutResourceKind::VertexInput:
- case LayoutResourceKind::FragmentOutput:
- return false;
-
- default:
- break;
- }
- }
-
- StructuralTypeMatchStack stack;
- stack.parent = nullptr;
- stack.leftDecl = varLayout->varDecl;
- stack.rightDecl = parameterInfo->varLayouts[0]->varDecl;
-
- validateTypesMatch(context, varLayout->typeLayout->type, parameterInfo->varLayouts[0]->typeLayout->type, &stack);
-
- return true;
-}
//
@@ -1020,90 +599,6 @@ static bool findLayoutArg(
return findLayoutArg<T>(declRef.getDecl(), outVal);
}
-//
-
-static bool isGLSLBuiltinName(VarDeclBase* varDecl)
-{
- return getText(getReflectionName(varDecl)).StartsWith("gl_");
-}
-
-RefPtr<Type> tryGetEffectiveTypeForGLSLVaryingInput(
- ParameterBindingContext* context,
- VarDeclBase* varDecl)
-{
- if (isGLSLBuiltinName(varDecl))
- return nullptr;
-
- auto type = varDecl->getType();
- if( varDecl->HasModifier<InModifier>() || as<GLSLInputParameterGroupType>(type))
- {
- // Special case to handle "arrayed" shader inputs, as used
- // for Geometry and Hull input
- switch( context->stage )
- {
- case Stage::Geometry:
- case Stage::Hull:
- case Stage::Domain:
- // Tessellation `patch` variables should stay as written
- if( !varDecl->HasModifier<GLSLPatchModifier>() )
- {
- // Unwrap array type, if present
- if( auto arrayType = as<ArrayExpressionType>(type) )
- {
- type = arrayType->baseType.Ptr();
- }
- }
- break;
-
- default:
- break;
- }
-
- return type;
- }
-
- return nullptr;
-}
-
-RefPtr<Type> tryGetEffectiveTypeForGLSLVaryingOutput(
- ParameterBindingContext* context,
- VarDeclBase* varDecl)
-{
- if (isGLSLBuiltinName(varDecl))
- return nullptr;
-
- auto type = varDecl->getType();
- if( varDecl->HasModifier<OutModifier>() || as<GLSLOutputParameterGroupType>(type))
- {
- // Special case to handle "arrayed" shader outputs, as used
- // for Hull Shader output
- //
- // Note(tfoley): there is unfortunate code duplication
- // with the `in` case above.
- switch( context->stage )
- {
- case Stage::Hull:
- // Tessellation `patch` variables should stay as written
- if( !varDecl->HasModifier<GLSLPatchModifier>() )
- {
- // Unwrap array type, if present
- if( auto arrayType = as<ArrayExpressionType>(type) )
- {
- type = arrayType->baseType.Ptr();
- }
- }
- break;
-
- default:
- break;
- }
-
- return type;
- }
-
- return nullptr;
-}
-
/// Determine how to lay out a global variable that might be a shader parameter.
///
/// Returns `nullptr` if the declaration does not represent a shader parameter.
@@ -1183,19 +678,21 @@ static void collectGlobalGenericParameter(
// Collect a single declaration into our set of parameters
static void collectGlobalScopeParameter(
- ParameterBindingContext* context,
- RefPtr<VarDeclBase> varDecl,
- SubstitutionSet globalGenericSubst)
+ ParameterBindingContext* context,
+ GlobalShaderParamInfo const& shaderParamInfo,
+ SubstitutionSet globalGenericSubst)
{
+ auto varDeclRef = shaderParamInfo.paramDeclRef;
+
// We apply any substitutions for global generic parameters here.
- auto type = varDecl->getType()->Substitute(globalGenericSubst).as<Type>();
+ auto type = GetType(varDeclRef)->Substitute(globalGenericSubst).as<Type>();
// We use a single operation to both check whether the
// variable represents a shader parameter, and to compute
// the layout for that parameter's type.
auto typeLayout = getTypeLayoutForGlobalShaderParameter(
context,
- varDecl,
+ varDeclRef.getDecl(),
type);
// If we did not find appropriate layout rules, then it
@@ -1207,45 +704,43 @@ static void collectGlobalScopeParameter(
// Now create a variable layout that we can use
RefPtr<VarLayout> varLayout = new VarLayout();
varLayout->typeLayout = typeLayout;
- varLayout->varDecl = DeclRef<Decl>(varDecl.Ptr(), nullptr).as<VarDeclBase>();
+ varLayout->varDecl = varDeclRef;
- // This declaration may represent the same logical parameter
- // as a declaration that came from a different translation unit.
- // If that is the case, we want to re-use the same `VarLayout`
- // across both parameters.
+ // The logic in `check.cpp` that created the `GlobalShaderParamInfo`
+ // will have identified any cases where there might be multiple
+ // global variables that logically represent the same shader parameter.
//
- // TODO: This logic currently detects *any* global-scope parameters
- // with matching names, but it should eventually be narrowly
- // scoped so that it only applies to parameters from unnamed modules.
+ // We will track the same basic information during layout using
+ // the `ParameterInfo` type.
//
- // First we look for an existing entry matching the name
- // of this parameter:
- auto parameterName = getReflectionName(varDecl);
- ParameterInfo* parameterInfo = nullptr;
- if( context->mapNameToParameterInfo.TryGetValue(parameterName, parameterInfo) )
- {
- // If the parameters have the same name, but don't "match" according to some reasonable rules,
- // then we need to bail out.
- if( !doesParameterMatch(context, varLayout, parameterInfo) )
- {
- parameterInfo = nullptr;
- }
- }
+ // TODO: `ParameterInfo` should probably become `LayoutParamInfo`.
+ //
+ ParameterInfo* parameterInfo = new ParameterInfo();
+ context->shared->parameters.Add(parameterInfo);
- // If we didn't find a matching parameter, then we need to create one here
- if( !parameterInfo )
- {
- parameterInfo = new ParameterInfo();
- context->shared->parameters.Add(parameterInfo);
- context->mapNameToParameterInfo.AddIfNotExists(parameterName, parameterInfo);
- }
- else
+ // Add the first variable declaration to the list of declarations for the parameter
+ parameterInfo->varLayouts.Add(varLayout);
+
+ // Add any additional variables to the list of declarations
+ for( auto additionalVarDeclRef : shaderParamInfo.additionalParamDeclRefs )
{
- varLayout->flags |= VarLayoutFlag::IsRedeclaration;
- }
+ // TODO: We should either eliminate the design choice where different
+ // declarations of the "same" shade parameter get merged across
+ // translation units (it is effectively just a compatiblity feature),
+ // or we should clean things up earlier in the chain so that we can
+ // re-use a single `VarLayout` across all of the different declarations.
+ //
+ // TODO: It would also make sense in these cases to ensure that
+ // such global shader parameters get the same mangled name across
+ // all translation units, so that they can automatically be collapsed
+ // during linking.
- // Add this variable declaration to the list of declarations for the parameter
- parameterInfo->varLayouts.Add(varLayout);
+ RefPtr<VarLayout> additionalVarLayout = new VarLayout();
+ additionalVarLayout->typeLayout = typeLayout;
+ additionalVarLayout->varDecl = additionalVarDeclRef;
+
+ parameterInfo->varLayouts.Add(additionalVarLayout);
+ }
}
static RefPtr<UsedRangeSet> findUsedRangeSetForSpace(
@@ -1783,41 +1278,6 @@ static void completeBindingsForParameter(
applyBindingInfoToParameter(varLayout, bindingInfos);
}
-
-
-static void collectGlobalScopeParameters(
- ParameterBindingContext* context,
- ModuleDecl* program,
- SubstitutionSet globalGenericSubst)
-{
- // First enumerate parameters at global scope
- // We collect two things here:
- // 1. A shader parameter, which is always a variable
- // 2. A global entry-point generic parameter type (`type_param`),
- // which is a GlobalGenericParamDecl
- // We collect global generic type parameters in the first pass,
- // So we can fill in the correct index into ordinary type layouts
- // for generic types in the second pass.
- for (auto decl : program->Members)
- {
- if (auto genParamDecl = as<GlobalGenericParamDecl>(decl))
- collectGlobalGenericParameter(context, genParamDecl);
- }
- for (auto decl : program->Members)
- {
- if (auto varDecl = as<VarDeclBase>(decl))
- collectGlobalScopeParameter(context, varDecl, globalGenericSubst);
- }
-
- // Next, we need to enumerate the parameters of
- // each entry point (which requires knowing what the
- // entry points *are*)
-
- // TODO(tfoley): Entry point functions should be identified
- // by looking for a generated modifier that is attached
- // to global-scope function declarations.
-}
-
struct SimpleSemanticInfo
{
String name;
@@ -2274,7 +1734,7 @@ static RefPtr<TypeLayout> processEntryPointVaryingParameter(
static RefPtr<TypeLayout> computeEntryPointParameterTypeLayout(
ParameterBindingContext* context,
SubstitutionSet typeSubst,
- DeclRef<ParamDecl> paramDeclRef,
+ DeclRef<VarDeclBase> paramDeclRef,
RefPtr<VarLayout> paramVarLayout,
EntryPointParameterState& state)
{
@@ -2537,8 +1997,10 @@ static void collectEntryPointParameters(
scopeBuilder.beginLayout(context);
auto paramsStructLayout = scopeBuilder.m_structLayout;
- for( auto paramDeclRef : getMembersOfType<ParamDecl>(entryPointFuncDeclRef) )
+ for( auto& shaderParamInfo : entryPoint->getShaderParams() )
{
+ auto paramDeclRef = shaderParamInfo.paramDeclRef;
+
// Any error messages we emit during the process should
// refer to the location of this parameter.
//
@@ -2656,17 +2118,33 @@ static void collectParameters(
// logical namespace/"linkage" so that two parameters
// with the same name should represent the same
// parameter, and get the same binding(s)
+
ParameterBindingContext contextData = *inContext;
auto context = &contextData;
+ context->stage = Stage::Unknown;
auto globalGenericSubst = program->getGlobalGenericSubstitution();
+ // We will start by looking for any global generic type parameters.
+
for(RefPtr<Module> module : program->getModuleDependencies())
{
- context->stage = Stage::Unknown;
+ for( auto genParamDecl : module->getModuleDecl()->getMembersOfType<GlobalGenericParamDecl>() )
+ {
+ collectGlobalGenericParameter(context, genParamDecl);
+ }
+ }
+
+ // Once we have enumerated global generic type parameters, we can
+ // begin enumerating shader parameters, starting at the global scope.
+ //
+ // Because we have already enumerated the global generic type parameters,
+ // we will be able to look up the index of a global generic type parameter
+ // when we see it referenced in the type of one of the shader parameters.
- // First look at global-scope parameters
- collectGlobalScopeParameters(context, module->getModuleDecl(), globalGenericSubst);
+ for(auto& globalParamInfo : program->getShaderParams() )
+ {
+ collectGlobalScopeParameter(context, globalParamInfo, globalGenericSubst);
}
// Next consider parameters for entry points