Skip to content

Commit 0ec8e5b

Browse files
Tim Foleycsyonghe
Tim Foley
andauthored
Refactor D3D12 renderer root signature creation (shader-slang#1779)
This change originated as an attempt to re-enable a test case, but it has ended up disabling more tests (for good reasons) than it re-enables. The main change here is a significant overhaul of the way that the D3D12 render path extracts information from the Slang reflection API to produce a root signature. There were also some supporting fixes in the reflection information to make sure it returns what the D3D12 back-end needed. The big picture here is that the D3D12 path now uses the descriptor ranges stored in the reflection data more or less directly. It still needs to use register/space offset information queried via the "old" reflection API, but it only does so at the top level now, for the program and entry points themselves. All other layout information is derived directly from what Slang provides. Smaller changes: * The "flat" reflection API was expanded to include `getBindingRangeDescriptorRangeCount()` which was clearly missing. * The "flat" reflection results for a constant buffer or parameter block that didn't contain any uniform data and was mapped to a plain constant buffer needed to be fixed up. That logic is still way to subtle to be trusted. * Several additional tests were disabled that relied on static specialization, global/entry-point generi type parameters, structured buffers of interfaces or other features we don't officially support with shader objects right now. All of the affected tests were somehow passing by sheer luck and because they often passed in specialization arguments via explicit `TEST_INPUT` lines. * The `inteface-shader-param` test is re-enabled now that we can properly describe its input with the new `set` mode on `TEST_INPUT` * `ShaderCursor::getElement()` can now be used on structure types (in addition to arrays) to support by-index access to fields * The `TEST_INPUT` system was expanded to support both by-name and by-index setting of structure fields for aggregates * The `TEST_INPUT` system was expanded to allow an `out` prefix to mark parts of an expression as outputs on a `set` lines * The `TEST_INPUT` system was expanded so that anything that would be allowed on a `TEST_INPUT` line by itself (like `ubuffer(...)`) can now be used as a sub-expression on a `set` line Co-authored-by: Yong He <yonghe@outlook.com>
1 parent 9475b11 commit 0ec8e5b

20 files changed

+471
-268
lines changed

slang.h

+7
Original file line numberDiff line numberDiff line change
@@ -1993,6 +1993,7 @@ extern "C"
19931993

19941994
SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeDescriptorSetIndex(SlangReflectionTypeLayout* typeLayout, SlangInt index);
19951995
SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeFirstDescriptorRangeIndex(SlangReflectionTypeLayout* typeLayout, SlangInt index);
1996+
SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeDescriptorRangeCount(SlangReflectionTypeLayout* typeLayout, SlangInt index);
19961997

19971998
SLANG_API SlangInt spReflectionTypeLayout_getDescriptorSetCount(SlangReflectionTypeLayout* typeLayout);
19981999
SLANG_API SlangInt spReflectionTypeLayout_getDescriptorSetSpaceOffset(SlangReflectionTypeLayout* typeLayout, SlangInt setIndex);
@@ -2608,6 +2609,12 @@ namespace slang
26082609
index);
26092610
}
26102611

2612+
SlangInt getBindingRangeDescriptorRangeCount(SlangInt index)
2613+
{
2614+
return spReflectionTypeLayout_getBindingRangeDescriptorRangeCount(
2615+
(SlangReflectionTypeLayout*) this,
2616+
index);
2617+
}
26112618

