From 7f8d62c566e84a9c043d6a9b3e9424a4d41b00d9 Mon Sep 17 00:00:00 2001 From: Finn Plummer Date: Thu, 13 Mar 2025 15:12:53 -0700 Subject: [PATCH 1/3] [RootSignature] Add frontend RootSignature testing this commit adds testing demonstrating the various behaviours of specifying a root signature through a function attribute in HLSL for any non-sampler descriptor type - Defaults.test: all default parameter values - Flags.test: various root/descriptor flags for M3 - NumberParameters.test: integer parameter edge-cases - ManualDescriptors.test: shows manual user specified `offset` and `numDescriptors` parameters and the edge-cases - ParameterInsensitivity.test: shows that parameters have no specified order, as well as, the case-insensitivity of keywords and enums --- test/M3/RootSignatures/Defaults.test | 93 +++++++++++++++ test/M3/RootSignatures/Flags.test | 107 ++++++++++++++++++ test/M3/RootSignatures/ManualDescriptors.test | 100 ++++++++++++++++ test/M3/RootSignatures/NumberParameters.test | 99 ++++++++++++++++ .../ParameterInsensitivity.test | 85 ++++++++++++++ 5 files changed, 484 insertions(+) create mode 100644 test/M3/RootSignatures/Defaults.test create mode 100644 test/M3/RootSignatures/Flags.test create mode 100644 test/M3/RootSignatures/ManualDescriptors.test create mode 100644 test/M3/RootSignatures/NumberParameters.test create mode 100644 test/M3/RootSignatures/ParameterInsensitivity.test diff --git a/test/M3/RootSignatures/Defaults.test b/test/M3/RootSignatures/Defaults.test new file mode 100644 index 00000000..3759aea9 --- /dev/null +++ b/test/M3/RootSignatures/Defaults.test @@ -0,0 +1,93 @@ +#--- source.hlsl + +cbuffer RootConstants : register(b0) { + float4 C; +}; + +struct Input { + float4 A; + float4 B; +}; + +struct Output { + float4 A; +}; + +StructuredBuffer In : register(t0); +RWStructuredBuffer Out1 : register(u1); +RWStructuredBuffer Out2 : register(u2); + +// Root signature to sanity test default values optional values + +#define RootSig \ + "RootConstants(num32BitConstants = 4, b0), " \ + "DescriptorTable( " \ + " SRV(t0), " \ + " UAV(u1) " \ + "), " \ + "UAV(u2) " + +[RootSignature(RootSig)] +[numthreads(1,1,1)] +void main(uint GI : SV_GroupIndex) { + Out1[GI].A = In[GI].A * In[GI].B * C; + Out2[GI].A = In[GI].A * In[GI].B * C * 2; +} + +//--- pipeline.yaml +--- +Shaders: + - Stage: Compute + Entry: main + DispatchSize: [1, 1, 1] +RuntimeSettings: + DirectX: + RootParameters: + - Kind: Constant + Name: Root + - Kind: DescriptorTable + - Kind: RootDescriptor + Resource: + Name: Out2 + Kind: RWStructuredBuffer +Buffers: + - Name: Root + Format: Float32 + Data: [ 2, 4, 6, 8 ] + - Name: In + Format: Float32 + Stride: 32 + Data: [ 2, 4, 6, 8, 10, 12, 14, 16] + - Name: Out1 + Format: Float32 + Channels: 4 + ZeroInitSize: 16 + - Name: Out2 + Format: Float32 + Channels: 4 + ZeroInitSize: 16 +DescriptorSets: + - Resources: + - Name: In + Kind: StructuredBuffer + DirectXBinding: + Register: 0 + Space: 0 + - Name: Out1 + Kind: RWStructuredBuffer + DirectXBinding: + Register: 1 + Space: 0 +... +#--- end + +# UNSUPPORTED: Clang + +# RUN: split-file %s %t +# RUN: %dxc_target -T cs_6_0 -Fo %t.o %t/source.hlsl +# RUN: %offloader %t/pipeline.yaml %t.o | FileCheck %s + +# CHECK-LABEL: Name: Out1 +# CHECK: Data: [ 40, 192, 504, 1024 ] +# CHECK-LABEL: Name: Out2 +# CHECK: Data: [ 80, 384, 1008, 2048 ] diff --git a/test/M3/RootSignatures/Flags.test b/test/M3/RootSignatures/Flags.test new file mode 100644 index 00000000..75ebedd4 --- /dev/null +++ b/test/M3/RootSignatures/Flags.test @@ -0,0 +1,107 @@ +#--- source.hlsl + +struct Input { + float4 A; + float4 B; +}; + +struct Output { + float4 A; +}; + +StructuredBuffer In : register(t0); +StructuredBuffer InExtra : register(t1); +RWStructuredBuffer Out1 : register(u1); +RWStructuredBuffer Out2 : register(u2); + +// Root signature to test specifying various flags: +// - Edge-case value of '0' +// - Demonstrate setting of non-sampler root flags +// - Demonstrate setting of all descriptor flags +// - Demonstrate '|' of applicable flags + +#define RootSig \ + "RootFlags( " \ + " ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | " \ + " CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED | " \ + " ALLOW_STREAM_OUTPUT " \ + "), " \ + "DescriptorTable( " \ + " SRV(t0, flags = 0), " \ + " SRV(t1, flags = DATA_STATIC_WHILE_SET_AT_EXECUTE), " \ + " UAV(u1, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE), " \ + " UAV(u2, " \ + " flags = DESCRIPTORS_STATIC_KEEPING_BUFFER_BOUNDS_CHECKS " \ + " | DATA_STATIC " \ + " ) " \ + ")" + +[RootSignature(RootSig)] +[numthreads(1,1,1)] +void main(uint GI : SV_GroupIndex) { + Out1[GI].A = In[GI].A * InExtra[GI].B; + Out2[GI].A = In[GI].A * InExtra[GI].B * 2; +} + +//--- pipeline.yaml +--- +Shaders: + - Stage: Compute + Entry: main + DispatchSize: [1, 1, 1] +RuntimeSettings: + DirectX: + RootParameters: + - Kind: DescriptorTable +Buffers: + - Name: In + Format: Float32 + Stride: 32 + Data: [ 2, 4, 6, 8, 10, 12, 14, 16] + - Name: InExtra + Format: Float32 + Stride: 32 + Data: [ 2, 4, 6, 8, 10, 12, 14, 16] + - Name: Out1 + Format: Float32 + Channels: 4 + ZeroInitSize: 16 + - Name: Out2 + Format: Float32 + Channels: 4 + ZeroInitSize: 16 +DescriptorSets: + - Resources: + - Name: In + Kind: StructuredBuffer + DirectXBinding: + Register: 0 + Space: 0 + - Name: InExtra + Kind: StructuredBuffer + DirectXBinding: + Register: 1 + Space: 0 + - Name: Out1 + Kind: RWStructuredBuffer + DirectXBinding: + Register: 1 + Space: 0 + - Name: Out2 + Kind: RWStructuredBuffer + DirectXBinding: + Register: 2 + Space: 0 +... +#--- end + +# UNSUPPORTED: Clang + +# RUN: split-file %s %t +# RUN: %dxc_target -T cs_6_0 -Fo %t.o %t/source.hlsl +# RUN: %offloader %t/pipeline.yaml %t.o | FileCheck %s + +# CHECK-LABEL: Name: Out1 +# CHECK: Data: [ 20, 48, 84, 128 ] +# CHECK-LABEL: Name: Out2 +# CHECK: Data: [ 40, 96, 168, 256 ] diff --git a/test/M3/RootSignatures/ManualDescriptors.test b/test/M3/RootSignatures/ManualDescriptors.test new file mode 100644 index 00000000..1470858a --- /dev/null +++ b/test/M3/RootSignatures/ManualDescriptors.test @@ -0,0 +1,100 @@ +#--- source.hlsl + +struct Input { + float4 A; + float4 B; +}; + +struct Output { + float4 A; +}; + +StructuredBuffer In : register(t0); +StructuredBuffer InExtra : register(t1); +RWStructuredBuffer Out1 : register(u1); +RWStructuredBuffer Out2 : register(u2); + +// Root signature to test manual `offset` and `numDescriptor` specification: +// - Demonstrate manually describing the offsets and numDescriptors +// - Edge-case value of `offset` = `DESCRIPTOR_RANGE_OFFSET_APPEND` +// - Edge-case value of `numDescriptors` = `unbounded` + +#define RootSig \ + "DescriptorTable( " \ + " UAV(u2, offset = 3, numDescriptors = unbounded), " \ + " SRV(t0, offset = 0, numDescriptors = 2), " \ + " UAV(u1, " \ + " offset = DESCRIPTOR_RANGE_OFFSET_APPEND, " \ + " numDescriptors = 1 " \ + " ) " \ + ")" + +[RootSignature(RootSig)] +[numthreads(1,1,1)] +void main(uint GI : SV_GroupIndex) { + Out1[GI].A = In[GI].A * InExtra[GI].B; + Out2[GI].A = In[GI].A * InExtra[GI].B * 2; +} + +//--- pipeline.yaml +--- +Shaders: + - Stage: Compute + Entry: main + DispatchSize: [1, 1, 1] +RuntimeSettings: + DirectX: + RootParameters: + - Kind: DescriptorTable +Buffers: + - Name: In + Format: Float32 + Stride: 32 + Data: [ 2, 4, 6, 8, 10, 12, 14, 16] + - Name: InExtra + Format: Float32 + Stride: 32 + Data: [ 2, 4, 6, 8, 10, 12, 14, 16] + - Name: Out1 + Format: Float32 + Channels: 4 + ZeroInitSize: 16 + - Name: Out2 + Format: Float32 + Channels: 4 + ZeroInitSize: 16 +DescriptorSets: + - Resources: + - Name: In + Kind: StructuredBuffer + DirectXBinding: + Register: 0 + Space: 0 + - Name: InExtra + Kind: StructuredBuffer + DirectXBinding: + Register: 1 + Space: 0 + - Name: Out1 + Kind: RWStructuredBuffer + DirectXBinding: + Register: 1 + Space: 0 + - Name: Out2 + Kind: RWStructuredBuffer + DirectXBinding: + Register: 2 + Space: 0 +... +#--- end + +# UNSUPPORTED: Clang + +# RUN: split-file %s %t +# RUN: %dxc_target -T cs_6_0 -Fo %t.o %t/source.hlsl +# RUN: %offloader %t/pipeline.yaml %t.o | FileCheck %s + +# CHECK-LABEL: Name: Out1 +# CHECK: Data: [ 20, 48, 84, 128 ] +# CHECK-LABEL: Name: Out2 +# CHECK: Data: [ 40, 96, 168, 256 ] diff --git a/test/M3/RootSignatures/NumberParameters.test b/test/M3/RootSignatures/NumberParameters.test new file mode 100644 index 00000000..9c589eaf --- /dev/null +++ b/test/M3/RootSignatures/NumberParameters.test @@ -0,0 +1,99 @@ +#--- source.hlsl + +cbuffer RootConstants : register(b0) { + float4 C; +}; + +struct Input { + float4 A; + float4 B; +}; + +struct Output { + float4 A; +}; + +StructuredBuffer In : register(t4294967294); +RWStructuredBuffer Out1 : register(u1, space4294967279); +RWStructuredBuffer Out2 : register(u2); + +// Root signature to test edge-cases of specify number arguments: +// - Maximum valid register value (0xfffffffe = 4294967294) +// - Maximum valid register space value (0x7fffffff = 4294967279) +// - Maximum valid num32BitConstants value +// (61 = 64 - # of used DWORDS for other params) +// - Using (un)signed integer parameter values + + +#define RootSig \ + "RootConstants(num32BitConstants = +61, b0), " \ + "DescriptorTable( " \ + " SRV(t4294967294), " \ + " UAV(u1, space = 4294967279) " \ + "), " \ + "UAV(u2) " + +[RootSignature(RootSig)] +[numthreads(1,1,1)] +void main(uint GI : SV_GroupIndex) { + Out1[GI].A = In[GI].A * In[GI].B * C; + Out2[GI].A = In[GI].A * In[GI].B * C * 2; +} + +//--- pipeline.yaml +--- +Shaders: + - Stage: Compute + Entry: main + DispatchSize: [1, 1, 1] +RuntimeSettings: + DirectX: + RootParameters: + - Kind: Constant + Name: Root + - Kind: DescriptorTable + - Kind: RootDescriptor + Resource: + Name: Out2 + Kind: RWStructuredBuffer +Buffers: + - Name: Root + Format: Float32 + Data: [ 2, 4, 6, 8 ] + - Name: In + Format: Float32 + Stride: 32 + Data: [ 2, 4, 6, 8, 10, 12, 14, 16] + - Name: Out1 + Format: Float32 + Channels: 4 + ZeroInitSize: 16 + - Name: Out2 + Format: Float32 + Channels: 4 + ZeroInitSize: 16 +DescriptorSets: + - Resources: + - Name: In + Kind: StructuredBuffer + DirectXBinding: + Register: 4294967294 + Space: 0 + - Name: Out1 + Kind: RWStructuredBuffer + DirectXBinding: + Register: 1 + Space: 4294967279 +... +#--- end + +# UNSUPPORTED: Clang + +# RUN: split-file %s %t +# RUN: %dxc_target -T cs_6_0 -Fo %t.o %t/source.hlsl +# RUN: %offloader %t/pipeline.yaml %t.o | FileCheck %s + +# CHECK-LABEL: Name: Out1 +# CHECK: Data: [ 40, 192, 504, 1024 ] +# CHECK-LABEL: Name: Out2 +# CHECK: Data: [ 80, 384, 1008, 2048 ] diff --git a/test/M3/RootSignatures/ParameterInsensitivity.test b/test/M3/RootSignatures/ParameterInsensitivity.test new file mode 100644 index 00000000..a121765a --- /dev/null +++ b/test/M3/RootSignatures/ParameterInsensitivity.test @@ -0,0 +1,85 @@ +#--- source.hlsl + +cbuffer RootConstants : register(b0, space2) { + float4 C; +}; + +struct Input { + float4 A; + float4 B; +}; + +struct Output { + float4 A; +}; + +StructuredBuffer In : register(t0); +RWStructuredBuffer Out : register(u1); + +// Root signature to demonstrate: +// - All keywords and enums are case in-sensitive +// - Registers are case sensitive +// - Mandatory and optional arguments can be specified in any order + +#define RootSig \ + "rootflags(allow_input_assembler_input_layout)," \ + "rootconstants(space = 2, b0, num32bitconstants = 4), " \ + "DESCRIPTORTABLE( " \ + " SRV(FLAGS = DATA_STATIC, t0, SPACE = 0), " \ + " VisibilitY = ShadeR_VisibilitY_AlL, " \ + " uav(u1, NumDescriptors = UNBOUNDED) " \ + ")" + +[RootSignature(RootSig)] +[numthreads(1,1,1)] +void main(uint GI : SV_GroupIndex) { + Out[GI].A = In[GI].A * In[GI].B * C; +} + +//--- pipeline.yaml +--- +Shaders: + - Stage: Compute + Entry: main + DispatchSize: [1, 1, 1] +RuntimeSettings: + DirectX: + RootParameters: + - Kind: Constant + Name: Root + - Kind: DescriptorTable +Buffers: + - Name: Root + Format: Float32 + Data: [ 2, 4, 6, 8 ] + - Name: In + Format: Float32 + Stride: 32 + Data: [ 2, 4, 6, 8, 10, 12, 14, 16] + - Name: Out + Format: Float32 + Channels: 4 + ZeroInitSize: 16 +DescriptorSets: + - Resources: + - Name: In + Kind: StructuredBuffer + DirectXBinding: + Register: 0 + Space: 0 + - Name: Out + Kind: RWStructuredBuffer + DirectXBinding: + Register: 1 + Space: 0 +... +#--- end + +# UNSUPPORTED: Clang + +# RUN: split-file %s %t +# RUN: %dxc_target -T cs_6_0 -Fo %t.o %t/source.hlsl +# RUN: %offloader %t/pipeline.yaml %t.o | FileCheck %s + +# CHECK-LABEL: Name: Out +# CHECK: Data: [ 40, 192, 504, 1024 ] From 9c5e4bd2f4c7fba00c2d4b1f258af641cfc8a3cb Mon Sep 17 00:00:00 2001 From: Finn Plummer Date: Wed, 19 Mar 2025 14:08:27 -0700 Subject: [PATCH 2/3] update applicable flags - the UAV buffer was incorrectly described as static but was being written to - this commit makes the constant input take the DATA_STATIC flag in hopes of resolved the test runner failures --- test/M3/RootSignatures/Flags.test | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/test/M3/RootSignatures/Flags.test b/test/M3/RootSignatures/Flags.test index 75ebedd4..deee95ee 100644 --- a/test/M3/RootSignatures/Flags.test +++ b/test/M3/RootSignatures/Flags.test @@ -27,13 +27,10 @@ RWStructuredBuffer Out2 : register(u2); " ALLOW_STREAM_OUTPUT " \ "), " \ "DescriptorTable( " \ - " SRV(t0, flags = 0), " \ + " SRV(t0, flags = DATA_STATIC), " \ " SRV(t1, flags = DATA_STATIC_WHILE_SET_AT_EXECUTE), " \ " UAV(u1, flags = DESCRIPTORS_VOLATILE | DATA_VOLATILE), " \ - " UAV(u2, " \ - " flags = DESCRIPTORS_STATIC_KEEPING_BUFFER_BOUNDS_CHECKS " \ - " | DATA_STATIC " \ - " ) " \ + " UAV(u2, flags = 0)" \ ")" [RootSignature(RootSig)] From c850a9a6966312c0315a76ef3eb6660de8b93f46 Mon Sep 17 00:00:00 2001 From: Finn Plummer <50529406+inbelic@users.noreply.github.com> Date: Tue, 25 Mar 2025 10:02:39 -0700 Subject: [PATCH 3/3] Apply suggestions from code review Correct clarifying typos --- test/M3/RootSignatures/Defaults.test | 3 ++- test/M3/RootSignatures/NumberParameters.test | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/test/M3/RootSignatures/Defaults.test b/test/M3/RootSignatures/Defaults.test index 3759aea9..ac346360 100644 --- a/test/M3/RootSignatures/Defaults.test +++ b/test/M3/RootSignatures/Defaults.test @@ -17,7 +17,8 @@ StructuredBuffer In : register(t0); RWStructuredBuffer Out1 : register(u1); RWStructuredBuffer Out2 : register(u2); -// Root signature to sanity test default values optional values +// Root signature to sanity test the default values that are given to optional +// parameters (`space = 0`, `offset = DESCRIPTOR_RANGE_OFFSET_APPEND`, etc) #define RootSig \ "RootConstants(num32BitConstants = 4, b0), " \ diff --git a/test/M3/RootSignatures/NumberParameters.test b/test/M3/RootSignatures/NumberParameters.test index 9c589eaf..851d0994 100644 --- a/test/M3/RootSignatures/NumberParameters.test +++ b/test/M3/RootSignatures/NumberParameters.test @@ -19,7 +19,7 @@ RWStructuredBuffer Out2 : register(u2); // Root signature to test edge-cases of specify number arguments: // - Maximum valid register value (0xfffffffe = 4294967294) -// - Maximum valid register space value (0x7fffffff = 4294967279) +// - Maximum valid register space value (0x7fffffff = 2147483647) // - Maximum valid num32BitConstants value // (61 = 64 - # of used DWORDS for other params) // - Using (un)signed integer parameter values