diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md index 4fdb82f2ca..ed8acbfad4 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 `keep-all`. `strip` will strip unused resources before generating bindings for resources without a `: register`, and `keep-all` will keep them around even for reflection (while marking them with D3D_SIF_UNUSED). 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..e1c7923606 100644 --- a/include/dxc/DXIL/DxilConstants.h +++ b/include/dxc/DXIL/DxilConstants.h @@ -15,6 +15,12 @@ namespace hlsl { +enum class UnusedResourceBinding : uint32_t { Strip, Reserved, KeepAll, Count }; + +static_assert(UnusedResourceBinding::Count <= UnusedResourceBinding(7), + "Only 3 bits are reserved for UnusedResourceBinding by HLOptions " + "and ShaderFlags"); + /* import hctdb_instrhelp */ diff --git a/include/dxc/DXIL/DxilModule.h b/include/dxc/DXIL/DxilModule.h index 3f1ba12f86..04137052ab 100644 --- a/include/dxc/DXIL/DxilModule.h +++ b/include/dxc/DXIL/DxilModule.h @@ -112,8 +112,10 @@ class DxilModule { const std::vector> &GetUAVs() const; void RemoveUnusedResources(); - void RemoveResourcesWithUnusedSymbols(); + bool RemoveResourcesWithUnusedSymbols(); + bool RemoveEmptyBuffers(); void RemoveFunction(llvm::Function *F); + bool MarkUnusedResources(); bool RenameResourcesWithPrefix(const std::string &prefix); bool RenameResourceGlobalsWithBinding(bool bKeepName = true); @@ -287,6 +289,9 @@ class DxilModule { // Intermediate options that do not make it to DXIL void SetLegacyResourceReservation(bool legacyResourceReservation); bool GetLegacyResourceReservation() const; + + void SetUnusedResourceBinding(UnusedResourceBinding unusedResourceBinding); + UnusedResourceBinding GetUnusedResourceBinding() const; void ClearIntermediateOptions(); // Hull and Domain shaders. @@ -344,9 +349,7 @@ class DxilModule { DXIL::PrimitiveTopology::Undefined; unsigned m_ActiveStreamMask = 0; - enum IntermediateFlags : uint32_t { - LegacyResourceReservation = 1 << 0, - }; + enum IntermediateFlags : uint32_t { LegacyResourceReservation = 1 << 0 }; llvm::LLVMContext &m_Ctx; llvm::Module *m_pModule = nullptr; @@ -383,6 +386,7 @@ class DxilModule { bool m_bUseMinPrecision = true; // use min precision by default; bool m_bAllResourcesBound = false; bool m_bResMayAlias = false; + UnusedResourceBinding m_unusedResourceBinding = UnusedResourceBinding::Strip; // properties from HLModule that should not make it to the final DXIL uint32_t m_IntermediateFlags = 0; diff --git a/include/dxc/DXIL/DxilResourceBase.h b/include/dxc/DXIL/DxilResourceBase.h index 0a595b9d6a..748787d7ab 100644 --- a/include/dxc/DXIL/DxilResourceBase.h +++ b/include/dxc/DXIL/DxilResourceBase.h @@ -46,6 +46,7 @@ class DxilResourceBase { llvm::Value *GetHandle() const; bool IsAllocated() const; bool IsUnbounded() const; + bool IsUnused() const; void SetKind(DxilResourceBase::Kind ResourceKind); void SetSpaceID(unsigned SpaceID); @@ -55,6 +56,7 @@ class DxilResourceBase { void SetGlobalName(const std::string &Name); void SetHandle(llvm::Value *pHandle); void SetHLSLType(llvm::Type *Ty); + void SetIsUnused(bool IsUnused); // TODO: check whether we can make this a protected method. void SetID(unsigned ID); @@ -75,6 +77,7 @@ class DxilResourceBase { unsigned m_SpaceID; // Root signature space. unsigned m_LowerBound; // Range lower bound. unsigned m_RangeSize; // Range size in entries. + bool m_IsUnused; llvm::Constant *m_pSymbol; // Global variable. std::string m_Name; // Unmangled name of the global variable. llvm::Value diff --git a/include/dxc/DXIL/DxilShaderFlags.h b/include/dxc/DXIL/DxilShaderFlags.h index 7b065c63fa..44c1ddfdfb 100644 --- a/include/dxc/DXIL/DxilShaderFlags.h +++ b/include/dxc/DXIL/DxilShaderFlags.h @@ -16,6 +16,7 @@ namespace hlsl { class DxilModule; struct DxilFunctionProps; +enum class UnusedResourceBinding : uint32_t; } namespace llvm { @@ -219,6 +220,14 @@ class ShaderFlags { void SetRequiresGroup(bool flag) { m_bRequiresGroup = flag; } bool GetRequiresGroup() const { return m_bRequiresGroup; } + void SetUnusedResourceBinding(UnusedResourceBinding bindings) { + m_UnusedResourceBinding = unsigned(bindings); + } + + UnusedResourceBinding GetUnusedResourceBinding() { + return UnusedResourceBinding(m_UnusedResourceBinding); + } + private: // Bit: 0 unsigned @@ -359,7 +368,9 @@ class ShaderFlags { unsigned m_bRequiresGroup : 1; // SHADER_FEATURE_OPT_REQUIRES_GROUP // (OptFeatureInfo_RequiresGroup) - uint32_t m_align1 : 23; // align to 64 bit. + unsigned m_UnusedResourceBinding : 3; + + uint32_t m_align1 : 20; // align to 64 bit. }; } // namespace hlsl diff --git a/include/dxc/HLSL/HLModule.h b/include/dxc/HLSL/HLModule.h index 653fc967d5..de851121fb 100644 --- a/include/dxc/HLSL/HLModule.h +++ b/include/dxc/HLSL/HLModule.h @@ -54,7 +54,7 @@ struct HLOptions { bDisableOptimizations(false), PackingStrategy(0), bUseMinPrecision(false), bDX9CompatMode(false), bFXCCompatMode(false), bLegacyResourceReservation(false), bForceZeroStoreLifetimes(false), - unused(0) {} + bUnusedResourceBinding(0), unused(0) {} uint32_t GetHLOptionsRaw() const; void SetHLOptionsRaw(uint32_t data); unsigned bDefaultRowMajor : 1; @@ -70,7 +70,8 @@ struct HLOptions { unsigned bLegacyResourceReservation : 1; unsigned bForceZeroStoreLifetimes : 1; unsigned bResMayAlias : 1; - unsigned unused : 19; + unsigned bUnusedResourceBinding : 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'keep-all' (keep all unused resources around but mark them with D3D_SIF_UNUSED for reflection).">; + ////////////////////////////////////////////////////////////////////////////// // Rewriter Options diff --git a/lib/DXIL/DxilMetadataHelper.cpp b/lib/DXIL/DxilMetadataHelper.cpp index c1282a980a..0ef96af17b 100644 --- a/lib/DXIL/DxilMetadataHelper.cpp +++ b/lib/DXIL/DxilMetadataHelper.cpp @@ -693,7 +693,9 @@ void DxilMDHelper::GetDxilResources(const MDOperand &MDO, const MDTuple *&pSRVs, void DxilMDHelper::EmitDxilResourceBase(const DxilResourceBase &R, Metadata *ppMDVals[]) { - ppMDVals[kDxilResourceBaseID] = Uint32ToConstMD(R.GetID()); + assert(R.GetID() < (1u << 31) && "R.GetId() out of bounds"); + uint32_t idAndIsUnused = R.GetID() | (R.IsUnused() ? (1u << 31) : 0); + ppMDVals[kDxilResourceBaseID] = Uint32ToConstMD(idAndIsUnused); Constant *GlobalSymbol = R.GetGlobalSymbol(); // For sm66+, global symbol will be mutated into handle type. // Save hlsl type by generate bitcast on global symbol. @@ -722,7 +724,11 @@ void DxilMDHelper::LoadDxilResourceBase(const MDOperand &MDO, IFTBOOL(pTupleMD->getNumOperands() >= kDxilResourceBaseNumFields, DXC_E_INCORRECT_DXIL_METADATA); - R.SetID(ConstMDToUint32(pTupleMD->getOperand(kDxilResourceBaseID))); + uint32_t idAndIsUnused = + ConstMDToUint32(pTupleMD->getOperand(kDxilResourceBaseID)); + + R.SetID(idAndIsUnused << 1 >> 1); + R.SetIsUnused(idAndIsUnused >> 31); Constant *GlobalSymbol = dyn_cast( ValueMDToValue(pTupleMD->getOperand(kDxilResourceBaseVariable))); // For sm66+, global symbol will be mutated into handle type. diff --git a/lib/DXIL/DxilModule.cpp b/lib/DXIL/DxilModule.cpp index f4abdd15aa..918e77c8bd 100644 --- a/lib/DXIL/DxilModule.cpp +++ b/lib/DXIL/DxilModule.cpp @@ -586,6 +586,15 @@ bool DxilModule::GetLegacyResourceReservation() const { return (m_IntermediateFlags & LegacyResourceReservation) != 0; } +void DxilModule::SetUnusedResourceBinding( + UnusedResourceBinding unusedResourceBinding) { + m_unusedResourceBinding = unusedResourceBinding; +} + +UnusedResourceBinding DxilModule::GetUnusedResourceBinding() const { + return m_unusedResourceBinding; +} + void DxilModule::ClearIntermediateOptions() { m_IntermediateFlags = 0; } unsigned DxilModule::GetInputControlPointCount() const { @@ -1021,8 +1030,9 @@ void DxilModule::RemoveUnusedResources() { namespace { template -static void RemoveResourcesWithUnusedSymbolsHelper( +static bool RemoveResourcesWithUnusedSymbolsHelper( std::vector> &vec) { + bool modif = false; unsigned resID = 0; std::unordered_set eraseList; // Need in case of duplicate defs of lib resources @@ -1031,6 +1041,7 @@ static void RemoveResourcesWithUnusedSymbolsHelper( Constant *symbol = (*c)->GetGlobalSymbol(); symbol->removeDeadConstantUsers(); if (symbol->user_empty()) { + modif = true; p = vec.erase(c); if (GlobalVariable *GV = dyn_cast(symbol)) eraseList.insert(GV); @@ -1044,14 +1055,80 @@ static void RemoveResourcesWithUnusedSymbolsHelper( for (auto gv : eraseList) { gv->eraseFromParent(); } + return modif; +} +} // namespace + +bool DxilModule::RemoveResourcesWithUnusedSymbols() { + bool modif = false; + modif |= RemoveResourcesWithUnusedSymbolsHelper(m_SRVs); + modif |= RemoveResourcesWithUnusedSymbolsHelper(m_UAVs); + modif |= RemoveResourcesWithUnusedSymbolsHelper(m_CBuffers); + modif |= RemoveResourcesWithUnusedSymbolsHelper(m_Samplers); + return modif; +} + +bool DxilModule::RemoveEmptyBuffers() { + + bool mod = false; + unsigned resID = 0; + std::unordered_set + eraseList; // Need in case of duplicate defs of lib resources + + for (auto p = m_CBuffers.begin(); p != m_CBuffers.end();) { + + auto c = p++; + + Constant *symbol = (*c)->GetGlobalSymbol(); + + if (!c->get()->GetSize()) { + p = m_CBuffers.erase(c); + if (GlobalVariable *GV = dyn_cast(symbol)) + eraseList.insert(GV); + mod = true; + continue; + } + + if ((*c)->GetID() != resID) + (*c)->SetID(resID); + + resID++; + } + + for (auto gv : eraseList) + gv->eraseFromParent(); + + return mod; +} + +namespace { +template +static bool MarkResourcesUnused(std::vector> &vec) { + + bool modif = false; + + for (auto p = vec.begin(); p != vec.end();) { + auto c = p++; + Constant *symbol = (*c)->GetGlobalSymbol(); + symbol->removeDeadConstantUsers(); + if (symbol->user_empty()) { + (*c)->SetIsUnused(true); + modif = true; + continue; + } + } + + return modif; } } // namespace -void DxilModule::RemoveResourcesWithUnusedSymbols() { - RemoveResourcesWithUnusedSymbolsHelper(m_SRVs); - RemoveResourcesWithUnusedSymbolsHelper(m_UAVs); - RemoveResourcesWithUnusedSymbolsHelper(m_CBuffers); - RemoveResourcesWithUnusedSymbolsHelper(m_Samplers); +bool DxilModule::MarkUnusedResources() { + bool modif = true; + modif |= MarkResourcesUnused(m_SRVs); + modif |= MarkResourcesUnused(m_UAVs); + modif |= MarkResourcesUnused(m_CBuffers); + modif |= MarkResourcesUnused(m_Samplers); + return modif; } namespace { @@ -1533,6 +1610,7 @@ void DxilModule::LoadDxilMetadata() { m_bUseMinPrecision = !m_ShaderFlags.GetUseNativeLowPrecision(); m_bDisableOptimizations = m_ShaderFlags.GetDisableOptimizations(); m_bAllResourcesBound = m_ShaderFlags.GetAllResourcesBound(); + m_unusedResourceBinding = m_ShaderFlags.GetUnusedResourceBinding(); m_bResMayAlias = !m_ShaderFlags.GetResMayNotAlias(); } diff --git a/lib/DXIL/DxilResourceBase.cpp b/lib/DXIL/DxilResourceBase.cpp index 4d74747b7a..3c786a558e 100644 --- a/lib/DXIL/DxilResourceBase.cpp +++ b/lib/DXIL/DxilResourceBase.cpp @@ -20,7 +20,7 @@ namespace hlsl { DxilResourceBase::DxilResourceBase(Class C) : m_Class(C), m_Kind(Kind::Invalid), m_ID(UINT_MAX), m_SpaceID(0), m_LowerBound(0), m_RangeSize(0), m_pSymbol(nullptr), m_pHandle(nullptr), - m_pHLSLTy(nullptr) {} + m_pHLSLTy(nullptr), m_IsUnused(false) {} DxilResourceBase::Class DxilResourceBase::GetClass() const { return m_Class; } DxilResourceBase::Kind DxilResourceBase::GetKind() const { return m_Kind; } @@ -48,6 +48,7 @@ llvm::Type *DxilResourceBase::GetHLSLType() const { } bool DxilResourceBase::IsAllocated() const { return m_LowerBound != UINT_MAX; } bool DxilResourceBase::IsUnbounded() const { return m_RangeSize == UINT_MAX; } +bool DxilResourceBase::IsUnused() const { return m_IsUnused; } void DxilResourceBase::SetClass(Class C) { m_Class = C; } void DxilResourceBase::SetID(unsigned ID) { m_ID = ID; } @@ -56,6 +57,7 @@ void DxilResourceBase::SetLowerBound(unsigned LB) { m_LowerBound = LB; } void DxilResourceBase::SetRangeSize(unsigned RangeSize) { m_RangeSize = RangeSize; } +void DxilResourceBase::SetIsUnused(bool IsUnused) { m_IsUnused = IsUnused; } void DxilResourceBase::SetGlobalSymbol(llvm::Constant *pGV) { m_pSymbol = pGV; } void DxilResourceBase::SetGlobalName(const std::string &Name) { m_Name = Name; } void DxilResourceBase::SetHandle(llvm::Value *pHandle) { m_pHandle = pHandle; } diff --git a/lib/DXIL/DxilShaderFlags.cpp b/lib/DXIL/DxilShaderFlags.cpp index 993038aaf1..9fc096dc86 100644 --- a/lib/DXIL/DxilShaderFlags.cpp +++ b/lib/DXIL/DxilShaderFlags.cpp @@ -47,7 +47,7 @@ ShaderFlags::ShaderFlags() m_bAdvancedTextureOps(false), m_bWriteableMSAATextures(false), m_bReserved(false), m_bSampleCmpGradientOrBias(false), m_bExtendedCommandInfo(false), m_bUsesDerivatives(false), - m_bRequiresGroup(false), m_align1(0) { + m_bRequiresGroup(false), m_UnusedResourceBinding(0), m_align1(0) { // Silence unused field warnings (void)m_align1; } @@ -412,6 +412,7 @@ ShaderFlags ShaderFlags::CollectShaderFlags(const Function *F, flag.SetUseNativeLowPrecision(!M->GetUseMinPrecision()); flag.SetDisableOptimizations(M->GetDisableOptimization()); flag.SetAllResourcesBound(M->GetAllResourcesBound()); + flag.SetUnusedResourceBinding(M->GetUnusedResourceBinding()); bool hasDouble = false; // ddiv dfma drcp d2i d2u i2d u2d. diff --git a/lib/DxcSupport/HLSLOptions.cpp b/lib/DxcSupport/HLSLOptions.cpp index 0c9330b1d1..232355b5b4 100644 --- a/lib/DxcSupport/HLSLOptions.cpp +++ b/lib/DxcSupport/HLSLOptions.cpp @@ -865,6 +865,21 @@ 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 == "keep-all") + opts.UnusedResourceBinding = UnusedResourceBinding::KeepAll; + else { + errors << "Error: Invalid value for -fhlsl-unused-resource-bindings option " + "specified (" + << UnusedResources << "). Must be one of: strip, keep-all"; + return 1; + } + 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..2dfc5f92d6 100644 --- a/lib/HLSL/DxilCondenseResources.cpp +++ b/lib/HLSL/DxilCondenseResources.cpp @@ -550,7 +550,8 @@ class DxilLowerCreateHandleForLib : public ModulePass { ResourceRegisterAllocator.GatherReservedRegisters(DM); // Remove unused resources. - DM.RemoveResourcesWithUnusedSymbols(); + if (DM.GetUnusedResourceBinding() == UnusedResourceBinding::Strip) + bChanged |= DM.RemoveResourcesWithUnusedSymbols(); unsigned newResources = DM.GetCBuffers().size() + DM.GetUAVs().size() + DM.GetSRVs().size() + DM.GetSamplers().size(); @@ -562,13 +563,18 @@ class DxilLowerCreateHandleForLib : public ModulePass { { DxilValueCache *DVC = &getAnalysis(); bool bLocalChanged = LegalizeResources(M, DVC); - if (bLocalChanged) { - // Remove unused resources. - DM.RemoveResourcesWithUnusedSymbols(); - } + if (bLocalChanged && + DM.GetUnusedResourceBinding() == UnusedResourceBinding::Strip) + bChanged |= DM.RemoveResourcesWithUnusedSymbols(); + bChanged |= bLocalChanged; } + if (DM.GetUnusedResourceBinding() == UnusedResourceBinding::KeepAll) { + bChanged |= DM.RemoveEmptyBuffers(); + bChanged |= DM.MarkUnusedResources(); + } + bChanged |= ResourceRegisterAllocator.AllocateRegisters(DM); // Fill in top-level CBuffer variable usage bit @@ -2122,6 +2128,15 @@ void DxilLowerCreateHandleForLib::ReplaceResourceUserWithHandle( void DxilLowerCreateHandleForLib::TranslateDxilResourceUses( DxilResourceBase &res) { OP *hlslOP = m_DM->GetOP(); + + Value *GV = res.GetGlobalSymbol(); + + if (isa(GV)) + return; + + DXASSERT(isa(GV), "DxilLowerCreateHandleForLib cannot deal with " + "resources that aren't GlobalValue."); + // Generate createHandleFromBinding for sm66 and later. bool bCreateFromBinding = m_DM->GetShaderModel()->IsSM66Plus(); OP::OpCode createOp = bCreateFromBinding ? OP::OpCode::CreateHandleFromBinding @@ -2149,10 +2164,6 @@ void DxilLowerCreateHandleForLib::TranslateDxilResourceUses( Value *isUniformRes = hlslOP->GetI1Const(0); - Value *GV = res.GetGlobalSymbol(); - DXASSERT(isa(GV), - "DxilLowerCreateHandleForLib cannot deal with unused resources."); - Module *pM = m_DM->GetModule(); // TODO: add debug info to create handle. DIVariable *DIV = nullptr; @@ -2327,6 +2338,7 @@ void InitTBuffer(const DxilCBuffer *pSource, DxilResource *pDest) { pDest->SetRW(false); pDest->SetROV(false); pDest->SetID(pSource->GetID()); + pDest->SetIsUnused(pSource->IsUnused()); pDest->SetSpaceID(pSource->GetSpaceID()); pDest->SetLowerBound(pSource->GetLowerBound()); pDest->SetRangeSize(pSource->GetRangeSize()); @@ -2539,6 +2551,7 @@ bool DxilLowerCreateHandleForLib::PatchTBuffers(DxilModule &DM) { auto srv = make_unique(); InitTBuffer(CB, srv.get()); srv->SetID(offset++); + srv->SetIsUnused(CB->IsUnused()); DM.AddSRV(std::move(srv)); GlobalVariable *GV = dyn_cast(CB->GetGlobalSymbol()); if (GV == nullptr) diff --git a/lib/HLSL/DxilContainerReflection.cpp b/lib/HLSL/DxilContainerReflection.cpp index 4cddab7b60..8a5f2f83e8 100644 --- a/lib/HLSL/DxilContainerReflection.cpp +++ b/lib/HLSL/DxilContainerReflection.cpp @@ -1779,10 +1779,17 @@ static D3D_SRV_DIMENSION ResourceToDimension(DxilResourceBase *RB) { } static UINT ResourceToFlags(DxilResourceBase *RB) { + + UINT isUnused = 0; + + if (RB->IsUnused()) + isUnused |= D3D_SIF_UNUSED; + if (RB->GetClass() == DXIL::ResourceClass::CBuffer) - return D3D_SIF_USERPACKED; - UINT result = 0; + return D3D_SIF_USERPACKED | isUnused; + DxilResource *R = DxilResourceFromBase(RB); + UINT result = 0; if (R != nullptr && (R->IsAnyTexture() || R->GetKind() == DXIL::ResourceKind::TypedBuffer)) { llvm::Type *RetTy = R->GetRetType(); @@ -1801,13 +1808,13 @@ static UINT ResourceToFlags(DxilResourceBase *RB) { } } } else if (R && R->IsTBuffer()) { - return D3D_SIF_USERPACKED; + return D3D_SIF_USERPACKED | isUnused; } else if (RB->GetClass() == DXIL::ResourceClass::Sampler) { DxilSampler *S = static_cast(RB); if (S->GetSamplerKind() == DXIL::SamplerKind::Comparison) result |= D3D_SIF_COMPARISON_SAMPLER; } - return result; + return result | isUnused; } void DxilModuleReflection::CreateReflectionObjectForResource( @@ -2790,6 +2797,7 @@ class CFunctionReflection final : public ID3D12FunctionReflection { std::string m_Name; typedef SmallSetVector ResourceUseSet; ResourceUseSet m_UsedResources; + ResourceUseSet m_UnusedResources; ResourceUseSet m_UsedCBs; UINT64 m_FeatureFlags; @@ -2809,9 +2817,17 @@ class CFunctionReflection final : public ID3D12FunctionReflection { } } void AddResourceReference(UINT resIndex) { m_UsedResources.insert(resIndex); } + void AddUnusedResourceReference(UINT resIndex) { + m_UnusedResources.insert(resIndex); + } void AddCBReference(UINT cbIndex) { m_UsedCBs.insert(cbIndex); } void SetFeatureFlags(UINT64 flags) { m_FeatureFlags = flags; } + bool HasBoundResource(UINT resIndex) const { + return std::find(m_UsedResources.begin(), m_UsedResources.end(), + resIndex) != m_UsedResources.end(); + } + // ID3D12FunctionReflection STDMETHOD(GetDesc)(D3D12_FUNCTION_DESC *pDesc); @@ -2850,7 +2866,8 @@ HRESULT CFunctionReflection::GetDesc(D3D12_FUNCTION_DESC *pDesc) { // Unset: UINT Flags; // Shader compilation/parse flags pDesc->ConstantBuffers = (UINT)m_UsedCBs.size(); - pDesc->BoundResources = (UINT)m_UsedResources.size(); + pDesc->BoundResources = + (UINT)(m_UsedResources.size() + m_UnusedResources.size()); // Unset: UINT InstructionCount; // Number of emitted instructions // Unset: UINT TempRegisterCount; // Number of temporary registers used @@ -2928,10 +2945,28 @@ CFunctionReflection::GetConstantBufferByName(LPCSTR Name) { HRESULT CFunctionReflection::GetResourceBindingDesc( UINT ResourceIndex, D3D12_SHADER_INPUT_BIND_DESC *pDesc) { DXASSERT_NOMSG(m_pLibraryReflection); - if (ResourceIndex >= m_UsedResources.size()) + + if (ResourceIndex >= (m_UsedResources.size() + m_UnusedResources.size())) return E_INVALIDARG; - return m_pLibraryReflection->_GetResourceBindingDesc( - m_UsedResources[ResourceIndex], pDesc); + + bool isUnused = ResourceIndex >= m_UsedResources.size(); + + HRESULT hr = m_pLibraryReflection->_GetResourceBindingDesc( + isUnused ? m_UnusedResources[ResourceIndex - m_UsedResources.size()] + : m_UsedResources[ResourceIndex], + pDesc); + + if (FAILED(hr)) + return hr; + + // Handling this here allows us to determine flags per function. + // Even though shader reflection may also set this if it determines a register + // is fully optimized out. + + if (isUnused) + pDesc->uFlags |= D3D_SIF_UNUSED; + + return S_OK; } ID3D12ShaderReflectionVariable * @@ -2980,6 +3015,10 @@ void DxilLibraryReflection::AddResourceDependencies() { IFTBOOL(resourceTable.Count() == m_Resources.size(), DXC_E_INCORRECT_DXIL_METADATA); + bool keepAllResources = + m_pModule->GetDxilModule().GetUnusedResourceBinding() == + UnusedResourceBinding::KeepAll; + for (unsigned iFunc = 0; iFunc < functionTable.Count(); ++iFunc) { auto FR = functionTable[iFunc]; auto &func = m_FunctionMap[FR.getName()]; @@ -3030,7 +3069,60 @@ void DxilLibraryReflection::AddResourceDependencies() { } for (auto &it : orderedMap) { - m_FunctionVector.push_back(it.second); + + CFunctionReflection *func = it.second; + + if (keepAllResources) { + + for (uint64_t i = 0; i < resourceTable.size(); ++i) { + + const auto &res = resourceTable[i]; + std::string resName = res.getName(); + + uint32_t offset = 0; + + bool isCBuffer = false; + + switch (res.getClass()) { + case DXIL::ResourceClass::CBuffer: + isCBuffer = true; + offset = 0; + break; + case DXIL::ResourceClass::Sampler: + offset = SamplersStart; + break; + case DXIL::ResourceClass::SRV: + offset = SRVsStart; + break; + case DXIL::ResourceClass::UAV: + offset = UAVsStart; + break; + } + + uint32_t id = offset + res.getID(); + + if (func->HasBoundResource(id)) + continue; + + func->AddUnusedResourceReference(id); + + bool isTBuffer = res.getKind() == DXIL::ResourceKind::TBuffer; + + if (isCBuffer || isTBuffer) { + auto it = m_CBsByName.find(resName); + if (it != m_CBsByName.end()) + func->AddCBReference(it->second); + } + + else if (DXIL::IsStructuredBuffer(res.getKind())) { + auto it = m_StructuredBufferCBsByName.find(resName + "[0]"); + if (it != m_StructuredBufferCBsByName.end()) + func->AddCBReference(it->second); + } + } + } + + m_FunctionVector.push_back(func); } } diff --git a/lib/HLSL/DxilGenerationPass.cpp b/lib/HLSL/DxilGenerationPass.cpp index c3a6ad7dfc..16f11a6894 100644 --- a/lib/HLSL/DxilGenerationPass.cpp +++ b/lib/HLSL/DxilGenerationPass.cpp @@ -70,6 +70,7 @@ void InitResourceBase(const DxilResourceBase *pSource, DXASSERT_NOMSG(pSource->GetClass() == pDest->GetClass()); pDest->SetKind(pSource->GetKind()); pDest->SetID(pSource->GetID()); + pDest->SetIsUnused(pSource->IsUnused()); pDest->SetSpaceID(pSource->GetSpaceID()); pDest->SetLowerBound(pSource->GetLowerBound()); pDest->SetRangeSize(pSource->GetRangeSize()); @@ -155,6 +156,8 @@ void InitDxilModuleFromHLModule(HLModule &H, DxilModule &M, bool HasDebugInfo) { // bool m_bDisableOptimizations; M.SetDisableOptimization(H.GetHLOptions().bDisableOptimizations); M.SetLegacyResourceReservation(H.GetHLOptions().bLegacyResourceReservation); + M.SetUnusedResourceBinding( + UnusedResourceBinding(H.GetHLOptions().bUnusedResourceBinding)); // bool m_bDisableMathRefactoring; // bool m_bEnableDoublePrecision; // bool m_bEnableDoubleExtensions; diff --git a/lib/HLSL/HLModule.cpp b/lib/HLSL/HLModule.cpp index bab6e23a30..caf980435f 100644 --- a/lib/HLSL/HLModule.cpp +++ b/lib/HLSL/HLModule.cpp @@ -231,12 +231,14 @@ void HLModule::RemoveFunction(llvm::Function *F) { namespace { template bool RemoveResource(std::vector> &vec, - GlobalVariable *pVariable, bool keepAllocated) { + GlobalVariable *pVariable, bool keepAllocated, + UnusedResourceBinding unusedResourceBinding) { for (auto p = vec.begin(), e = vec.end(); p != e; ++p) { if ((*p)->GetGlobalSymbol() != pVariable) continue; - if (keepAllocated && (*p)->IsAllocated()) { + if ((keepAllocated && (*p)->IsAllocated()) || + unusedResourceBinding == UnusedResourceBinding::KeepAll) { // Keep the resource, but it has no more symbol. (*p)->SetGlobalSymbol(UndefValue::get(pVariable->getType())); } else { @@ -262,16 +264,19 @@ void HLModule::RemoveGlobal(llvm::GlobalVariable *GV) { // register range from being allocated to other resources. bool keepAllocated = GetHLOptions().bLegacyResourceReservation; + UnusedResourceBinding unusedResourceBinding = + UnusedResourceBinding(GetHLOptions().bUnusedResourceBinding); + // 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, unusedResourceBinding)) return; - if (RemoveResource(m_SRVs, GV, keepAllocated)) + if (RemoveResource(m_SRVs, GV, keepAllocated, unusedResourceBinding)) return; - if (RemoveResource(m_UAVs, GV, keepAllocated)) + if (RemoveResource(m_UAVs, GV, keepAllocated, unusedResourceBinding)) return; - if (RemoveResource(m_Samplers, GV, keepAllocated)) + if (RemoveResource(m_Samplers, GV, keepAllocated, unusedResourceBinding)) 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..b69cf75360 100644 --- a/tools/clang/include/clang/Frontend/CodeGenOptions.h +++ b/tools/clang/include/clang/Frontend/CodeGenOptions.h @@ -187,6 +187,9 @@ class CodeGenOptions : public CodeGenOptionsBase { 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..c4edd003de 100644 --- a/tools/clang/lib/CodeGen/CGHLSLMS.cpp +++ b/tools/clang/lib/CodeGen/CGHLSLMS.cpp @@ -400,6 +400,8 @@ CGMSHLSLRuntime::CGMSHLSLRuntime(CodeGenModule &CGM) opts.PackingStrategy = CGM.getCodeGenOpts().HLSLSignaturePackingStrategy; opts.bLegacyResourceReservation = CGM.getCodeGenOpts().HLSLLegacyResourceReservation; + opts.bUnusedResourceBinding = + unsigned(CGM.getCodeGenOpts().HLSLUnusedResourceBinding); opts.bForceZeroStoreLifetimes = CGM.getCodeGenOpts().HLSLForceZeroStoreLifetimes; diff --git a/tools/clang/test/HLSLFileCheck/d3dreflect/keep_all_resources.hlsl b/tools/clang/test/HLSLFileCheck/d3dreflect/keep_all_resources.hlsl new file mode 100644 index 0000000000..8fbfcaa78b --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/d3dreflect/keep_all_resources.hlsl @@ -0,0 +1,83 @@ +// RUN: %dxc -T lib_6_3 -auto-binding-space 11 -default-linkage external -fhlsl-unused-resource-bindings=keep-all %s | %D3DReflect %s | FileCheck %s -check-prefix=CHECK +// RUN: %dxc -T cs_6_3 -E main -auto-binding-space 11 -fhlsl-unused-resource-bindings=keep-all %s | %D3DReflect %s | FileCheck %s -check-prefix=CHECK2 + +struct Foo +{ + float4 a; + uint b; +}; + +RWStructuredBuffer g_buffer[2] : register(u0); +Texture2D g_test : register(t0); +SamplerState g_sampler : register(s0); + +cbuffer tes2 { float a; }; + +RWTexture2D g_output : register(u2); + +[shader("compute")] +[numthreads(1,1,1)] +void main() { g_output[0.xx] = 0.xxxx; } + +// 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: 5 +// CHECK: Bound Resources: +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: g_output +// CHECK: Type: D3D_SIT_UAV_RWTYPED +// CHECK: BindPoint: 2 +// CHECK: Space: 0 +// CHECK: uFlags: (D3D_SIF_TEXTURE_COMPONENT_0 | D3D_SIF_TEXTURE_COMPONENT_1) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: tes2 +// CHECK: BindPoint: 0 +// CHECK: Space: 11 +// CHECK: uFlags: (D3D_SIF_USERPACKED | D3D_SIF_UNUSED +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: g_sampler +// CHECK: Type: D3D_SIT_SAMPLER +// CHECK: BindPoint: 0 +// CHECK: Space: 0 +// CHECK: uFlags: (D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: g_test +// CHECK: Type: D3D_SIT_TEXTURE +// CHECK: BindPoint: 0 +// CHECK: Space: 0 +// CHECK: uFlags: (D3D_SIF_TEXTURE_COMPONENT_0 | D3D_SIF_TEXTURE_COMPONENT_1 | D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: g_buffer +// CHECK: Type: D3D_SIT_UAV_RWSTRUCTURED +// CHECK: BindPoint: 0 +// CHECK: Space: 0 +// CHECK: uFlags: (D3D_SIF_UNUSED) + + +// CHECK2: ID3D12ShaderReflection: +// CHECK2: D3D12_SHADER_DESC: +// CHECK2: BoundResources: 5 +// CHECK2: Bound Resources: +// CHECK2: D3D12_SHADER_INPUT_BIND_DESC: Name: tes2 +// CHECK2: BindPoint: 0 +// CHECK2: Space: 11 +// CHECK2: uFlags: (D3D_SIF_USERPACKED | D3D_SIF_UNUSED +// CHECK2: D3D12_SHADER_INPUT_BIND_DESC: Name: g_sampler +// CHECK2: Type: D3D_SIT_SAMPLER +// CHECK2: BindPoint: 0 +// CHECK2: Space: 0 +// CHECK2: uFlags: (D3D_SIF_UNUSED) +// CHECK2: D3D12_SHADER_INPUT_BIND_DESC: Name: g_test +// CHECK2: Type: D3D_SIT_TEXTURE +// CHECK2: BindPoint: 0 +// CHECK2: Space: 0 +// CHECK2: uFlags: (D3D_SIF_TEXTURE_COMPONENT_0 | D3D_SIF_TEXTURE_COMPONENT_1 | D3D_SIF_UNUSED) +// CHECK2: D3D12_SHADER_INPUT_BIND_DESC: Name: g_buffer +// CHECK2: Type: D3D_SIT_UAV_RWSTRUCTURED +// CHECK2: BindPoint: 0 +// CHECK2: Space: 0 +// CHECK2: uFlags: (D3D_SIF_UNUSED) +// CHECK2: D3D12_SHADER_INPUT_BIND_DESC: Name: g_output +// CHECK2: Type: D3D_SIT_UAV_RWTYPED +// CHECK2: BindPoint: 2 +// CHECK2: Space: 0 +// CHECK2: uFlags: (D3D_SIF_TEXTURE_COMPONENT_0 | D3D_SIF_TEXTURE_COMPONENT_1) diff --git a/tools/clang/test/HLSLFileCheck/d3dreflect/keep_all_resources_complex.hlsl b/tools/clang/test/HLSLFileCheck/d3dreflect/keep_all_resources_complex.hlsl new file mode 100644 index 0000000000..6dba14b0ab --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/d3dreflect/keep_all_resources_complex.hlsl @@ -0,0 +1,209 @@ +// RUN: %dxc -T lib_6_3 -auto-binding-space 0 -fhlsl-unused-resource-bindings=keep-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) { } + +// 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: uFlags: (D3D_SIF_USERPACKED | D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: test +// CHECK: Type: D3D_SIT_CBUFFER +// CHECK: BindPoint: 0 +// CHECK: Space: 0 +// CHECK: uFlags: (D3D_SIF_USERPACKED | D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: test2 +// CHECK: Type: D3D_SIT_CBUFFER +// CHECK: BindPoint: 2 +// CHECK: Space: 0 +// CHECK: uFlags: (D3D_SIF_USERPACKED | D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: test3 +// CHECK: Type: D3D_SIT_CBUFFER +// CHECK: BindPoint: 0 +// CHECK: Space: 1 +// CHECK: uFlags: (D3D_SIF_USERPACKED | D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: test4 +// CHECK: Type: D3D_SIT_CBUFFER +// CHECK: BindPoint: 1 +// CHECK: Space: 1 +// CHECK: uFlags: (D3D_SIF_USERPACKED | D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: sampler0 +// CHECK: Type: D3D_SIT_SAMPLER +// CHECK: BindPoint: 1 +// CHECK: Space: 0 +// CHECK: uFlags: (D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: sampler1 +// CHECK: Type: D3D_SIT_SAMPLER +// CHECK: BindPoint: 2 +// CHECK: Space: 0 +// CHECK: uFlags: (D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: sampler2 +// CHECK: Type: D3D_SIT_SAMPLER +// CHECK: BindPoint: 0 +// CHECK: Space: 0 +// CHECK: uFlags: (D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: sampler3 +// CHECK: Type: D3D_SIT_SAMPLER +// CHECK: BindPoint: 1 +// CHECK: Space: 1 +// CHECK: uFlags: (D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: sampler4 +// CHECK: Type: D3D_SIT_SAMPLER +// CHECK: BindPoint: 0 +// CHECK: Space: 1 +// CHECK: uFlags: (D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: test5 +// CHECK: Type: D3D_SIT_STRUCTURED +// CHECK: BindPoint: 1 +// CHECK: Space: 0 +// CHECK: uFlags: (D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: input13 +// CHECK: Type: D3D_SIT_BYTEADDRESS +// CHECK: BindPoint: 2 +// CHECK: Space: 0 +// CHECK: uFlags: (D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: input14 +// CHECK: Type: D3D_SIT_BYTEADDRESS +// CHECK: BindPoint: 15 +// CHECK: Space: 0 +// CHECK: uFlags: (D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: input15 +// CHECK: Type: D3D_SIT_BYTEADDRESS +// CHECK: BindPoint: 0 +// CHECK: Space: 0 +// CHECK: uFlags: (D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: input16 +// CHECK: Type: D3D_SIT_BYTEADDRESS +// CHECK: BindPoint: 3 +// CHECK: Space: 0 +// CHECK: uFlags: (D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: input17 +// CHECK: Type: D3D_SIT_BYTEADDRESS +// CHECK: BindPoint: 13 +// CHECK: Space: 1 +// CHECK: uFlags: (D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: input18 +// CHECK: Type: D3D_SIT_BYTEADDRESS +// CHECK: BindPoint: 1 +// CHECK: Space: 1 +// CHECK: uFlags: (D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: input19 +// CHECK: Type: D3D_SIT_BYTEADDRESS +// CHECK: BindPoint: 15 +// CHECK: Space: 1 +// CHECK: uFlags: (D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: input20 +// CHECK: Type: D3D_SIT_BYTEADDRESS +// CHECK: BindPoint: 0 +// CHECK: Space: 1 +// CHECK: uFlags: (D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: tex +// CHECK: BindPoint: 16 +// CHECK: Space: 0 +// CHECK: uFlags: (D3D_SIF_TEXTURE_COMPONENT_0 | D3D_SIF_TEXTURE_COMPONENT_1 | D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: output1 +// CHECK: Type: D3D_SIT_UAV_RWBYTEADDRESS +// CHECK: BindPoint: 2 +// CHECK: Space: 0 +// CHECK: uFlags: (D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: output2 +// CHECK: Type: D3D_SIT_UAV_RWBYTEADDRESS +// CHECK: BindPoint: 15 +// CHECK: Space: 0 +// CHECK: uFlags: (D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: output3 +// CHECK: Type: D3D_SIT_UAV_RWBYTEADDRESS +// CHECK: BindPoint: 0 +// CHECK: Space: 0 +// CHECK: uFlags: (D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: output4 +// CHECK: BindPoint: 0 +// CHECK: Space: 1 +// CHECK: uFlags: (D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: output5 +// CHECK: Type: D3D_SIT_UAV_RWBYTEADDRESS +// CHECK: BindPoint: 16 +// CHECK: Space: 0 +// CHECK: uFlags: (D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: output6 +// CHECK: Type: D3D_SIT_UAV_RWBYTEADDRESS +// CHECK: BindPoint: 17 +// CHECK: Space: 0 +// CHECK: uFlags: (D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: output7 +// CHECK: Type: D3D_SIT_UAV_RWBYTEADDRESS +// CHECK: BindPoint: 1 +// CHECK: Space: 0 +// CHECK: uFlags: (D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: output8 +// CHECK: Type: D3D_SIT_UAV_RWBYTEADDRESS +// CHECK: BindPoint: 3 +// CHECK: Space: 0 +// CHECK: uFlags: (D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: output9 +// CHECK: Type: D3D_SIT_UAV_RWBYTEADDRESS +// CHECK: BindPoint: 18 +// CHECK: Space: 0 +// CHECK: uFlags: (D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: output10 +// CHECK: Type: D3D_SIT_UAV_RWBYTEADDRESS +// CHECK: BindPoint: 1 +// CHECK: Space: 1 +// CHECK: uFlags: (D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: output11 +// CHECK: Type: D3D_SIT_UAV_RWBYTEADDRESS +// CHECK: BindPoint: 33 +// CHECK: Space: 2 +// CHECK: uFlags: (D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: output12 +// CHECK: Type: D3D_SIT_UAV_RWBYTEADDRESS +// CHECK: BindPoint: 0 +// CHECK: Space: 2 +// CHECK: uFlags: (D3D_SIF_UNUSED) \ No newline at end of file diff --git a/tools/clang/test/HLSLFileCheck/d3dreflect/keep_all_resources_multiple_entrypoints.hlsl b/tools/clang/test/HLSLFileCheck/d3dreflect/keep_all_resources_multiple_entrypoints.hlsl new file mode 100644 index 0000000000..92745d6aae --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/d3dreflect/keep_all_resources_multiple_entrypoints.hlsl @@ -0,0 +1,85 @@ +// RUN: %dxc -T lib_6_3 -auto-binding-space 11 -fhlsl-unused-resource-bindings=keep-all %s | %D3DReflect %s | FileCheck %s + +struct Foo +{ + float4 a; + uint b; +}; + +RWStructuredBuffer g_buffer[2] : register(u0); +Texture2D g_test : register(t0); +SamplerState g_sampler : register(s0); + +cbuffer tes2 { float a; }; + +RWTexture2D g_output : register(u2); + +[shader("compute")] +[numthreads(1,1,1)] +void main() { g_output[0.xx] = 0.xxxx; } + +[shader("compute")] +[numthreads(1,1,1)] +void main2() { g_buffer[0][0] = (Foo) 0; } + +// CHECK: ID3D12LibraryReflection: +// CHECK: D3D12_LIBRARY_DESC: +// CHECK: FunctionCount: 2 +// CHECK: ID3D12FunctionReflection: +// CHECK: D3D12_FUNCTION_DESC: Name: main +// CHECK: Shader Version: Compute 6.3 +// CHECK: BoundResources: 5 +// CHECK: Bound Resources: +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: g_output +// CHECK: Type: D3D_SIT_UAV_RWTYPED +// CHECK: BindPoint: 2 +// CHECK: Space: 0 +// CHECK: uFlags: (D3D_SIF_TEXTURE_COMPONENT_0 | D3D_SIF_TEXTURE_COMPONENT_1) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: tes2 +// CHECK: BindPoint: 0 +// CHECK: Space: 11 +// CHECK: uFlags: (D3D_SIF_USERPACKED | D3D_SIF_UNUSED +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: g_sampler +// CHECK: Type: D3D_SIT_SAMPLER +// CHECK: BindPoint: 0 +// CHECK: Space: 0 +// CHECK: uFlags: (D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: g_test +// CHECK: Type: D3D_SIT_TEXTURE +// CHECK: BindPoint: 0 +// CHECK: Space: 0 +// CHECK: uFlags: (D3D_SIF_TEXTURE_COMPONENT_0 | D3D_SIF_TEXTURE_COMPONENT_1 | D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: g_buffer +// CHECK: Type: D3D_SIT_UAV_RWSTRUCTURED +// CHECK: BindPoint: 0 +// CHECK: Space: 0 +// CHECK: uFlags: (D3D_SIF_UNUSED) +// CHECK: ID3D12FunctionReflection: +// CHECK: D3D12_FUNCTION_DESC: Name: main2 +// CHECK: Shader Version: Compute 6.3 +// CHECK: BoundResources: 5 +// CHECK: Bound Resources: +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: g_buffer +// CHECK: Type: D3D_SIT_UAV_RWSTRUCTURED +// CHECK: BindPoint: 0 +// CHECK: Space: 0 +// CHECK: uFlags: 0 +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: tes2 +// CHECK: BindPoint: 0 +// CHECK: Space: 11 +// CHECK: uFlags: (D3D_SIF_USERPACKED | D3D_SIF_UNUSED +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: g_sampler +// CHECK: Type: D3D_SIT_SAMPLER +// CHECK: BindPoint: 0 +// CHECK: Space: 0 +// CHECK: uFlags: (D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: g_test +// CHECK: Type: D3D_SIT_TEXTURE +// CHECK: BindPoint: 0 +// CHECK: Space: 0 +// CHECK: uFlags: (D3D_SIF_TEXTURE_COMPONENT_0 | D3D_SIF_TEXTURE_COMPONENT_1 | D3D_SIF_UNUSED) +// CHECK: D3D12_SHADER_INPUT_BIND_DESC: Name: g_output +// CHECK: Type: D3D_SIT_UAV_RWTYPED +// CHECK: BindPoint: 2 +// CHECK: Space: 0 +// CHECK: uFlags: (D3D_SIF_TEXTURE_COMPONENT_0 | D3D_SIF_TEXTURE_COMPONENT_1 | D3D_SIF_UNUSED) diff --git a/tools/clang/tools/dxcompiler/dxcompilerobj.cpp b/tools/clang/tools/dxcompiler/dxcompilerobj.cpp index 230047b4a8..f96cc7e6d3 100644 --- a/tools/clang/tools/dxcompiler/dxcompilerobj.cpp +++ b/tools/clang/tools/dxcompiler/dxcompilerobj.cpp @@ -1595,6 +1595,8 @@ class DxcCompiler : public IDxcCompiler3, 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;