Skip to content
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
9887b09
Added rewriter option ConsistentBindings (-consistent-bindings) for t…
Nielsbishere Jul 14, 2025
8454274
Option -consistent-bindings now properly generates bindings for not f…
Nielsbishere Jul 15, 2025
f60c594
Added a test for generating consistent bindings and changed tests to …
Nielsbishere Jul 15, 2025
74283d1
Applied clang format
Nielsbishere Jul 16, 2025
6f5689d
Now supporting multi dimensional register arrays for -consistent-bind…
Nielsbishere Aug 3, 2025
26a7f54
Removed rewriter option -consistent-bindings and now doing it in the …
Nielsbishere Sep 1, 2025
b63cdd2
Reset some incorrect merges
Nielsbishere Sep 1, 2025
8d7dc86
Cleanup for PR
Nielsbishere Sep 1, 2025
298ff34
clang format
Nielsbishere Sep 1, 2025
28b24f1
Clang format again
Nielsbishere Sep 1, 2025
cb9f345
Added two unit tests; one for more complex scenarios (e.g. overlappin…
Nielsbishere Nov 5, 2025
777a50e
RemoveResourcesWithUnusedSymbolsHelper and RemoveResourcesWithUnusedS…
Nielsbishere Nov 6, 2025
3fc2f2e
Applied clang format
Nielsbishere Nov 6, 2025
f5c545b
Merge upstream into fork
Nielsbishere Nov 6, 2025
ea760bf
Fixed an issue where resources without a global variable would not pr…
Nielsbishere Nov 7, 2025
9169ce0
Added -fhlsl-unused-resource-bindings<value> with options strip or re…
Nielsbishere Nov 12, 2025
6a15db9
Updated unit tests
Nielsbishere Nov 12, 2025
895724d
Merge branch 'main' of https://github.com/Microsoft/DirectXShaderComp…
Nielsbishere Nov 12, 2025
a633dc6
Clang format that somehow doesn't get formatted correctly?
Nielsbishere Nov 12, 2025
316e493
PR feedback, re. reserve-all, bChanged and revert formatting done to …
Nielsbishere Nov 13, 2025
68f20d6
Merge branch 'rewriter_generate_consistent_bindings' of https://githu…
Nielsbishere Nov 13, 2025
6d0531b
Removed ConsistentBindings from intermediate flags and moved it to Dx…
Nielsbishere Nov 13, 2025
75f9cc0
Clang format
Nielsbishere Nov 13, 2025
c2b24ed
Changed modif to Changed
NielsbishereAlt Nov 19, 2025
d018f94
Removed leftover b in front of bUnusedResourceBinding, removed unused…
Nielsbishere Nov 19, 2025
c8efa7b
RemoveResourcesWithUnusedSymbolsHelper is now the one properly skippi…
Nielsbishere Nov 19, 2025
5c96b53
Removed leftover code
Nielsbishere Nov 19, 2025
77275a4
Clang format and remove leftover dxil shader flag enum class
Nielsbishere Nov 19, 2025
ba1b43b
Moved legacyResourceReservation into UnusedResourceBinding::ReserveEx…
Nielsbishere Nov 21, 2025
2f482a9
Clang format
Nielsbishere Nov 21, 2025
4492c44
HLModule::RemoveGlobal now relies on DxilCondenseResources to remove …
Nielsbishere Nov 21, 2025
118363f
Clang format
Nielsbishere Nov 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/dxc/DXIL/DxilModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,8 @@ class DxilModule {
// Intermediate options that do not make it to DXIL
void SetLegacyResourceReservation(bool legacyResourceReservation);
bool GetLegacyResourceReservation() const;
void SetConsistentBindings(bool consistentBindings);
bool GetConsistentBindings() const;
void ClearIntermediateOptions();

// Hull and Domain shaders.
Expand Down Expand Up @@ -346,6 +348,7 @@ class DxilModule {

enum IntermediateFlags : uint32_t {
LegacyResourceReservation = 1 << 0,
ConsistentBindings = 1 << 1
};

llvm::LLVMContext &m_Ctx;
Expand Down
3 changes: 2 additions & 1 deletion include/dxc/HLSL/HLModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ struct HLOptions {
bDisableOptimizations(false), PackingStrategy(0),
bUseMinPrecision(false), bDX9CompatMode(false), bFXCCompatMode(false),
bLegacyResourceReservation(false), bForceZeroStoreLifetimes(false),
unused(0) {}
bConsistentBindings(false), unused(0) {}
uint32_t GetHLOptionsRaw() const;
void SetHLOptionsRaw(uint32_t data);
unsigned bDefaultRowMajor : 1;
Expand All @@ -70,6 +70,7 @@ struct HLOptions {
unsigned bLegacyResourceReservation : 1;
unsigned bForceZeroStoreLifetimes : 1;
unsigned bResMayAlias : 1;
unsigned bConsistentBindings : 1;
unsigned unused : 19;
};

Expand Down
1 change: 1 addition & 0 deletions include/dxc/Support/HLSLOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ class DxcOpts {
std::string TimeTrace = ""; // OPT_ftime_trace[EQ]
unsigned TimeTraceGranularity = 500; // OPT_ftime_trace_granularity_EQ
bool VerifyDiagnostics = false; // OPT_verify
bool ConsistentBindings = false; // OPT_consistent_bindings

// Optimization pass enables, disables and selects
OptimizationToggles
Expand Down
3 changes: 3 additions & 0 deletions include/dxc/Support/HLSLOptions.td
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,9 @@ def getprivate : JoinedOrSeparate<["-", "/"], "getprivate">, Flags<[DriverOption
def nologo : Flag<["-", "/"], "nologo">, Group<hlslcore_Group>, Flags<[DriverOption, HelpHidden]>,
HelpText<"Suppress copyright message">;

def consistent_bindings : Flag<["-", "/"], "consistent-bindings">, Group<hlslcomp_Group>, Flags<[CoreOption]>,
HelpText<"Generate bindings for registers with no pre-declared binding (consistently regardless of optimization).">;

//////////////////////////////////////////////////////////////////////////////
// Rewriter Options

Expand Down
10 changes: 10 additions & 0 deletions lib/DXIL/DxilModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,16 @@ bool DxilModule::GetLegacyResourceReservation() const {
return (m_IntermediateFlags & LegacyResourceReservation) != 0;
}

void DxilModule::SetConsistentBindings(bool consistentBindings) {
m_IntermediateFlags &= ~ConsistentBindings;
if (consistentBindings)
m_IntermediateFlags |= ConsistentBindings;
}

bool DxilModule::GetConsistentBindings() const {
return (m_IntermediateFlags & ConsistentBindings) != 0;
}

void DxilModule::ClearIntermediateOptions() { m_IntermediateFlags = 0; }

unsigned DxilModule::GetInputControlPointCount() const {
Expand Down
4 changes: 4 additions & 0 deletions lib/DxcSupport/HLSLOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,10 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
opts.TimeReport = Args.hasFlag(OPT_ftime_report, OPT_INVALID, false);
opts.TimeTrace = Args.hasFlag(OPT_ftime_trace, OPT_INVALID, false) ? "-" : "";
opts.VerifyDiagnostics = Args.hasFlag(OPT_verify, OPT_INVALID, false);

opts.ConsistentBindings =
Args.hasFlag(OPT_consistent_bindings, OPT_INVALID, false);

if (Args.hasArg(OPT_ftime_trace_EQ))
opts.TimeTrace = Args.getLastArgValue(OPT_ftime_trace_EQ);
if (Arg *A = Args.getLastArg(OPT_ftime_trace_granularity_EQ)) {
Expand Down
6 changes: 5 additions & 1 deletion lib/HLSL/DxilCondenseResources.cpp
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need an IR-based pass test for changes that impact this pass.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where do I add that? Any examples? (Same with the comment on DxilGenerationPass.cpp)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding these IR-based tests, there's a helper script: utils/hct/ExtractIRForPassTest.py -h for option help.
You pass in the desired pass and it stops at that point and generates the test output with the needed RUN line. You'll want to add -hlsl-dxilemit to the end of the pass list to emit the metadata.

However, as I was anticipating questions related to how to target this specific area, I tried crafting a test myself. Along the way, I ran into a bug in the pass, so I put a PR up to fix the bug, along with a couple pass tests.

Here's the PR: #7934
You could copy and modify the legalize-resource-phi.ll pass test for the purposes of testing changes to this hlsl-dxil-lower-handle-for-lib pass.

Notice how the metadata indicates unbound resources, then it checks the binding. For this change, this should check several things:

  • The unused resources are removed from the resource list, like the example test already checks.
  • The binding remains as-if the removed resources reserved registers (so u2 has binding 2 instead of 0 as this test currently checks).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do in a bit. Already pulled your PR into mine locally.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tex3d I have a bit of trouble trying to wrap my head around this process. So if I simplify it in steps maybe you can see where it goes wrong.

  1. python3 utils\hct\ExtractIRForPassTest.py D:\programming\repos\DirectXShaderCompiler\tools\clang\test\HLSLFileCheck\d3dreflect\consistent_bindings_simple.hlsl -p hlsl-dxil-lower-handle-for-lib -o test.txt -- -T cs_6_3 -E mainB -auto-binding-space 0 -fhlsl-unused-resource-bindings=reserve-all
  2. Changing the RUN %dxopt line in the file it generated and adding -hlsl-dxilemit there like your example
  3. Changing the UAV line/other checks to my example as well as the other checks to ensure it goes well?
  4. Running the dxopt manually can allow me to see what I should be checking against/validate it goes well

So a few questions:

  • I still get DI (debug info?) in my ll, as well as the dxc version info and resource info. How did you end up stripping that? Qstrip_debug doesn't work.
  • Do I need to use the same HLSL file you generated the IL from so it behaves about the same? Or is the consistent bindings simple test fine as long as I keep similar checks as yours regarding the resources (e.g. check for u1 and u0 to be stripped)

Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,8 @@ class DxilLowerCreateHandleForLib : public ModulePass {
ResourceRegisterAllocator.GatherReservedRegisters(DM);

// Remove unused resources.
DM.RemoveResourcesWithUnusedSymbols();
if (!DM.GetConsistentBindings())
DM.RemoveResourcesWithUnusedSymbols();

unsigned newResources = DM.GetCBuffers().size() + DM.GetUAVs().size() +
DM.GetSRVs().size() + DM.GetSamplers().size();
Expand All @@ -571,6 +572,9 @@ class DxilLowerCreateHandleForLib : public ModulePass {

bChanged |= ResourceRegisterAllocator.AllocateRegisters(DM);

if (DM.GetConsistentBindings())
DM.RemoveResourcesWithUnusedSymbols();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Above, after the call to LegalizeResources, it calls RemoveResourcesWithUnusedSymbols if bLocalChanged. Don't you want to predicate that with if (!DM.GetConsistentBindings())? Otherwise, resources may be removed before calling AllocateRegisters.

Also, it seems we should be tracking changes from this with bChanged. bChanged = bChanged || (numResources != newResources); is used earlier for this, and a similar thing could be done here after updating newResources. An alternative is to modify RemoveResourcesWithUnusedSymbols to return true if any changes were made.

Side note: Looking a little further up, I noticed when ApplyBindingTableFromMetadata is called, it doesn't update bChanged either, but that's an existing bug.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably need a test where LegalizeResources eliminates a resource use to test that code path. This relies on DxilValueCache, which was added largely to handle known-constant values in -Od cases where these values aren't simplified in the IR, but certain transformations we need to perform require these known values. In other words, you may be able to hit this code path using -Od with something that uses one resource or another in two code paths, depending on some condition that can be simplified to a constant, but is not normally simplified for -Od.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catches, have adjusted RemoveResourcesWithUnusedSymbols to return isModified and passing it along to bChanged. Also fixed the issue you said with LegalizeResources.
Since the issue ApplyBindingTableFromMetadata was already in there, it might be worth tackling this in a further PR/issue.
As for the test case for LegalizeResources; I'm not entirely sure where this would happen, I tried to read the code of LegalizeResources but it wasn't completely clear to me. Is there a unit test that tests legalize resources that I can combine with -consistent-bindings as a test case?


// Fill in top-level CBuffer variable usage bit
UpdateCBufferUsage();

Expand Down
1 change: 1 addition & 0 deletions lib/HLSL/DxilGenerationPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ void InitDxilModuleFromHLModule(HLModule &H, DxilModule &M, bool HasDebugInfo) {
// bool m_bDisableOptimizations;
M.SetDisableOptimization(H.GetHLOptions().bDisableOptimizations);
M.SetLegacyResourceReservation(H.GetHLOptions().bLegacyResourceReservation);
M.SetConsistentBindings(H.GetHLOptions().bConsistentBindings);
// bool m_bDisableMathRefactoring;
// bool m_bEnableDoublePrecision;
// bool m_bEnableDoubleExtensions;
Expand Down
20 changes: 14 additions & 6 deletions lib/HLSL/HLModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,17 +231,19 @@ void HLModule::RemoveFunction(llvm::Function *F) {
namespace {
template <typename TResource>
bool RemoveResource(std::vector<std::unique_ptr<TResource>> &vec,
GlobalVariable *pVariable, bool keepAllocated) {
GlobalVariable *pVariable, bool keepAllocated,
bool consistentBindings) {
for (auto p = vec.begin(), e = vec.end(); p != e; ++p) {
if ((*p)->GetGlobalSymbol() != pVariable)
continue;

if (keepAllocated && (*p)->IsAllocated()) {
if ((keepAllocated && (*p)->IsAllocated()) || consistentBindings) {
// Keep the resource, but it has no more symbol.
(*p)->SetGlobalSymbol(UndefValue::get(pVariable->getType()));
} else {
// Erase the resource alltogether and update IDs of subsequent ones
p = vec.erase(p);

for (e = vec.end(); p != e; ++p) {
unsigned ID = (*p)->GetID() - 1;
(*p)->SetID(ID);
Expand All @@ -262,16 +264,22 @@ void HLModule::RemoveGlobal(llvm::GlobalVariable *GV) {
// register range from being allocated to other resources.
bool keepAllocated = GetHLOptions().bLegacyResourceReservation;

// Consistent bindings are different than -flegacy-resource-reservation;
// We need the IDs to stay the same, but it's fine to remove unused registers.
// It's actually wanted, because that allows us to know what registers are
// optimized out.
bool consistentBindings = GetHLOptions().bConsistentBindings;

// This could be considerably faster - check variable type to see which
// resource type this is rather than scanning all lists, and look for
// usage and removal patterns.
if (RemoveResource(m_CBuffers, GV, keepAllocated))
if (RemoveResource(m_CBuffers, GV, keepAllocated, consistentBindings))
return;
if (RemoveResource(m_SRVs, GV, keepAllocated))
if (RemoveResource(m_SRVs, GV, keepAllocated, consistentBindings))
return;
if (RemoveResource(m_UAVs, GV, keepAllocated))
if (RemoveResource(m_UAVs, GV, keepAllocated, consistentBindings))
return;
if (RemoveResource(m_Samplers, GV, keepAllocated))
if (RemoveResource(m_Samplers, GV, keepAllocated, consistentBindings))
return;
// TODO: do m_TGSMVariables and m_StreamOutputs need maintenance?
}
Expand Down
2 changes: 2 additions & 0 deletions tools/clang/include/clang/Frontend/CodeGenOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ class CodeGenOptions : public CodeGenOptionsBase {
bool HLSLOnlyWarnOnUnrollFail = false;
/// Whether use legacy resource reservation.
bool HLSLLegacyResourceReservation = false;
/// Whether to keep bindings consistent even if optimized out.
bool HLSLConsistentBindings = false;
/// Set [branch] on every if.
bool HLSLPreferControlFlow = false;
/// Set [flatten] on every if.
Expand Down
1 change: 1 addition & 0 deletions tools/clang/lib/CodeGen/CGHLSLMS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@ CGMSHLSLRuntime::CGMSHLSLRuntime(CodeGenModule &CGM)
opts.PackingStrategy = CGM.getCodeGenOpts().HLSLSignaturePackingStrategy;
opts.bLegacyResourceReservation =
CGM.getCodeGenOpts().HLSLLegacyResourceReservation;
opts.bConsistentBindings = CGM.getCodeGenOpts().HLSLConsistentBindings;
opts.bForceZeroStoreLifetimes =
CGM.getCodeGenOpts().HLSLForceZeroStoreLifetimes;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
// RUN: %dxc -T lib_6_3 -auto-binding-space 0 -consistent-bindings %s | %D3DReflect %s | FileCheck %s

RWByteAddressBuffer output1;
RWByteAddressBuffer output2;
RWByteAddressBuffer output3 : register(u0);
RWByteAddressBuffer output4 : register(space1);
RWByteAddressBuffer output5 : SEMA;
RWByteAddressBuffer output6;
RWByteAddressBuffer output7 : register(u1);
RWByteAddressBuffer output8[12] : register(u3);
RWByteAddressBuffer output9[12];
RWByteAddressBuffer output10[33] : register(space1);
RWByteAddressBuffer output11[33] : register(space2);
RWByteAddressBuffer output12[33] : register(u0, space2);

StructuredBuffer<float> test5;
ByteAddressBuffer input13 : SEMA;
ByteAddressBuffer input14;
ByteAddressBuffer input15 : register(t0);
ByteAddressBuffer input16[12] : register(t3);
ByteAddressBuffer input17[2] : register(space1);
ByteAddressBuffer input18[12] : register(t1, space1);
ByteAddressBuffer input19[3] : register(space1);
ByteAddressBuffer input20 : register(space1);
Texture2D tex;

SamplerState sampler0;
SamplerState sampler1;
SamplerState sampler2 : register(s0);
SamplerState sampler3 : register(space1);
SamplerState sampler4 : register(s0, space1);

cbuffer test : register(b0) { float a; };
cbuffer test2 { float b; };
cbuffer test3 : register(space1) { float c; };
cbuffer test4 : register(space1) { float d; };

float e; //$Global is always the first to receive bindings before cbuffers without register annotation

[shader("compute")]
[numthreads(16, 16, 1)]
void main(uint id : SV_DispatchThreadID) {
output1.Store(0, test5[0]);
output2.Store(id * 4, a * b * c * d * e); //Only use 1 output, but this won't result into output2 receiving wrong bindings
output3.Store(0, input13.Load(0));
output4.Store(0, input14.Load(0));
output5.Store(0, input15.Load(0));
output6.Store(0, input16[0].Load(0));
output7.Store(0, input17[0].Load(0));
output8[0].Store(0, input18[0].Load(0));
output9[0].Store(0, input19[0].Load(0));
output10[0].Store(0, input20.Load(0));
output11[0].Store(0, tex.SampleLevel(sampler0, 0.xx, 0));
output12[0].Store(0, tex.SampleLevel(sampler1, 0.xx, 0) * tex.SampleLevel(sampler2, 0.xx, 0) * tex.SampleLevel(sampler3, 0.xx, 0) * tex.SampleLevel(sampler4, 0.xx, 0));
}

// CHECK: ID3D12LibraryReflection:
// CHECK: D3D12_LIBRARY_DESC:
// CHECK: FunctionCount: 1
// CHECK: ID3D12FunctionReflection:
// CHECK: D3D12_FUNCTION_DESC: Name: main
// CHECK: Shader Version: Compute 6.3
// CHECK: BoundResources: 32
// CHECK: Bound Resources:
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: $Globals
// CHECK: Type: D3D_SIT_CBUFFER
// CHECK: BindPoint: 1
// CHECK: Space: 0
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: test
// CHECK: Type: D3D_SIT_CBUFFER
// CHECK: BindPoint: 0
// CHECK: Space: 0
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: test2
// CHECK: Type: D3D_SIT_CBUFFER
// CHECK: BindPoint: 2
// CHECK: Space: 0
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: test3
// CHECK: Type: D3D_SIT_CBUFFER
// CHECK: BindPoint: 0
// CHECK: Space: 1
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: test4
// CHECK: Type: D3D_SIT_CBUFFER
// CHECK: BindPoint: 1
// CHECK: Space: 1
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: sampler0
// CHECK: Type: D3D_SIT_SAMPLER
// CHECK: BindPoint: 1
// CHECK: Space: 0
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: sampler1
// CHECK: Type: D3D_SIT_SAMPLER
// CHECK: BindPoint: 2
// CHECK: Space: 0
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: sampler2
// CHECK: Type: D3D_SIT_SAMPLER
// CHECK: BindPoint: 0
// CHECK: Space: 0
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: sampler3
// CHECK: Type: D3D_SIT_SAMPLER
// CHECK: BindPoint: 1
// CHECK: Space: 1
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: sampler4
// CHECK: Type: D3D_SIT_SAMPLER
// CHECK: BindPoint: 0
// CHECK: Space: 1
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: test5
// CHECK: Type: D3D_SIT_STRUCTURED
// CHECK: BindPoint: 1
// CHECK: Space: 0
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: input13
// CHECK: Type: D3D_SIT_BYTEADDRESS
// CHECK: BindPoint: 2
// CHECK: Space: 0
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: input14
// CHECK: Type: D3D_SIT_BYTEADDRESS
// CHECK: BindPoint: 15
// CHECK: Space: 0
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: input15
// CHECK: Type: D3D_SIT_BYTEADDRESS
// CHECK: BindPoint: 0
// CHECK: Space: 0
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: input16
// CHECK: Type: D3D_SIT_BYTEADDRESS
// CHECK: BindPoint: 3
// CHECK: Space: 0
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: input17
// CHECK: Type: D3D_SIT_BYTEADDRESS
// CHECK: BindPoint: 13
// CHECK: Space: 1
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: input18
// CHECK: Type: D3D_SIT_BYTEADDRESS
// CHECK: BindPoint: 1
// CHECK: Space: 1
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: input19
// CHECK: Type: D3D_SIT_BYTEADDRESS
// CHECK: BindPoint: 15
// CHECK: Space: 1
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: input20
// CHECK: Type: D3D_SIT_BYTEADDRESS
// CHECK: BindPoint: 0
// CHECK: Space: 1
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: tex
// CHECK: BindPoint: 16
// CHECK: Space: 0
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: output1
// CHECK: Type: D3D_SIT_UAV_RWBYTEADDRESS
// CHECK: BindPoint: 2
// CHECK: Space: 0
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: output2
// CHECK: Type: D3D_SIT_UAV_RWBYTEADDRESS
// CHECK: BindPoint: 15
// CHECK: Space: 0
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: output3
// CHECK: Type: D3D_SIT_UAV_RWBYTEADDRESS
// CHECK: BindPoint: 0
// CHECK: Space: 0
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: output4
// CHECK: BindPoint: 0
// CHECK: Space: 1
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: output5
// CHECK: Type: D3D_SIT_UAV_RWBYTEADDRESS
// CHECK: BindPoint: 16
// CHECK: Space: 0
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: output6
// CHECK: Type: D3D_SIT_UAV_RWBYTEADDRESS
// CHECK: BindPoint: 17
// CHECK: Space: 0
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: output7
// CHECK: Type: D3D_SIT_UAV_RWBYTEADDRESS
// CHECK: BindPoint: 1
// CHECK: Space: 0
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: output8
// CHECK: Type: D3D_SIT_UAV_RWBYTEADDRESS
// CHECK: BindPoint: 3
// CHECK: Space: 0
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: output9
// CHECK: Type: D3D_SIT_UAV_RWBYTEADDRESS
// CHECK: BindPoint: 18
// CHECK: Space: 0
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: output10
// CHECK: Type: D3D_SIT_UAV_RWBYTEADDRESS
// CHECK: BindPoint: 1
// CHECK: Space: 1
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: output11
// CHECK: Type: D3D_SIT_UAV_RWBYTEADDRESS
// CHECK: BindPoint: 33
// CHECK: Space: 2
// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: output12
// CHECK: Type: D3D_SIT_UAV_RWBYTEADDRESS
// CHECK: BindPoint: 0
// CHECK: Space: 2
Loading