diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md index 4fdb82f2ca..8f7cb7685f 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -23,6 +23,7 @@ The included licenses apply to the following files: - Fixed regression: [#7508](https://github.com/microsoft/DirectXShaderCompiler/issues/7508) crash when calling `Load` with `status`. - Header file `dxcpix.h` was added to the release package. - Moved Linear Algebra (Cooperative Vector) DXIL Opcodes to experimental Shader Model 6.10 +- Added `-fhlsl-unused-resource-bindings=` an option to allow deciding on how to treat unused resource bindings in DXIL; `strip` (default) or `reserve-all`. `strip` will strip unused resources before generating bindings for resources without a `: register`, and `reserve-all` will keep them reserved for generated bindings while stripping them afterwards. See [explanation](https://github.com/microsoft/DirectXShaderCompiler/pull/7643#issuecomment-3496917202) for more details. ### Version 1.8.2505 diff --git a/include/dxc/DXIL/DxilConstants.h b/include/dxc/DXIL/DxilConstants.h index d66f14a1e9..441ed30977 100644 --- a/include/dxc/DXIL/DxilConstants.h +++ b/include/dxc/DXIL/DxilConstants.h @@ -15,6 +15,18 @@ namespace hlsl { +enum class UnusedResourceBinding : uint32_t { + Strip, + ReserveAll, + Reserved, + ReserveExplicit, + Count +}; + +static_assert(unsigned(UnusedResourceBinding::Count) <= 7u, + "Only 3 bits are reserved for UnusedResourceBinding by HLOptions " + "and IntermediateFlags"); + /* import hctdb_instrhelp */ diff --git a/include/dxc/DXIL/DxilModule.h b/include/dxc/DXIL/DxilModule.h index 3f1ba12f86..03989803c9 100644 --- a/include/dxc/DXIL/DxilModule.h +++ b/include/dxc/DXIL/DxilModule.h @@ -112,7 +112,7 @@ class DxilModule { const std::vector> &GetUAVs() const; void RemoveUnusedResources(); - void RemoveResourcesWithUnusedSymbols(); + bool RemoveResourcesWithUnusedSymbols(bool AfterAllocation = false); void RemoveFunction(llvm::Function *F); bool RenameResourcesWithPrefix(const std::string &prefix); @@ -284,10 +284,10 @@ class DxilModule { void SetResMayAlias(bool resMayAlias); bool GetResMayAlias() const; - // Intermediate options that do not make it to DXIL - void SetLegacyResourceReservation(bool legacyResourceReservation); - bool GetLegacyResourceReservation() const; - void ClearIntermediateOptions(); + void SetUnusedResourceBinding(UnusedResourceBinding unusedResourceBinding); + UnusedResourceBinding GetUnusedResourceBinding() const; + + void ResetUnusedResourceBinding(); // Hull and Domain shaders. unsigned GetInputControlPointCount() const; @@ -344,10 +344,6 @@ class DxilModule { DXIL::PrimitiveTopology::Undefined; unsigned m_ActiveStreamMask = 0; - enum IntermediateFlags : uint32_t { - LegacyResourceReservation = 1 << 0, - }; - llvm::LLVMContext &m_Ctx; llvm::Module *m_pModule = nullptr; llvm::Function *m_pEntryFunc = nullptr; @@ -385,7 +381,7 @@ class DxilModule { bool m_bResMayAlias = false; // properties from HLModule that should not make it to the final DXIL - uint32_t m_IntermediateFlags = 0; + UnusedResourceBinding m_UnusedResourceBinding = UnusedResourceBinding::Strip; uint32_t m_AutoBindingSpace = UINT_MAX; std::unique_ptr m_pSubobjects; diff --git a/include/dxc/HLSL/HLModule.h b/include/dxc/HLSL/HLModule.h index 653fc967d5..55437fdb7c 100644 --- a/include/dxc/HLSL/HLModule.h +++ b/include/dxc/HLSL/HLModule.h @@ -53,7 +53,7 @@ struct HLOptions { : bDefaultRowMajor(false), bIEEEStrict(false), bAllResourcesBound(false), bDisableOptimizations(false), PackingStrategy(0), bUseMinPrecision(false), bDX9CompatMode(false), bFXCCompatMode(false), - bLegacyResourceReservation(false), bForceZeroStoreLifetimes(false), + reserved(0), bForceZeroStoreLifetimes(false), UnusedResourceBinding(0), unused(0) {} uint32_t GetHLOptionsRaw() const; void SetHLOptionsRaw(uint32_t data); @@ -67,10 +67,11 @@ struct HLOptions { unsigned bUseMinPrecision : 1; unsigned bDX9CompatMode : 1; unsigned bFXCCompatMode : 1; - unsigned bLegacyResourceReservation : 1; + unsigned reserved : 1; unsigned bForceZeroStoreLifetimes : 1; unsigned bResMayAlias : 1; - unsigned unused : 19; + unsigned UnusedResourceBinding : 3; + unsigned unused : 17; }; typedef std::unordered_map, Flags<[DriverOption def nologo : Flag<["-", "/"], "nologo">, Group, Flags<[DriverOption, HelpHidden]>, HelpText<"Suppress copyright message">; +def fhlsl_unused_resource_bindings_EQ : Joined<["-"], "fhlsl-unused-resource-bindings=">, Group, Flags<[CoreOption]>, + HelpText<"Control handling of unused resource bindings:\n\t\t\t'strip' (default, unused resources are stripped and their binding slots are freed up).\n\t\t\t'reserve-all' (do not use binding slots of unused resources when assigning bindings).">; + ////////////////////////////////////////////////////////////////////////////// // Rewriter Options diff --git a/lib/DXIL/DxilModule.cpp b/lib/DXIL/DxilModule.cpp index f4abdd15aa..f2cfebdb82 100644 --- a/lib/DXIL/DxilModule.cpp +++ b/lib/DXIL/DxilModule.cpp @@ -576,17 +576,18 @@ void DxilModule::SetResMayAlias(bool resMayAlias) { bool DxilModule::GetResMayAlias() const { return m_bResMayAlias; } -void DxilModule::SetLegacyResourceReservation(bool legacyResourceReservation) { - m_IntermediateFlags &= ~LegacyResourceReservation; - if (legacyResourceReservation) - m_IntermediateFlags |= LegacyResourceReservation; +void DxilModule::SetUnusedResourceBinding( + UnusedResourceBinding unusedResourceBinding) { + m_UnusedResourceBinding = unusedResourceBinding; } -bool DxilModule::GetLegacyResourceReservation() const { - return (m_IntermediateFlags & LegacyResourceReservation) != 0; +UnusedResourceBinding DxilModule::GetUnusedResourceBinding() const { + return m_UnusedResourceBinding; } -void DxilModule::ClearIntermediateOptions() { m_IntermediateFlags = 0; } +void DxilModule::ResetUnusedResourceBinding() { + m_UnusedResourceBinding = UnusedResourceBinding::Strip; +} unsigned DxilModule::GetInputControlPointCount() const { if (!(m_pSM->IsHS() || m_pSM->IsDS())) @@ -1021,8 +1022,11 @@ void DxilModule::RemoveUnusedResources() { namespace { template -static void RemoveResourcesWithUnusedSymbolsHelper( - std::vector> &vec) { +static bool RemoveResourcesWithUnusedSymbolsHelper( + std::vector> &vec, bool AfterAllocation, + UnusedResourceBinding UnusedBinding) { + bool KeepAllocated = UnusedBinding == UnusedResourceBinding::ReserveExplicit; + bool Changed = false; unsigned resID = 0; std::unordered_set eraseList; // Need in case of duplicate defs of lib resources @@ -1031,9 +1035,14 @@ static void RemoveResourcesWithUnusedSymbolsHelper( Constant *symbol = (*c)->GetGlobalSymbol(); symbol->removeDeadConstantUsers(); if (symbol->user_empty()) { + if (!AfterAllocation && + (UnusedBinding == UnusedResourceBinding::ReserveAll || + (KeepAllocated && (*c)->IsAllocated()))) + continue; p = vec.erase(c); if (GlobalVariable *GV = dyn_cast(symbol)) eraseList.insert(GV); + Changed = true; continue; } if ((*c)->GetID() != resID) { @@ -1044,14 +1053,21 @@ static void RemoveResourcesWithUnusedSymbolsHelper( for (auto gv : eraseList) { gv->eraseFromParent(); } + return Changed; } } // namespace -void DxilModule::RemoveResourcesWithUnusedSymbols() { - RemoveResourcesWithUnusedSymbolsHelper(m_SRVs); - RemoveResourcesWithUnusedSymbolsHelper(m_UAVs); - RemoveResourcesWithUnusedSymbolsHelper(m_CBuffers); - RemoveResourcesWithUnusedSymbolsHelper(m_Samplers); +bool DxilModule::RemoveResourcesWithUnusedSymbols(bool AfterAllocation) { + bool Changed = false; + Changed |= RemoveResourcesWithUnusedSymbolsHelper(m_SRVs, AfterAllocation, + GetUnusedResourceBinding()); + Changed |= RemoveResourcesWithUnusedSymbolsHelper(m_UAVs, AfterAllocation, + GetUnusedResourceBinding()); + Changed |= RemoveResourcesWithUnusedSymbolsHelper(m_CBuffers, AfterAllocation, + GetUnusedResourceBinding()); + Changed |= RemoveResourcesWithUnusedSymbolsHelper(m_Samplers, AfterAllocation, + GetUnusedResourceBinding()); + return Changed; } namespace { @@ -1405,7 +1421,7 @@ void DxilModule::EmitDxilMetadata() { m_pMDHelper->EmitDxilVersion(m_DxilMajor, m_DxilMinor); m_pMDHelper->EmitValidatorVersion(m_ValMajor, m_ValMinor); m_pMDHelper->EmitDxilShaderModel(m_pSM); - m_pMDHelper->EmitDxilIntermediateOptions(m_IntermediateFlags); + m_pMDHelper->EmitDxilIntermediateOptions(uint32_t(m_UnusedResourceBinding)); MDTuple *pMDProperties = nullptr; uint64_t flag = m_ShaderFlags.GetShaderFlagsRaw(); @@ -1500,7 +1516,9 @@ void DxilModule::LoadDxilMetadata() { m_pMDHelper->LoadValidatorVersion(m_ValMajor, m_ValMinor); const ShaderModel *loadedSM; m_pMDHelper->LoadDxilShaderModel(loadedSM); - m_pMDHelper->LoadDxilIntermediateOptions(m_IntermediateFlags); + uint32_t options; + m_pMDHelper->LoadDxilIntermediateOptions(options); + m_UnusedResourceBinding = UnusedResourceBinding(options); // This must be set before LoadDxilEntryProperties m_pMDHelper->SetShaderModel(loadedSM); diff --git a/lib/DxcSupport/HLSLOptions.cpp b/lib/DxcSupport/HLSLOptions.cpp index 0c9330b1d1..fad05cfcb7 100644 --- a/lib/DxcSupport/HLSLOptions.cpp +++ b/lib/DxcSupport/HLSLOptions.cpp @@ -843,8 +843,6 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude, opts.DisaseembleHex = Args.hasFlag(OPT_Lx, OPT_INVALID, false); opts.LegacyMacroExpansion = Args.hasFlag(OPT_flegacy_macro_expansion, OPT_INVALID, false); - opts.LegacyResourceReservation = - Args.hasFlag(OPT_flegacy_resource_reservation, OPT_INVALID, false); opts.ExportShadersOnly = Args.hasFlag(OPT_export_shaders_only, OPT_INVALID, false); opts.PrintBeforeAll = Args.hasFlag(OPT_print_before_all, OPT_INVALID, false); @@ -865,6 +863,33 @@ 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); + + std::string UnusedResources = + Args.getLastArgValue(OPT_fhlsl_unused_resource_bindings_EQ, "strip"); + + if (UnusedResources == "strip") + opts.UnusedResourceBinding = UnusedResourceBinding::Strip; + else if (UnusedResources == "reserve-all") + opts.UnusedResourceBinding = UnusedResourceBinding::ReserveAll; + else { + errors << "Error: Invalid value for -fhlsl-unused-resource-bindings option " + "specified (" + << UnusedResources << "). Must be one of: strip, reserve-all"; + return 1; + } + + // TODO: Move to OPT_fhlsl_unused_resource_bindings_EQ + if (Args.hasFlag(OPT_flegacy_resource_reservation, OPT_INVALID, false)) { + + if (unsigned(opts.UnusedResourceBinding)) { + errors << "Error: Unused resource bindings can't be used at the same " + "time as flegacy_resource_reservation"; + return 1; + } + + opts.UnusedResourceBinding = UnusedResourceBinding::ReserveExplicit; + } + opts.Verbose = Args.hasFlag(OPT_verbose, OPT_INVALID, false); if (Args.hasArg(OPT_ftime_trace_EQ)) opts.TimeTrace = Args.getLastArgValue(OPT_ftime_trace_EQ); diff --git a/lib/HLSL/DxilCondenseResources.cpp b/lib/HLSL/DxilCondenseResources.cpp index 09dd9cea64..8c5b6d2cd3 100644 --- a/lib/HLSL/DxilCondenseResources.cpp +++ b/lib/HLSL/DxilCondenseResources.cpp @@ -242,7 +242,8 @@ class DxilResourceRegisterAllocator { // For backcompat with FXC, shader models 5.0 and below will not // auto-allocate resources at a register explicitely assigned to even an // unused resource. - if (DM.GetLegacyResourceReservation()) { + if (DM.GetUnusedResourceBinding() == + UnusedResourceBinding::ReserveExplicit) { GatherReservedRegisters(DM.GetCBuffers(), m_reservedCBufferRegisters); GatherReservedRegisters(DM.GetSamplers(), m_reservedSamplerRegisters); GatherReservedRegisters(DM.GetUAVs(), m_reservedUAVRegisters); @@ -527,6 +528,8 @@ class DxilLowerCreateHandleForLib : public ModulePass { SetNonUniformIndexForDynamicResource(DM); } + bChanged |= DM.RemoveResourcesWithUnusedSymbols(); + unsigned numResources = DM.GetCBuffers().size() + DM.GetUAVs().size() + DM.GetSRVs().size() + DM.GetSamplers().size(); @@ -550,11 +553,10 @@ class DxilLowerCreateHandleForLib : public ModulePass { ResourceRegisterAllocator.GatherReservedRegisters(DM); // Remove unused resources. - DM.RemoveResourcesWithUnusedSymbols(); + bChanged |= DM.RemoveResourcesWithUnusedSymbols(); unsigned newResources = DM.GetCBuffers().size() + DM.GetUAVs().size() + DM.GetSRVs().size() + DM.GetSamplers().size(); - bChanged = bChanged || (numResources != newResources); if (0 == newResources) return bChanged; @@ -564,12 +566,13 @@ class DxilLowerCreateHandleForLib : public ModulePass { bool bLocalChanged = LegalizeResources(M, DVC); if (bLocalChanged) { // Remove unused resources. - DM.RemoveResourcesWithUnusedSymbols(); + bChanged |= DM.RemoveResourcesWithUnusedSymbols(); } bChanged |= bLocalChanged; } bChanged |= ResourceRegisterAllocator.AllocateRegisters(DM); + bChanged |= DM.RemoveResourcesWithUnusedSymbols(true); // Fill in top-level CBuffer variable usage bit UpdateCBufferUsage(); diff --git a/lib/HLSL/DxilGenerationPass.cpp b/lib/HLSL/DxilGenerationPass.cpp index c3a6ad7dfc..867d2948d4 100644 --- a/lib/HLSL/DxilGenerationPass.cpp +++ b/lib/HLSL/DxilGenerationPass.cpp @@ -154,7 +154,8 @@ void InitDxilModuleFromHLModule(HLModule &H, DxilModule &M, bool HasDebugInfo) { // Shader properties. // bool m_bDisableOptimizations; M.SetDisableOptimization(H.GetHLOptions().bDisableOptimizations); - M.SetLegacyResourceReservation(H.GetHLOptions().bLegacyResourceReservation); + M.SetUnusedResourceBinding( + UnusedResourceBinding(H.GetHLOptions().UnusedResourceBinding)); // bool m_bDisableMathRefactoring; // bool m_bEnableDoublePrecision; // bool m_bEnableDoubleExtensions; diff --git a/lib/HLSL/DxilPreparePasses.cpp b/lib/HLSL/DxilPreparePasses.cpp index 68da520984..1e5c0bf12e 100644 --- a/lib/HLSL/DxilPreparePasses.cpp +++ b/lib/HLSL/DxilPreparePasses.cpp @@ -1003,7 +1003,7 @@ class DxilFinalizeModule : public ModulePass { DM.UpgradeToMinValidatorVersion(); // Clear intermediate options that shouldn't be in the final DXIL - DM.ClearIntermediateOptions(); + DM.ResetUnusedResourceBinding(); // Remove unused AllocateRayQuery calls RemoveUnusedRayQuery(M); diff --git a/lib/HLSL/HLModule.cpp b/lib/HLSL/HLModule.cpp index bab6e23a30..f729103fe9 100644 --- a/lib/HLSL/HLModule.cpp +++ b/lib/HLSL/HLModule.cpp @@ -231,22 +231,12 @@ void HLModule::RemoveFunction(llvm::Function *F) { namespace { template bool RemoveResource(std::vector> &vec, - GlobalVariable *pVariable, bool keepAllocated) { + GlobalVariable *pVariable) { for (auto p = vec.begin(), e = vec.end(); p != e; ++p) { if ((*p)->GetGlobalSymbol() != pVariable) continue; - if (keepAllocated && (*p)->IsAllocated()) { - // 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); - } - } + (*p)->SetGlobalSymbol(UndefValue::get(pVariable->getType())); return true; } @@ -257,21 +247,16 @@ bool RemoveResource(std::vector> &vec, void HLModule::RemoveGlobal(llvm::GlobalVariable *GV) { DXASSERT_NOMSG(GV != nullptr); - // With legacy resource reservation, we must keep unused resources around - // when they have a register allocation because they prevent that - // register range from being allocated to other resources. - bool keepAllocated = GetHLOptions().bLegacyResourceReservation; - // 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)) return; - if (RemoveResource(m_SRVs, GV, keepAllocated)) + if (RemoveResource(m_SRVs, GV)) return; - if (RemoveResource(m_UAVs, GV, keepAllocated)) + if (RemoveResource(m_UAVs, GV)) return; - if (RemoveResource(m_Samplers, GV, keepAllocated)) + if (RemoveResource(m_Samplers, GV)) return; // TODO: do m_TGSMVariables and m_StreamOutputs need maintenance? } diff --git a/tools/clang/include/clang/Frontend/CodeGenOptions.h b/tools/clang/include/clang/Frontend/CodeGenOptions.h index 859cba53da..5126b37023 100644 --- a/tools/clang/include/clang/Frontend/CodeGenOptions.h +++ b/tools/clang/include/clang/Frontend/CodeGenOptions.h @@ -185,8 +185,9 @@ class CodeGenOptions : public CodeGenOptionsBase { bool HLSLAllowPreserveValues = false; /// Whether we fail compilation if loop fails to unroll bool HLSLOnlyWarnOnUnrollFail = false; - /// Whether use legacy resource reservation. - bool HLSLLegacyResourceReservation = false; + /// How to handle unused resource bindings. + hlsl::UnusedResourceBinding HLSLUnusedResourceBinding = + hlsl::UnusedResourceBinding::Strip; /// Set [branch] on every if. bool HLSLPreferControlFlow = false; /// Set [flatten] on every if. diff --git a/tools/clang/lib/CodeGen/CGHLSLMS.cpp b/tools/clang/lib/CodeGen/CGHLSLMS.cpp index 6c68381a20..f31819e252 100644 --- a/tools/clang/lib/CodeGen/CGHLSLMS.cpp +++ b/tools/clang/lib/CodeGen/CGHLSLMS.cpp @@ -42,6 +42,7 @@ #include #include "dxc/DXIL/DxilCBuffer.h" +#include "dxc/DXIL/DxilConstants.h" #include "dxc/DXIL/DxilResourceProperties.h" #include "dxc/DxilRootSignature/DxilRootSignature.h" #include "dxc/HLSL/DxilExportMap.h" @@ -398,8 +399,8 @@ CGMSHLSLRuntime::CGMSHLSLRuntime(CodeGenModule &CGM) opts.bAllResourcesBound = CGM.getCodeGenOpts().HLSLAllResourcesBound; opts.bResMayAlias = CGM.getCodeGenOpts().HLSLResMayAlias; opts.PackingStrategy = CGM.getCodeGenOpts().HLSLSignaturePackingStrategy; - opts.bLegacyResourceReservation = - CGM.getCodeGenOpts().HLSLLegacyResourceReservation; + opts.UnusedResourceBinding = + unsigned(CGM.getCodeGenOpts().HLSLUnusedResourceBinding); opts.bForceZeroStoreLifetimes = CGM.getCodeGenOpts().HLSLForceZeroStoreLifetimes; @@ -3130,7 +3131,8 @@ void GetResourceDeclElemTypeAndRangeSize(CodeGenModule &CGM, HLModule &HL, rangeSize *= cast(arrayType)->getSize().getLimitedValue(); } else { - if (HL.GetHLOptions().bLegacyResourceReservation) { + if (HL.GetHLOptions().UnusedResourceBinding == + unsigned(UnusedResourceBinding::ReserveExplicit)) { DiagnosticsEngine &Diags = CGM.getDiags(); unsigned DiagID = Diags.getCustomDiagID( DiagnosticsEngine::Error, "unbounded resources are not supported " diff --git a/tools/clang/test/HLSLFileCheck/d3dreflect/consistent_bindings_complex.hlsl b/tools/clang/test/HLSLFileCheck/d3dreflect/consistent_bindings_complex.hlsl new file mode 100644 index 0000000000..2aef348bd9 --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/d3dreflect/consistent_bindings_complex.hlsl @@ -0,0 +1,190 @@ +// RUN: %dxc -T lib_6_3 -auto-binding-space 0 -fhlsl-unused-resource-bindings=reserve-all %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 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 \ No newline at end of file diff --git a/tools/clang/test/HLSLFileCheck/d3dreflect/consistent_bindings_simple.hlsl b/tools/clang/test/HLSLFileCheck/d3dreflect/consistent_bindings_simple.hlsl new file mode 100644 index 0000000000..021eb82877 --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/d3dreflect/consistent_bindings_simple.hlsl @@ -0,0 +1,58 @@ +// RUN: %dxc -T lib_6_3 -auto-binding-space 0 -fhlsl-unused-resource-bindings=reserve-all %s | %D3DReflect %s | FileCheck %s -check-prefix=CHECK +// RUN: %dxc -T cs_6_3 -E mainA -auto-binding-space 0 -fhlsl-unused-resource-bindings=reserve-all %s | %D3DReflect %s | FileCheck %s -check-prefix=CHECK2 +// RUN: %dxc -T cs_6_3 -E mainB -auto-binding-space 0 -fhlsl-unused-resource-bindings=reserve-all %s | %D3DReflect %s | FileCheck %s -check-prefix=CHECK3 + +RWByteAddressBuffer a; +RWByteAddressBuffer b; + +[shader("compute")] +[numthreads(16, 16, 1)] +void mainA(uint id : SV_DispatchThreadID) { + a.Store(0, float4(id, 0.xxx)); +} + +[shader("compute")] +[numthreads(16, 16, 1)] +void mainB(uint id : SV_DispatchThreadID) { + b.Store(0, float4(id, 0.xxx)); +} + +// CHECK: ID3D12LibraryReflection: +// CHECK: D3D12_LIBRARY_DESC: +// CHECK: FunctionCount: 2 +// CHECK: ID3D12FunctionReflection: +// CHECK: D3D12_FUNCTION_DESC: Name: mainA +// CHECK: Shader Version: Compute 6.3 +// CHECK: BoundResources: 1 +// CHECK: Bound Resources: +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: a +// CHECK: Type: D3D_SIT_UAV_RWBYTEADDRESS +// CHECK: BindPoint: 0 +// CHECK: Space: 0 +// CHECK: ID3D12FunctionReflection: +// CHECK: D3D12_FUNCTION_DESC: Name: mainB +// CHECK: Shader Version: Compute 6.3 +// CHECK: BoundResources: 1 +// CHECK: Bound Resources: +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: b +// CHECK: Type: D3D_SIT_UAV_RWBYTEADDRESS +// CHECK: BindPoint: 1 +// CHECK: Space: 0 + +// CHECK2: ID3D12ShaderReflection: +// CHECK2: D3D12_SHADER_DESC: +// CHECK2: Shader Version: Compute +// CHECK2: Bound Resources: +// CHECK2: D3D12_SHADER_INPUT_BIND_DESC: Name: a +// CHECK2: Type: D3D_SIT_UAV_RWBYTEADDRESS +// CHECK2: BindPoint: 0 +// CHECK2: Space: 0 + +// CHECK3: ID3D12ShaderReflection: +// CHECK3: D3D12_SHADER_DESC: +// CHECK3: Shader Version: Compute +// CHECK3: Bound Resources: +// CHECK3: D3D12_SHADER_INPUT_BIND_DESC: Name: b +// CHECK3: Type: D3D_SIT_UAV_RWBYTEADDRESS +// CHECK3: BindPoint: 1 +// CHECK3: Space: 0 \ No newline at end of file diff --git a/tools/clang/tools/dxcompiler/dxcompilerobj.cpp b/tools/clang/tools/dxcompiler/dxcompilerobj.cpp index 230047b4a8..17cd32595f 100644 --- a/tools/clang/tools/dxcompiler/dxcompilerobj.cpp +++ b/tools/clang/tools/dxcompiler/dxcompilerobj.cpp @@ -1593,8 +1593,8 @@ class DxcCompiler : public IDxcCompiler3, compiler.getCodeGenOpts().HLSLOverrideSemDefs = Opts.OverrideSemDefs; compiler.getCodeGenOpts().HLSLPreferControlFlow = Opts.PreferFlowControl; compiler.getCodeGenOpts().HLSLAvoidControlFlow = Opts.AvoidFlowControl; - compiler.getCodeGenOpts().HLSLLegacyResourceReservation = - Opts.LegacyResourceReservation; + compiler.getCodeGenOpts().HLSLUnusedResourceBinding = + Opts.UnusedResourceBinding; compiler.getCodeGenOpts().HLSLDefines = defines; compiler.getCodeGenOpts().HLSLPreciseOutputs = Opts.PreciseOutputs; compiler.getCodeGenOpts().MainFileName = pMainFile; diff --git a/tools/clang/unittests/HLSL/OptimizerTest.cpp b/tools/clang/unittests/HLSL/OptimizerTest.cpp index 1294a41434..f6ff1b83fe 100644 --- a/tools/clang/unittests/HLSL/OptimizerTest.cpp +++ b/tools/clang/unittests/HLSL/OptimizerTest.cpp @@ -163,9 +163,9 @@ TEST_F(OptimizerTest, OptimizerWhenSlice3ThenOK) { } TEST_F(OptimizerTest, OptimizerWhenSliceWithIntermediateOptionsThenOK) { - // The program below working depends on the LegacyResourceReservation option - // being carried through to the resource register allocator, even though it is - // not preserved in the final shader. + // The program below working depends on the -flegacy-resource-reservation + // option being carried through to the resource register allocator, even + // though it is not preserved in the final shader. LPCSTR SampleProgram = "Texture2D tex0 : register(t0);\r\n" "Texture2D tex1;\r\n" // tex1 should get register t1 "float4 main() : SV_Target {\r\n"