26122619
SlangInt getDescriptorSetCount()
26132620
{

source/slang/slang-reflection-api.cpp

+33-5
Original file line numberDiff line numberDiff line change
@@ -1326,38 +1326,53 @@ namespace Slang
13261326
Index bindingRangeIndex = m_extendedInfo->m_bindingRanges.getCount();
13271327
SlangBindingType bindingType = SLANG_BINDING_TYPE_CONSTANT_BUFFER;
13281328
Index spaceOffset = -1;
1329+
bool usesIndirectAllocation = false;
13291330
LayoutResourceKind kind = LayoutResourceKind::None;
13301331

13311332
// TODO: It is unclear if this should be looking at the resource
13321333
// usage of the parameter group, or of its "container" layout.
13331334
//
13341335
for(auto& resInfo : parameterGroupTypeLayout->resourceInfos)
13351336
{
1337+
if( spaceOffset == -1 )
1338+
{
1339+
spaceOffset = _calcSpaceOffset(path, kind);
1340+
}
1341+
13361342
kind = resInfo.kind;
13371343
switch(kind)
13381344
{
13391345
default:
13401346
continue;
13411347

1348+
case LayoutResourceKind::ConstantBuffer:
1349+
case LayoutResourceKind::PushConstantBuffer:
1350+
case LayoutResourceKind::DescriptorTableSlot:
1351+
break;
1352+
1353+
// Certain cases indicate a parameter block that
1354+
// actually involves indirection.
1355+
//
13421356
// Note: the only case where a parameter group should
13431357
// reflect as consuming `Uniform` storage is on CPU/CUDA,
13441358
// where that will be the only resource it contains.
13451359
//
13461360
// TODO: If we ever support targets that don't have
13471361
// constant buffers at all, this logic would be questionable.
13481362
//
1349-
case LayoutResourceKind::ConstantBuffer:
1350-
case LayoutResourceKind::PushConstantBuffer:
13511363
case LayoutResourceKind::RegisterSpace:
1352-
case LayoutResourceKind::DescriptorTableSlot:
13531364
case LayoutResourceKind::Uniform:
1365+
usesIndirectAllocation = true;
13541366
break;
13551367
}
13561368

13571369
bindingType = _calcBindingType(typeLayout, kind);
1358-
spaceOffset = _calcSpaceOffset(path, kind);
13591370
break;
13601371
}
1372+
if(spaceOffset == -1)
1373+
{
1374+
spaceOffset = 0;
1375+
}
13611376

13621377
TypeLayout::ExtendedInfo::BindingRangeInfo bindingRange;
13631378
bindingRange.leafTypeLayout = typeLayout;
@@ -1419,7 +1434,7 @@ namespace Slang
14191434
// because the physical storage for `C.a` is provided by the
14201435
// memory allocation for `C` itself.
14211436

1422-
if( spaceOffset != -1 )
1437+
if( !usesIndirectAllocation )
14231438
{
14241439
// The logic here assumes that when a parameter group consumes
14251440
// resources that must "leak" into the outer scope (including
@@ -1848,6 +1863,19 @@ SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeFirstDescriptorRangeInd
18481863
return bindingRange.firstDescriptorRangeIndex;
18491864
}
18501865

1866+
SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeDescriptorRangeCount(SlangReflectionTypeLayout* inTypeLayout, SlangInt index)
1867+
{
1868+
auto typeLayout = convert(inTypeLayout);
1869+
if(!typeLayout) return 0;
1870+
1871+
auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout);
1872+
if(index < 0) return 0;
1873+
if(index >= extTypeLayout->m_bindingRanges.getCount()) return 0;
1874+
auto& bindingRange = extTypeLayout->m_bindingRanges[index];
1875+
1876+
return bindingRange.descriptorRangeCount;
1877+
}
1878+
18511879
SLANG_API SlangInt spReflectionTypeLayout_getDescriptorSetCount(SlangReflectionTypeLayout* inTypeLayout)
18521880
{
18531881
auto typeLayout = convert(inTypeLayout);

source/slang/slang.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -2832,7 +2832,9 @@ SLANG_NO_THROW SlangResult SLANG_MCALL ComponentType::specialize(
28322832
auto specializationParamCount = getSpecializationParamCount();
28332833
if( specializationArgCount != specializationParamCount )
28342834
{
2835-
// TODO: diagnose
2835+
sink.diagnose(SourceLoc(), Diagnostics::mismatchSpecializationArguments,
2836+
specializationParamCount,
2837+
specializationArgCount);
28362838
sink.getBlobIfNeeded(outDiagnostics);
28372839
return SLANG_FAIL;
28382840
}

tests/bugs/gh-357.slang

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//TEST(compute):COMPARE_COMPUTE: -shaderobj
1+
//DISABLED_TEST(compute):COMPARE_COMPUTE: -shaderobj
22

33
//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name outputBuffer
44

tests/compute/assoctype-generic-arg.slang

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
//TEST(compute):COMPARE_COMPUTE:-cpu -shaderobj
2-
//TEST(compute):COMPARE_COMPUTE: -shaderobj
1+
//DISABLED_TEST(compute):COMPARE_COMPUTE:-cpu -shaderobj
2+
//DISABLED_TEST(compute):COMPARE_COMPUTE: -shaderobj
33

44
//TEST_INPUT:type AssocImpl
55

tests/compute/global-generic-value-param.slang

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// global-generic-value-param.slang
22

3-
//TEST(compute):COMPARE_COMPUTE: -shaderobj
3+
//DISABLED_TEST(compute):COMPARE_COMPUTE: -shaderobj
44

55
// This is a basic test of support for global generic
66
// value parameters: explicit named parameters at global

tests/compute/global-type-param-in-entrypoint.slang

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//TEST(compute):COMPARE_RENDER_COMPUTE: -shaderobj
1+
//DISABLED_TEST(compute):COMPARE_RENDER_COMPUTE: -shaderobj
22

33
//TEST_INPUT: cbuffer(data=[1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0]):name Uniforms
44
//TEST_INPUT: ubuffer(data=[0 0 0 0], stride=4):out,name outputBuffer

tests/compute/global-type-param.slang

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//TEST(smoke,compute):COMPARE_COMPUTE: -shaderobj
1+
//DISABLED_TEST(smoke,compute):COMPARE_COMPUTE: -shaderobj
22

33
//TEST_INPUT:type Wrapper<Impl>
44

tests/compute/int-generic.slang

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//TEST(compute):COMPARE_COMPUTE: -shaderobj
1+
//DISABLED_TEST(compute):COMPARE_COMPUTE: -shaderobj
22

33
//TEST_INPUT:type Material<1,2>
44

tests/compute/interface-assoc-type-param.slang

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Tests using associated types through an existential-struct-typed param.
22

3-
//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -cuda -shaderobj
4-
//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -cpu -shaderobj
3+
//DISABLED_TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -cuda -shaderobj
4+
//DISABLED_TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -cpu -shaderobj
55

66
[anyValueSize(8)]
77
interface IInterface

tests/compute/interface-func-param-in-struct.slang

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Tests specializing a function with existential-struct-typed param.
22

3-
//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -cuda -shaderobj
4-
//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -cpu -shaderobj
3+
//DISABLED_TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -cuda -shaderobj
4+
//DISABLED_TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -cpu -shaderobj
55

66
[anyValueSize(8)]
77
interface IInterface
@@ -31,8 +31,6 @@ void compute(uint tid, Params p)
3131
gOutputBuffer[tid] = p.obj[0].eval();
3232
}
3333

34-
//TEST_INPUT: entryPointExistentialType Impl
35-
3634
[numthreads(4, 1, 1)]
3735
void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID,
3836
//TEST_INPUT:ubuffer(data=[0 0 0 0 1 0], stride=4):name=params.obj

tests/compute/interface-shader-param-in-struct.slang

+5-21
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
// inside of structure types to make sure that works
55

66
//DISABLED_TEST(compute):COMPARE_COMPUTE_EX:-slang -compute
7-
87
//DISABLED_TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -dx12 -profile sm_6_0 -use-dxil
98
//DISABLED_TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute
109

@@ -42,7 +41,7 @@ int test(
4241
}
4342

4443

45-
//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out
44+
//TEST_INPUT:set gOutputBuffer = out ubuffer(data=[0 0 0 0], stride=4)
4645
RWStructuredBuffer<int> gOutputBuffer;
4746

4847
// Note: even though `C` doesn't include any
@@ -52,7 +51,8 @@ RWStructuredBuffer<int> gOutputBuffer;
5251
// that it *will* contain uniform/ordinary data
5352
// after specialization.
5453
//
55-
//TEST_INPUT:cbuffer(data=[0 0 0 0 0 0 0 0]):
54+
//TEST_INPUT:set C = new{ new MyStrategy{ ubuffer(data=[1 2 4 8], stride=4) } }
55+
//TEST_INPUT: globalExistentialType MyStrategy
5656
cbuffer C
5757
{
5858
IRandomNumberGenerationStrategy gStrategy;
@@ -64,23 +64,10 @@ struct Stuff
6464
int extra;
6565
}
6666

67-
// Note: the data for global-scope existential parameters
68-
// is being introduced *before* the entry point declaration,
69-
// because the default policy used by `slangc` (which the
70-
// render test also uses) is to specialize the parameters at
71-
// the global scope (producing a new layout) and then compose
72-
// that specialized global scope with the entry point.
73-
//
74-
// (The net result is that data related to global-scope
75-
// specialization always precedes the data for entry point
76-
// parameters in these tests today)
77-
//
78-
//TEST_INPUT: globalExistentialType MyStrategy
79-
//TEST_INPUT:ubuffer(data=[1 2 4 8], stride=4):
80-
8167
[numthreads(4, 1, 1)]
8268
void computeMain(
83-
//TEST_INPUT:root_constants(data=[0 0 0 0 0 0 0 0 256]):
69+
//TEST_INPUT:set stuff = { new MyModifier{ ubuffer(data=[16 32 64 128], stride=4) }, 256 }
70+
//TEST_INPUT: entryPointExistentialType MyModifier
8471
uniform Stuff stuff,
8572

8673
uint3 dispatchThreadID : SV_DispatchThreadID)
@@ -129,6 +116,3 @@ struct MyModifier : IModifier
129116
return val ^ localModifiers[val & 3];
130117
}
131118
}
132-
133-
//TEST_INPUT: entryPointExistentialType MyModifier
134-
//TEST_INPUT:ubuffer(data=[16 32 64 128], stride=4):

