summaryrefslogtreecommitdiffstats
path: root/source/slang/parameter-binding.cpp
diff options
context:
space:
mode:
authorTim Foley <tfoley@nvidia.com>2017-07-18 07:49:33 -0700
committerTim Foley <tfoley@nvidia.com>2017-07-18 12:58:48 -0700
commit1c022e2c3654de868c45658683f9e04cf4d68cc0 (patch)
treed4a5f0cefd50c96aaf22921f9fef715b6359c0c5 /source/slang/parameter-binding.cpp
parent361e29572ff8e2cdd1e4ffe2cb62599e9ef06461 (diff)
Support scalarization of varying input/output for GLSL
GLSL technically supports varying (`in`, `out`) parameters of `struct` type, but there are some annoying constraints (not allowed for VS input), and it doesn't work with how an HLSL user would usually put "system-value" inputs/outputs into a `struct` together with ordinary inputs/outputs. To work around this, this change adds support for using an imported Slang `struct` type for an `in` or `out` parameter, in which case it will (1) be scalarized and (2) will have system-value semantics mapped appropriately, just as for an entry-point parameter when cross-compiling an HLSL-style `main()`. Changes: - Add a notion of a `VaryingTupleExpr` and `VaryingTupleVarDecl`, similar to those for the resources-in-structs case - Trigger use of these when we have a global-scope varying in/out using an imported `struct` type - Also use these in the cross-compilation case for ordinary varying input/output (since this approach seems like it should be more general, and can hopefully handle stuff like GS input/output some day) - When generating parameter binding information, special case global-scope input/output, and treat it the same as entry-point-parameter input/output - Revamp how used resource ranges are computed so that we can eventually make this specific to an entry point - Actually implement first signs of life for `maybeMoveTemp` so that assignments to the tuple-ified outputs will work better - Add first test case that actually seems to work - Add diagnostics for conflicting explicit bindings on a parameter - Add diagnostic for different parameters with overlapping bindings - Make global-scope varying input/output use a tracking data structure specific to the translation unit for computing locations (so that they are independent of other TUs)
Diffstat (limited to 'source/slang/parameter-binding.cpp')
-rw-r--r--source/slang/parameter-binding.cpp417
1 files changed, 338 insertions, 79 deletions
diff --git a/source/slang/parameter-binding.cpp b/source/slang/parameter-binding.cpp
index ca135f1ba..15025f1e4 100644
--- a/source/slang/parameter-binding.cpp
+++ b/source/slang/parameter-binding.cpp
@@ -11,9 +11,15 @@
namespace Slang {
+struct ParameterInfo;
+
// Information on ranges of registers already claimed/used
struct UsedRange
{
+ // What parameter has claimed this range?
+ ParameterInfo* parameter = nullptr;
+
+ // Begin/end of the range (half-open interval)
UInt begin;
UInt end;
};
@@ -26,42 +32,78 @@ bool operator<(UsedRange left, UsedRange right)
return false;
}
+static bool rangesOverlap(UsedRange const& x, UsedRange const& y)
+{
+ assert(x.begin <= x.end);
+ assert(y.begin <= y.end);
+
+ // If they don't overlap, then one must be earlier than the other,
+ // and that one must therefore *end* before the other *begins*
+
+ if (x.end <= y.begin) return false;
+ if (y.end <= x.begin) return false;
+
+ // Otherwise they must overlap
+ return true;
+}
+
+
struct UsedRanges
{
List<UsedRange> ranges;
// Add a range to the set, either by extending
// an existing range, or by adding a new one...
- void Add(UsedRange const& range)
+ //
+ // If we find that the new range overlaps with
+ // an existing range for a *different* parameter
+ // then we return that parameter so that the
+ // caller can issue an error.
+ ParameterInfo* Add(UsedRange const& range)
{
+ ParameterInfo* newParam = range.parameter;
+ ParameterInfo* existingParam = nullptr;
+ for (auto& rr : ranges)
+ {
+ if (rangesOverlap(rr, range)
+ && rr.parameter
+ && rr.parameter != newParam)
+ {
+ // there was an overlap!
+ existingParam = rr.parameter;
+ }
+ }
+
for (auto& rr : ranges)
{
if (rr.begin == range.end)
{
rr.begin = range.begin;
- return;
+ return existingParam;
}
else if (rr.end == range.begin)
{
rr.end = range.end;
- return;
+ return existingParam;
}
}
ranges.Add(range);
ranges.Sort();
+ return existingParam;
}
- void Add(UInt begin, UInt end)
+ ParameterInfo* Add(ParameterInfo* param, UInt begin, UInt end)
{
UsedRange range;
+ range.parameter = param;
range.begin = begin;
range.end = end;
- Add(range);
+ return Add(range);
}
// Try to find space for `count` entries
- UInt Allocate(UInt count)
+ UInt Allocate(ParameterInfo* param, UInt count)
{
UInt begin = 0;
@@ -76,7 +118,7 @@ struct UsedRanges
if (end >= begin + count)
{
// ... then claim it and be done
- Add(begin, begin + count);
+ Add(param, begin, begin + count);
return begin;
}
@@ -87,7 +129,7 @@ struct UsedRanges
// We've run out of ranges to check, so we
// can safely go after the last one!
- Add(begin, begin + count);
+ Add(param, begin, begin + count);
return begin;
}
};
@@ -104,6 +146,13 @@ enum
kLayoutResourceKindCount = SLANG_PARAMETER_CATEGORY_COUNT,
};
+struct UsedRangeSet : RefObject
+{
+ // Information on what ranges of "registers" have already
+ // been claimed, for each resource type
+ UsedRanges usedResourceRanges[kLayoutResourceKindCount];
+};
+
// Information on a single parameter
struct ParameterInfo : RefObject
{
@@ -115,6 +164,9 @@ struct ParameterInfo : RefObject
// The next parameter that has the same name...
ParameterInfo* nextOfSameName;
+ // The translation unit this parameter is specific to, if any
+ TranslationUnitRequest* translationUnit = nullptr;
+
ParameterInfo()
{
// Make sure we aren't claiming any resources yet
@@ -125,10 +177,19 @@ struct ParameterInfo : RefObject
}
};
+struct EntryPointParameterBindingContext
+{
+ // What ranges of resources bindings are already claimed for this translation unit
+ UsedRangeSet usedRangeSet;
+};
+
// State that is shared during parameter binding,
// across all translation units
struct SharedParameterBindingContext
{
+ // The base compile request
+ CompileRequest* compileRequest;
+
LayoutRulesFamilyImpl* defaultLayoutRules;
// All shader parameters we've discovered so far, and started to lay out...
@@ -137,15 +198,29 @@ struct SharedParameterBindingContext
// The program layout we are trying to construct
RefPtr<ProgramLayout> programLayout;
- // Information on what ranges of "registers" have already
- // been claimed, for each resource type
- UsedRanges usedResourceRanges[kLayoutResourceKindCount];
+ // What ranges of resources bindings are already claimed at the global scope?
+ // We store one of these for each declared binding space/set.
+ //
+ Dictionary<UInt, RefPtr<UsedRangeSet>> globalSpaceUsedRangeSets;
+
+ // What ranges of resource bindings are claimed for particular translation unit?
+ // This is only used for varying input/output.
+ //
+ Dictionary<TranslationUnitRequest*, RefPtr<UsedRangeSet>> translationUnitUsedRangeSets;
};
+static DiagnosticSink* getSink(SharedParameterBindingContext* shared)
+{
+ return &shared->compileRequest->mSink;
+}
+
// State that might be specific to a single translation unit
// or event to an entry point.
struct ParameterBindingContext
{
+ // The translation unit we are processing right now
+ TranslationUnitRequest* translationUnit;
+
// All the shared state needs to be available
SharedParameterBindingContext* shared;
@@ -162,6 +237,12 @@ struct ParameterBindingContext
SourceLanguage sourceLanguage;
};
+static DiagnosticSink* getSink(ParameterBindingContext* context)
+{
+ return getSink(context->shared);
+}
+
+
struct LayoutSemanticInfo
{
LayoutResourceKind kind; // the register kind
@@ -298,37 +379,19 @@ static bool findLayoutArg(
//
-RefPtr<TypeLayout>
-getTypeLayoutForGlobalShaderParameter_GLSL(
+static bool isGLSLBuiltinName(VarDeclBase* varDecl)
+{
+ return varDecl->getName().StartsWith("gl_");
+}
+
+RefPtr<ExpressionType> tryGetEffectiveTypeForGLSLVaryingInput(
ParameterBindingContext* context,
VarDeclBase* varDecl)
{
- auto rules = context->layoutRules;
- auto type = varDecl->getType();
-
- // A GLSL shader parameter will be marked with
- // a qualifier to match the boundary it uses
- //
- // In the case of a parameter block, we will have
- // consumed this qualifier as part of parsing,
- // so that it won't be present on the declaration
- // any more. As such we also inspect the type
- // of the variable.
-
- // We want to check for a constant-buffer type with a `push_constant` layout
- // qualifier before we move on to anything else.
- if (varDecl->HasModifier<GLSLPushConstantLayoutModifier>() && type->As<ConstantBufferType>())
- return CreateTypeLayout(type, rules->getPushConstantBufferRules());
-
- // TODO(tfoley): We have multiple variations of
- // the `uniform` modifier right now, and that
- // needs to get fixed...
- if(varDecl->HasModifier<HLSLUniformModifier>() || type->As<ConstantBufferType>())
- return CreateTypeLayout(type, rules->getConstantBufferRules());
-
- if(varDecl->HasModifier<GLSLBufferModifier>() || type->As<GLSLShaderStorageBufferType>())
- return CreateTypeLayout(type, rules->getShaderStorageBufferRules());
+ if (isGLSLBuiltinName(varDecl))
+ return nullptr;
+ auto type = varDecl->getType();
if( varDecl->HasModifier<InModifier>() || type->As<GLSLInputParameterBlockType>())
{
// Special case to handle "arrayed" shader inputs, as used
@@ -353,9 +416,20 @@ getTypeLayoutForGlobalShaderParameter_GLSL(
break;
}
- return CreateTypeLayout(type, rules->getVaryingInputRules());
+ return type;
}
+ return nullptr;
+}
+
+RefPtr<ExpressionType> tryGetEffectiveTypeForGLSLVaryingOutput(
+ ParameterBindingContext* context,
+ VarDeclBase* varDecl)
+{
+ if (isGLSLBuiltinName(varDecl))
+ return nullptr;
+
+ auto type = varDecl->getType();
if( varDecl->HasModifier<OutModifier>() || type->As<GLSLOutputParameterBlockType>())
{
// Special case to handle "arrayed" shader outputs, as used
@@ -381,7 +455,55 @@ getTypeLayoutForGlobalShaderParameter_GLSL(
break;
}
- return CreateTypeLayout(type, rules->getVaryingOutputRules());
+ return type;
+ }
+
+ return nullptr;
+}
+
+RefPtr<TypeLayout>
+getTypeLayoutForGlobalShaderParameter_GLSL(
+ ParameterBindingContext* context,
+ VarDeclBase* varDecl)
+{
+ auto rules = context->layoutRules;
+ auto type = varDecl->getType();
+
+ // A GLSL shader parameter will be marked with
+ // a qualifier to match the boundary it uses
+ //
+ // In the case of a parameter block, we will have
+ // consumed this qualifier as part of parsing,
+ // so that it won't be present on the declaration
+ // any more. As such we also inspect the type
+ // of the variable.
+
+ // We want to check for a constant-buffer type with a `push_constant` layout
+ // qualifier before we move on to anything else.
+ if (varDecl->HasModifier<GLSLPushConstantLayoutModifier>() && type->As<ConstantBufferType>())
+ return CreateTypeLayout(type, rules->getPushConstantBufferRules());
+
+ // TODO(tfoley): We have multiple variations of
+ // the `uniform` modifier right now, and that
+ // needs to get fixed...
+ if(varDecl->HasModifier<HLSLUniformModifier>() || type->As<ConstantBufferType>())
+ return CreateTypeLayout(type, rules->getConstantBufferRules());
+
+ if(varDecl->HasModifier<GLSLBufferModifier>() || type->As<GLSLShaderStorageBufferType>())
+ return CreateTypeLayout(type, rules->getShaderStorageBufferRules());
+
+ if (auto effectiveVaryingInputType = tryGetEffectiveTypeForGLSLVaryingInput(context, varDecl))
+ {
+ // We expect to handle these elsewhere
+ assert(!"unexpected");
+ return CreateTypeLayout(effectiveVaryingInputType, rules->getVaryingInputRules());
+ }
+
+ if (auto effectiveVaryingOutputType = tryGetEffectiveTypeForGLSLVaryingOutput(context, varDecl))
+ {
+ // We expect to handle these elsewhere
+ assert(!"unexpected");
+ return CreateTypeLayout(effectiveVaryingOutputType, rules->getVaryingOutputRules());
}
// A `const` global with a `layout(constant_id = ...)` modifier
@@ -446,13 +568,83 @@ getTypeLayoutForGlobalShaderParameter(
//
+enum EntryPointParameterDirection
+{
+ kEntryPointParameterDirection_Input = 0x1,
+ kEntryPointParameterDirection_Output = 0x2,
+};
+typedef unsigned int EntryPointParameterDirectionMask;
+
+struct EntryPointParameterState
+{
+ String* optSemanticName = nullptr;
+ int* ioSemanticIndex = nullptr;
+ EntryPointParameterDirectionMask directionMask;
+ int semanticSlotCount;
+};
+
+
+static RefPtr<TypeLayout> processEntryPointParameter(
+ ParameterBindingContext* context,
+ RefPtr<ExpressionType> type,
+ EntryPointParameterState const& state,
+ RefPtr<VarLayout> varLayout);
+
+static void collectGlobalScopeGLSLVaryingParameter(
+ ParameterBindingContext* context,
+ RefPtr<VarDeclBase> varDecl,
+ RefPtr<ExpressionType> effectiveType,
+ EntryPointParameterDirection direction)
+{
+ int defaultSemanticIndex = 0;
+
+ EntryPointParameterState state;
+ state.directionMask = direction;
+ state.ioSemanticIndex = &defaultSemanticIndex;
+
+ RefPtr<VarLayout> varLayout = new VarLayout();
+ varLayout->varDecl = makeDeclRef(varDecl.Ptr());
+
+ varLayout->typeLayout = processEntryPointParameter(
+ context,
+ effectiveType,
+ state,
+ varLayout);
+
+ // Now add it to our list of reflection parameters, so
+ // that it can get a location assigned later...
+ auto parameterName = varDecl->Name.Content;
+ ParameterInfo* parameterInfo = new ParameterInfo();
+ parameterInfo->translationUnit = context->translationUnit;
+ context->shared->parameters.Add(parameterInfo);
+ parameterInfo->varLayouts.Add(varLayout);
+}
// Collect a single declaration into our set of parameters
static void collectGlobalScopeParameter(
ParameterBindingContext* context,
RefPtr<VarDeclBase> varDecl)
{
+ // HACK: We need to intercept GLSL varying `in` and `out` here, way earlier
+ // in the process, so that we can avoid all kinds of nastiness that would
+ // otherwise be applied to them.
+ if (context->sourceLanguage == SourceLanguage::GLSL)
+ {
+ if (auto effectiveVaryingInputType = tryGetEffectiveTypeForGLSLVaryingInput(context, varDecl))
+ {
+ collectGlobalScopeGLSLVaryingParameter(context, varDecl, effectiveVaryingInputType, kEntryPointParameterDirection_Input);
+ return;
+ }
+
+ if (auto effectiveVaryingOutputType = tryGetEffectiveTypeForGLSLVaryingOutput(context, varDecl))
+ {
+ collectGlobalScopeGLSLVaryingParameter(context, varDecl, effectiveVaryingOutputType, kEntryPointParameterDirection_Output);
+ return;
+ }
+ }
+
+
// 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.
@@ -506,11 +698,41 @@ static void collectGlobalScopeParameter(
parameterInfo->varLayouts.Add(varLayout);
}
+static RefPtr<UsedRangeSet> findUsedRangeSetForSpace(
+ ParameterBindingContext* context,
+ UInt space)
+{
+ RefPtr<UsedRangeSet> usedRangeSet;
+ if (context->shared->globalSpaceUsedRangeSets.TryGetValue(space, usedRangeSet))
+ return usedRangeSet;
+
+ usedRangeSet = new UsedRangeSet();
+ context->shared->globalSpaceUsedRangeSets.Add(space, usedRangeSet);
+ return usedRangeSet;
+}
+
+static RefPtr<UsedRangeSet> findUsedRangeSetForTranslationUnit(
+ ParameterBindingContext* context,
+ TranslationUnitRequest* translationUnit)
+{
+ if (!translationUnit)
+ return findUsedRangeSetForSpace(context, 0);
+
+ RefPtr<UsedRangeSet> usedRangeSet;
+ if (context->shared->translationUnitUsedRangeSets.TryGetValue(translationUnit, usedRangeSet))
+ return usedRangeSet;
+
+ usedRangeSet = new UsedRangeSet();
+ context->shared->translationUnitUsedRangeSets.Add(translationUnit, usedRangeSet);
+ return usedRangeSet;
+}
+
static void addExplicitParameterBinding(
ParameterBindingContext* context,
RefPtr<ParameterInfo> parameterInfo,
LayoutSemanticInfo const& semanticInfo,
- UInt count)
+ UInt count,
+ RefPtr<UsedRangeSet> usedRangeSet = nullptr)
{
auto kind = semanticInfo.kind;
@@ -524,7 +746,8 @@ static void addExplicitParameterBinding(
|| bindingInfo.index != semanticInfo.index
|| bindingInfo.space != semanticInfo.space )
{
- // TODO: diagnose!
+ auto firstVarDecl = parameterInfo->varLayouts[0]->varDecl.getDecl();
+ getSink(context)->diagnose(firstVarDecl, Diagnostics::conflictingExplicitBindingsForParameter, firstVarDecl->getName());
}
// TODO(tfoley): `register` semantics can technically be
@@ -536,14 +759,21 @@ static void addExplicitParameterBinding(
bindingInfo.index = semanticInfo.index;
bindingInfo.space = semanticInfo.space;
- // If things are bound in `space0` (the default), then we need
- // to lay claim to the register range used, so that automatic
- // assignment doesn't go and use the same registers.
- if (semanticInfo.space == 0)
+ if (!usedRangeSet)
+ {
+ usedRangeSet = findUsedRangeSetForSpace(context, semanticInfo.space);
+ }
+ auto overlappedParameterInfo = usedRangeSet->usedResourceRanges[(int)semanticInfo.kind].Add(
+ parameterInfo,
+ semanticInfo.index,
+ semanticInfo.index + count);
+
+ if (overlappedParameterInfo)
{
- context->shared->usedResourceRanges[(int)semanticInfo.kind].Add(
- semanticInfo.index,
- semanticInfo.index + count);
+ auto paramA = parameterInfo->varLayouts[0]->varDecl.getDecl();
+ auto paramB = overlappedParameterInfo->varLayouts[0]->varDecl.getDecl();
+
+ getSink(context)->diagnose(paramA, Diagnostics::parameterBindingsOverlap, paramA->getName(), paramB->getName());
}
}
}
@@ -603,6 +833,11 @@ static void addExplicitParameterBindings_GLSL(
// the index/offset/etc.
//
+ // We also may need to store explicit binding info in a different place,
+ // in the case of varying input/output, since we don't want to collect
+ // things globally;
+ RefPtr<UsedRangeSet> usedRangeSet;
+
TypeLayout::ResourceInfo* resInfo = nullptr;
LayoutSemanticInfo semanticInfo;
semanticInfo.index = 0;
@@ -620,12 +855,16 @@ static void addExplicitParameterBindings_GLSL(
// Try to find `location` binding
if(!findLayoutArg<GLSLLocationLayoutModifier>(varDecl, &semanticInfo.index))
return;
+
+ usedRangeSet = findUsedRangeSetForTranslationUnit(context, parameterInfo->translationUnit);
}
else if( (resInfo = typeLayout->FindResourceInfo(LayoutResourceKind::FragmentOutput)) != nullptr )
{
// Try to find `location` binding
if(!findLayoutArg<GLSLLocationLayoutModifier>(varDecl, &semanticInfo.index))
return;
+
+ usedRangeSet = findUsedRangeSetForTranslationUnit(context, parameterInfo->translationUnit);
}
else if( (resInfo = typeLayout->FindResourceInfo(LayoutResourceKind::SpecializationConstant)) != nullptr )
{
@@ -642,7 +881,7 @@ static void addExplicitParameterBindings_GLSL(
auto count = resInfo->count;
semanticInfo.kind = kind;
- addExplicitParameterBinding(context, parameterInfo, semanticInfo, int(count));
+ addExplicitParameterBinding(context, parameterInfo, semanticInfo, int(count), usedRangeSet);
}
// Given a single parameter, collect whatever information we have on
@@ -696,12 +935,31 @@ static void completeBindingsForParameter(
continue;
}
+ // For now we only auto-generate bindings in space zero
+ //
+ // TODO: we may want to support searching for a space with
+ // capacity for our resource, just in case somebody has
+ // claimed the entire range...
+ UInt space = 0;
+
+ RefPtr<UsedRangeSet> usedRangeSet;
+ switch (kind)
+ {
+ default:
+ usedRangeSet = findUsedRangeSetForSpace(context, space);
+ break;
+
+ case LayoutResourceKind::VertexInput:
+ case LayoutResourceKind::FragmentOutput:
+ usedRangeSet = findUsedRangeSetForTranslationUnit(context, parameterInfo->translationUnit);
+ break;
+ }
+
auto count = typeRes.count;
bindingInfo.count = count;
- bindingInfo.index = context->shared->usedResourceRanges[(int)kind].Allocate((int) count);
+ bindingInfo.index = usedRangeSet->usedResourceRanges[(int)kind].Allocate(parameterInfo, (int) count);
- // For now we only auto-generate bindings in space zero
- bindingInfo.space = 0;
+ bindingInfo.space = space;
}
// At this point we should have explicit binding locations chosen for
@@ -799,21 +1057,6 @@ SimpleSemanticInfo decomposeSimpleSemantic(
return info;
}
-enum EntryPointParameterDirection
-{
- kEntryPointParameterDirection_Input = 0x1,
- kEntryPointParameterDirection_Output = 0x2,
-};
-typedef unsigned int EntryPointParameterDirectionMask;
-
-struct EntryPointParameterState
-{
- String* optSemanticName;
- int* ioSemanticIndex;
- EntryPointParameterDirectionMask directionMask;
- int semanticSlotCount;
-};
-
static RefPtr<TypeLayout> processSimpleEntryPointParameter(
ParameterBindingContext* context,
RefPtr<ExpressionType> type,
@@ -844,7 +1087,18 @@ static RefPtr<TypeLayout> processSimpleEntryPointParameter(
// once we've gone to the trouble of looking it all up...
if( sn == "sv_target" )
{
- context->shared->usedResourceRanges[int(LayoutResourceKind::UnorderedAccess)].Add(semanticIndex, semanticIndex + semanticSlotCount);
+ // TODO: construct a `ParameterInfo` we can use here so that
+ // overlapped layout errors get reported nicely.
+
+ auto usedResourceSet = findUsedRangeSetForSpace(context, 0);
+ usedResourceSet->usedResourceRanges[int(LayoutResourceKind::UnorderedAccess)].Add(nullptr, semanticIndex, semanticIndex + semanticSlotCount);
+
+
+ // We also need to track this as an ordinary varying output from the stage,
+ // since that is how GLSL will want to see it.
+ auto rules = context->layoutRules->getVaryingOutputRules();
+ SimpleLayoutInfo layout = GetLayout(type, rules);
+ typeLayout->addResourceUsage(layout.kind, layout.size);
}
}
@@ -882,12 +1136,6 @@ static RefPtr<TypeLayout> processSimpleEntryPointParameter(
return typeLayout;
}
-static RefPtr<TypeLayout> processEntryPointParameter(
- ParameterBindingContext* context,
- RefPtr<ExpressionType> type,
- EntryPointParameterState const& state,
- RefPtr<VarLayout> varLayout);
-
static RefPtr<TypeLayout> processEntryPointParameterWithPossibleSemantic(
ParameterBindingContext* context,
Decl* declForSemantic,
@@ -908,7 +1156,7 @@ static RefPtr<TypeLayout> processEntryPointParameterWithPossibleSemantic(
subState.optSemanticName = &semanticInfo.name;
subState.ioSemanticIndex = &semanticIndex;
- processEntryPointParameter(context, type, subState, varLayout);
+ return processEntryPointParameter(context, type, subState, varLayout);
}
}
@@ -1200,6 +1448,8 @@ static void collectModuleParameters(
ParameterBindingContext contextData = *inContext;
auto context = &contextData;
+ context->translationUnit = nullptr;
+
context->stage = Stage::Unknown;
// All imported modules are implicitly Slang code
@@ -1225,6 +1475,7 @@ static void collectParameters(
for( auto& translationUnit : request->translationUnits )
{
+ context->translationUnit = translationUnit;
context->stage = inferStageForTranslationUnit(translationUnit.Ptr());
context->sourceLanguage = translationUnit->sourceLanguage;
@@ -1262,6 +1513,7 @@ void generateParameterBindings(
// Create a context to hold shared state during the process
// of generating parameter bindings
SharedParameterBindingContext sharedContext;
+ sharedContext.compileRequest = request;
sharedContext.defaultLayoutRules = rules;
sharedContext.programLayout = programLayout;
@@ -1269,6 +1521,7 @@ void generateParameterBindings(
// declared into the global scope
ParameterBindingContext context;
context.shared = &sharedContext;
+ context.translationUnit = nullptr;
context.layoutRules = sharedContext.defaultLayoutRules;
// Walk through AST to discover all the parameters
@@ -1299,12 +1552,18 @@ void generateParameterBindings(
ParameterBindingInfo globalConstantBufferBinding;
if( anyGlobalUniforms )
{
+ // TODO: this logic is only correct for D3D targets, where
+ // global-scope uniforms get wrapped into a constant buffer.
+
+ UInt space = 0;
+ auto usedRangeSet = findUsedRangeSetForSpace(&context, space);
+
globalConstantBufferBinding.index =
- context.shared->usedResourceRanges[
- (int)LayoutResourceKind::ConstantBuffer].Allocate(1);
+ usedRangeSet->usedResourceRanges[
+ (int)LayoutResourceKind::ConstantBuffer].Allocate(nullptr, 1);
// For now we only auto-generate bindings in space zero
- globalConstantBufferBinding.space = 0;
+ globalConstantBufferBinding.space = space;
}