Skip to content

Commit 3ae31a6

Browse files
author
Tim Foley
authored
Improve logic for when a "default space" is needed (shader-slang#925)
If the user declares global shader parameters for D3D SM5.1+ or Vulkan, then they need to go into an appropriate `space` or `set`: ```hlsl Texture2D t; // should go in space/set 0 SamplerState s; // same here... ``` This also applies to allocation of spaces/sets to parameter blocks: ```hlsl ParameterBlock<X> x; // should get space/set 0 ParameterBlock<Y> y; // should get space/set 1 ``` In cases where there are a combination of explicitly and implicitly bound parameters, anything left implicitly bound goes into a "default" space/set: ``` ParameterBlock<X> x : register(space0); // this has claimed space/set 0 Texture2D t; // this needs a space, so a "default" space/set of 1 will be claimed SamplerState s; // this also needs a space/set, and will use the default ``` The logic for deciding when a default space/set was needing was, more or less, looking at all the global shader parameters and seeing if any of them needed a `register`/`binding`, and if so determining that a default space /set would be needed. There was a bug in that logic, though, because of cases like the following: ```hlsl ParameterBlock<X> x; Texture2D t : register(t0, space99); ``` In this case, the parameter `t` already has an explicit binding, so it doesn't actually need a default space to be allocated. If we allocate a default space/set of 0 on the basis of `t`, then `x` will end up being shifted to space/set 1. The fix is to only consider global parameters that need `register`s/`binding`s *if* they don't have an explicit binding already (which is luckily something we are tracking during parameter binding). Note: just to clarify the behavior here, the "do we need a default space/set?" logic is done *before* automatic binding of parameters, so in a shader with any global texture/buffer/sampler parameters, those will all end up in space/set zero (in the absence of explicit bindings), and explicit blocks will start at space/set one, independent of the order of declaration. This behavior is maybe too subtle, and we might decide we need to change it, but it will have to do for now.
1 parent 2f4029a commit 3ae31a6

File tree

3 files changed

+94
-7
lines changed

3 files changed

+94
-7
lines changed

source/slang/parameter-binding.cpp

+27-7
Original file line numberDiff line numberDiff line change
@@ -2298,23 +2298,43 @@ RefPtr<ProgramLayout> generateParameterBindings(
22982298
// As a starting point, we will definitely need a "default" space if
22992299
// we are creating a default constant buffer, since it should get
23002300
// a binding in that "default" space.
2301+
//
23012302
bool needDefaultSpace = needDefaultConstantBuffer;
23022303
if (!needDefaultSpace)
23032304
{
2305+
// Next we will look at the global-scope parameters and see if
2306+
// any of them requires a `register` or `binding` that will
2307+
// thus need to land in a default space.
2308+
//
23042309
for (auto& parameterInfo : sharedContext.parameters)
23052310
{
23062311
SLANG_RELEASE_ASSERT(parameterInfo->varLayouts.Count() != 0);
23072312
auto firstVarLayout = parameterInfo->varLayouts.First();
23082313

2309-
// Does the parameter have any resource usage that isn't just
2310-
// allocating a whole register space?
2314+
// For each parameter, we will look at each resource it consumes.
2315+
//
23112316
for (auto resInfo : firstVarLayout->typeLayout->resourceInfos)
23122317
{
2313-
if (resInfo.kind != LayoutResourceKind::RegisterSpace)
2314-
{
2315-
needDefaultSpace = true;
2316-
break;
2317-
}
2318+
// We don't care about whole register spaces/sets, since
2319+
// we don't need to allocate a default space/set for a parameter
2320+
// that itself consumes a whole space/set.
2321+
//
2322+
if( resInfo.kind == LayoutResourceKind::RegisterSpace )
2323+
continue;
2324+
2325+
// We also don't want to consider resource kinds for which
2326+
// the variable already has an (explicit) binding, since
2327+
// the space from the explicit binding will be used, so
2328+
// that a default space isn't needed.
2329+
//
2330+
if( parameterInfo->bindingInfo[resInfo.kind].count != 0 )
2331+
continue;
2332+
2333+
// Otherwise, we have a shader parameter that will need
2334+
// a default space or set to live in.
2335+
//
2336+
needDefaultSpace = true;
2337+
break;
23182338
}
23192339
}
23202340
}

tests/reflection/default-space.slang

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//TEST:REFLECTION:-profile sm_5_1 -stage fragment -target hlsl
2+
3+
// This test is to confirm that we do not allocate a "default"
4+
// space/set for global shader parameters unless it is
5+
// really required. In particular, if there are global-scope
6+
// resource parameters *but* they are all explicitly bound,
7+
// then a default space isn't needed.
8+
9+
10+
// An explicitly-bound global texture.
11+
Texture2D a : register(t0, space99);
12+
13+
// An implicitly-bound global parameter block.
14+
//
15+
// This parameter should be given `space0`, because
16+
// it is the first available space after all explicitly-bound
17+
// parameters have claimed their registers/spaces.
18+
//
19+
struct B { Texture2D b; }
20+
ParameterBlock<B> b;
21+
22+
float4 main() : SV_Target
23+
{ return 0.0; }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
result code = 0
2+
standard error = {
3+
}
4+
standard output = {
5+
{
6+
"parameters": [
7+
{
8+
"name": "a",
9+
"binding": {"kind": "shaderResource", "space": 99, "index": 0},
10+
"type": {
11+
"kind": "resource",
12+
"baseShape": "texture2D"
13+
}
14+
},
15+
{
16+
"name": "b",
17+
"binding": {"kind": "registerSpace", "index": 0},
18+
"type": {
19+
"kind": "parameterBlock",
20+
"elementType": {
21+
"kind": "struct",
22+
"name": "B",
23+
"fields": [
24+
{
25+
"name": "b",
26+
"type": {
27+
"kind": "resource",
28+
"baseShape": "texture2D"
29+
},
30+
"binding": {"kind": "shaderResource", "index": 0}
31+
}
32+
]
33+
}
34+
}
35+
}
36+
],
37+
"entryPoints": [
38+
{
39+
"name": "main",
40+
"stage:": "fragment"
41+
}
42+
]
43+
}
44+
}

0 commit comments

Comments
 (0)