tests/compute/interface-shader-param.slang

+7-26
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
// Test using interface tops as top-level shader parameters
44
// (whether global, or on an entry point).
55

6-
//DISABLED_TEST(compute):COMPARE_COMPUTE_EX:-slang -compute
6+
//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute
77

8-
//DISABLED_TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -dx12 -profile sm_6_0 -use-dxil
9-
//DISABLED_TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute
10-
//DISABLE_TEST(compute):COMPARE_COMPUTE_EX:-cpu -compute
8+
//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -dx12 -profile sm_6_0 -use-dxil
9+
//TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute
10+
//TEST(compute):COMPARE_COMPUTE_EX:-cpu -compute
1111

1212
// First we will define some fake interfaces for testing.
1313
// Let's pretend we are doing some kind of random number
@@ -70,43 +70,27 @@ int test(
7070
return modifiedVal;
7171
}
7272

73-
// The global-scope parameters for this example include
74-
// some `uniform` parameters, and that will trigger
75-
// the allocation of a global-scope constant buffer to
76-
// hold them. Slang's layout rules mean that the buffer
77-
// will be allocated before any other global-scope parameters.
78-
//
79-
// In this example, the buffer will not be needed after specialization,
80-
// but we need to declare/allocate it here so that the application
81-
// creates a descriptor table/set that matches what the shader
82-
// signature expects.
83-
//
84-
//TEST_INPUT:cbuffer(data=[0], stride=4):name=gStrategy
85-
86-
87-
8873
// Now we'll define a shader entry point that will use
8974
// these interfaces to define its behavior.
9075
//
9176
// We'll start with the buffer for writing the test output.
9277

93-
//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=gOutputBuffer
78+
//TEST_INPUT:set gOutputBuffer = out ubuffer(data=[0 0 0 0], stride=4)
9479
RWStructuredBuffer<int> gOutputBuffer;
9580

9681
// Now we'll define a global shader parameter for the
9782
// random number generation strategy.
9883
//
99-
//__disabled__TEST_INPUT:object(type=MyStrategy):name=gStrategy
84+
//TEST_INPUT:set gStrategy = new MyStrategy{}
10085
uniform IRandomNumberGenerationStrategy gStrategy;
10186

10287
// The other parameter (for the modifier) will be attached
10388
// the entry point instead, so that we are testing both
10489
// cases.
10590
//
106-
//__disabled__TEST_INPUT:object(type=MyModifier):name=modifier
10791
[numthreads(4, 1, 1)]
10892
void computeMain(
109-
//TEST_INPUT:root_constants(data=[0], stride=4):
93+
//TEST_INPUT:set modifier = new MyModifier{}
11094
uniform IModifier modifier,
11195
uint3 dispatchThreadID : SV_DispatchThreadID)
11296
{
@@ -150,6 +134,3 @@ struct MyModifier : IModifier
150134
return val * 16;
151135
}
152136
}
153-
154-
//TEST_INPUT: globalExistentialType MyStrategy
155-
//TEST_INPUT: entryPointExistentialType MyModifier

tests/compute/parameter-block.slang

+3-4
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,6 @@
33
//TEST(compute):COMPARE_COMPUTE:-vk -shaderobj
44
//TEST(compute):COMPARE_COMPUTE:-shaderobj
55

6-
7-
//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=block0.buffer
8-
//TEST_INPUT:ubuffer(data=[0 1 2 3], stride=4):name=block1.buffer
9-
106
// Ensure that Slang `ParameterBlock` type is lowered
117
// to HLSL in the fashion that we expect.
128

@@ -15,7 +11,10 @@ struct P
1511
RWStructuredBuffer<int> buffer;
1612
};
1713

14+
//TEST_INPUT: set block0 = new{ out ubuffer(data=[0 0 0 0], stride=4) }
1815
ParameterBlock<P> block0;
16+
17+
//TEST_INPUT: set block1 = new{ ubuffer(data=[0 1 2 3], stride=4) }
1918
ParameterBlock<P> block1;
2019

2120
[numthreads(4, 1, 1)]

tests/disabled-tests.txt

+39-2
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,53 @@ Test that don't work with shader objects in render-test
99
The following tests were disabled because they had been running on non `-shaderobj` code paths that have since been removed.
1010
These tests will need to be re-enabled together with changes to the shader object implementation, or removed entirely if they no longer test useful functionality.
1111

12+
### `ConstantBuffer<ISomething>`
13+
14+
These tests rely on details of how a `ConstantBuffer<ISomething>` or `ParameterBlock<ISomething>` gets laid out.
15+
We need to fix the compiler and shader object implementation to agree that a `ConstantBuffer<ISomething>`
16+
should compile as `exists T : ISomething . ConstantBuffer<T>` and *not* `ConstantBuffer<exists T : ISomething . T>`
17+
like it currently does.
18+
(The reason for this choice is that we want a shader object created from `SomeConcreteType`, where `SomeConcreteType : ISomething`, to be directly usable for a `ConstantBuffer<ISomething>` parameter with its existing buffer allocation.)
19+
1220
* compute/dynamic-dispatch-12.slang
21+
22+
### `StructuredBuffer<ISomething>`
23+
24+
These tests require support for structured buffers where the element type either is an interface type or transitively contains one.
25+
1326
* compute/dynamic-dispatch-13.slang
1427
* compute/dynamic-dispatch-14.slang
1528
* compute/dynamic-dispatch-bindless-texture.slang
16-
* compute/global-type-param2.slang
29+
* compute/interface-func-param-in-struct.slang
30+
* compute/interface-assoc-type-param.slang
31+
32+
### Generic Specialization Parameters
33+
34+
These tests make use of generic specialization parameters in ways that don't easily align with the implementation approach that is more focused on existential parameters.
35+
They should either be ported to use existentials directly (at which point we potentially get rid of support for generic specialization at global or entry-point scope?) or we should refine the implementation of generic specialization to be consistent with existential specialization.
36+
1737
* compute/global-type-param-array.slang
1838
* compute/global-type-param1.slang
39+
* compute/global-type-param2.slang
40+
* bugs/gh-357.slang
41+
* compute/assoctype-generic-arg.slang
42+
* compute/global-generic-value-param.slang
43+
* compute/global-type-param-in-entrypoint.slang
44+
* compute/global-type-param.slang
45+
* compute/int-generic.slang
46+
47+
### Static Specialization
48+
49+
These tests rely on the ability of the static specialization path to provide locations for data that doesn't "fit" into the fixed-size payload of an existential-type field/value.
50+
They will need to wait until the shader object implementation(s) are updated to support that case.
51+
1952
* compute/interface-shader-param-in-struct.slang
2053
* compute/interface-shader-param-legalization.slang
54+
55+
### Uncategorized
56+
57+
These tests need to be binned according to what features they need.
58+
2159
* compute/interface-shader-param.slang
2260
* compute/performance-profile.slang
2361
* compute/rewriter-parameter-block-complex.hlsl
@@ -40,4 +78,3 @@ These tests will need to be re-enabled together with changes to the shader objec
4078
* render/tess.hlsl
4179
* render/unused-discard.hlsl
4280
* compute/interface-param-partial-specialize.slang
43-
* compute/array-existential-parameter.slang

0 commit comments

Comments
 (0)