diff options
| author | azhirnov <zh1dron@gmail.com> | 2021-02-05 21:35:37 +0000 |
|---|---|---|
| committer | assiduous <assiduous@diligentgraphics.com> | 2021-03-19 00:31:35 +0000 |
| commit | 78fa6c94992a6d1a140da1354448a004e62c9683 (patch) | |
| tree | c21183a39d58ba9ccc89d9d8ea6fe1aa9de2ec35 /Graphics/GraphicsEngineD3D12 | |
| parent | Merged master (diff) | |
| download | DiligentCore-78fa6c94992a6d1a140da1354448a004e62c9683.tar.gz DiligentCore-78fa6c94992a6d1a140da1354448a004e62c9683.zip | |
merged with resource_signature
Diffstat (limited to 'Graphics/GraphicsEngineD3D12')
21 files changed, 3860 insertions, 4227 deletions
diff --git a/Graphics/GraphicsEngineD3D12/CMakeLists.txt b/Graphics/GraphicsEngineD3D12/CMakeLists.txt index a4f0c4c9..84c1d47c 100644 --- a/Graphics/GraphicsEngineD3D12/CMakeLists.txt +++ b/Graphics/GraphicsEngineD3D12/CMakeLists.txt @@ -31,7 +31,6 @@ set(INCLUDE include/ShaderD3D12Impl.hpp include/ShaderResourceBindingD3D12Impl.hpp include/ShaderResourceCacheD3D12.hpp - include/ShaderResourceLayoutD3D12.hpp include/ShaderResourcesD3D12.hpp include/ShaderVariableD3D12.hpp include/SwapChainD3D12Impl.hpp @@ -40,6 +39,7 @@ set(INCLUDE include/BottomLevelASD3D12Impl.hpp include/TopLevelASD3D12Impl.hpp include/ShaderBindingTableD3D12Impl.hpp + include/PipelineResourceSignatureD3D12Impl.hpp ) set(INTERFACE @@ -89,7 +89,6 @@ set(SRC src/ShaderD3D12Impl.cpp src/ShaderResourceBindingD3D12Impl.cpp src/ShaderResourceCacheD3D12.cpp - src/ShaderResourceLayoutD3D12.cpp src/ShaderResourcesD3D12.cpp src/ShaderVariableD3D12.cpp src/SwapChainD3D12Impl.cpp @@ -98,6 +97,7 @@ set(SRC src/BottomLevelASD3D12Impl.cpp src/TopLevelASD3D12Impl.cpp src/ShaderBindingTableD3D12Impl.cpp + src/PipelineResourceSignatureD3D12Impl.cpp ) if(PLATFORM_WIN32) diff --git a/Graphics/GraphicsEngineD3D12/include/CommandContext.hpp b/Graphics/GraphicsEngineD3D12/include/CommandContext.hpp index a51ec38b..a71c0bd6 100644 --- a/Graphics/GraphicsEngineD3D12/include/CommandContext.hpp +++ b/Graphics/GraphicsEngineD3D12/include/CommandContext.hpp @@ -156,7 +156,7 @@ public: { return pSrvCbvUavHeap == rhs.pSrvCbvUavHeap && pSamplerHeap == rhs.pSamplerHeap; } - operator bool() const + explicit operator bool() const { return pSrvCbvUavHeap != nullptr || pSamplerHeap != nullptr; } @@ -248,6 +248,7 @@ protected: class ComputeContext : public CommandContext { public: + // For compute and ray tracing. void SetComputeRootSignature(ID3D12RootSignature* pRootSig) { if (pRootSig != m_pCurComputeRootSignature) diff --git a/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.hpp index 39ac2431..5ed3a1dc 100644 --- a/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.hpp @@ -386,6 +386,37 @@ private: ID3D12Resource*& pd3d12ArgsBuff, Uint64& BuffDataStartByteOffset); + struct RootTableInfo + { + using Bitfield = Uint8; + static_assert(sizeof(Bitfield) * 8 >= MAX_RESOURCE_SIGNATURES, "not enought space to store MAX_RESOURCE_SIGNATURES bits"); + + //Bitfield ActiveSRBMask ; // Indicates which SRBs are active in current PSO + bool bRootViewsCommitted; // Indicates if root views have been committed since the time SRB has been committed. + bool bRootTablesCommited; + bool IsCompute : 1; + ID3D12RootSignature* pRootSig; + + std::array<class ShaderResourceBindingD3D12Impl*, MAX_RESOURCE_SIGNATURES> SRBs; + + RootTableInfo(bool _IsCompute) + { + memset(this, 0, sizeof(*this)); + IsCompute = _IsCompute; + } + + __forceinline bool RequireUpdate(bool DynamicBuffersIntact = false) const + { + return true; //(StaleSRBMask & ActiveSRBMask) != 0 || ((DynamicBuffersMask & ActiveSRBMask) != 0 && !DynamicBuffersIntact); + } + }; + __forceinline RootTableInfo& GetRootTableInfo(PIPELINE_TYPE PipelineType); + + __forceinline void CommitRootTables(RootTableInfo& RootInfo); +#ifdef DILIGENT_DEVELOPMENT + void DvpValidateCommittedShaderResources(); +#endif + struct TextureUploadSpace { D3D12DynamicAllocation Allocation; @@ -424,13 +455,13 @@ private: // Indicates if currently committed D3D11 index buffer is up to date bool bCommittedD3D12IBUpToDate = false; - // Indicates if root views have been committed since the time SRB - // has been committed. - bool bRootViewsCommitted = false; - - class ShaderResourceCacheD3D12* pCommittedResourceCache = nullptr; + // AZ TODO + bool CommittedResourcesValidated = false; } m_State; + RootTableInfo m_GraphicsResources; + RootTableInfo m_ComputeResources; + CComPtr<ID3D12CommandSignature> m_pDrawIndirectSignature; CComPtr<ID3D12CommandSignature> m_pDrawIndexedIndirectSignature; CComPtr<ID3D12CommandSignature> m_pDispatchIndirectSignature; diff --git a/Graphics/GraphicsEngineD3D12/include/PipelineResourceSignatureD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/PipelineResourceSignatureD3D12Impl.hpp new file mode 100644 index 00000000..db5b4030 --- /dev/null +++ b/Graphics/GraphicsEngineD3D12/include/PipelineResourceSignatureD3D12Impl.hpp @@ -0,0 +1,482 @@ +/* + * Copyright 2019-2021 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +/// \file +/// Declaration of Diligent::PipelineResourceSignatureD3D12Impl class + +#include <array> + +#include "PipelineResourceSignatureBase.hpp" +#include "SRBMemoryAllocator.hpp" + +namespace Diligent +{ + +class CommandContext; +class RenderDeviceD3D12Impl; +class DeviceContextD3D12Impl; +class ShaderResourceCacheD3D12; +class ShaderVariableManagerD3D12; + +/// Implementation of the Diligent::PipelineResourceSignatureD3D12Impl class +class PipelineResourceSignatureD3D12Impl final : public PipelineResourceSignatureBase<IPipelineResourceSignature, RenderDeviceD3D12Impl> +{ + friend class RootSignatureD3D12; + +public: + using TPipelineResourceSignatureBase = PipelineResourceSignatureBase<IPipelineResourceSignature, RenderDeviceD3D12Impl>; + + PipelineResourceSignatureD3D12Impl(IReferenceCounters* pRefCounters, + RenderDeviceD3D12Impl* pDevice, + const PipelineResourceSignatureDesc& Desc, + bool bIsDeviceInternal = false); + ~PipelineResourceSignatureD3D12Impl(); + + enum class CacheContentType + { + Signature = 0, // only static resources + SRB = 1 // in SRB + }; + + // sizeof(ResourceAttribs) == 16, x64 + struct ResourceAttribs + { + private: + static constexpr Uint32 _BindPointBits = 16; + static constexpr Uint32 _SpaceBits = 8; + static constexpr Uint32 _SRBRootIndexBits = 16; + static constexpr Uint32 _SigRootIndexBits = 3; + static constexpr Uint32 _SamplerIndBits = 16; + static constexpr Uint32 _SamplerAssignedBits = 1; + static constexpr Uint32 _SigOffsetBits = 16; + static constexpr Uint32 _RootViewBits = 1; + + static_assert((1u << _BindPointBits) >= MAX_RESOURCES_IN_SIGNATURE, "Not enough bits to store bind point"); + static_assert((1u << _SamplerIndBits) >= MAX_RESOURCES_IN_SIGNATURE, "Not enough bits to store sampler resource index"); + + public: + static constexpr Uint32 InvalidSamplerInd = (1u << _SamplerIndBits) - 1; + static constexpr Uint32 InvalidSRBRootIndex = (1u << _SRBRootIndexBits) - 1; + static constexpr Uint32 InvalidSigRootIndex = (1u << _SigRootIndexBits) - 1; + static constexpr Uint32 InvalidBindPoint = (1u << _BindPointBits) - 1; + static constexpr Uint32 InvalidOffset = ~0u; + + // clang-format off + const Uint32 BindPoint : _BindPointBits; // shader register + const Uint32 SRBRootIndex : _SRBRootIndexBits; // Root view/table index for SRB + const Uint32 SamplerInd : _SamplerIndBits; // Index in m_Desc.Resources and m_pResourceAttribs + const Uint32 SigRootIndex : _SigRootIndexBits; // Root table index for signature (static only) + const Uint32 Space : _SpaceBits; // shader register space + const Uint32 ImtblSamplerAssigned : _SamplerAssignedBits; // Immutable sampler flag + const Uint32 RootView : _RootViewBits; // Is root view (for debugging) + const Uint32 SigOffsetFromTableStart; // Offset in the root table for signature (static only) + const Uint32 SRBOffsetFromTableStart; // Offset in the root table for SRB + // clang-format on + + ResourceAttribs(Uint32 _BindPoint, + Uint32 _Space, + Uint32 _SamplerInd, + Uint32 _SRBRootIndex, + Uint32 _SRBOffsetFromTableStart, + Uint32 _SigRootIndex, + Uint32 _SigOffsetFromTableStart, + bool _ImtblSamplerAssigned, + bool _IsRootView) noexcept : + // clang-format off + BindPoint {_BindPoint }, + SRBRootIndex {_SRBRootIndex }, + SamplerInd {_SamplerInd }, + SigRootIndex {_SigRootIndex }, + Space {_Space }, + ImtblSamplerAssigned {_ImtblSamplerAssigned ? 1u : 0u}, + RootView {_IsRootView ? 1u : 0u }, + SigOffsetFromTableStart{_SigOffsetFromTableStart }, + SRBOffsetFromTableStart{_SRBOffsetFromTableStart } + // clang-format on + { + VERIFY(BindPoint == _BindPoint, "Bind point (", _BindPoint, ") exceeds maximum representable value"); + VERIFY(SRBRootIndex == _SRBRootIndex, "SRB Root index (", _SRBRootIndex, ") exceeds maximum representable value"); + VERIFY(SigRootIndex == _SigRootIndex, "Signature Root index (", SigRootIndex, ") exceeds maximum representable value"); + VERIFY(SamplerInd == _SamplerInd, "Sampler index (", _SamplerInd, ") exceeds maximum representable value"); + VERIFY(Space == _Space, "Space (", Space, ") exceeds maximum representable value"); + } + + bool IsImmutableSamplerAssigned() const { return ImtblSamplerAssigned != 0; } + bool IsCombinedWithSampler() const { return SamplerInd != InvalidSamplerInd; } + bool IsRootView() const { return RootView != 0; } + + Uint32 RootIndex(CacheContentType Type) const { return Type == CacheContentType::SRB ? SRBRootIndex : SigRootIndex; } + Uint32 OffsetFromTableStart(CacheContentType Type) const { return Type == CacheContentType::SRB ? SRBOffsetFromTableStart : SigOffsetFromTableStart; } + }; + + const ResourceAttribs& GetResourceAttribs(Uint32 ResIndex) const + { + VERIFY_EXPR(ResIndex < m_Desc.NumResources); + return m_pResourceAttribs[ResIndex]; + } + + const PipelineResourceDesc& GetResourceDesc(Uint32 ResIndex) const + { + VERIFY_EXPR(ResIndex < m_Desc.NumResources); + return m_Desc.Resources[ResIndex]; + } + + struct ImmutableSamplerAttribs + { + private: + static constexpr Uint32 _ShaderRegisterBits = 16; + static constexpr Uint32 _RegisterSpaceBits = 16; + static constexpr Uint32 _InvalidShaderRegister = (1u << _ShaderRegisterBits) - 1; + static constexpr Uint32 _InvalidRegisterSpace = (1u << _RegisterSpaceBits) - 1; + + public: + Uint32 ArraySize = 1; + Uint32 ShaderRegister : _ShaderRegisterBits; + Uint32 RegisterSpace : _RegisterSpaceBits; + + ImmutableSamplerAttribs() : + ShaderRegister{_InvalidShaderRegister}, + RegisterSpace{_InvalidRegisterSpace} + {} + + ImmutableSamplerAttribs(Uint32 _ArraySize, + Uint32 _ShaderRegister, + Uint32 _RegisterSpace) noexcept : + // clang-format off + ArraySize {_ArraySize }, + ShaderRegister{_ShaderRegister}, + RegisterSpace {_RegisterSpace } + // clang-format on + { + VERIFY(ShaderRegister == _ShaderRegister, "Shader register (", _ShaderRegister, ") exceeds maximum representable value"); + VERIFY(RegisterSpace == _RegisterSpace, "Shader register space (", _RegisterSpace, ") exceeds maximum representable value"); + } + + bool IsAssigned() const { return ShaderRegister != _InvalidShaderRegister; } + }; + + const ImmutableSamplerAttribs& GetImmutableSamplerAttribs(Uint32 SampIndex) const + { + VERIFY_EXPR(SampIndex < m_Desc.NumImmutableSamplers); + return m_ImmutableSamplers[SampIndex]; + } + + const ImmutableSamplerDesc& GetImmutableSamplerDesc(Uint32 SampIndex) const + { + VERIFY_EXPR(SampIndex < m_Desc.NumImmutableSamplers); + return m_Desc.ImmutableSamplers[SampIndex]; + } + + Uint32 GetTotalRootCount() const + { + return m_RootParams.GetNumRootTables() + m_RootParams.GetNumRootViews(); + } + + Uint32 GetBaseRegisterSpace() const + { + return m_Desc.BindingIndex * MAX_SPACES_PER_SIGNATURE; + } + + virtual void DILIGENT_CALL_TYPE CreateShaderResourceBinding(IShaderResourceBinding** ppShaderResourceBinding, + bool InitStaticResources) override final; + + virtual IShaderResourceVariable* DILIGENT_CALL_TYPE GetStaticVariableByName(SHADER_TYPE ShaderType, const Char* Name) override final; + + virtual IShaderResourceVariable* DILIGENT_CALL_TYPE GetStaticVariableByIndex(SHADER_TYPE ShaderType, Uint32 Index) override final; + + virtual Uint32 DILIGENT_CALL_TYPE GetStaticVariableCount(SHADER_TYPE ShaderType) const override final; + + virtual void DILIGENT_CALL_TYPE BindStaticResources(Uint32 ShaderFlags, + IResourceMapping* pResourceMapping, + Uint32 Flags) override final; + + virtual bool DILIGENT_CALL_TYPE IsCompatibleWith(const IPipelineResourceSignature* pPRS) const override final + { + VERIFY_EXPR(pPRS != nullptr); + return IsCompatibleWith(*ValidatedCast<const PipelineResourceSignatureD3D12Impl>(pPRS)); + } + + bool IsCompatibleWith(const PipelineResourceSignatureD3D12Impl& Other) const; + + bool IsIncompatibleWith(const PipelineResourceSignatureD3D12Impl& Other) const + { + return GetHash() != Other.GetHash(); + } + + SRBMemoryAllocator& GetSRBMemoryAllocator() + { + return m_SRBMemAllocator; + } + + void InitSRBResourceCache(ShaderResourceCacheD3D12& ResourceCache, + IMemoryAllocator& CacheMemAllocator, + const char* DbgPipelineName) const; + + void InitializeStaticSRBResources(ShaderResourceCacheD3D12& ResourceCache) const; + + // Binds object pObj to resource with index ResIndex in m_Desc.Resources and + // array index ArrayIndex. + void BindResource(IDeviceObject* pObj, + Uint32 ArrayIndex, + Uint32 ResIndex, + ShaderResourceCacheD3D12& ResourceCache) const; + + bool IsBound(Uint32 ArrayIndex, + Uint32 ResIndex, + ShaderResourceCacheD3D12& ResourceCache) const; + + void TransitionResources(ShaderResourceCacheD3D12& ResourceCache, CommandContext& Ctx, bool PerformResourceTransitions, bool ValidateStates) const; + + void CommitRootTables(ShaderResourceCacheD3D12& ResourceCache, + CommandContext& Ctx, + DeviceContextD3D12Impl* pDeviceCtx, + Uint32 DeviceCtxId, + bool IsCompute, + Uint32 FirstRootIndex); + + void CommitRootViews(ShaderResourceCacheD3D12& ResourceCache, + CommandContext& Ctx, + DeviceContextD3D12Impl* pDeviceCtx, + Uint32 DeviceCtxId, + bool IsCompute, + Uint32 FirstRootIndex); + +private: + enum ROOT_TYPE : Uint8 + { + ROOT_TYPE_STATIC = 0, + ROOT_TYPE_DYNAMIC = 1, + ROOT_TYPE_COUNT + }; + static ROOT_TYPE GetRootType(SHADER_RESOURCE_VARIABLE_TYPE VarType); + + + class RootParameter + { + public: + RootParameter(D3D12_ROOT_PARAMETER_TYPE ParameterType, + Uint32 RootIndex, + UINT Register, + UINT RegisterSpace, + D3D12_SHADER_VISIBILITY Visibility, + ROOT_TYPE RootType) noexcept; + + RootParameter(D3D12_ROOT_PARAMETER_TYPE ParameterType, + Uint32 RootIndex, + UINT Register, + UINT RegisterSpace, + UINT NumDwords, + D3D12_SHADER_VISIBILITY Visibility, + ROOT_TYPE RootType) noexcept; + + RootParameter(D3D12_ROOT_PARAMETER_TYPE ParameterType, + Uint32 RootIndex, + UINT NumRanges, + D3D12_DESCRIPTOR_RANGE* pRanges, + D3D12_SHADER_VISIBILITY Visibility, + ROOT_TYPE RootType) noexcept; + + RootParameter(const RootParameter& RP) noexcept; + + RootParameter(const RootParameter& RP, + UINT NumRanges, + D3D12_DESCRIPTOR_RANGE* pRanges) noexcept; + + RootParameter& operator=(const RootParameter&) = delete; + RootParameter& operator=(RootParameter&&) = delete; + + void SetDescriptorRange(UINT RangeIndex, + D3D12_DESCRIPTOR_RANGE_TYPE Type, + UINT Register, + UINT RegisterSpace, + UINT Count, + UINT OffsetFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND); + + ROOT_TYPE GetRootType() const { return m_RootType; } + + Uint32 GetDescriptorTableSize() const; + + D3D12_SHADER_VISIBILITY GetShaderVisibility() const { return m_RootParam.ShaderVisibility; } + D3D12_ROOT_PARAMETER_TYPE GetParameterType() const { return m_RootParam.ParameterType; } + + Uint32 GetLocalRootIndex() const { return m_RootIndex; } + + operator const D3D12_ROOT_PARAMETER&() const { return m_RootParam; } + + bool operator==(const RootParameter& rhs) const; + bool operator!=(const RootParameter& rhs) const { return !(*this == rhs); } + + size_t GetHash() const; + + private: + ROOT_TYPE m_RootType = static_cast<ROOT_TYPE>(-1); + D3D12_ROOT_PARAMETER m_RootParam = {}; + Uint32 m_DescriptorTableSize = 0; + Uint32 m_RootIndex = static_cast<Uint32>(-1); + }; + + + class RootParamsManager + { + public: + RootParamsManager(IMemoryAllocator& MemAllocator); + + // clang-format off + RootParamsManager (const RootParamsManager&) = delete; + RootParamsManager& operator=(const RootParamsManager&) = delete; + RootParamsManager (RootParamsManager&&) = delete; + RootParamsManager& operator=(RootParamsManager&&) = delete; + // clang-format on + + Uint32 GetNumRootTables() const { return m_NumRootTables; } + Uint32 GetNumRootViews() const { return m_NumRootViews; } + + const RootParameter& GetRootTable(Uint32 TableInd) const + { + VERIFY_EXPR(TableInd < m_NumRootTables); + return m_pRootTables[TableInd]; + } + + RootParameter& GetRootTable(Uint32 TableInd) + { + VERIFY_EXPR(TableInd < m_NumRootTables); + return m_pRootTables[TableInd]; + } + + const RootParameter& GetRootView(Uint32 ViewInd) const + { + VERIFY_EXPR(ViewInd < m_NumRootViews); + return m_pRootViews[ViewInd]; + } + + RootParameter& GetRootView(Uint32 ViewInd) + { + VERIFY_EXPR(ViewInd < m_NumRootViews); + return m_pRootViews[ViewInd]; + } + + void AddRootView(D3D12_ROOT_PARAMETER_TYPE ParameterType, + Uint32 RootIndex, + UINT Register, + UINT RegisterSpace, + D3D12_SHADER_VISIBILITY Visibility, + ROOT_TYPE RootType); + + void AddRootTable(Uint32 RootIndex, + D3D12_SHADER_VISIBILITY Visibility, + ROOT_TYPE RootType, + Uint32 NumRangesInNewTable = 1); + + void AddDescriptorRanges(Uint32 RootTableInd, Uint32 NumExtraRanges = 1); + + template <class TOperation> + void ProcessRootTables(TOperation) const; + + bool operator==(const RootParamsManager& RootParams) const; + + private: + size_t GetRequiredMemorySize(Uint32 NumExtraRootTables, + Uint32 NumExtraRootViews, + Uint32 NumExtraDescriptorRanges) const; + + D3D12_DESCRIPTOR_RANGE* Extend(Uint32 NumExtraRootTables, + Uint32 NumExtraRootViews, + Uint32 NumExtraDescriptorRanges, + Uint32 RootTableToAddRanges = static_cast<Uint32>(-1)); + + IMemoryAllocator& m_MemAllocator; + std::unique_ptr<void, STDDeleter<void, IMemoryAllocator>> m_pMemory; + Uint32 m_NumRootTables = 0; + Uint32 m_NumRootViews = 0; + Uint32 m_TotalDescriptorRanges = 0; + RootParameter* m_pRootTables = nullptr; + RootParameter* m_pRootViews = nullptr; + }; + + using CacheOffsetsType = std::array<Uint32, 2>; + + void CreateLayout(); + + // Allocates root signature slot for the given resource. + // For graphics and compute pipelines, BindPoint is the same as the original bind point. + // For ray-tracing pipeline, BindPoint will be overriden. Bind points are then + // remapped by PSO constructor. + void AllocateResourceSlot(SHADER_TYPE ShaderStages, + SHADER_RESOURCE_VARIABLE_TYPE VariableType, + D3D12_DESCRIPTOR_RANGE_TYPE RangeType, + Uint32 ArraySize, + bool IsRootView, + Uint32 BindPoint, + Uint32 Space, + Uint32& RootIndex, + Uint32& OffsetFromTableStart); + + size_t CalculateHash() const; + + void Destruct(); + + std::vector<Uint32, STDAllocatorRawMem<Uint32>> GetCacheTableSizes() const; + + Uint32 FindAssignedSampler(const PipelineResourceDesc& SepImg) const; + +private: + static constexpr Uint8 InvalidRootTableIndex = static_cast<Uint8>(-1); + static constexpr Uint32 MAX_SPACES_PER_SIGNATURE = 128; + + ResourceAttribs* m_pResourceAttribs = nullptr; // [m_Desc.NumResources] + + std::array<Int8, MAX_SHADERS_IN_PIPELINE> m_StaticVarIndex = {-1, -1, -1, -1, -1, -1}; + static_assert(MAX_SHADERS_IN_PIPELINE == 6, "Please update the initializer list above"); + + // The array below contains array index of a CBV/SRV/UAV root table + // in m_RootParams (NOT the Root Index!), for every variable type + // (static, mutable, dynamic) and every shader type, + // or -1, if the table is not yet assigned to the combination + std::array<Uint8, ROOT_TYPE_COUNT* MAX_SHADERS_IN_PIPELINE> m_SrvCbvUavRootTablesMap = {}; + // This array contains the same data for Sampler root table + std::array<Uint8, ROOT_TYPE_COUNT* MAX_SHADERS_IN_PIPELINE> m_SamplerRootTablesMap = {}; + + std::array<Uint32, ROOT_TYPE_COUNT> m_TotalSrvCbvUavSlots = {}; + std::array<Uint32, ROOT_TYPE_COUNT> m_TotalSamplerSlots = {}; + std::array<Uint32, ROOT_TYPE_COUNT> m_TotalRootViews = {}; + + Uint32 m_NumSpaces = 0; + + ShaderResourceCacheD3D12* m_pStaticResCache = nullptr; + ShaderVariableManagerD3D12* m_StaticVarsMgrs = nullptr; // [m_NumShaderStages] + + ImmutableSamplerAttribs* m_ImmutableSamplers = nullptr; // [m_Desc.NumImmutableSamplers] + + RootParamsManager m_RootParams; + + SRBMemoryAllocator m_SRBMemAllocator; +}; + + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.hpp index 71a3fcda..91881398 100644 --- a/Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.hpp @@ -34,10 +34,7 @@ #include "PipelineStateD3D12.h" #include "PipelineStateBase.hpp" #include "RootSignature.hpp" -#include "ShaderResourceLayoutD3D12.hpp" -#include "SRBMemoryAllocator.hpp" #include "RenderDeviceD3D12Impl.hpp" -#include "ShaderVariableD3D12.hpp" #include "ShaderD3D12Impl.hpp" namespace Diligent @@ -58,24 +55,15 @@ public: IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_PipelineStateD3D12, TPipelineStateBase) - /// Implementation of IPipelineState::BindStaticResources() in Direct3D12 backend. - virtual void DILIGENT_CALL_TYPE BindStaticResources(Uint32 ShaderFlags, IResourceMapping* pResourceMapping, Uint32 Flags) override final; - - /// Implementation of IPipelineState::GetStaticVariableCount() in Direct3D12 backend. - virtual Uint32 DILIGENT_CALL_TYPE GetStaticVariableCount(SHADER_TYPE ShaderType) const override final; - - /// Implementation of IPipelineState::GetStaticVariableByName() in Direct3D12 backend. - virtual IShaderResourceVariable* DILIGENT_CALL_TYPE GetStaticVariableByName(SHADER_TYPE ShaderType, const Char* Name) override final; - - /// Implementation of IPipelineState::GetStaticVariableByIndex() in Direct3D12 backend. - virtual IShaderResourceVariable* DILIGENT_CALL_TYPE GetStaticVariableByIndex(SHADER_TYPE ShaderType, Uint32 Index) override final; - - /// Implementation of IPipelineState::CreateShaderResourceBinding() in Direct3D12 backend. - virtual void DILIGENT_CALL_TYPE CreateShaderResourceBinding(IShaderResourceBinding** ppShaderResourceBinding, bool InitStaticResources) override final; - /// Implementation of IPipelineState::IsCompatibleWith() in Direct3D12 backend. virtual bool DILIGENT_CALL_TYPE IsCompatibleWith(const IPipelineState* pPSO) const override final; + /// Implementation of IPipelineState::GetResourceSignatureCount() in Direct3D12 backend. + virtual Uint32 DILIGENT_CALL_TYPE GetResourceSignatureCount() const override final { return GetSignatureCount(); } + + /// Implementation of IPipelineState::GetResourceSignature() in Direct3D12 backend. + virtual IPipelineResourceSignature* DILIGENT_CALL_TYPE GetResourceSignature(Uint32 Index) const override final { return GetSignature(Index); } + /// Implementation of IPipelineStateD3D12::GetD3D12PipelineState(). virtual ID3D12PipelineState* DILIGENT_CALL_TYPE GetD3D12PipelineState() const override final { return static_cast<ID3D12PipelineState*>(m_pd3d12PSO.p); } @@ -83,45 +71,16 @@ public: virtual ID3D12StateObject* DILIGENT_CALL_TYPE GetD3D12StateObject() const override final { return static_cast<ID3D12StateObject*>(m_pd3d12PSO.p); } /// Implementation of IPipelineStateD3D12::GetD3D12RootSignature(). - virtual ID3D12RootSignature* DILIGENT_CALL_TYPE GetD3D12RootSignature() const override final { return m_RootSig.GetD3D12RootSignature(); } - - struct CommitAndTransitionResourcesAttribs - { - Uint32 CtxId = 0; - IShaderResourceBinding* pShaderResourceBinding = nullptr; - bool CommitResources = false; - bool TransitionResources = false; - bool ValidateStates = false; - }; - ShaderResourceCacheD3D12* CommitAndTransitionShaderResources(class DeviceContextD3D12Impl* pDeviceCtx, - class CommandContext& CmdCtx, - CommitAndTransitionResourcesAttribs& Attrib) const; - - const RootSignature& GetRootSignature() const { return m_RootSig; } + virtual ID3D12RootSignature* DILIGENT_CALL_TYPE GetD3D12RootSignature() const override final { return m_RootSig->GetD3D12RootSignature(); } - const ShaderResourceLayoutD3D12& GetShaderResLayout(Uint32 ShaderInd) const - { - VERIFY_EXPR(ShaderInd < GetNumShaderStages()); - return m_pShaderResourceLayouts[ShaderInd]; - } + const RootSignatureD3D12* GetRootSignature() const { return m_RootSig; } - const ShaderResourceLayoutD3D12& GetStaticShaderResLayout(Uint32 ShaderInd) const - { - VERIFY_EXPR(ShaderInd < GetNumShaderStages()); - return m_pShaderResourceLayouts[GetNumShaderStages() + ShaderInd]; - } + Uint32 GetSignatureCount() const { return m_SignatureCount; } - ShaderResourceCacheD3D12& GetStaticShaderResCache(Uint32 ShaderInd) const + PipelineResourceSignatureD3D12Impl* GetSignature(Uint32 index) const { - VERIFY_EXPR(ShaderInd < GetNumShaderStages()); - return m_pStaticResourceCaches[ShaderInd]; - } - - bool ContainsShaderResources() const; - - SRBMemoryAllocator& GetSRBMemoryAllocator() - { - return m_SRBMemAllocator; + VERIFY_EXPR(index < m_SignatureCount); + return m_Signatures[index].RawPtr<PipelineResourceSignatureD3D12Impl>(); } private: @@ -133,37 +92,45 @@ private: void Append(ShaderD3D12Impl* pShader); size_t Count() const; - SHADER_TYPE Type = SHADER_TYPE_UNKNOWN; - std::vector<ShaderD3D12Impl*> Shaders; + SHADER_TYPE Type = SHADER_TYPE_UNKNOWN; + std::vector<ShaderD3D12Impl*> Shaders; + std::vector<CComPtr<ID3DBlob>> ByteCodes; }; using TShaderStages = std::vector<ShaderStageInfo>; template <typename PSOCreateInfoType> void InitInternalObjects(const PSOCreateInfoType& CreateInfo, - RootSignatureBuilder& RootSigBuilder, TShaderStages& ShaderStages, - LocalRootSignature* pLocalRoot = nullptr); + LocalRootSignatureD3D12* pLocalRootSig = nullptr); + + void InitRootSignature(const PipelineStateCreateInfo& CreateInfo, + TShaderStages& ShaderStages, + LocalRootSignatureD3D12* pLocalRootSig); - void InitResourceLayouts(const PipelineStateCreateInfo& CreateInfo, - RootSignatureBuilder& RootSigBuilder, - TShaderStages& ShaderStages, - LocalRootSignature* pLocalRoot); + void CreateDefaultResourceSignature(const PipelineStateCreateInfo& CreateInfo, + TShaderStages& ShaderStages, + LocalRootSignatureD3D12* pLocalRootSig, + IPipelineResourceSignature** ppImplicitSignature); void Destruct(); - CComPtr<ID3D12DeviceChild> m_pd3d12PSO; - RootSignature m_RootSig; +private: + CComPtr<ID3D12DeviceChild> m_pd3d12PSO; + RefCntAutoPtr<RootSignatureD3D12> m_RootSig; + + using SignatureArrayType = RootSignatureD3D12::SignatureArrayType; - SRBMemoryAllocator m_SRBMemAllocator; + Uint8 m_SignatureCount = 0; + SignatureArrayType m_Signatures = {}; - ShaderResourceLayoutD3D12* m_pShaderResourceLayouts = nullptr; // [m_NumShaderStages * 2] - ShaderResourceCacheD3D12* m_pStaticResourceCaches = nullptr; // [m_NumShaderStages] - ShaderVariableManagerD3D12* m_pStaticVarManagers = nullptr; // [m_NumShaderStages] + void* m_pRawMem = nullptr; // AZ TODO: move to base class - // Resource layout index in m_pShaderResourceLayouts array for every shader stage, - // indexed by the shader type pipeline index (returned by GetShaderTypePipelineIndex) - std::array<Int8, MAX_SHADERS_IN_PIPELINE> m_ResourceLayoutIndex = {-1, -1, -1, -1, -1, -1}; - static_assert(MAX_SHADERS_IN_PIPELINE == 6, "Please update the initializer list above"); +#ifdef DILIGENT_DEVELOPMENT + // Shader resources for all shaders in all shader stages + std::vector<std::shared_ptr<const ShaderResourcesD3D12>> m_ShaderResources; + // Resource info for every resource in m_ShaderResources, in the same order + //std::vector<PipelineLayoutVk::ResourceInfo> m_ResInfo; +#endif }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp index 707e59c0..b369299f 100644 --- a/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp @@ -41,6 +41,7 @@ #include "GenerateMips.hpp" #include "QueryManagerD3D12.hpp" #include "DXCompiler.hpp" +#include "RootSignature.hpp" // The macros below are only defined in Win SDK 19041+ and are missing in 17763 #ifndef D3D12_RAYTRACING_MAX_RAY_GENERATION_SHADER_THREADS @@ -137,6 +138,14 @@ public: virtual void DILIGENT_CALL_TYPE CreateSBT(const ShaderBindingTableDesc& Desc, IShaderBindingTable** ppSBT) override final; + /// Implementation of IRenderDevice::CreatePipelineResourceSignature() in Direct3D12 backend. + virtual void DILIGENT_CALL_TYPE CreatePipelineResourceSignature(const PipelineResourceSignatureDesc& Desc, + IPipelineResourceSignature** ppSignature) override final; + + void CreatePipelineResourceSignature(const PipelineResourceSignatureDesc& Desc, + IPipelineResourceSignature** ppSignature, + bool IsDeviceInternal); + /// Implementation of IRenderDeviceD3D12::GetD3D12Device(). virtual ID3D12Device* DILIGENT_CALL_TYPE GetD3D12Device() override final { return m_pd3d12Device; } @@ -163,6 +172,10 @@ public: RESOURCE_STATE InitialState, ITopLevelAS** ppTLAS) override final; + void CreateRootSignature(const RefCntAutoPtr<class PipelineResourceSignatureD3D12Impl>* ppSignatures, Uint32 SignatureCount, RootSignatureD3D12** ppRootSig); + + RootSignatureCacheD3D12& GetRootSignatureCache() { return m_RootSignatureCache; } + DescriptorHeapAllocation AllocateDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE Type, UINT Count = 1); DescriptorHeapAllocation AllocateGPUDescriptors(D3D12_DESCRIPTOR_HEAP_TYPE Type, UINT Count = 1); @@ -262,6 +275,9 @@ private: Properties m_Properties; std::unique_ptr<IDXCompiler> m_pDxCompiler; + + FixedBlockMemoryAllocator m_RootSignatureAllocator; + RootSignatureCacheD3D12 m_RootSignatureCache; }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/include/RootSignature.hpp b/Graphics/GraphicsEngineD3D12/include/RootSignature.hpp index 05952908..d7391086 100644 --- a/Graphics/GraphicsEngineD3D12/include/RootSignature.hpp +++ b/Graphics/GraphicsEngineD3D12/include/RootSignature.hpp @@ -28,621 +28,134 @@ #pragma once /// \file -/// Declaration of Diligent::RootSignature class +/// Declaration of Diligent::RootSignatureD3D12 class #include <array> -#include "ShaderResourceLayoutD3D12.hpp" -#include "BufferD3D12Impl.hpp" +#include <mutex> +#include <unordered_set> + #include "D3D12TypeConversions.hpp" +#include "ShaderResourceCacheD3D12.hpp" +#include "PipelineResourceSignatureD3D12Impl.hpp" +#include "PrivateConstants.h" +#include "ShaderResources.hpp" namespace Diligent { -class RootParameter +class RenderDeviceD3D12Impl; +class PipelineResourceSignatureD3D12Impl; + +/// Implementation of the Diligent::RootSignature class +class RootSignatureD3D12 final : public ObjectBase<IObject> { public: - RootParameter(D3D12_ROOT_PARAMETER_TYPE ParameterType, - Uint32 RootIndex, - UINT Register, - UINT RegisterSpace, - D3D12_SHADER_VISIBILITY Visibility, - SHADER_RESOURCE_VARIABLE_TYPE VarType) noexcept : - // clang-format off - m_RootIndex {RootIndex}, - m_ShaderVarType{VarType } - // clang-format on - { - VERIFY(ParameterType == D3D12_ROOT_PARAMETER_TYPE_CBV || ParameterType == D3D12_ROOT_PARAMETER_TYPE_SRV || ParameterType == D3D12_ROOT_PARAMETER_TYPE_UAV, "Unexpected parameter type - verify argument list"); - m_RootParam.ParameterType = ParameterType; - m_RootParam.ShaderVisibility = Visibility; - m_RootParam.Descriptor.ShaderRegister = Register; - m_RootParam.Descriptor.RegisterSpace = RegisterSpace; - } + RootSignatureD3D12(IReferenceCounters* pRefCounters, + RenderDeviceD3D12Impl* pDeviceD3D12Impl, + const RefCntAutoPtr<PipelineResourceSignatureD3D12Impl>* ppSignatures, + Uint32 SignatureCount); + ~RootSignatureD3D12(); - RootParameter(D3D12_ROOT_PARAMETER_TYPE ParameterType, - Uint32 RootIndex, - UINT Register, - UINT RegisterSpace, - UINT NumDwords, - D3D12_SHADER_VISIBILITY Visibility, - SHADER_RESOURCE_VARIABLE_TYPE VarType) noexcept : - // clang-format off - m_RootIndex {RootIndex}, - m_ShaderVarType{VarType } - // clang-format on - { - VERIFY(ParameterType == D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS, "Unexpected parameter type - verify argument list"); - m_RootParam.ParameterType = ParameterType; - m_RootParam.ShaderVisibility = Visibility; - m_RootParam.Constants.Num32BitValues = NumDwords; - m_RootParam.Constants.ShaderRegister = Register; - m_RootParam.Constants.RegisterSpace = RegisterSpace; - } + void Finalize(); - RootParameter(D3D12_ROOT_PARAMETER_TYPE ParameterType, - Uint32 RootIndex, - UINT NumRanges, - D3D12_DESCRIPTOR_RANGE* pRanges, - D3D12_SHADER_VISIBILITY Visibility, - SHADER_RESOURCE_VARIABLE_TYPE VarType) noexcept : - // clang-format off - m_RootIndex {RootIndex}, - m_ShaderVarType{VarType } - // clang-format on - { - VERIFY(ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Unexpected parameter type - verify argument list"); - VERIFY_EXPR(pRanges != nullptr); - m_RootParam.ParameterType = ParameterType; - m_RootParam.ShaderVisibility = Visibility; - m_RootParam.DescriptorTable.NumDescriptorRanges = NumRanges; - m_RootParam.DescriptorTable.pDescriptorRanges = pRanges; -#ifdef DILIGENT_DEBUG - for (Uint32 r = 0; r < NumRanges; ++r) - pRanges[r].RangeType = static_cast<D3D12_DESCRIPTOR_RANGE_TYPE>(-1); -#endif - } + size_t GetHash() const { return m_Hash; } - RootParameter(const RootParameter& RP) noexcept : - // clang-format off - m_RootParam {RP.m_RootParam }, - m_DescriptorTableSize{RP.m_DescriptorTableSize}, - m_ShaderVarType {RP.m_ShaderVarType }, - m_RootIndex {RP.m_RootIndex } - // clang-format on - { - VERIFY(m_RootParam.ParameterType != D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Use another constructor to copy descriptor table"); - } + Uint32 GetSignatureCount() const { return m_SignatureCount; } - RootParameter(const RootParameter& RP, - UINT NumRanges, - D3D12_DESCRIPTOR_RANGE* pRanges) noexcept : - // clang-format off - m_RootParam {RP.m_RootParam }, - m_DescriptorTableSize{RP.m_DescriptorTableSize}, - m_ShaderVarType {RP.m_ShaderVarType }, - m_RootIndex {RP.m_RootIndex } - // clang-format on + PipelineResourceSignatureD3D12Impl* GetSignature(Uint32 index) const { - VERIFY(m_RootParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Root parameter is expected to be a descriptor table"); - VERIFY(NumRanges >= m_RootParam.DescriptorTable.NumDescriptorRanges, "New table must be larger than source one"); - auto& DstTbl = m_RootParam.DescriptorTable; - DstTbl.NumDescriptorRanges = NumRanges; - DstTbl.pDescriptorRanges = pRanges; - const auto& SrcTbl = RP.m_RootParam.DescriptorTable; - memcpy(pRanges, SrcTbl.pDescriptorRanges, SrcTbl.NumDescriptorRanges * sizeof(D3D12_DESCRIPTOR_RANGE)); -#ifdef DILIGENT_DEBUG - { - Uint32 dbgTableSize = 0; - for (Uint32 r = 0; r < SrcTbl.NumDescriptorRanges; ++r) - { - const auto& Range = SrcTbl.pDescriptorRanges[r]; - dbgTableSize = std::max(dbgTableSize, Range.OffsetInDescriptorsFromTableStart + Range.NumDescriptors); - } - VERIFY(dbgTableSize == m_DescriptorTableSize, "Incorrect descriptor table size"); - - for (Uint32 r = SrcTbl.NumDescriptorRanges; r < DstTbl.NumDescriptorRanges; ++r) - pRanges[r].RangeType = static_cast<D3D12_DESCRIPTOR_RANGE_TYPE>(-1); - } -#endif + VERIFY_EXPR(index < m_SignatureCount); + return m_Signatures[index].RawPtr<PipelineResourceSignatureD3D12Impl>(); } - RootParameter& operator=(const RootParameter&) = delete; - RootParameter& operator=(RootParameter&&) = delete; - - void SetDescriptorRange(UINT RangeIndex, - D3D12_DESCRIPTOR_RANGE_TYPE Type, - UINT Register, - UINT Count, - UINT Space = 0, - UINT OffsetFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) + ID3D12RootSignature* GetD3D12RootSignature() const { - VERIFY(m_RootParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Incorrect parameter table: descriptor table is expected"); - auto& Tbl = m_RootParam.DescriptorTable; - VERIFY(RangeIndex < Tbl.NumDescriptorRanges, "Invalid descriptor range index"); - D3D12_DESCRIPTOR_RANGE& range = const_cast<D3D12_DESCRIPTOR_RANGE&>(Tbl.pDescriptorRanges[RangeIndex]); - VERIFY(range.RangeType == static_cast<D3D12_DESCRIPTOR_RANGE_TYPE>(-1), "Descriptor range has already been initialized. m_DescriptorTableSize may be updated incorrectly"); - range.RangeType = Type; - range.NumDescriptors = Count; - range.BaseShaderRegister = Register; - range.RegisterSpace = Space; - range.OffsetInDescriptorsFromTableStart = OffsetFromTableStart; - m_DescriptorTableSize = std::max(m_DescriptorTableSize, OffsetFromTableStart + Count); + VERIFY_EXPR(m_pd3d12RootSignature); + return m_pd3d12RootSignature; } - SHADER_RESOURCE_VARIABLE_TYPE GetShaderVariableType() const { return m_ShaderVarType; } - - Uint32 GetDescriptorTableSize() const + Uint32 GetFirstRootIndex(Uint32 BindingIndex) const { - VERIFY(m_RootParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Incorrect parameter table: descriptor table is expected"); - return m_DescriptorTableSize; + VERIFY_EXPR(BindingIndex < m_SignatureCount); + return m_FirstRootIndex[BindingIndex]; } - D3D12_SHADER_VISIBILITY GetShaderVisibility() const { return m_RootParam.ShaderVisibility; } - D3D12_ROOT_PARAMETER_TYPE GetParameterType() const { return m_RootParam.ParameterType; } + using SignatureArrayType = std::array<RefCntAutoPtr<PipelineResourceSignatureD3D12Impl>, MAX_RESOURCE_SIGNATURES>; - Uint32 GetRootIndex() const { return m_RootIndex; } +private: + using FirstRootIndexArrayType = std::array<Uint32, MAX_RESOURCE_SIGNATURES>; // AZ TODO: use 8 or 16 bit int + FirstRootIndexArrayType m_FirstRootIndex = {}; - operator const D3D12_ROOT_PARAMETER&() const { return m_RootParam; } + size_t m_Hash = 0; + CComPtr<ID3D12RootSignature> m_pd3d12RootSignature; - bool operator==(const RootParameter& rhs) const - { - if (m_ShaderVarType != rhs.m_ShaderVarType || - m_DescriptorTableSize != rhs.m_DescriptorTableSize || - m_RootIndex != rhs.m_RootIndex) - return false; + // The number of resource signatures used by this root signature + // (Maximum is MAX_RESOURCE_SIGNATURES) + Uint8 m_SignatureCount = 0; + SignatureArrayType m_Signatures = {}; - if (m_RootParam.ParameterType != rhs.m_RootParam.ParameterType || - m_RootParam.ShaderVisibility != rhs.m_RootParam.ShaderVisibility) - return false; + RenderDeviceD3D12Impl* m_pDeviceD3D12Impl; +}; - switch (m_RootParam.ParameterType) - { - case D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE: - { - const auto& tbl0 = m_RootParam.DescriptorTable; - const auto& tbl1 = rhs.m_RootParam.DescriptorTable; - if (tbl0.NumDescriptorRanges != tbl1.NumDescriptorRanges) - return false; - for (UINT r = 0; r < tbl0.NumDescriptorRanges; ++r) - { - const auto& rng0 = tbl0.pDescriptorRanges[r]; - const auto& rng1 = tbl1.pDescriptorRanges[r]; - if (memcmp(&rng0, &rng1, sizeof(rng0)) != 0) - return false; - } - } - break; - - case D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS: - { - const auto& cnst0 = m_RootParam.Constants; - const auto& cnst1 = rhs.m_RootParam.Constants; - if (memcmp(&cnst0, &cnst1, sizeof(cnst0)) != 0) - return false; - } - break; - - case D3D12_ROOT_PARAMETER_TYPE_CBV: - case D3D12_ROOT_PARAMETER_TYPE_SRV: - case D3D12_ROOT_PARAMETER_TYPE_UAV: - { - const auto& dscr0 = m_RootParam.Descriptor; - const auto& dscr1 = rhs.m_RootParam.Descriptor; - if (memcmp(&dscr0, &dscr1, sizeof(dscr0)) != 0) - return false; - } - break; - - default: UNEXPECTED("Unexpected root parameter type"); - } - return true; - } - bool operator!=(const RootParameter& rhs) const - { - return !(*this == rhs); - } - - size_t GetHash() const - { - size_t hash = ComputeHash(m_ShaderVarType, m_DescriptorTableSize, m_RootIndex); - HashCombine(hash, m_RootParam.ParameterType, m_RootParam.ShaderVisibility); +class LocalRootSignatureD3D12 +{ +public: + LocalRootSignatureD3D12(const char* pCBName, Uint32 ShaderRecordSize); - switch (m_RootParam.ParameterType) - { - case D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE: - { - const auto& tbl = m_RootParam.DescriptorTable; - HashCombine(hash, tbl.NumDescriptorRanges); - for (UINT r = 0; r < tbl.NumDescriptorRanges; ++r) - { - const auto& rng = tbl.pDescriptorRanges[r]; - HashCombine(hash, rng.BaseShaderRegister, rng.NumDescriptors, rng.OffsetInDescriptorsFromTableStart, rng.RangeType, rng.RegisterSpace); - } - } - break; - - case D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS: - { - const auto& cnst = m_RootParam.Constants; - HashCombine(hash, cnst.Num32BitValues, cnst.RegisterSpace, cnst.ShaderRegister); - } - break; - - case D3D12_ROOT_PARAMETER_TYPE_CBV: - case D3D12_ROOT_PARAMETER_TYPE_SRV: - case D3D12_ROOT_PARAMETER_TYPE_UAV: - { - const auto& dscr = m_RootParam.Descriptor; - HashCombine(hash, dscr.RegisterSpace, dscr.ShaderRegister); - } - break; - - default: UNEXPECTED("Unexpected root parameter type"); - } + bool IsShaderRecord(const D3DShaderResourceAttribs& CB); - return hash; - } + ID3D12RootSignature* Create(ID3D12Device* pDevice); private: - SHADER_RESOURCE_VARIABLE_TYPE m_ShaderVarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(-1); - D3D12_ROOT_PARAMETER m_RootParam = {}; - Uint32 m_DescriptorTableSize = 0; - Uint32 m_RootIndex = static_cast<Uint32>(-1); + static constexpr Uint32 InvalidBindPoint = ~0u; + + const char* m_pName = nullptr; + Uint32 m_BindPoint = InvalidBindPoint; + const Uint32 m_ShaderRecordSize = 0; + CComPtr<ID3D12RootSignature> m_pd3d12RootSignature; }; -/// Implementation of the Diligent::RootSignature class -class RootSignature +class RootSignatureCacheD3D12 { - friend class RootSignatureBuilder; - public: - RootSignature(); - - ID3D12RootSignature* GetD3D12RootSignature() const { return m_pd3d12RootSignature; } - - void InitResourceCache(class RenderDeviceD3D12Impl* pDeviceD3D12Impl, class ShaderResourceCacheD3D12& ResourceCache, IMemoryAllocator& CacheMemAllocator) const; - - // This method should be thread-safe as it does not modify any object state - void (RootSignature::*CommitDescriptorHandles)(class RenderDeviceD3D12Impl* pRenderDeviceD3D12, - ShaderResourceCacheD3D12& ResourceCache, - class CommandContext& Ctx, - bool IsCompute, - bool ValidateStates) const = nullptr; - - void (RootSignature::*TransitionAndCommitDescriptorHandles)(class RenderDeviceD3D12Impl* pRenderDeviceD3D12, - ShaderResourceCacheD3D12& ResourceCache, - class CommandContext& Ctx, - bool IsCompute, - bool ValidateStates) const = nullptr; - - void TransitionResources(ShaderResourceCacheD3D12& ResourceCache, - class CommandContext& Ctx) const; - - __forceinline void CommitRootViews(ShaderResourceCacheD3D12& ResourceCache, - class CommandContext& CmdCtx, - bool IsCompute, - Uint32 DeviceCtxId, - class DeviceContextD3D12Impl* pDeviceCtx, - bool CommitViews, - bool ProcessDynamicBuffers, - bool ProcessNonDynamicBuffers, - bool TransitionStates, - bool ValidateStates) const; - - Uint32 GetTotalSrvCbvUavSlots(SHADER_RESOURCE_VARIABLE_TYPE VarType) const - { - return m_TotalSrvCbvUavSlots[VarType]; - } - Uint32 GetTotalSamplerSlots(SHADER_RESOURCE_VARIABLE_TYPE VarType) const - { - return m_TotalSamplerSlots[VarType]; - } - Uint32 GetTotalRootViews(SHADER_RESOURCE_VARIABLE_TYPE VarType) const - { - return m_TotalRootViews[VarType]; - } - - bool IsSameAs(const RootSignature& RS) const - { - return m_RootParams == RS.m_RootParams; - } - size_t GetHash() const - { - return m_RootParams.GetHash(); - } + RootSignatureCacheD3D12(RenderDeviceD3D12Impl& DeviceD3D12Impl); -private: -#ifdef DILIGENT_DEVELOPMENT - static void DvpVerifyResourceState(const ShaderResourceCacheD3D12::Resource& Res, - D3D12_DESCRIPTOR_RANGE_TYPE RangeType); -#endif + // clang-format off + RootSignatureCacheD3D12 (const RootSignatureCacheD3D12&) = delete; + RootSignatureCacheD3D12 (RootSignatureCacheD3D12&&) = delete; + RootSignatureCacheD3D12& operator = (const RootSignatureCacheD3D12&) = delete; + RootSignatureCacheD3D12& operator = (RootSignatureCacheD3D12&&) = delete; + // clang-format on - std::vector<Uint32, STDAllocatorRawMem<Uint32>> GetCacheTableSizes() const; + ~RootSignatureCacheD3D12(); - std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES> m_TotalSrvCbvUavSlots = {}; - std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES> m_TotalSamplerSlots = {}; - std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES> m_TotalRootViews = {}; + RefCntAutoPtr<RootSignatureD3D12> GetRootSig(const RefCntAutoPtr<PipelineResourceSignatureD3D12Impl>* ppSignatures, Uint32 SignatureCount); - CComPtr<ID3D12RootSignature> m_pd3d12RootSignature; + void OnDestroyRootSig(RootSignatureD3D12* pRootSig); - class RootParamsManager +private: + struct RootSignatureHash { - public: - RootParamsManager(IMemoryAllocator& MemAllocator); - - // clang-format off - RootParamsManager (const RootParamsManager&) = delete; - RootParamsManager& operator=(const RootParamsManager&) = delete; - RootParamsManager (RootParamsManager&&) = delete; - RootParamsManager& operator=(RootParamsManager&&) = delete; - // clang-format on - - Uint32 GetNumRootTables() const { return m_NumRootTables; } - Uint32 GetNumRootViews() const { return m_NumRootViews; } - - const RootParameter& GetRootTable(Uint32 TableInd) const - { - VERIFY_EXPR(TableInd < m_NumRootTables); - return m_pRootTables[TableInd]; - } - - RootParameter& GetRootTable(Uint32 TableInd) - { - VERIFY_EXPR(TableInd < m_NumRootTables); - return m_pRootTables[TableInd]; - } - - const RootParameter& GetRootView(Uint32 ViewInd) const + std::size_t operator()(const RootSignatureD3D12* Key) const noexcept { - VERIFY_EXPR(ViewInd < m_NumRootViews); - return m_pRootViews[ViewInd]; + return Key->GetHash(); } - - RootParameter& GetRootView(Uint32 ViewInd) - { - VERIFY_EXPR(ViewInd < m_NumRootViews); - return m_pRootViews[ViewInd]; - } - - void AddRootView(D3D12_ROOT_PARAMETER_TYPE ParameterType, - Uint32 RootIndex, - UINT Register, - D3D12_SHADER_VISIBILITY Visibility, - SHADER_RESOURCE_VARIABLE_TYPE VarType); - - void AddRootTable(Uint32 RootIndex, - D3D12_SHADER_VISIBILITY Visibility, - SHADER_RESOURCE_VARIABLE_TYPE VarType, - Uint32 NumRangesInNewTable = 1); - - void AddDescriptorRanges(Uint32 RootTableInd, Uint32 NumExtraRanges = 1); - - template <class TOperation> - void ProcessRootTables(TOperation) const; - - bool operator==(const RootParamsManager& RootParams) const; - size_t GetHash() const; - - private: - size_t GetRequiredMemorySize(Uint32 NumExtraRootTables, - Uint32 NumExtraRootViews, - Uint32 NumExtraDescriptorRanges) const; - - D3D12_DESCRIPTOR_RANGE* Extend(Uint32 NumExtraRootTables, - Uint32 NumExtraRootViews, - Uint32 NumExtraDescriptorRanges, - Uint32 RootTableToAddRanges = static_cast<Uint32>(-1)); - - IMemoryAllocator& m_MemAllocator; - std::unique_ptr<void, STDDeleter<void, IMemoryAllocator>> m_pMemory; - Uint32 m_NumRootTables = 0; - Uint32 m_NumRootViews = 0; - Uint32 m_TotalDescriptorRanges = 0; - RootParameter* m_pRootTables = nullptr; - RootParameter* m_pRootViews = nullptr; }; - static constexpr Uint8 InvalidRootTableIndex = static_cast<Uint8>(-1); - - // The array below contains array index of a CBV/SRV/UAV root table - // in m_RootParams (NOT the Root Index!), for every variable type - // (static, mutable, dynamic) and every shader type, - // or -1, if the table is not yet assigned to the combination - std::array<Uint8, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES* MAX_SHADERS_IN_PIPELINE> m_SrvCbvUavRootTablesMap = {}; - // This array contains the same data for Sampler root table - std::array<Uint8, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES* MAX_SHADERS_IN_PIPELINE> m_SamplerRootTablesMap = {}; - - RootParamsManager m_RootParams; - - IMemoryAllocator& m_MemAllocator; - - // Commits descriptor handles for static and mutable variables - template <bool PerformResourceTransitions> - void CommitDescriptorHandlesInternal_SM(class RenderDeviceD3D12Impl* pRenderDeviceD3D12, - ShaderResourceCacheD3D12& ResourceCache, - class CommandContext& Ctx, - bool IsCompute, - bool ValidateStates) const; - template <bool PerformResourceTransitions> - // Commits descriptor handles for static, mutable, and dynamic variables - void CommitDescriptorHandlesInternal_SMD(class RenderDeviceD3D12Impl* pRenderDeviceD3D12, - ShaderResourceCacheD3D12& ResourceCache, - class CommandContext& Ctx, - bool IsCompute, - bool ValidateStates) const; -}; - - -class RootSignatureBuilder -{ -public: - RootSignatureBuilder(RootSignature& RootSig, const PipelineResourceLayoutDesc& PipelineResLayout); - - void InitImmutableSampler(SHADER_TYPE ShaderType, - const char* SamplerName, - const char* SamplerSuffix, - const D3DShaderResourceAttribs& ShaderResAttribs); - - // Allocates root signature slot for the given resource. - // For graphics and compute pipelines, BindPoint is the same as the original bind point. - // For ray-tracing pipeline, BindPoint will be overriden. Bind points are then - // remapped by PSO constructor. - void AllocateResourceSlot(SHADER_TYPE ShaderType, - PIPELINE_TYPE PipelineType, - const D3DShaderResourceAttribs& ShaderResAttribs, - SHADER_RESOURCE_VARIABLE_TYPE VariableType, - D3D12_DESCRIPTOR_RANGE_TYPE RangeType, - Uint32& BindPoint, - Uint32& RootIndex, - Uint32& OffsetFromTableStart); - - void Finalize(ID3D12Device* pd3d12Device); - - size_t GetResourceCacheRequiredMemSize() const; - - size_t GetHash() const + struct RootSignatureCompare { - return m_RootSig.GetHash(); - } - - struct ImmutableSamplerAttribs - { - const SamplerDesc& Desc; - const String SamplerName; - const UINT ShaderRegister; - const UINT ArraySize; - const UINT RegisterSpace; - const SHADER_TYPE ShaderType; - - ImmutableSamplerAttribs( - const SamplerDesc& _Desc, - const char* _SamplerName, - const UINT _ShaderRegister, - const UINT _ArraySize, - const UINT _RegisterSpace, - const SHADER_TYPE _ShaderType) noexcept : - // clang-format off - Desc {_Desc}, - SamplerName {_SamplerName}, - ShaderRegister{_ShaderRegister}, - ArraySize {_ArraySize}, - RegisterSpace {_RegisterSpace}, - ShaderType {_ShaderType} - // clang-format on - {} + bool operator()(const RootSignatureD3D12* lhs, const RootSignatureD3D12* rhs) const noexcept; }; - const ImmutableSamplerAttribs* GetImmutableSamplers() const { return m_ImmutableSamplers.data(); } - size_t GetImmutableSamplerCount() const { return m_ImmutableSamplers.size(); } private: -#ifdef DILIGENT_DEBUG - void dbgVerifyRootParameters() const; -#endif - - RootSignature& m_RootSig; - - const PipelineResourceLayoutDesc& m_PipelineResLayout; + RenderDeviceD3D12Impl& m_DeviceD3D12Impl; - // Resource counters for every descriptor range type used to assign bind points - // for ray-tracing shaders. - std::array<Uint32, D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER + 1> m_NumResources = {}; + std::mutex m_RootSigCacheGuard; - std::vector<ImmutableSamplerAttribs, STDAllocatorRawMem<ImmutableSamplerAttribs>> m_ImmutableSamplers; -}; - - -void RootSignature::CommitRootViews(ShaderResourceCacheD3D12& ResourceCache, - CommandContext& CmdCtx, - bool IsCompute, - Uint32 DeviceCtxId, - DeviceContextD3D12Impl* pDeviceCtx, - bool CommitViews, - bool ProcessDynamicBuffers, - bool ProcessNonDynamicBuffers, - bool TransitionStates, - bool ValidateStates) const -{ - for (Uint32 rv = 0; rv < m_RootParams.GetNumRootViews(); ++rv) - { - auto& RootView = m_RootParams.GetRootView(rv); - auto RootInd = RootView.GetRootIndex(); - - SHADER_TYPE dbgShaderType = SHADER_TYPE_UNKNOWN; -#ifdef DILIGENT_DEBUG - { - auto& Param = static_cast<const D3D12_ROOT_PARAMETER&>(RootView); - VERIFY_EXPR(Param.ParameterType == D3D12_ROOT_PARAMETER_TYPE_CBV); - dbgShaderType = D3D12ShaderVisibilityToShaderType(Param.ShaderVisibility); - } -#endif - - auto& Res = ResourceCache.GetRootTable(RootInd).GetResource(0, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, dbgShaderType); - if (auto* pBuffToTransition = Res.pObject.RawPtr<BufferD3D12Impl>()) - { - bool IsDynamic = pBuffToTransition->GetDesc().Usage == USAGE_DYNAMIC; - if (IsDynamic && ProcessDynamicBuffers || !IsDynamic && ProcessNonDynamicBuffers) - { - if (IsDynamic) - { -#ifdef DILIGENT_DEBUG - if (pBuffToTransition->IsInKnownState()) - { - VERIFY(pBuffToTransition->CheckState(RESOURCE_STATE_CONSTANT_BUFFER), - "Dynamic buffers must always have RESOURCE_STATE_CONSTANT_BUFFER state flag set"); - } -#endif - } - else - { - if (TransitionStates) - { - if (pBuffToTransition->IsInKnownState() && !pBuffToTransition->CheckState(RESOURCE_STATE_CONSTANT_BUFFER)) - { - CmdCtx.TransitionResource(pBuffToTransition, RESOURCE_STATE_CONSTANT_BUFFER); - } - } -#ifdef DILIGENT_DEVELOPMENT - else if (ValidateStates) - { - - DvpVerifyResourceState(Res, D3D12_DESCRIPTOR_RANGE_TYPE_CBV); - } -#endif - } - - if (CommitViews) - { - D3D12_GPU_VIRTUAL_ADDRESS CBVAddress = pBuffToTransition->GetGPUAddress(DeviceCtxId, pDeviceCtx); - if (IsCompute) - CmdCtx.GetCommandList()->SetComputeRootConstantBufferView(RootInd, CBVAddress); - else - CmdCtx.GetCommandList()->SetGraphicsRootConstantBufferView(RootInd, CBVAddress); - } - } - } - } -} - - -class LocalRootSignature -{ -public: - LocalRootSignature(const char* pCBName, Uint32 ShaderRecordSize); - - bool SetOrMerge(const D3DShaderResourceAttribs& CB); - - ID3D12RootSignature* Create(ID3D12Device* pDevice); - -private: - static constexpr Uint32 InvalidBindPoint = ~0u; - - const char* m_pName = nullptr; - Uint32 m_BindPoint = InvalidBindPoint; - const Uint32 m_ShaderRecordSize = 0; - CComPtr<ID3D12RootSignature> m_pd3d12RootSignature; + std::unordered_set<RootSignatureD3D12*, RootSignatureHash, RootSignatureCompare> m_RootSigCache; }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/include/ShaderResourceBindingD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/ShaderResourceBindingD3D12Impl.hpp index b9289611..69d97431 100644 --- a/Graphics/GraphicsEngineD3D12/include/ShaderResourceBindingD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/ShaderResourceBindingD3D12Impl.hpp @@ -34,24 +34,22 @@ #include "RenderDeviceD3D12.h" #include "ShaderResourceBindingBase.hpp" #include "ShaderResourceCacheD3D12.hpp" -#include "ShaderResourceLayoutD3D12.hpp" #include "ShaderVariableD3D12.hpp" +#include "PipelineResourceSignatureD3D12Impl.hpp" namespace Diligent { -class PipelineStateD3D12Impl; - /// Implementation of the Diligent::IShaderResourceBindingD3D12 interface // sizeof(ShaderResourceBindingD3D12Impl) == 152 (x64, msvc, Release) -class ShaderResourceBindingD3D12Impl final : public ShaderResourceBindingBase<IShaderResourceBindingD3D12, PipelineStateD3D12Impl> +class ShaderResourceBindingD3D12Impl final : public ShaderResourceBindingBase<IShaderResourceBindingD3D12, PipelineResourceSignatureD3D12Impl> { public: - using TBase = ShaderResourceBindingBase<IShaderResourceBindingD3D12, PipelineStateD3D12Impl>; + using TBase = ShaderResourceBindingBase<IShaderResourceBindingD3D12, PipelineResourceSignatureD3D12Impl>; - ShaderResourceBindingD3D12Impl(IReferenceCounters* pRefCounters, - PipelineStateD3D12Impl* pPSO, - bool IsPSOInternal); + ShaderResourceBindingD3D12Impl(IReferenceCounters* pRefCounters, + PipelineResourceSignatureD3D12Impl* pPRS, + bool IsDeviceInternal); ~ShaderResourceBindingD3D12Impl(); IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_ShaderResourceBindingD3D12, TBase) @@ -66,11 +64,9 @@ public: virtual void DILIGENT_CALL_TYPE InitializeStaticResources(const IPipelineState* pPipelineState) override final; - ShaderResourceCacheD3D12& GetResourceCache() { return m_ShaderResourceCache; } + virtual void DILIGENT_CALL_TYPE InitializeStaticResourcesWithSignature(const IPipelineResourceSignature* pResourceSignature) override final; -#ifdef DILIGENT_DEVELOPMENT - void dvpVerifyResourceBindings(const PipelineStateD3D12Impl* pPSO) const; -#endif + ShaderResourceCacheD3D12& GetResourceCache() { return m_ShaderResourceCache; } bool StaticResourcesInitialized() const { @@ -85,7 +81,7 @@ private: // Resource layout index in m_ShaderResourceCache array for every shader stage, // indexed by the shader type pipeline index (returned by GetShaderTypePipelineIndex) - std::array<Int8, MAX_SHADERS_IN_PIPELINE> m_ResourceLayoutIndex = {-1, -1, -1, -1, -1, -1}; + std::array<Int8, MAX_SHADERS_IN_PIPELINE> m_ShaderVarIndex = {-1, -1, -1, -1, -1, -1}; static_assert(MAX_SHADERS_IN_PIPELINE == 6, "Please update the initializer list above"); bool m_bStaticResourcesInitialized = false; diff --git a/Graphics/GraphicsEngineD3D12/include/ShaderResourceCacheD3D12.hpp b/Graphics/GraphicsEngineD3D12/include/ShaderResourceCacheD3D12.hpp index f28f3b8a..36e2388f 100644 --- a/Graphics/GraphicsEngineD3D12/include/ShaderResourceCacheD3D12.hpp +++ b/Graphics/GraphicsEngineD3D12/include/ShaderResourceCacheD3D12.hpp @@ -84,44 +84,19 @@ // #include "DescriptorHeap.hpp" +#include "PipelineResourceSignatureD3D12Impl.hpp" namespace Diligent { -enum class CachedResourceType : Int32 -{ - Unknown = -1, - CBV = 0, - TexSRV, - BufSRV, - TexUAV, - BufUAV, - Sampler, - AccelStruct, - NumTypes -}; - class ShaderResourceCacheD3D12 { public: - // This enum is used for debug purposes only - enum DbgCacheContentType - { - StaticShaderResources, - SRBResources - }; + using CacheContentType = PipelineResourceSignatureD3D12Impl::CacheContentType; - explicit ShaderResourceCacheD3D12(DbgCacheContentType dbgContentType) noexcept - // clang-format off -#ifdef DILIGENT_DEBUG - : m_DbgContentType - { - dbgContentType - } -#endif - // clang-format on - { - } + explicit ShaderResourceCacheD3D12(CacheContentType ContentType) noexcept : + m_ContentType{static_cast<Uint32>(ContentType)} + {} ~ShaderResourceCacheD3D12(); @@ -139,7 +114,7 @@ public: { Resource() noexcept {} - CachedResourceType Type = CachedResourceType::Unknown; + SHADER_RESOURCE_TYPE Type = SHADER_RESOURCE_TYPE_UNKNOWN; // CPU descriptor handle of a cached resource in CPU-only descriptor heap // Note that for dynamic resources, this is the only available CPU descriptor handle D3D12_CPU_DESCRIPTOR_HANDLE CPUDescriptorHandle = {0}; @@ -163,20 +138,18 @@ public: } inline const Resource& GetResource(Uint32 OffsetFromTableStart, - const D3D12_DESCRIPTOR_HEAP_TYPE dbgDescriptorHeapType, - const SHADER_TYPE dbgRefShaderType) const + const D3D12_DESCRIPTOR_HEAP_TYPE dbgDescriptorHeapType) const { VERIFY(m_dbgHeapType == dbgDescriptorHeapType, "Incosistent descriptor heap type"); - VERIFY(dbgRefShaderType == SHADER_TYPE_UNKNOWN || m_dbgShaderType == SHADER_TYPE_UNKNOWN || m_dbgShaderType == dbgRefShaderType, "Incosistent shader type"); + //VERIFY(dbgRefShaderType == SHADER_TYPE_UNKNOWN || m_dbgShaderType == SHADER_TYPE_UNKNOWN || m_dbgShaderType == dbgRefShaderType, "Incosistent shader type"); VERIFY(OffsetFromTableStart < m_NumResources, "Root table is not large enough to store descriptor at offset ", OffsetFromTableStart); return m_pResources[OffsetFromTableStart]; } inline Resource& GetResource(Uint32 OffsetFromTableStart, - const D3D12_DESCRIPTOR_HEAP_TYPE dbgDescriptorHeapType, - const SHADER_TYPE dbgRefShaderType) + const D3D12_DESCRIPTOR_HEAP_TYPE dbgDescriptorHeapType) { - return const_cast<Resource&>(const_cast<const RootTable*>(this)->GetResource(OffsetFromTableStart, dbgDescriptorHeapType, dbgRefShaderType)); + return const_cast<Resource&>(const_cast<const RootTable*>(this)->GetResource(OffsetFromTableStart, dbgDescriptorHeapType)); } inline Uint32 GetSize() const { return m_NumResources; } @@ -187,22 +160,25 @@ public: #ifdef DILIGENT_DEBUG void SetDebugAttribs(Uint32 MaxOffset, const D3D12_DESCRIPTOR_HEAP_TYPE dbgDescriptorHeapType, - const SHADER_TYPE dbgRefShaderType) + bool isDynamic) { VERIFY_EXPR(m_NumResources == MaxOffset); - m_dbgHeapType = dbgDescriptorHeapType; - m_dbgShaderType = dbgRefShaderType; + m_dbgHeapType = dbgDescriptorHeapType; + //m_dbgShaderType = dbgRefShaderType; + m_dbgIsDynamic = isDynamic; } D3D12_DESCRIPTOR_HEAP_TYPE DbgGetHeapType() const { return m_dbgHeapType; } + bool IsDynamic() const { return m_dbgIsDynamic; } #endif const Uint32 m_NumResources = 0; private: #ifdef DILIGENT_DEBUG - D3D12_DESCRIPTOR_HEAP_TYPE m_dbgHeapType = D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; - SHADER_TYPE m_dbgShaderType = SHADER_TYPE_UNKNOWN; + D3D12_DESCRIPTOR_HEAP_TYPE m_dbgHeapType = D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; + //SHADER_TYPE m_dbgShaderType = SHADER_TYPE_UNKNOWN; + bool m_dbgIsDynamic = false; #endif Resource* const m_pResources = nullptr; @@ -320,10 +296,10 @@ public: // Returns the number of dynamic constant buffers bound in the cache regardless of their variable types Uint32 GetNumDynamicCBsBound() const { return m_NumDynamicCBsBound; } + CacheContentType GetContentType() const { return static_cast<CacheContentType>(m_ContentType); } + #ifdef DILIGENT_DEBUG - // Only for debug purposes: indicates what types of resources are stored in the cache - DbgCacheContentType DbgGetContentType() const { return m_DbgContentType; } - void DbgVerifyBoundDynamicCBsCounter() const; + void DbgVerifyBoundDynamicCBsCounter() const; #endif private: @@ -346,10 +322,8 @@ private: // The number of the dynamic buffers bound in the resource cache regardless of their variable type Uint32 m_NumDynamicCBsBound = 0; -#ifdef DILIGENT_DEBUG - // Only for debug purposes: indicates what types of resources are stored in the cache - const DbgCacheContentType m_DbgContentType; -#endif + // Indicates what types of resources are stored in the cache + const Uint32 m_ContentType : 1; }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/include/ShaderResourceLayoutD3D12.hpp b/Graphics/GraphicsEngineD3D12/include/ShaderResourceLayoutD3D12.hpp deleted file mode 100644 index 943d0c12..00000000 --- a/Graphics/GraphicsEngineD3D12/include/ShaderResourceLayoutD3D12.hpp +++ /dev/null @@ -1,402 +0,0 @@ -/* - * Copyright 2019-2021 Diligent Graphics LLC - * Copyright 2015-2019 Egor Yusov - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * In no event and under no legal theory, whether in tort (including negligence), - * contract, or otherwise, unless required by applicable law (such as deliberate - * and grossly negligent acts) or agreed to in writing, shall any Contributor be - * liable for any damages, including any direct, indirect, special, incidental, - * or consequential damages of any character arising as a result of this License or - * out of the use or inability to use the software (including but not limited to damages - * for loss of goodwill, work stoppage, computer failure or malfunction, or any and - * all other commercial damages or losses), even if such Contributor has been advised - * of the possibility of such damages. - */ - -#pragma once - -/// \file -/// Declaration of Diligent::ShaderResourceLayoutD3D12 class - -// http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-layout/ - -// All resources are stored in a single continuous chunk of memory using the following layout: -// -// m_ResourceBuffer -// | | | -// | D3D12Resource[0] ... | D3D12Resource[s] ... | D3D12Resource[s+m] ... | D3D12Resource[smd] ... | D3D12Resource[smd+s'] ... | D3D12Resource[smd+s'+m'] ... D3D12Resource[s+m+d+s'+m'+d'-1] || -// | | | | | | || -// | SRV/CBV/UAV - STATIC | SRV/CBV/UAV - MUTABLE | SRV/CBV/UAV - DYNAMIC | Samplers - STATIC | Samplers - MUTABLE | Samplers - DYNAMIC || -// | | | | -// -// s == NumCbvSrvUav[SHADER_RESOURCE_VARIABLE_TYPE_STATIC] -// m == NumCbvSrvUav[SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE] -// d == NumCbvSrvUav[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC] -// smd = s+m+d -// -// s' == NumSamplers[SHADER_RESOURCE_VARIABLE_TYPE_STATIC] -// m' == NumSamplers[SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE] -// d' == NumSamplers[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC] -// -// -// -// ___________________________ ____________________________________________________________________________________________________________ -// | | unique_ptr | | | | | | | -// | ShaderResourceLayoutD3D12 |--------------->| D3D12Resource[0] | D3D12Resource[1] | ... | D3D12Resource[smd] | D3D12Resource[smd+1] | ... | -// |___________________________| |__________________|__________________|_______________|____________________|______________________|__________| -// A A | A A -// | \ |______________\____SamplerId________________________| -// | \ \ -// | Ref Ref -// | \ \_____ -// | \ \ -// ____________|_______________ ________\_______________________\__________________________________________ -// | | | | | | -// | ShaderVariableManagerD3D12 |---------------->| ShaderVariableD3D12Impl[0] | ShaderVariableD3D12Impl[1] | ... | -// |____________________________| |____________________________|____________________________|_________________| -// -// -// -// -// -// One ShaderResourceLayoutD3D12 instance can be referenced by multiple objects -// -// -// ________________________ _<m_pShaderResourceLayouts>_ _____<m_pShaderVarMgrs>_____ ________________________________ -// | | | | | | | | -// | PipelineStateD3D12Impl |========>| ShaderResourceLayoutD3D12 |<-------| ShaderVariableManagerD3D12 |<====| ShaderResourceBindingD3D12Impl | -// |________________________| |____________________________| |____________________________| |________________________________| -// A -// \ -// \ _____<m_pShaderVarMgrs>_____ ________________________________ -// \ | | | | -// '-------| ShaderVariableManagerD3D12 |<====| ShaderResourceBindingD3D12Impl | -// |____________________________| |________________________________| -// -// -// -// Resources in the resource cache are identified by the root index and offset in the descriptor table -// -// -// ShaderResourceLayoutD3D12 is used as follows: -// * Every pipeline state object (PipelineStateD3D12Impl) maintains shader resource layout for every active shader stage -// ** These resource layouts are used as reference layouts for shader resource binding objects -// ** All variable types are preserved -// ** Root indices and descriptor table offsets are assigned during the initialization -// * Every pipeline state object also contains shader resource layout that facilitates management of static shader resources -// ** The resource layout defines artificial layout where root index matches the resource type (CBV/SRV/UAV/SAM) -// ** Only static variables are referenced -// -// * Every shader resource binding object (ShaderResourceBindingD3D12Impl) encompasses shader variable -// manager (ShaderVariableManagerD3D12) for every active shader stage in the parent pipeline state that -// handles mutable and dynamic resources - -#include <array> - -#include "ShaderBase.hpp" -#include "ShaderResourceCacheD3D12.hpp" -#include "ShaderD3D12Impl.hpp" -#include "StringPool.hpp" -#include "D3DCommonTypeConversions.hpp" - -namespace Diligent -{ - -/// Diligent::ShaderResourceLayoutD3D12 class -// sizeof(ShaderResourceLayoutD3D12) == 56 (MS compiler, x64) -class ShaderResourceLayoutD3D12 final -{ -public: - ShaderResourceLayoutD3D12(IObject& Owner, ID3D12Device* pd3d12Device) noexcept : - m_Owner{Owner}, - m_pd3d12Device{pd3d12Device} - { -#if defined(_MSC_VER) && defined(_WIN64) - static_assert(sizeof(*this) == 56, "Unexpected sizeof(ShaderResourceLayoutD3D12)"); -#endif - } - - // Initializes reference layouts that address all types of resources (static, mutable, dynamic). - // Root indices and descriptor table offsets are assigned during the initialization. - void Initialize(PIPELINE_TYPE PipelineType, - const PipelineResourceLayoutDesc& ResourceLayout, - const std::vector<ShaderD3D12Impl*>& Shaders, - IMemoryAllocator& LayoutDataAllocator, - class RootSignatureBuilder& RootSgnBldr, - class LocalRootSignature* pLocalRootSig); - - // Copies static resources from the source layout and initializes the - // resource cache. Uses bind points from the source layout. - void InitializeStaticReourceLayout(const ShaderResourceLayoutD3D12& SrcLayout, - IMemoryAllocator& LayoutDataAllocator, - ShaderResourceCacheD3D12& ResourceCache); - - // clang-format off - ShaderResourceLayoutD3D12 (const ShaderResourceLayoutD3D12&) = delete; - ShaderResourceLayoutD3D12 (ShaderResourceLayoutD3D12&&) = delete; - ShaderResourceLayoutD3D12& operator =(const ShaderResourceLayoutD3D12&) = delete; - ShaderResourceLayoutD3D12& operator =(ShaderResourceLayoutD3D12&&) = delete; - // clang-format on - - ~ShaderResourceLayoutD3D12(); - - // sizeof(D3D12Resource) == 32 (x64) - struct D3D12Resource final - { - // clang-format off - D3D12Resource (const D3D12Resource&) = delete; - D3D12Resource ( D3D12Resource&&) = delete; - D3D12Resource& operator=(const D3D12Resource&) = delete; - D3D12Resource& operator=( D3D12Resource&&) = delete; - // clang-format on - - static constexpr Uint32 ResourceTypeBits = 3; - static constexpr Uint32 VariableTypeBits = 2; - static constexpr Uint32 RootIndexBits = 32 - ResourceTypeBits - VariableTypeBits; - - static constexpr Uint32 InvalidRootIndex = (1U << RootIndexBits) - 1U; - static constexpr Uint32 MaxRootIndex = InvalidRootIndex - 1U; - - static constexpr Uint32 InvalidOffset = static_cast<Uint32>(-1); - - static_assert(SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES < (1 << VariableTypeBits), "Not enough bits to represent SHADER_RESOURCE_VARIABLE_TYPE"); - static_assert(static_cast<int>(CachedResourceType::NumTypes) < (1 << ResourceTypeBits), "Not enough bits to represent CachedResourceType"); - - /* 0 */ const ShaderResourceLayoutD3D12& ParentResLayout; - /* 8 */ const D3DShaderResourceAttribs Attribs; // Copy of the attributes, potentially with some changes to bindings - /*24 */ const Uint32 OffsetFromTableStart; - /*28.0*/ const Uint32 ResourceType : ResourceTypeBits; // | 0 1 2 | - /*28.3*/ const Uint32 VariableType : VariableTypeBits; // | 3 4 | - /*28.5*/ const Uint32 RootIndex : RootIndexBits; // | 5 6 7 ... 15 | - /*32 */ // End of data - - D3D12Resource(const ShaderResourceLayoutD3D12& _ParentLayout, - StringPool& _StringPool, - const D3DShaderResourceAttribs& _Attribs, - Uint32 _SamplerId, - SHADER_RESOURCE_VARIABLE_TYPE _VariableType, - CachedResourceType _ResType, - Uint32 _BindPoint, - Uint32 _RootIndex, - Uint32 _OffsetFromTableStart) noexcept : - // clang-format off - ParentResLayout{_ParentLayout}, - Attribs - { - _StringPool, - _Attribs, - _SamplerId, - _BindPoint - }, - ResourceType {static_cast<Uint32>(_ResType) }, - VariableType {static_cast<Uint32>(_VariableType)}, - RootIndex {static_cast<Uint32>(_RootIndex) }, - OffsetFromTableStart{ _OffsetFromTableStart } - // clang-format on - { -#if defined(_MSC_VER) && defined(_WIN64) - static_assert(sizeof(*this) == 32, "Unexpected sizeof(D3D12Resource)"); -#endif - - VERIFY(IsValidOffset(), "Offset must be valid"); - VERIFY(IsValidRootIndex(), "Root index must be valid"); - VERIFY(_RootIndex <= MaxRootIndex, "Root index (", _RootIndex, ") exceeds max allowed value (", MaxRootIndex, ")"); - VERIFY(static_cast<Uint32>(_ResType) < (1 << ResourceTypeBits), "Resource type is out of representable range"); - VERIFY(_VariableType < (1 << VariableTypeBits), "Variable type is out of representable range"); - } - - bool IsBound(Uint32 ArrayIndex, - const ShaderResourceCacheD3D12& ResourceCache) const; - - void BindResource(IDeviceObject* pObject, - Uint32 ArrayIndex, - ShaderResourceCacheD3D12& ResourceCache) const; - - // clang-format off - bool IsValidRootIndex() const { return RootIndex != InvalidRootIndex; } - bool IsValidOffset() const { return OffsetFromTableStart != InvalidOffset; } - // clang-format on - - CachedResourceType GetResType() const { return static_cast<CachedResourceType>(ResourceType); } - SHADER_RESOURCE_VARIABLE_TYPE GetVariableType() const { return static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VariableType); } - - private: - void CacheCB(IDeviceObject* pBuffer, - ShaderResourceCacheD3D12::Resource& DstRes, - Uint32 ArrayInd, - D3D12_CPU_DESCRIPTOR_HANDLE ShdrVisibleHeapCPUDescriptorHandle, - Uint32& BoundDynamicCBsCounter) const; - - template <typename TResourceViewType, - typename TViewTypeEnum, - typename TBindSamplerProcType> - void CacheResourceView(IDeviceObject* pView, - ShaderResourceCacheD3D12::Resource& DstRes, - Uint32 ArrayIndex, - D3D12_CPU_DESCRIPTOR_HANDLE ShdrVisibleHeapCPUDescriptorHandle, - TViewTypeEnum dbgExpectedViewType, - TBindSamplerProcType BindSamplerProc) const; - - void CacheSampler(IDeviceObject* pSampler, - ShaderResourceCacheD3D12::Resource& DstSam, - Uint32 ArrayIndex, - D3D12_CPU_DESCRIPTOR_HANDLE ShdrVisibleHeapCPUDescriptorHandle) const; - - void CacheAccelStruct(IDeviceObject* pTLAS, - ShaderResourceCacheD3D12::Resource& DstRes, - Uint32 ArrayIndex, - D3D12_CPU_DESCRIPTOR_HANDLE ShdrVisibleHeapCPUDescriptorHandle) const; - }; - - void CopyStaticResourceDesriptorHandles(const ShaderResourceCacheD3D12& SrcCache, - const ShaderResourceLayoutD3D12& DstLayout, - ShaderResourceCacheD3D12& DstCache) const; - -#ifdef DILIGENT_DEVELOPMENT - bool dvpVerifyBindings(const ShaderResourceCacheD3D12& ResourceCache) const; -#endif - - IObject& GetOwner() - { - return m_Owner; - } - - Uint32 GetCbvSrvUavCount(SHADER_RESOURCE_VARIABLE_TYPE VarType) const - { - return m_CbvSrvUavOffsets[VarType + 1] - m_CbvSrvUavOffsets[VarType]; - } - Uint32 GetSamplerCount(SHADER_RESOURCE_VARIABLE_TYPE VarType) const - { - return m_SamplersOffsets[VarType + 1] - m_SamplersOffsets[VarType]; - } - Uint32 GetTotalResourceCount() const - { - return m_SamplersOffsets[SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES]; - } - - const D3D12Resource& GetSrvCbvUav(SHADER_RESOURCE_VARIABLE_TYPE VarType, Uint32 r) const - { - VERIFY_EXPR(r < GetCbvSrvUavCount(VarType)); - return GetResource(GetSrvCbvUavOffset(VarType, r)); - } - const D3D12Resource& GetSampler(SHADER_RESOURCE_VARIABLE_TYPE VarType, Uint32 s) const - { - VERIFY_EXPR(s < GetSamplerCount(VarType)); - return GetResource(GetSamplerOffset(VarType, s)); - } - - const D3D12Resource& GetResource(Uint32 r) const - { - VERIFY_EXPR(r < GetTotalResourceCount()); - const auto* Resources = reinterpret_cast<const D3D12Resource*>(m_ResourceBuffer.get()); - return Resources[r]; - } - - const bool IsUsingSeparateSamplers() const { return m_IsUsingSeparateSamplers; } - - SHADER_TYPE GetShaderType() const { return m_ShaderType; } - - bool IsCompatibleWith(const ShaderResourceLayoutD3D12& ResLayout) const; - -private: - const D3D12Resource& GetAssignedSampler(const D3D12Resource& TexSrv) const; - D3D12Resource& GetAssignedSampler(const D3D12Resource& TexSrv); - - Uint32 FindSamplerByName(const char* SamplerName) const; - - const Char* GetShaderName() const - { - return GetStringPoolData(); - } - - - Uint32 GetTotalSrvCbvUavCount() const - { - VERIFY_EXPR(m_CbvSrvUavOffsets[0] == 0); - return m_CbvSrvUavOffsets[SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES]; - } - Uint32 GetTotalSamplerCount() const - { - return m_SamplersOffsets[SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES] - m_SamplersOffsets[0]; - } - - D3D12Resource& GetResource(Uint32 r) - { - VERIFY_EXPR(r < GetTotalResourceCount()); - auto* Resources = reinterpret_cast<D3D12Resource*>(m_ResourceBuffer.get()); - return Resources[r]; - } - - Uint32 GetSrvCbvUavOffset(SHADER_RESOURCE_VARIABLE_TYPE VarType, Uint32 r) const - { - Uint32 Offset = m_CbvSrvUavOffsets[VarType] + r; - VERIFY_EXPR(Offset < m_CbvSrvUavOffsets[VarType + 1]); - return Offset; - } - D3D12Resource& GetSrvCbvUav(SHADER_RESOURCE_VARIABLE_TYPE VarType, Uint32 r) - { - VERIFY_EXPR(r < GetCbvSrvUavCount(VarType)); - return GetResource(GetSrvCbvUavOffset(VarType, r)); - } - const D3D12Resource& GetSrvCbvUav(Uint32 r) const - { - VERIFY_EXPR(r < GetTotalSrvCbvUavCount()); - return GetResource(m_CbvSrvUavOffsets[0] + r); - } - - - Uint32 GetSamplerOffset(SHADER_RESOURCE_VARIABLE_TYPE VarType, Uint32 s) const - { - auto Offset = m_SamplersOffsets[VarType] + s; - VERIFY_EXPR(Offset < m_SamplersOffsets[VarType + 1]); - return Offset; - } - D3D12Resource& GetSampler(SHADER_RESOURCE_VARIABLE_TYPE VarType, Uint32 s) - { - VERIFY_EXPR(s < GetSamplerCount(VarType)); - return GetResource(GetSamplerOffset(VarType, s)); - } - const D3D12Resource& GetSampler(Uint32 s) const - { - VERIFY_EXPR(s < GetTotalSamplerCount()); - return GetResource(m_SamplersOffsets[0] + s); - } - - const char* GetStringPoolData() const - { - const auto* Resources = reinterpret_cast<const D3D12Resource*>(m_ResourceBuffer.get()); - return reinterpret_cast<const char*>(Resources + GetTotalResourceCount()); - } - - StringPool AllocateMemory(IMemoryAllocator& Allocator, - const std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES>& CbvSrvUavCount, - const std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES>& SamplerCount, - size_t StringPoolSize); - // clang-format off - -/* 0 */ std::unique_ptr<void, STDDeleterRawMem<void> > m_ResourceBuffer; -/* 16 */ std::array<Uint16, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES + 1> m_CbvSrvUavOffsets = {}; -/* 24 */ std::array<Uint16, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES + 1> m_SamplersOffsets = {}; - -/* 32 */ IObject& m_Owner; -/* 40 */ CComPtr<ID3D12Device> m_pd3d12Device; -/* 48 */ SHADER_TYPE m_ShaderType = SHADER_TYPE_UNKNOWN; -/* */ bool m_IsUsingSeparateSamplers = false; -/* 56 */ // End of data - - // clang-format on -}; - -} // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/include/ShaderVariableD3D12.hpp b/Graphics/GraphicsEngineD3D12/include/ShaderVariableD3D12.hpp index 6a0d5e0a..cacd8e49 100644 --- a/Graphics/GraphicsEngineD3D12/include/ShaderVariableD3D12.hpp +++ b/Graphics/GraphicsEngineD3D12/include/ShaderVariableD3D12.hpp @@ -64,8 +64,9 @@ #include <memory> #include "ShaderResourceVariableD3D.h" -#include "ShaderResourceLayoutD3D12.hpp" #include "ShaderResourceVariableBase.hpp" +#include "ShaderResourceCacheD3D12.hpp" +#include "PipelineResourceSignatureD3D12Impl.hpp" namespace Diligent { @@ -82,10 +83,11 @@ public: m_ResourceCache{ResourceCache} {} - void Initialize(const ShaderResourceLayoutD3D12& Layout, - IMemoryAllocator& Allocator, - const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, - Uint32 NumAllowedTypes); + void Initialize(const PipelineResourceSignatureD3D12Impl& Signature, + IMemoryAllocator& Allocator, + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes, + SHADER_TYPE ShaderType); ~ShaderVariableManagerD3D12(); void Destroy(IMemoryAllocator& Allocator); @@ -95,48 +97,61 @@ public: void BindResources(IResourceMapping* pResourceMapping, Uint32 Flags); - static size_t GetRequiredMemorySize(const ShaderResourceLayoutD3D12& Layout, - const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, - Uint32 NumAllowedTypes, - Uint32& NumVariables); + static size_t GetRequiredMemorySize(const PipelineResourceSignatureD3D12Impl& Signature, + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes, + SHADER_TYPE ShaderType, + Uint32& NumVariables); Uint32 GetVariableCount() const { return m_NumVariables; } private: friend ShaderVariableD3D12Impl; + using ResourceAttribs = PipelineResourceSignatureD3D12Impl::ResourceAttribs; Uint32 GetVariableIndex(const ShaderVariableD3D12Impl& Variable); - // clang-format off + const PipelineResourceDesc& GetResourceDesc(Uint32 Index) const + { + VERIFY_EXPR(m_pSignature); + return m_pSignature->GetResourceDesc(Index); + } + const ResourceAttribs& GetResourceAttribs(Uint32 Index) const + { + VERIFY_EXPR(m_pSignature); + return m_pSignature->GetResourceAttribs(Index); + } - IObject& m_Owner; +private: + PipelineResourceSignatureD3D12Impl const* m_pSignature = nullptr; + + IObject& m_Owner; // Variable mgr is owned by either Pipeline state object (in which case m_ResourceCache references - // static resource cache owned by the same PSO object), or by SRB object (in which case + // static resource cache owned by the same PSO object), or by SRB object (in which case // m_ResourceCache references the cache in the SRB). Thus the cache and the resource layout // (which the variables reference) are guaranteed to be alive while the manager is alive. - ShaderResourceCacheD3D12& m_ResourceCache; + ShaderResourceCacheD3D12& m_ResourceCache; // Memory is allocated through the allocator provided by the pipeline state. If allocation granularity > 1, fixed block // memory allocator is used. This ensures that all resources from different shader resource bindings reside in // continuous memory. If allocation granularity == 1, raw allocator is used. - ShaderVariableD3D12Impl* m_pVariables = nullptr; - Uint32 m_NumVariables = 0; + ShaderVariableD3D12Impl* m_pVariables = nullptr; + Uint32 m_NumVariables = 0; #ifdef DILIGENT_DEBUG - IMemoryAllocator* m_pDbgAllocator = nullptr; + IMemoryAllocator* m_pDbgAllocator = nullptr; #endif - // clang-format on }; // sizeof(ShaderVariableD3D12Impl) == 24 (x64) class ShaderVariableD3D12Impl final : public IShaderResourceVariableD3D { public: - ShaderVariableD3D12Impl(ShaderVariableManagerD3D12& ParentManager, - const ShaderResourceLayoutD3D12::D3D12Resource& Resource) : + ShaderVariableD3D12Impl(ShaderVariableManagerD3D12& ParentManager, + Uint32 ResIndex) : m_ParentManager{ParentManager}, - m_Resource{Resource} + m_ResIndex{ResIndex} {} // clang-format off @@ -176,29 +191,19 @@ public: virtual SHADER_RESOURCE_VARIABLE_TYPE DILIGENT_CALL_TYPE GetType() const override final { - return m_Resource.GetVariableType(); + return GetDesc().VarType; } - virtual void DILIGENT_CALL_TYPE Set(IDeviceObject* pObject) override final - { - m_Resource.BindResource(pObject, 0, m_ParentManager.m_ResourceCache); - } + virtual void DILIGENT_CALL_TYPE Set(IDeviceObject* pObject) override final; - virtual void DILIGENT_CALL_TYPE SetArray(IDeviceObject* const* ppObjects, Uint32 FirstElement, Uint32 NumElements) override final - { - VerifyAndCorrectSetArrayArguments(m_Resource.Attribs.Name, m_Resource.Attribs.BindCount, FirstElement, NumElements); - for (Uint32 Elem = 0; Elem < NumElements; ++Elem) - m_Resource.BindResource(ppObjects[Elem], FirstElement + Elem, m_ParentManager.m_ResourceCache); - } + virtual void DILIGENT_CALL_TYPE SetArray(IDeviceObject* const* ppObjects, Uint32 FirstElement, Uint32 NumElements) override final; virtual void DILIGENT_CALL_TYPE GetResourceDesc(ShaderResourceDesc& ResourceDesc) const override final { - ResourceDesc = GetHLSLResourceDesc(); - } - - virtual HLSLShaderResourceDesc DILIGENT_CALL_TYPE GetHLSLResourceDesc() const override final - { - return m_Resource.Attribs.GetHLSLResourceDesc(); + const auto& Desc = GetDesc(); + ResourceDesc.Name = Desc.Name; + ResourceDesc.Type = Desc.ResourceType; + ResourceDesc.ArraySize = Desc.ArraySize; } virtual Uint32 DILIGENT_CALL_TYPE GetIndex() const override final @@ -206,21 +211,26 @@ public: return m_ParentManager.GetVariableIndex(*this); } - virtual bool DILIGENT_CALL_TYPE IsBound(Uint32 ArrayIndex) const override final - { - return m_Resource.IsBound(ArrayIndex, m_ParentManager.m_ResourceCache); - } + virtual bool DILIGENT_CALL_TYPE IsBound(Uint32 ArrayIndex) const override final; - const ShaderResourceLayoutD3D12::D3D12Resource& GetResource() const + virtual HLSLShaderResourceDesc DILIGENT_CALL_TYPE GetHLSLResourceDesc() const override final { - return m_Resource; + // AZ TODO + return {}; } private: friend ShaderVariableManagerD3D12; + using ResourceAttribs = PipelineResourceSignatureD3D12Impl::ResourceAttribs; + + const PipelineResourceDesc& GetDesc() const { return m_ParentManager.GetResourceDesc(m_ResIndex); } + const ResourceAttribs& GetAttribs() const { return m_ParentManager.GetResourceAttribs(m_ResIndex); } - ShaderVariableManagerD3D12& m_ParentManager; - const ShaderResourceLayoutD3D12::D3D12Resource& m_Resource; + void BindResource(IDeviceObject* pObj, Uint32 ArrayIndex) const; + +private: + ShaderVariableManagerD3D12& m_ParentManager; + const Uint32 m_ResIndex; }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp index 1cd2f766..4dbfe323 100644 --- a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp @@ -43,6 +43,7 @@ #include "CommandListD3D12Impl.hpp" #include "DXGITypeConversions.hpp" #include "ShaderBindingTableD3D12Impl.hpp" +#include "ShaderResourceBindingD3D12Impl.hpp" namespace Diligent { @@ -74,6 +75,8 @@ DeviceContextD3D12Impl::DeviceContextD3D12Impl(IReferenceCounters* pRef bIsDeferred ? std::numeric_limits<decltype(m_NumCommandsToFlush)>::max() : EngineCI.NumCommandsToFlushCmdList, bIsDeferred }, + m_GraphicsResources{false}, + m_ComputeResources {true }, m_DynamicHeap { pDeviceD3D12Impl->GetDynamicMemoryManager(), @@ -224,7 +227,16 @@ void DeviceContextD3D12Impl::SetPipelineState(IPipelineState* pPipelineState) TDeviceContextBase::SetPipelineState(pPipelineStateD3D12, 0 /*Dummy*/); - auto& CmdCtx = GetCmdContext(); + auto& CmdCtx = GetCmdContext(); + auto& RootInfo = GetRootTableInfo(PSODesc.PipelineType); + auto* pd3d12RootSig = pPipelineStateD3D12->GetRootSignature()->GetD3D12RootSignature(); + + if (RootInfo.pRootSig != pd3d12RootSig) + { + RootInfo.pRootSig = pd3d12RootSig; + RootInfo.bRootTablesCommited = false; + RootInfo.bRootViewsCommitted = false; + } switch (PSODesc.PipelineType) { @@ -235,6 +247,7 @@ void DeviceContextD3D12Impl::SetPipelineState(IPipelineState* pPipelineState) auto& GraphicsCtx = CmdCtx.AsGraphicsContext(); auto* pd3d12PSO = pPipelineStateD3D12->GetD3D12PipelineState(); GraphicsCtx.SetPipelineState(pd3d12PSO); + GraphicsCtx.SetGraphicsRootSignature(pd3d12RootSig); if (PSODesc.PipelineType == PIPELINE_TYPE_GRAPHICS) { @@ -262,21 +275,62 @@ void DeviceContextD3D12Impl::SetPipelineState(IPipelineState* pPipelineState) case PIPELINE_TYPE_COMPUTE: { auto* pd3d12PSO = pPipelineStateD3D12->GetD3D12PipelineState(); - CmdCtx.AsComputeContext().SetPipelineState(pd3d12PSO); + auto& CompCtx = CmdCtx.AsComputeContext(); + CompCtx.SetPipelineState(pd3d12PSO); + CompCtx.SetComputeRootSignature(pd3d12RootSig); break; } case PIPELINE_TYPE_RAY_TRACING: { auto* pd3d12SO = pPipelineStateD3D12->GetD3D12StateObject(); - CmdCtx.AsGraphicsContext4().SetRayTracingPipelineState(pd3d12SO); + auto& RTCtx = CmdCtx.AsGraphicsContext4(); + RTCtx.SetRayTracingPipelineState(pd3d12SO); + RTCtx.SetComputeRootSignature(pd3d12RootSig); break; } default: UNEXPECTED("unknown pipeline type"); } +} + +void DeviceContextD3D12Impl::CommitRootTables(RootTableInfo& RootInfo) +{ + const auto& RootSig = *m_pPipelineState->GetRootSignature(); + auto& CmdCtx = GetCmdContext(); + + if (!RootInfo.bRootTablesCommited) + { + RootInfo.bRootTablesCommited = true; + + for (Uint32 s = 0; s < RootSig.GetSignatureCount(); ++s) + { + auto* pSignature = RootSig.GetSignature(s); + auto* pSRB = RootInfo.SRBs[s]; + + if (pSignature == nullptr) + continue; + + VERIFY_EXPR(pSRB != nullptr); + pSignature->CommitRootTables(pSRB->GetResourceCache(), CmdCtx, this, GetContextId(), RootInfo.IsCompute, RootSig.GetFirstRootIndex(s)); + } + } + + if (!RootInfo.bRootViewsCommitted) + { + RootInfo.bRootViewsCommitted = true; + + for (Uint32 s = 0; s < RootSig.GetSignatureCount(); ++s) + { + auto* pSignature = RootSig.GetSignature(s); + auto* pSRB = RootInfo.SRBs[s]; + + if (pSignature == nullptr) + continue; - m_State.pCommittedResourceCache = nullptr; - m_State.bRootViewsCommitted = false; + VERIFY_EXPR(pSRB != nullptr); + pSignature->CommitRootViews(pSRB->GetResourceCache(), CmdCtx, this, GetContextId(), RootInfo.IsCompute, RootSig.GetFirstRootIndex(s)); + } + } } void DeviceContextD3D12Impl::TransitionShaderResources(IPipelineState* pPipelineState, IShaderResourceBinding* pShaderResourceBinding) @@ -288,17 +342,11 @@ void DeviceContextD3D12Impl::TransitionShaderResources(IPipelineState* pPipeline return; } - auto& Ctx = GetCmdContext(); - - auto* pPipelineStateD3D12 = ValidatedCast<PipelineStateD3D12Impl>(pPipelineState); + auto& CmdCtx = GetCmdContext(); + auto* pResBindingD3D12Impl = ValidatedCast<ShaderResourceBindingD3D12Impl>(pShaderResourceBinding); + auto& ResourceCache = pResBindingD3D12Impl->GetResourceCache(); - PipelineStateD3D12Impl::CommitAndTransitionResourcesAttribs Attribs; - Attribs.CtxId = m_ContextId; - Attribs.pShaderResourceBinding = pShaderResourceBinding; - Attribs.CommitResources = false; - Attribs.TransitionResources = true; - Attribs.ValidateStates = false; - pPipelineStateD3D12->CommitAndTransitionShaderResources(this, Ctx, Attribs); + pResBindingD3D12Impl->GetSignature()->TransitionResources(ResourceCache, CmdCtx, true, false); } void DeviceContextD3D12Impl::CommitShaderResources(IShaderResourceBinding* pShaderResourceBinding, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) @@ -306,17 +354,91 @@ void DeviceContextD3D12Impl::CommitShaderResources(IShaderResourceBinding* pShad if (!DeviceContextBase::CommitShaderResources(pShaderResourceBinding, StateTransitionMode, 0 /*Dummy*/)) return; - auto& Ctx = GetCmdContext(); + auto* pResBindingD3D12Impl = ValidatedCast<ShaderResourceBindingD3D12Impl>(pShaderResourceBinding); + auto& ResourceCache = pResBindingD3D12Impl->GetResourceCache(); + auto& CmdCtx = GetCmdContext(); + auto* pSignature = pResBindingD3D12Impl->GetSignature(); + + //if (pSignature->GetTotalRootCount() == 0) + //{ + // Ignore SRBs that contain no resources + // return; + //} + +#ifdef DILIGENT_DEBUG + //ResourceCache.DbgVerifyDynamicBuffersCounter(); +#endif + + if (StateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION) + { + pSignature->TransitionResources(ResourceCache, CmdCtx, true, false); + } +#ifdef DILIGENT_DEVELOPMENT + else if (StateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_VERIFY) + { + pSignature->TransitionResources(ResourceCache, CmdCtx, false, true); + } +#endif + + auto& RootInfo = GetRootTableInfo(pSignature->GetPipelineType()); + + RootInfo.SRBs[pSignature->GetDesc().BindingIndex] = pResBindingD3D12Impl; + + RootInfo.bRootTablesCommited = false; + RootInfo.bRootViewsCommitted = false; +} + +DeviceContextD3D12Impl::RootTableInfo& DeviceContextD3D12Impl::GetRootTableInfo(PIPELINE_TYPE PipelineType) +{ + return PipelineType == PIPELINE_TYPE_GRAPHICS || PipelineType == PIPELINE_TYPE_MESH ? + m_GraphicsResources : + m_ComputeResources; +} + +#ifdef DILIGENT_DEVELOPMENT +void DeviceContextD3D12Impl::DvpValidateCommittedShaderResources() +{ + if (m_State.CommittedResourcesValidated) + return; + + const auto& RootSig = *m_pPipelineState->GetRootSignature(); + auto& RootInfo = GetRootTableInfo(m_pPipelineState->GetDesc().PipelineType); + const auto SignCount = RootSig.GetSignatureCount(); + + for (Uint32 i = 0; i < SignCount; ++i) + { + auto* pSignature = RootSig.GetSignature(i); + if (pSignature == nullptr) + continue; + + if (pSignature->GetTotalRootCount() == 0) + { + // Skip signatures without any resources + continue; + } + + const auto* pSRB = RootInfo.SRBs[i]; + if (pSRB == nullptr) + { + LOG_ERROR_MESSAGE("Shader resource binding is not bound to index (", i, ")."); + continue; + } + + auto* pSRBSign = pSRB->GetSignature(); + VERIFY_EXPR(pSRBSign != nullptr); + + if (!pSignature->IsCompatibleWith(*pSRBSign)) + { + LOG_ERROR_MESSAGE("Shader resource binding at index ", i, " with signature '", pSRBSign->GetDesc().Name, + "' is not compatible with pipeline layout in current pipeline '", m_pPipelineState->GetDesc().Name, "'."); + } + } + + //m_pPipelineState->DvpVerifySRBResources(RootInfo.SRBs); - PipelineStateD3D12Impl::CommitAndTransitionResourcesAttribs Attribs; - Attribs.CtxId = m_ContextId; - Attribs.pShaderResourceBinding = pShaderResourceBinding; - Attribs.CommitResources = true; - Attribs.TransitionResources = StateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION; - Attribs.ValidateStates = StateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_VERIFY; - m_State.pCommittedResourceCache = m_pPipelineState->CommitAndTransitionShaderResources(this, Ctx, Attribs); - m_State.bRootViewsCommitted = false; + m_State.CommittedResourcesValidated = true; } +#endif void DeviceContextD3D12Impl::SetStencilRef(Uint32 StencilRef) { @@ -456,37 +578,14 @@ void DeviceContextD3D12Impl::PrepareForDraw(GraphicsContext& GraphCtx, DRAW_FLAG } #endif - GraphCtx.SetGraphicsRootSignature(m_pPipelineState->GetD3D12RootSignature()); - - if (m_State.pCommittedResourceCache != nullptr) + auto& RootInfo = GetRootTableInfo(PIPELINE_TYPE_GRAPHICS); + if (RootInfo.RequireUpdate(Flags & DRAW_FLAG_DYNAMIC_RESOURCE_BUFFERS_INTACT)) { - if (m_State.pCommittedResourceCache->GetNumDynamicCBsBound() > 0) - { - if (!m_State.bRootViewsCommitted || (Flags & DRAW_FLAG_DYNAMIC_RESOURCE_BUFFERS_INTACT) == 0) - { - // Only process dynamic buffers. Non-dynamic buffers are committed by CommitShaderResources - m_pPipelineState->GetRootSignature() - .CommitRootViews(*m_State.pCommittedResourceCache, - GraphCtx, - false, // IsCompute - m_ContextId, - this, - true, // CommitViews - true, // ProcessDynamicBuffers - false, // ProcessNonDynamicBuffers - false, // TransitionStates - false // ValidateStates - ); - m_State.bRootViewsCommitted = true; - } - } + CommitRootTables(RootInfo); } + #ifdef DILIGENT_DEVELOPMENT - else - { - if (m_pPipelineState->ContainsShaderResources()) - LOG_ERROR_MESSAGE("Pipeline state '", m_pPipelineState->GetDesc().Name, "' contains shader resources, but IDeviceContext::CommitShaderResources() was not called with non-null SRB"); - } + DvpValidateCommittedShaderResources(); #endif } @@ -612,63 +711,27 @@ void DeviceContextD3D12Impl::DrawMeshIndirect(const DrawMeshIndirectAttribs& Att void DeviceContextD3D12Impl::PrepareForDispatchCompute(ComputeContext& ComputeCtx) { - ComputeCtx.SetComputeRootSignature(m_pPipelineState->GetD3D12RootSignature()); - if (m_State.pCommittedResourceCache != nullptr) + auto& RootInfo = GetRootTableInfo(PIPELINE_TYPE_COMPUTE); + if (RootInfo.RequireUpdate()) { - if (m_State.pCommittedResourceCache->GetNumDynamicCBsBound() > 0) - { - // Only process dynamic buffers. Non-dynamic buffers are committed by CommitShaderResources - m_pPipelineState->GetRootSignature() - .CommitRootViews(*m_State.pCommittedResourceCache, - ComputeCtx, - true, // IsCompute - m_ContextId, - this, - true, // CommitViews - true, // ProcessDynamicBuffers - false, // ProcessNonDynamicBuffers - false, // TransitionStates - false // ValidateStates - ); - } + CommitRootTables(RootInfo); } + #ifdef DILIGENT_DEVELOPMENT - else - { - if (m_pPipelineState->ContainsShaderResources()) - LOG_ERROR_MESSAGE("Pipeline state '", m_pPipelineState->GetDesc().Name, "' contains shader resources, but IDeviceContext::CommitShaderResources() was not called with non-null SRB"); - } + DvpValidateCommittedShaderResources(); #endif } void DeviceContextD3D12Impl::PrepareForDispatchRays(GraphicsContext& GraphCtx) { - GraphCtx.SetComputeRootSignature(m_pPipelineState->GetD3D12RootSignature()); - if (m_State.pCommittedResourceCache != nullptr) + auto& RootInfo = GetRootTableInfo(PIPELINE_TYPE_RAY_TRACING); + if (RootInfo.RequireUpdate()) { - if (m_State.pCommittedResourceCache->GetNumDynamicCBsBound() > 0) - { - // Only process dynamic buffers. Non-dynamic buffers are committed by CommitShaderResources - m_pPipelineState->GetRootSignature() - .CommitRootViews(*m_State.pCommittedResourceCache, - GraphCtx, - true, // IsCompute - m_ContextId, - this, - true, // CommitViews - true, // ProcessDynamicBuffers - false, // ProcessNonDynamicBuffers - false, // TransitionStates - false // ValidateStates - ); - } + CommitRootTables(RootInfo); } + #ifdef DILIGENT_DEVELOPMENT - else - { - if (m_pPipelineState->ContainsShaderResources()) - LOG_ERROR_MESSAGE("Pipeline state '", m_pPipelineState->GetDesc().Name, "' contains shader resources, but IDeviceContext::CommitShaderResources() was not called with non-null SRB"); - } + DvpValidateCommittedShaderResources(); #endif } @@ -833,6 +896,9 @@ void DeviceContextD3D12Impl::Flush(bool RequestNewCmdCtx, m_State = State{}; + m_GraphicsResources = RootTableInfo{false}; + m_ComputeResources = RootTableInfo{true}; + // Setting pipeline state to null makes sure that render targets and other // states will be restored in the command list next time a PSO is bound. m_pPipelineState = nullptr; diff --git a/Graphics/GraphicsEngineD3D12/src/PipelineResourceSignatureD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/PipelineResourceSignatureD3D12Impl.cpp new file mode 100644 index 00000000..81c80f81 --- /dev/null +++ b/Graphics/GraphicsEngineD3D12/src/PipelineResourceSignatureD3D12Impl.cpp @@ -0,0 +1,2199 @@ +/* + * Copyright 2019-2021 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "pch.h" +#include "PipelineResourceSignatureD3D12Impl.hpp" +#include "ShaderResourceCacheD3D12.hpp" +#include "ShaderVariableD3D12.hpp" +#include "RenderDeviceD3D12Impl.hpp" +#include "ShaderResourceBindingD3D12Impl.hpp" +#include "BufferD3D12Impl.hpp" +#include "BufferViewD3D12Impl.hpp" +#include "SamplerD3D12Impl.hpp" +#include "TextureD3D12Impl.hpp" +#include "TextureViewD3D12Impl.hpp" +#include "TopLevelASD3D12Impl.hpp" + +namespace Diligent +{ + +PipelineResourceSignatureD3D12Impl::RootParameter::RootParameter(D3D12_ROOT_PARAMETER_TYPE ParameterType, + Uint32 RootIndex, + UINT Register, + UINT RegisterSpace, + D3D12_SHADER_VISIBILITY Visibility, + ROOT_TYPE RootType) noexcept : + // clang-format off + m_RootIndex{RootIndex}, + m_RootType {RootType } +// clang-format on +{ + VERIFY(ParameterType == D3D12_ROOT_PARAMETER_TYPE_CBV || ParameterType == D3D12_ROOT_PARAMETER_TYPE_SRV || ParameterType == D3D12_ROOT_PARAMETER_TYPE_UAV, "Unexpected parameter type - verify argument list"); + m_RootParam.ParameterType = ParameterType; + m_RootParam.ShaderVisibility = Visibility; + m_RootParam.Descriptor.ShaderRegister = Register; + m_RootParam.Descriptor.RegisterSpace = RegisterSpace; +} + +PipelineResourceSignatureD3D12Impl::RootParameter::RootParameter(D3D12_ROOT_PARAMETER_TYPE ParameterType, + Uint32 RootIndex, + UINT Register, + UINT RegisterSpace, + UINT NumDwords, + D3D12_SHADER_VISIBILITY Visibility, + ROOT_TYPE RootType) noexcept : + // clang-format off + m_RootIndex{RootIndex}, + m_RootType {RootType } +// clang-format on +{ + VERIFY(ParameterType == D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS, "Unexpected parameter type - verify argument list"); + m_RootParam.ParameterType = ParameterType; + m_RootParam.ShaderVisibility = Visibility; + m_RootParam.Constants.Num32BitValues = NumDwords; + m_RootParam.Constants.ShaderRegister = Register; + m_RootParam.Constants.RegisterSpace = RegisterSpace; +} + +PipelineResourceSignatureD3D12Impl::RootParameter::RootParameter(D3D12_ROOT_PARAMETER_TYPE ParameterType, + Uint32 RootIndex, + UINT NumRanges, + D3D12_DESCRIPTOR_RANGE* pRanges, + D3D12_SHADER_VISIBILITY Visibility, + ROOT_TYPE RootType) noexcept : + // clang-format off + m_RootIndex{RootIndex}, + m_RootType {RootType } +// clang-format on +{ + VERIFY(ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Unexpected parameter type - verify argument list"); + VERIFY_EXPR(pRanges != nullptr); + m_RootParam.ParameterType = ParameterType; + m_RootParam.ShaderVisibility = Visibility; + m_RootParam.DescriptorTable.NumDescriptorRanges = NumRanges; + m_RootParam.DescriptorTable.pDescriptorRanges = pRanges; +#ifdef DILIGENT_DEBUG + for (Uint32 r = 0; r < NumRanges; ++r) + pRanges[r].RangeType = static_cast<D3D12_DESCRIPTOR_RANGE_TYPE>(-1); +#endif +} + +PipelineResourceSignatureD3D12Impl::RootParameter::RootParameter(const RootParameter& RP) noexcept : + // clang-format off + m_RootParam {RP.m_RootParam }, + m_DescriptorTableSize{RP.m_DescriptorTableSize}, + m_RootType {RP.m_RootType }, + m_RootIndex {RP.m_RootIndex } +// clang-format on +{ + VERIFY(m_RootParam.ParameterType != D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Use another constructor to copy descriptor table"); +} + +PipelineResourceSignatureD3D12Impl::RootParameter::RootParameter(const RootParameter& RP, + UINT NumRanges, + D3D12_DESCRIPTOR_RANGE* pRanges) noexcept : + // clang-format off + m_RootParam {RP.m_RootParam }, + m_DescriptorTableSize{RP.m_DescriptorTableSize}, + m_RootType {RP.m_RootType }, + m_RootIndex {RP.m_RootIndex } +// clang-format on +{ + VERIFY(m_RootParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Root parameter is expected to be a descriptor table"); + VERIFY(NumRanges >= m_RootParam.DescriptorTable.NumDescriptorRanges, "New table must be larger than source one"); + auto& DstTbl = m_RootParam.DescriptorTable; + DstTbl.NumDescriptorRanges = NumRanges; + DstTbl.pDescriptorRanges = pRanges; + const auto& SrcTbl = RP.m_RootParam.DescriptorTable; + memcpy(pRanges, SrcTbl.pDescriptorRanges, SrcTbl.NumDescriptorRanges * sizeof(D3D12_DESCRIPTOR_RANGE)); +#ifdef DILIGENT_DEBUG + { + Uint32 dbgTableSize = 0; + for (Uint32 r = 0; r < SrcTbl.NumDescriptorRanges; ++r) + { + const auto& Range = SrcTbl.pDescriptorRanges[r]; + dbgTableSize = std::max(dbgTableSize, Range.OffsetInDescriptorsFromTableStart + Range.NumDescriptors); + } + VERIFY(dbgTableSize == m_DescriptorTableSize, "Incorrect descriptor table size"); + + for (Uint32 r = SrcTbl.NumDescriptorRanges; r < DstTbl.NumDescriptorRanges; ++r) + pRanges[r].RangeType = static_cast<D3D12_DESCRIPTOR_RANGE_TYPE>(-1); + } +#endif +} + +void PipelineResourceSignatureD3D12Impl::RootParameter::SetDescriptorRange(UINT RangeIndex, + D3D12_DESCRIPTOR_RANGE_TYPE Type, + UINT Register, + UINT RegisterSpace, + UINT Count, + UINT OffsetFromTableStart) +{ + VERIFY(m_RootParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Incorrect parameter table: descriptor table is expected"); + auto& Tbl = m_RootParam.DescriptorTable; + VERIFY(RangeIndex < Tbl.NumDescriptorRanges, "Invalid descriptor range index"); + D3D12_DESCRIPTOR_RANGE& range = const_cast<D3D12_DESCRIPTOR_RANGE&>(Tbl.pDescriptorRanges[RangeIndex]); + VERIFY(range.RangeType == static_cast<D3D12_DESCRIPTOR_RANGE_TYPE>(-1), "Descriptor range has already been initialized. m_DescriptorTableSize may be updated incorrectly"); + range.RangeType = Type; + range.NumDescriptors = Count; + range.BaseShaderRegister = Register; + range.RegisterSpace = RegisterSpace; + range.OffsetInDescriptorsFromTableStart = OffsetFromTableStart; + m_DescriptorTableSize = std::max(m_DescriptorTableSize, OffsetFromTableStart + Count); +} + +Uint32 PipelineResourceSignatureD3D12Impl::RootParameter::GetDescriptorTableSize() const +{ + VERIFY(m_RootParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Incorrect parameter table: descriptor table is expected"); + return m_DescriptorTableSize; +} + +bool PipelineResourceSignatureD3D12Impl::RootParameter::operator==(const RootParameter& rhs) const +{ + if (m_RootType != rhs.m_RootType || + m_DescriptorTableSize != rhs.m_DescriptorTableSize || + m_RootIndex != rhs.m_RootIndex) + return false; + + if (m_RootParam.ParameterType != rhs.m_RootParam.ParameterType || + m_RootParam.ShaderVisibility != rhs.m_RootParam.ShaderVisibility) + return false; + + switch (m_RootParam.ParameterType) + { + case D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE: + { + const auto& tbl0 = m_RootParam.DescriptorTable; + const auto& tbl1 = rhs.m_RootParam.DescriptorTable; + if (tbl0.NumDescriptorRanges != tbl1.NumDescriptorRanges) + return false; + for (UINT r = 0; r < tbl0.NumDescriptorRanges; ++r) + { + const auto& rng0 = tbl0.pDescriptorRanges[r]; + const auto& rng1 = tbl1.pDescriptorRanges[r]; + if (memcmp(&rng0, &rng1, sizeof(rng0)) != 0) + return false; + } + } + break; + + case D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS: + { + const auto& cnst0 = m_RootParam.Constants; + const auto& cnst1 = rhs.m_RootParam.Constants; + if (memcmp(&cnst0, &cnst1, sizeof(cnst0)) != 0) + return false; + } + break; + + case D3D12_ROOT_PARAMETER_TYPE_CBV: + case D3D12_ROOT_PARAMETER_TYPE_SRV: + case D3D12_ROOT_PARAMETER_TYPE_UAV: + { + const auto& dscr0 = m_RootParam.Descriptor; + const auto& dscr1 = rhs.m_RootParam.Descriptor; + if (memcmp(&dscr0, &dscr1, sizeof(dscr0)) != 0) + return false; + } + break; + + default: UNEXPECTED("Unexpected root parameter type"); + } + + return true; +} + +size_t PipelineResourceSignatureD3D12Impl::RootParameter::GetHash() const +{ + size_t hash = ComputeHash(m_RootType, m_DescriptorTableSize, m_RootIndex); + HashCombine(hash, m_RootParam.ParameterType, m_RootParam.ShaderVisibility); + + switch (m_RootParam.ParameterType) + { + case D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE: + { + const auto& tbl = m_RootParam.DescriptorTable; + HashCombine(hash, tbl.NumDescriptorRanges); + for (UINT r = 0; r < tbl.NumDescriptorRanges; ++r) + { + const auto& rng = tbl.pDescriptorRanges[r]; + HashCombine(hash, rng.BaseShaderRegister, rng.NumDescriptors, rng.OffsetInDescriptorsFromTableStart, rng.RangeType, rng.RegisterSpace); + } + } + break; + + case D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS: + { + const auto& cnst = m_RootParam.Constants; + HashCombine(hash, cnst.Num32BitValues, cnst.RegisterSpace, cnst.ShaderRegister); + } + break; + + case D3D12_ROOT_PARAMETER_TYPE_CBV: + case D3D12_ROOT_PARAMETER_TYPE_SRV: + case D3D12_ROOT_PARAMETER_TYPE_UAV: + { + const auto& dscr = m_RootParam.Descriptor; + HashCombine(hash, dscr.RegisterSpace, dscr.ShaderRegister); + } + break; + + default: UNEXPECTED("Unexpected root parameter type"); + } + + return hash; +} + + +PipelineResourceSignatureD3D12Impl::RootParamsManager::RootParamsManager(IMemoryAllocator& MemAllocator) : + m_MemAllocator{MemAllocator}, + m_pMemory{nullptr, STDDeleter<void, IMemoryAllocator>(MemAllocator)} +{} + +size_t PipelineResourceSignatureD3D12Impl::RootParamsManager::GetRequiredMemorySize(Uint32 NumExtraRootTables, + Uint32 NumExtraRootViews, + Uint32 NumExtraDescriptorRanges) const +{ + return sizeof(RootParameter) * (m_NumRootTables + NumExtraRootTables + m_NumRootViews + NumExtraRootViews) + sizeof(D3D12_DESCRIPTOR_RANGE) * (m_TotalDescriptorRanges + NumExtraDescriptorRanges); +} + +D3D12_DESCRIPTOR_RANGE* PipelineResourceSignatureD3D12Impl::RootParamsManager::Extend(Uint32 NumExtraRootTables, + Uint32 NumExtraRootViews, + Uint32 NumExtraDescriptorRanges, + Uint32 RootTableToAddRanges) +{ + VERIFY(NumExtraRootTables > 0 || NumExtraRootViews > 0 || NumExtraDescriptorRanges > 0, "At least one root table, root view or descriptor range must be added"); + auto MemorySize = GetRequiredMemorySize(NumExtraRootTables, NumExtraRootViews, NumExtraDescriptorRanges); + VERIFY_EXPR(MemorySize > 0); + auto* pNewMemory = ALLOCATE_RAW(m_MemAllocator, "Memory buffer for root tables, root views & descriptor ranges", MemorySize); + memset(pNewMemory, 0, MemorySize); + + // Note: this order is more efficient than views->tables->ranges + auto* pNewRootTables = reinterpret_cast<RootParameter*>(pNewMemory); + auto* pNewRootViews = pNewRootTables + (m_NumRootTables + NumExtraRootTables); + auto* pCurrDescriptorRangePtr = reinterpret_cast<D3D12_DESCRIPTOR_RANGE*>(pNewRootViews + m_NumRootViews + NumExtraRootViews); + + // Copy existing root tables to new memory + for (Uint32 rt = 0; rt < m_NumRootTables; ++rt) + { + const auto& SrcTbl = GetRootTable(rt); + auto& D3D12SrcTbl = static_cast<const D3D12_ROOT_PARAMETER&>(SrcTbl).DescriptorTable; + auto NumRanges = D3D12SrcTbl.NumDescriptorRanges; + if (rt == RootTableToAddRanges) + { + VERIFY(NumExtraRootTables == 0 || NumExtraRootTables == 1, "Up to one descriptor table can be extended at a time"); + NumRanges += NumExtraDescriptorRanges; + } + new (pNewRootTables + rt) RootParameter(SrcTbl, NumRanges, pCurrDescriptorRangePtr); + pCurrDescriptorRangePtr += NumRanges; + } + + // Copy existing root views to new memory + for (Uint32 rv = 0; rv < m_NumRootViews; ++rv) + { + const auto& SrcView = GetRootView(rv); + new (pNewRootViews + rv) RootParameter(SrcView); + } + + m_pMemory.reset(pNewMemory); + m_NumRootTables += NumExtraRootTables; + m_NumRootViews += NumExtraRootViews; + m_TotalDescriptorRanges += NumExtraDescriptorRanges; + m_pRootTables = m_NumRootTables != 0 ? pNewRootTables : nullptr; + m_pRootViews = m_NumRootViews != 0 ? pNewRootViews : nullptr; + + return pCurrDescriptorRangePtr; +} + +void PipelineResourceSignatureD3D12Impl::RootParamsManager::AddRootView(D3D12_ROOT_PARAMETER_TYPE ParameterType, + Uint32 RootIndex, + UINT Register, + UINT RegisterSpace, + D3D12_SHADER_VISIBILITY Visibility, + ROOT_TYPE RootType) +{ + auto* pRangePtr = Extend(0, 1, 0); + VERIFY_EXPR((char*)pRangePtr == (char*)m_pMemory.get() + GetRequiredMemorySize(0, 0, 0)); + new (m_pRootViews + m_NumRootViews - 1) RootParameter(ParameterType, RootIndex, Register, RegisterSpace, Visibility, RootType); +} + +void PipelineResourceSignatureD3D12Impl::RootParamsManager::AddRootTable(Uint32 RootIndex, + D3D12_SHADER_VISIBILITY Visibility, + ROOT_TYPE RootType, + Uint32 NumRangesInNewTable) +{ + auto* pRangePtr = Extend(1, 0, NumRangesInNewTable); + VERIFY_EXPR((char*)(pRangePtr + NumRangesInNewTable) == (char*)m_pMemory.get() + GetRequiredMemorySize(0, 0, 0)); + new (m_pRootTables + m_NumRootTables - 1) RootParameter(D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, RootIndex, NumRangesInNewTable, pRangePtr, Visibility, RootType); +} + +void PipelineResourceSignatureD3D12Impl::RootParamsManager::AddDescriptorRanges(Uint32 RootTableInd, Uint32 NumExtraRanges) +{ + auto* pRangePtr = Extend(0, 0, NumExtraRanges, RootTableInd); + VERIFY_EXPR((char*)pRangePtr == (char*)m_pMemory.get() + GetRequiredMemorySize(0, 0, 0)); +} + +bool PipelineResourceSignatureD3D12Impl::RootParamsManager::operator==(const RootParamsManager& RootParams) const +{ + if (m_NumRootTables != RootParams.m_NumRootTables || + m_NumRootViews != RootParams.m_NumRootViews) + return false; + + for (Uint32 rv = 0; rv < m_NumRootViews; ++rv) + { + const auto& RV0 = GetRootView(rv); + const auto& RV1 = RootParams.GetRootView(rv); + if (RV0 != RV1) + return false; + } + + for (Uint32 rv = 0; rv < m_NumRootTables; ++rv) + { + const auto& RT0 = GetRootTable(rv); + const auto& RT1 = RootParams.GetRootTable(rv); + if (RT0 != RT1) + return false; + } + + return true; +} + +template <class TOperation> +__forceinline void PipelineResourceSignatureD3D12Impl::RootParamsManager::ProcessRootTables(TOperation Operation) const +{ + for (Uint32 rt = 0; rt < m_NumRootTables; ++rt) + { + auto& RootTable = GetRootTable(rt); + auto RootInd = RootTable.GetLocalRootIndex(); + const D3D12_ROOT_PARAMETER& D3D12Param = RootTable; + + VERIFY_EXPR(D3D12Param.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE); + + auto& d3d12Table = D3D12Param.DescriptorTable; + VERIFY(d3d12Table.NumDescriptorRanges > 0 && RootTable.GetDescriptorTableSize() > 0, "Unexepected empty descriptor table"); + bool IsResourceTable = d3d12Table.pDescriptorRanges[0].RangeType != D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; + D3D12_DESCRIPTOR_HEAP_TYPE dbgHeapType = D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; +#ifdef DILIGENT_DEBUG + dbgHeapType = IsResourceTable ? D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV : D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; +#endif + Operation(RootInd, RootTable, D3D12Param, IsResourceTable, dbgHeapType); + } +} + + +namespace +{ + +D3D12_DESCRIPTOR_RANGE_TYPE GetDescriptorRangeType(SHADER_RESOURCE_TYPE ResType) +{ + static_assert(SHADER_RESOURCE_TYPE_LAST == SHADER_RESOURCE_TYPE_ACCEL_STRUCT, "Please update the switch below to handle the new resource type"); + + switch (ResType) + { + // clang-format off + case SHADER_RESOURCE_TYPE_CONSTANT_BUFFER: return D3D12_DESCRIPTOR_RANGE_TYPE_CBV; + case SHADER_RESOURCE_TYPE_TEXTURE_SRV: return D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + case SHADER_RESOURCE_TYPE_BUFFER_SRV: return D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + case SHADER_RESOURCE_TYPE_TEXTURE_UAV: return D3D12_DESCRIPTOR_RANGE_TYPE_UAV; + case SHADER_RESOURCE_TYPE_BUFFER_UAV: return D3D12_DESCRIPTOR_RANGE_TYPE_UAV; + case SHADER_RESOURCE_TYPE_SAMPLER: return D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; + case SHADER_RESOURCE_TYPE_ACCEL_STRUCT: return D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + // clang-format on + case SHADER_RESOURCE_TYPE_INPUT_ATTACHMENT: + default: + UNEXPECTED("Unknown resource type"); + return static_cast<D3D12_DESCRIPTOR_RANGE_TYPE>(~0u); + } +} + +void GetRootTableIndex(SHADER_TYPE ShaderType, + D3D12_SHADER_VISIBILITY& ShaderVisibility, + Uint32& RootTableIndex) +{ + // Use VISIBILITY_ALL if used in many stages. + if (ShaderType & (ShaderType - 1)) + { + RootTableIndex = 0; + ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + return; + } + + // https://developer.nvidia.com/dx12-dos-and-donts#roots + // * Start with the entries for the pixel stage + // * Carry on with decreasing execution frequency of the shader stages + static_assert(SHADER_TYPE_LAST == SHADER_TYPE_CALLABLE, "Please update the switch below to handle the new shader type"); + switch (ShaderType) + { + case SHADER_TYPE_PIXEL: + RootTableIndex = 1; + ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; + break; + + case SHADER_TYPE_VERTEX: + RootTableIndex = 2; + ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX; + break; + + case SHADER_TYPE_GEOMETRY: + RootTableIndex = 3; + ShaderVisibility = D3D12_SHADER_VISIBILITY_GEOMETRY; + break; + + case SHADER_TYPE_HULL: + RootTableIndex = 4; + ShaderVisibility = D3D12_SHADER_VISIBILITY_HULL; + break; + + case SHADER_TYPE_DOMAIN: + RootTableIndex = 5; + ShaderVisibility = D3D12_SHADER_VISIBILITY_DOMAIN; + break; + +#ifdef D3D12_H_HAS_MESH_SHADER + case SHADER_TYPE_AMPLIFICATION: + RootTableIndex = 2; + ShaderVisibility = D3D12_SHADER_VISIBILITY_AMPLIFICATION; + break; + + case SHADER_TYPE_MESH: + RootTableIndex = 3; + ShaderVisibility = D3D12_SHADER_VISIBILITY_MESH; + break; +#endif + + case SHADER_TYPE_COMPUTE: + case SHADER_TYPE_RAY_GEN: + case SHADER_TYPE_RAY_MISS: + case SHADER_TYPE_RAY_CLOSEST_HIT: + case SHADER_TYPE_RAY_ANY_HIT: + case SHADER_TYPE_RAY_INTERSECTION: + case SHADER_TYPE_CALLABLE: + RootTableIndex = 0; + ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + break; + + default: + UNEXPECTED("Unknown shader type"); + break; + } +} + +template <class TOperation> +__forceinline void ProcessCachedTableResources(Uint32 RootInd, + const D3D12_ROOT_PARAMETER& D3D12Param, + ShaderResourceCacheD3D12& ResourceCache, + D3D12_DESCRIPTOR_HEAP_TYPE dbgHeapType, + TOperation Operation) +{ + for (UINT r = 0; r < D3D12Param.DescriptorTable.NumDescriptorRanges; ++r) + { + const auto& range = D3D12Param.DescriptorTable.pDescriptorRanges[r]; + for (UINT d = 0; d < range.NumDescriptors; ++d) + { + VERIFY(dbgHeapType == HeapTypeFromRangeType(range.RangeType), "Mistmatch between descriptor heap type and descriptor range type"); + + auto OffsetFromTableStart = range.OffsetInDescriptorsFromTableStart + d; + auto& Res = ResourceCache.GetRootTable(RootInd).GetResource(OffsetFromTableStart, dbgHeapType); + + Operation(OffsetFromTableStart, range, Res); + } + } +} + +__forceinline void TransitionResource(CommandContext& Ctx, + ShaderResourceCacheD3D12::Resource& Res, + D3D12_DESCRIPTOR_RANGE_TYPE RangeType) +{ + static_assert(SHADER_RESOURCE_TYPE_LAST == SHADER_RESOURCE_TYPE_ACCEL_STRUCT, "Please update this function to handle the new resource type"); + switch (Res.Type) + { + case SHADER_RESOURCE_TYPE_CONSTANT_BUFFER: + { + VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_CBV, "Unexpected descriptor range type"); + // Not using QueryInterface() for the sake of efficiency + auto* pBuffToTransition = Res.pObject.RawPtr<BufferD3D12Impl>(); + if (pBuffToTransition->IsInKnownState() && !pBuffToTransition->CheckState(RESOURCE_STATE_CONSTANT_BUFFER)) + Ctx.TransitionResource(pBuffToTransition, RESOURCE_STATE_CONSTANT_BUFFER); + } + break; + + case SHADER_RESOURCE_TYPE_BUFFER_SRV: + { + VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV, "Unexpected descriptor range type"); + auto* pBuffViewD3D12 = Res.pObject.RawPtr<BufferViewD3D12Impl>(); + auto* pBuffToTransition = pBuffViewD3D12->GetBuffer<BufferD3D12Impl>(); + if (pBuffToTransition->IsInKnownState() && !pBuffToTransition->CheckState(RESOURCE_STATE_SHADER_RESOURCE)) + Ctx.TransitionResource(pBuffToTransition, RESOURCE_STATE_SHADER_RESOURCE); + } + break; + + case SHADER_RESOURCE_TYPE_BUFFER_UAV: + { + VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_UAV, "Unexpected descriptor range type"); + auto* pBuffViewD3D12 = Res.pObject.RawPtr<BufferViewD3D12Impl>(); + auto* pBuffToTransition = pBuffViewD3D12->GetBuffer<BufferD3D12Impl>(); + if (pBuffToTransition->IsInKnownState()) + { + // We must always call TransitionResource() even when the state is already + // RESOURCE_STATE_UNORDERED_ACCESS as in this case UAV barrier must be executed + Ctx.TransitionResource(pBuffToTransition, RESOURCE_STATE_UNORDERED_ACCESS); + } + } + break; + + case SHADER_RESOURCE_TYPE_TEXTURE_SRV: + { + VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV, "Unexpected descriptor range type"); + auto* pTexViewD3D12 = Res.pObject.RawPtr<TextureViewD3D12Impl>(); + auto* pTexToTransition = pTexViewD3D12->GetTexture<TextureD3D12Impl>(); + if (pTexToTransition->IsInKnownState() && !pTexToTransition->CheckAnyState(RESOURCE_STATE_SHADER_RESOURCE | RESOURCE_STATE_INPUT_ATTACHMENT)) + Ctx.TransitionResource(pTexToTransition, RESOURCE_STATE_SHADER_RESOURCE); + } + break; + + case SHADER_RESOURCE_TYPE_TEXTURE_UAV: + { + VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_UAV, "Unexpected descriptor range type"); + auto* pTexViewD3D12 = Res.pObject.RawPtr<TextureViewD3D12Impl>(); + auto* pTexToTransition = pTexViewD3D12->GetTexture<TextureD3D12Impl>(); + if (pTexToTransition->IsInKnownState()) + { + // We must always call TransitionResource() even when the state is already + // RESOURCE_STATE_UNORDERED_ACCESS as in this case UAV barrier must be executed + Ctx.TransitionResource(pTexToTransition, RESOURCE_STATE_UNORDERED_ACCESS); + } + } + break; + + case SHADER_RESOURCE_TYPE_SAMPLER: + VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, "Unexpected descriptor range type"); + break; + + case SHADER_RESOURCE_TYPE_ACCEL_STRUCT: + { + VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV, "Unexpected descriptor range type"); + auto* pTLASD3D12 = Res.pObject.RawPtr<TopLevelASD3D12Impl>(); + if (pTLASD3D12->IsInKnownState()) + Ctx.TransitionResource(pTLASD3D12, RESOURCE_STATE_RAY_TRACING); + } + break; + + default: + // Resource not bound + VERIFY(Res.Type == SHADER_RESOURCE_TYPE_UNKNOWN, "Unexpected resource type"); + VERIFY(Res.pObject == nullptr && Res.CPUDescriptorHandle.ptr == 0, "Bound resource is unexpected"); + } +} + +#ifdef DILIGENT_DEVELOPMENT +void DvpVerifyResourceState(const ShaderResourceCacheD3D12::Resource& Res, D3D12_DESCRIPTOR_RANGE_TYPE RangeType) +{ + static_assert(SHADER_RESOURCE_TYPE_LAST == SHADER_RESOURCE_TYPE_ACCEL_STRUCT, "Please update this function to handle the new resource type"); + switch (Res.Type) + { + case SHADER_RESOURCE_TYPE_CONSTANT_BUFFER: + { + VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_CBV, "Unexpected descriptor range type"); + // Not using QueryInterface() for the sake of efficiency + const auto* pBufferD3D12 = Res.pObject.RawPtr<const BufferD3D12Impl>(); + if (pBufferD3D12->IsInKnownState() && !pBufferD3D12->CheckState(RESOURCE_STATE_CONSTANT_BUFFER)) + { + LOG_ERROR_MESSAGE("Buffer '", pBufferD3D12->GetDesc().Name, "' must be in RESOURCE_STATE_CONSTANT_BUFFER state. Actual state: ", + GetResourceStateString(pBufferD3D12->GetState()), + ". Call IDeviceContext::TransitionShaderResources(), use RESOURCE_STATE_TRANSITION_MODE_TRANSITION " + "when calling IDeviceContext::CommitShaderResources() or explicitly transition the buffer state " + "with IDeviceContext::TransitionResourceStates()."); + } + } + break; + + case SHADER_RESOURCE_TYPE_BUFFER_SRV: + { + VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV, "Unexpected descriptor range type"); + const auto* pBuffViewD3D12 = Res.pObject.RawPtr<const BufferViewD3D12Impl>(); + const auto* pBufferD3D12 = pBuffViewD3D12->GetBuffer<const BufferD3D12Impl>(); + if (pBufferD3D12->IsInKnownState() && !pBufferD3D12->CheckState(RESOURCE_STATE_SHADER_RESOURCE)) + { + LOG_ERROR_MESSAGE("Buffer '", pBufferD3D12->GetDesc().Name, "' must be in RESOURCE_STATE_SHADER_RESOURCE state. Actual state: ", + GetResourceStateString(pBufferD3D12->GetState()), + ". Call IDeviceContext::TransitionShaderResources(), use RESOURCE_STATE_TRANSITION_MODE_TRANSITION " + "when calling IDeviceContext::CommitShaderResources() or explicitly transition the buffer state " + "with IDeviceContext::TransitionResourceStates()."); + } + } + break; + + case SHADER_RESOURCE_TYPE_BUFFER_UAV: + { + VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_UAV, "Unexpected descriptor range type"); + const auto* pBuffViewD3D12 = Res.pObject.RawPtr<const BufferViewD3D12Impl>(); + const auto* pBufferD3D12 = pBuffViewD3D12->GetBuffer<const BufferD3D12Impl>(); + if (pBufferD3D12->IsInKnownState() && !pBufferD3D12->CheckState(RESOURCE_STATE_UNORDERED_ACCESS)) + { + LOG_ERROR_MESSAGE("Buffer '", pBufferD3D12->GetDesc().Name, "' must be in RESOURCE_STATE_UNORDERED_ACCESS state. Actual state: ", + GetResourceStateString(pBufferD3D12->GetState()), + ". Call IDeviceContext::TransitionShaderResources(), use RESOURCE_STATE_TRANSITION_MODE_TRANSITION " + "when calling IDeviceContext::CommitShaderResources() or explicitly transition the buffer state " + "with IDeviceContext::TransitionResourceStates()."); + } + } + break; + + case SHADER_RESOURCE_TYPE_TEXTURE_SRV: + { + VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV, "Unexpected descriptor range type"); + const auto* pTexViewD3D12 = Res.pObject.RawPtr<const TextureViewD3D12Impl>(); + const auto* pTexD3D12 = pTexViewD3D12->GetTexture<TextureD3D12Impl>(); + if (pTexD3D12->IsInKnownState() && !pTexD3D12->CheckAnyState(RESOURCE_STATE_SHADER_RESOURCE | RESOURCE_STATE_INPUT_ATTACHMENT)) + { + LOG_ERROR_MESSAGE("Texture '", pTexD3D12->GetDesc().Name, "' must be in RESOURCE_STATE_SHADER_RESOURCE state. Actual state: ", + GetResourceStateString(pTexD3D12->GetState()), + ". Call IDeviceContext::TransitionShaderResources(), use RESOURCE_STATE_TRANSITION_MODE_TRANSITION " + "when calling IDeviceContext::CommitShaderResources() or explicitly transition the texture state " + "with IDeviceContext::TransitionResourceStates()."); + } + } + break; + + case SHADER_RESOURCE_TYPE_TEXTURE_UAV: + { + VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_UAV, "Unexpected descriptor range type"); + const auto* pTexViewD3D12 = Res.pObject.RawPtr<const TextureViewD3D12Impl>(); + const auto* pTexD3D12 = pTexViewD3D12->GetTexture<const TextureD3D12Impl>(); + if (pTexD3D12->IsInKnownState() && !pTexD3D12->CheckState(RESOURCE_STATE_UNORDERED_ACCESS)) + { + LOG_ERROR_MESSAGE("Texture '", pTexD3D12->GetDesc().Name, "' must be in RESOURCE_STATE_UNORDERED_ACCESS state. Actual state: ", + GetResourceStateString(pTexD3D12->GetState()), + ". Call IDeviceContext::TransitionShaderResources(), use RESOURCE_STATE_TRANSITION_MODE_TRANSITION " + "when calling IDeviceContext::CommitShaderResources() or explicitly transition the texture state " + "with IDeviceContext::TransitionResourceStates()."); + } + } + break; + + case SHADER_RESOURCE_TYPE_SAMPLER: + VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, "Unexpected descriptor range type"); + break; + + case SHADER_RESOURCE_TYPE_ACCEL_STRUCT: + { + VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV, "Unexpected descriptor range type"); + const auto* pTLASD3D12 = Res.pObject.RawPtr<const TopLevelASD3D12Impl>(); + if (pTLASD3D12->IsInKnownState() && !pTLASD3D12->CheckState(RESOURCE_STATE_RAY_TRACING)) + { + LOG_ERROR_MESSAGE("TLAS '", pTLASD3D12->GetDesc().Name, "' must be in RESOURCE_STATE_RAY_TRACING state. Actual state: ", + GetResourceStateString(pTLASD3D12->GetState()), + ". Call IDeviceContext::TransitionShaderResources(), use RESOURCE_STATE_TRANSITION_MODE_TRANSITION " + "when calling IDeviceContext::CommitShaderResources() or explicitly transition the TLAS state " + "with IDeviceContext::TransitionResourceStates()."); + } + } + break; + + default: + // Resource not bound + VERIFY(Res.Type == SHADER_RESOURCE_TYPE_UNKNOWN, "Unexpected resource type"); + VERIFY(Res.pObject == nullptr && Res.CPUDescriptorHandle.ptr == 0, "Bound resource is unexpected"); + } +} +#endif // DILIGENT_DEVELOPMENT + +// clang-format off +static D3D12_DESCRIPTOR_HEAP_TYPE RangeType2HeapTypeMap[] +{ + D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, //D3D12_DESCRIPTOR_RANGE_TYPE_SRV = 0 + D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, //D3D12_DESCRIPTOR_RANGE_TYPE_UAV = ( D3D12_DESCRIPTOR_RANGE_TYPE_SRV + 1 ) + D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, //D3D12_DESCRIPTOR_RANGE_TYPE_CBV = ( D3D12_DESCRIPTOR_RANGE_TYPE_UAV + 1 ) + D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER //D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER = ( D3D12_DESCRIPTOR_RANGE_TYPE_CBV + 1 ) +}; +// clang-format on +D3D12_DESCRIPTOR_HEAP_TYPE HeapTypeFromRangeType(D3D12_DESCRIPTOR_RANGE_TYPE RangeType) +{ + VERIFY_EXPR(RangeType >= D3D12_DESCRIPTOR_RANGE_TYPE_SRV && RangeType <= D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER); + auto HeapType = RangeType2HeapTypeMap[RangeType]; + +#ifdef DILIGENT_DEBUG + switch (RangeType) + { + // clang-format off + case D3D12_DESCRIPTOR_RANGE_TYPE_CBV: VERIFY_EXPR(HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); break; + case D3D12_DESCRIPTOR_RANGE_TYPE_SRV: VERIFY_EXPR(HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); break; + case D3D12_DESCRIPTOR_RANGE_TYPE_UAV: VERIFY_EXPR(HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); break; + case D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER: VERIFY_EXPR(HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); break; + // clang-format on + default: UNEXPECTED("Unexpected descriptor range type"); break; + } +#endif + return HeapType; +} + +Int32 FindImmutableSampler(const PipelineResourceDesc& Res, + const PipelineResourceSignatureDesc& Desc, + const char* SamplerSuffix) +{ + for (Uint32 s = 0; s < Desc.NumImmutableSamplers; ++s) + { + const auto& ImtblSam = Desc.ImmutableSamplers[s]; + if (((ImtblSam.ShaderStages & Res.ShaderStages) != 0) && StreqSuff(Res.Name, ImtblSam.SamplerOrTextureName, SamplerSuffix)) + { + DEV_CHECK_ERR((ImtblSam.ShaderStages & Res.ShaderStages) == Res.ShaderStages, + "Immutable sampler '", ImtblSam.SamplerOrTextureName, + "' is specified for only some of the shader stages that resource '", Res.Name, "' is defined for."); + return s; + } + } + + return -1; +} + +inline bool ResourcesCompatible(const PipelineResourceSignatureD3D12Impl::ResourceAttribs& lhs, + const PipelineResourceSignatureD3D12Impl::ResourceAttribs& rhs) +{ + // Ignore sampler index, signature root index & offset. + // clang-format off + return lhs.BindPoint == rhs.BindPoint && + lhs.Space == rhs.Space && + lhs.SRBRootIndex == rhs.SRBRootIndex && + lhs.SRBOffsetFromTableStart == rhs.SRBOffsetFromTableStart && + lhs.ImtblSamplerAssigned == rhs.ImtblSamplerAssigned; + // clang-format on +} + +inline bool ResourcesCompatible(const PipelineResourceDesc& lhs, const PipelineResourceDesc& rhs) +{ + // Ignore resource names. + // clang-format off + return lhs.ShaderStages == rhs.ShaderStages && + lhs.ArraySize == rhs.ArraySize && + lhs.ResourceType == rhs.ResourceType && + lhs.VarType == rhs.VarType && + lhs.Flags == rhs.Flags; + // clang-format on +} +} // namespace + + +inline PipelineResourceSignatureD3D12Impl::ROOT_TYPE +PipelineResourceSignatureD3D12Impl::GetRootType(SHADER_RESOURCE_VARIABLE_TYPE VarType) +{ + return VarType == SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC ? ROOT_TYPE_DYNAMIC : ROOT_TYPE_STATIC; +} + +PipelineResourceSignatureD3D12Impl::PipelineResourceSignatureD3D12Impl(IReferenceCounters* pRefCounters, + RenderDeviceD3D12Impl* pDevice, + const PipelineResourceSignatureDesc& Desc, + bool bIsDeviceInternal) : + TPipelineResourceSignatureBase{pRefCounters, pDevice, Desc, bIsDeviceInternal}, + m_RootParams{GetRawAllocator()}, + m_SRBMemAllocator{GetRawAllocator()} +{ + try + { + m_SrvCbvUavRootTablesMap.fill(InvalidRootTableIndex); + m_SamplerRootTablesMap.fill(InvalidRootTableIndex); + + FixedLinearAllocator MemPool{GetRawAllocator()}; + + // Reserve at least 1 element because m_pResourceAttribs must hold a pointer to memory + MemPool.AddSpace<ResourceAttribs>(std::max(1u, Desc.NumResources)); + MemPool.AddSpace<ImmutableSamplerAttribs>(m_Desc.NumImmutableSamplers); + + ReserveSpaceForDescription(MemPool, Desc); + + std::array<Uint32, D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER + 1> StaticResCacheTblSizes = {}; + + SHADER_TYPE StaticResStages = SHADER_TYPE_UNKNOWN; // Shader stages that have static resources + for (Uint32 i = 0; i < Desc.NumResources; ++i) + { + const auto& ResDesc = Desc.Resources[i]; + + m_ShaderStages |= ResDesc.ShaderStages; + + if (ResDesc.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC) + { + StaticResStages |= ResDesc.ShaderStages; + + // Use artifial root signature: + // SRVs at root index D3D12_DESCRIPTOR_RANGE_TYPE_SRV (0) + // UAVs at root index D3D12_DESCRIPTOR_RANGE_TYPE_UAV (1) + // CBVs at root index D3D12_DESCRIPTOR_RANGE_TYPE_CBV (2) + // Samplers at root index D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER (3) + const Uint32 RootIndex = GetDescriptorRangeType(ResDesc.ResourceType); + StaticResCacheTblSizes[RootIndex] += ResDesc.ArraySize; + } + } + + m_NumShaderStages = static_cast<Uint8>(PlatformMisc::CountOneBits(static_cast<Uint32>(m_ShaderStages))); + if (m_ShaderStages != SHADER_TYPE_UNKNOWN) + { + m_PipelineType = PipelineTypeFromShaderStages(m_ShaderStages); + DEV_CHECK_ERR(m_PipelineType != PIPELINE_TYPE_INVALID, "Failed to deduce pipeline type from shader stages"); + } + + int StaticVarStageCount = 0; // The number of shader stages that have static variables + for (; StaticResStages != SHADER_TYPE_UNKNOWN; ++StaticVarStageCount) + { + const auto StageBit = ExtractLSB(StaticResStages); + const auto ShaderTypeInd = GetShaderTypePipelineIndex(StageBit, m_PipelineType); + m_StaticVarIndex[ShaderTypeInd] = static_cast<Int8>(StaticVarStageCount); + } + if (StaticVarStageCount > 0) + { + MemPool.AddSpace<ShaderResourceCacheD3D12>(1); + MemPool.AddSpace<ShaderVariableManagerD3D12>(StaticVarStageCount); + } + + MemPool.Reserve(); + + m_pResourceAttribs = MemPool.Allocate<ResourceAttribs>(std::max(1u, m_Desc.NumResources)); + m_ImmutableSamplers = MemPool.ConstructArray<ImmutableSamplerAttribs>(m_Desc.NumImmutableSamplers); + + // The memory is now owned by PipelineResourceSignatureD3D12Impl and will be freed by Destruct(). + auto* Ptr = MemPool.ReleaseOwnership(); + VERIFY_EXPR(Ptr == m_pResourceAttribs); + (void)Ptr; + + CopyDescription(MemPool, Desc); + + if (StaticVarStageCount > 0) + { + m_pStaticResCache = MemPool.Construct<ShaderResourceCacheD3D12>(CacheContentType::Signature); + m_StaticVarsMgrs = MemPool.Allocate<ShaderVariableManagerD3D12>(StaticVarStageCount); + + m_pStaticResCache->Initialize(GetRawAllocator(), static_cast<Uint32>(StaticResCacheTblSizes.size()), StaticResCacheTblSizes.data()); +#ifdef DILIGENT_DEBUG + m_pStaticResCache->GetRootTable(D3D12_DESCRIPTOR_RANGE_TYPE_SRV).SetDebugAttribs(StaticResCacheTblSizes[D3D12_DESCRIPTOR_RANGE_TYPE_SRV], D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, false); + m_pStaticResCache->GetRootTable(D3D12_DESCRIPTOR_RANGE_TYPE_UAV).SetDebugAttribs(StaticResCacheTblSizes[D3D12_DESCRIPTOR_RANGE_TYPE_UAV], D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, false); + m_pStaticResCache->GetRootTable(D3D12_DESCRIPTOR_RANGE_TYPE_CBV).SetDebugAttribs(StaticResCacheTblSizes[D3D12_DESCRIPTOR_RANGE_TYPE_CBV], D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, false); + m_pStaticResCache->GetRootTable(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER).SetDebugAttribs(StaticResCacheTblSizes[D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER], D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, false); +#endif + } + + CreateLayout(); + + if (StaticVarStageCount > 0) + { + const SHADER_RESOURCE_VARIABLE_TYPE AllowedVarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_STATIC}; + + for (Uint32 i = 0; i < m_StaticVarIndex.size(); ++i) + { + Int8 Idx = m_StaticVarIndex[i]; + if (Idx >= 0) + { + VERIFY_EXPR(Idx < StaticVarStageCount); + const auto ShaderType = GetShaderTypeFromPipelineIndex(i, GetPipelineType()); + new (m_StaticVarsMgrs + Idx) ShaderVariableManagerD3D12{*this, *m_pStaticResCache}; + m_StaticVarsMgrs[Idx].Initialize(*this, GetRawAllocator(), AllowedVarTypes, _countof(AllowedVarTypes), ShaderType); + } + } + } + + m_Hash = CalculateHash(); + } + catch (...) + { + Destruct(); + throw; + } +} + +void PipelineResourceSignatureD3D12Impl::CreateLayout() +{ + const Uint32 FirstSpace = GetBaseRegisterSpace(); + + std::array<Uint32, D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER + 1> NumResources = {}; + std::array<Uint32, D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER + 1> StaticResCacheTblSizes = {}; + + for (Uint32 i = 0; i < m_Desc.NumResources; ++i) + { + const auto& ResDesc = m_Desc.Resources[i]; + + VERIFY(i == 0 || ResDesc.VarType >= m_Desc.Resources[i - 1].VarType, "Resources must be sorted by variable type"); + + const bool IsRuntimeSizedArray = (ResDesc.Flags & PIPELINE_RESOURCE_FLAG_RUNTIME_ARRAY) != 0; + const auto DescriptorRangeType = GetDescriptorRangeType(ResDesc.ResourceType); + const Uint32 BindPoint = IsRuntimeSizedArray ? 0 : NumResources[DescriptorRangeType]; + const Uint32 Space = (IsRuntimeSizedArray ? m_NumSpaces++ : 0); + Uint32 SRBRootIndex = ResourceAttribs::InvalidSRBRootIndex; + Uint32 SRBOffsetFromTableStart = ResourceAttribs::InvalidOffset; + Uint32 SigRootIndex = ResourceAttribs::InvalidSigRootIndex; + Uint32 SigOffsetFromTableStart = ResourceAttribs::InvalidOffset; + + if (ResDesc.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC) + { + // Use artifial root signature: + // SRVs at root index D3D12_DESCRIPTOR_RANGE_TYPE_SRV (0) + // UAVs at root index D3D12_DESCRIPTOR_RANGE_TYPE_UAV (1) + // CBVs at root index D3D12_DESCRIPTOR_RANGE_TYPE_CBV (2) + // Samplers at root index D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER (3) + SigRootIndex = GetDescriptorRangeType(ResDesc.ResourceType); + SigOffsetFromTableStart = StaticResCacheTblSizes[SigRootIndex]; + StaticResCacheTblSizes[SigRootIndex] += ResDesc.ArraySize; + } + + //* + const bool IsBuffer = + ResDesc.ResourceType == SHADER_RESOURCE_TYPE_CONSTANT_BUFFER || + ResDesc.ResourceType == SHADER_RESOURCE_TYPE_BUFFER_SRV || + ResDesc.ResourceType == SHADER_RESOURCE_TYPE_BUFFER_UAV; + const bool UseDynamicOffset = (ResDesc.Flags & PIPELINE_RESOURCE_FLAG_NO_DYNAMIC_BUFFERS) == 0; + const bool IsFormattedBuffer = (ResDesc.Flags & PIPELINE_RESOURCE_FLAG_FORMATTED_BUFFER) != 0; + const bool IsRootView = IsBuffer && UseDynamicOffset && !IsFormattedBuffer; + /*/ + const bool IsRootView = false; + //*/ + + // runtime sized array must be in separate space + if (!IsRuntimeSizedArray) + NumResources[DescriptorRangeType] += ResDesc.ArraySize; + + const Int32 SrcImmutableSamplerInd = ResDesc.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER ? + FindImmutableSampler(ResDesc, m_Desc, GetCombinedSamplerSuffix()) : + -1; + + const auto AssignedSamplerInd = (SrcImmutableSamplerInd == -1 && ResDesc.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_SRV) ? + FindAssignedSampler(ResDesc) : + ResourceAttribs::InvalidSamplerInd; + + if (SrcImmutableSamplerInd >= 0) + { + auto& ImmutableSampler = m_ImmutableSamplers[SrcImmutableSamplerInd]; + + if (!ImmutableSampler.IsAssigned()) + { + ImmutableSampler.ShaderRegister = BindPoint; + ImmutableSampler.RegisterSpace = Space; + ImmutableSampler.ArraySize = ResDesc.ArraySize; + } + else + { + // Use previous bind point and decrease resource counter + if (!IsRuntimeSizedArray) + NumResources[DescriptorRangeType] -= ResDesc.ArraySize; + } + } + else + { + AllocateResourceSlot(ResDesc.ShaderStages, ResDesc.VarType, DescriptorRangeType, ResDesc.ArraySize, IsRootView, BindPoint, FirstSpace + Space, SRBRootIndex, SRBOffsetFromTableStart); + } + + new (m_pResourceAttribs + i) ResourceAttribs // + { + BindPoint, + Space, + AssignedSamplerInd, + SRBRootIndex, + SRBOffsetFromTableStart, + SigRootIndex, + SigOffsetFromTableStart, + SrcImmutableSamplerInd >= 0, + IsRootView // + }; + } + + // Add immutable samplers that do not exist in m_Desc.Resources + for (Uint32 i = 0; i < m_Desc.NumImmutableSamplers; ++i) + { + auto& ImmutableSampler = m_ImmutableSamplers[i]; + if (ImmutableSampler.IsAssigned()) + continue; + + const auto DescriptorRangeType = GetDescriptorRangeType(SHADER_RESOURCE_TYPE_SAMPLER); + + ImmutableSampler.RegisterSpace = FirstSpace; + ImmutableSampler.ShaderRegister = NumResources[DescriptorRangeType]; + NumResources[DescriptorRangeType] += 1; + } + + if (m_Desc.SRBAllocationGranularity > 1) + { + std::array<size_t, MAX_SHADERS_IN_PIPELINE> ShaderVariableDataSizes = {}; + for (Uint32 s = 0; s < GetNumActiveShaderStages(); ++s) + { + const SHADER_RESOURCE_VARIABLE_TYPE AllowedVarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC}; + + Uint32 UnusedNumVars = 0; + ShaderVariableDataSizes[s] = ShaderVariableManagerD3D12::GetRequiredMemorySize(*this, AllowedVarTypes, _countof(AllowedVarTypes), GetActiveShaderStageType(s), UnusedNumVars); + } + + auto CacheTableSizes = GetCacheTableSizes(); + auto CacheMemorySize = ShaderResourceCacheD3D12::GetRequiredMemorySize(static_cast<Uint32>(CacheTableSizes.size()), CacheTableSizes.data()); + m_SRBMemAllocator.Initialize(m_Desc.SRBAllocationGranularity, GetNumActiveShaderStages(), ShaderVariableDataSizes.data(), 1, &CacheMemorySize); + } +} + +Uint32 PipelineResourceSignatureD3D12Impl::FindAssignedSampler(const PipelineResourceDesc& SepImg) const +{ + Uint32 SamplerInd = ResourceAttribs::InvalidSamplerInd; + if (IsUsingCombinedSamplers()) + { + const auto IdxRange = GetResourceIndexRange(SepImg.VarType); + + for (Uint32 i = IdxRange.first; i < IdxRange.second; ++i) + { + const auto& Res = m_Desc.Resources[i]; + VERIFY_EXPR(SepImg.VarType == Res.VarType); + + if (Res.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER && + (SepImg.ShaderStages & Res.ShaderStages) && + StreqSuff(Res.Name, SepImg.Name, GetCombinedSamplerSuffix())) + { + VERIFY_EXPR((Res.ShaderStages & SepImg.ShaderStages) == SepImg.ShaderStages); + SamplerInd = i; + break; + } + } + } + return SamplerInd; +} + +// http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-layout#Initializing-Shader-Resource-Layouts-and-Root-Signature-in-a-Pipeline-State-Object +void PipelineResourceSignatureD3D12Impl::AllocateResourceSlot(SHADER_TYPE ShaderStages, + SHADER_RESOURCE_VARIABLE_TYPE VariableType, + D3D12_DESCRIPTOR_RANGE_TYPE RangeType, + Uint32 ArraySize, + bool IsRootView, + Uint32 BindPoint, + Uint32 Space, + Uint32& RootIndex, // Output parameter + Uint32& OffsetFromTableStart // Output parameter +) +{ + D3D12_SHADER_VISIBILITY ShaderVisibility; + Uint32 RootTableIndex; + GetRootTableIndex(ShaderStages, ShaderVisibility, RootTableIndex); + + const auto RootType = GetRootType(VariableType); + + // Get the next available root index past all allocated tables and root views + RootIndex = m_RootParams.GetNumRootTables() + m_RootParams.GetNumRootViews(); + + if (IsRootView) + { + // Allocate single CBV directly in the root signature + OffsetFromTableStart = 0; + + // Add new root view to existing root parameters + m_RootParams.AddRootView(D3D12_ROOT_PARAMETER_TYPE_CBV, RootIndex, BindPoint, Space, ShaderVisibility, RootType); // AZ TODO: add SRV & UAV + } + else + { + const bool IsSampler = (RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER); + const auto TableIndKey = RootTableIndex * ROOT_TYPE_COUNT + Uint32{RootType}; + // Get the table array index (this is not the root index!) + auto& RootTableArrayInd = (IsSampler ? m_SamplerRootTablesMap : m_SrvCbvUavRootTablesMap)[TableIndKey]; + if (RootTableArrayInd == InvalidRootTableIndex) + { + // Root table has not been assigned to this combination yet + VERIFY_EXPR(m_RootParams.GetNumRootTables() < 255); + RootTableArrayInd = static_cast<Uint8>(m_RootParams.GetNumRootTables()); + // Add root table with one single-descriptor range + m_RootParams.AddRootTable(RootIndex, ShaderVisibility, RootType, 1); + } + else + { + // Add a new single-descriptor range to the existing table at index RootTableArrayInd + m_RootParams.AddDescriptorRanges(RootTableArrayInd, 1); + } + + (IsSampler ? m_TotalSamplerSlots : m_TotalSrvCbvUavSlots)[RootType] += ArraySize; + + // Reference to either existing or just added table + auto& CurrParam = m_RootParams.GetRootTable(RootTableArrayInd); + RootIndex = CurrParam.GetLocalRootIndex(); + + const auto& d3d12RootParam = static_cast<const D3D12_ROOT_PARAMETER&>(CurrParam); + + VERIFY(d3d12RootParam.ShaderVisibility == ShaderVisibility, "Shader visibility is not correct"); + + // Descriptors are tightly packed, so the next descriptor offset is the + // current size of the table + OffsetFromTableStart = CurrParam.GetDescriptorTableSize(); + + // New just added range is the last range in the descriptor table + Uint32 NewDescriptorRangeIndex = d3d12RootParam.DescriptorTable.NumDescriptorRanges - 1; + CurrParam.SetDescriptorRange(NewDescriptorRangeIndex, + RangeType, // Range type (CBV, SRV, UAV or SAMPLER) + BindPoint, // Shader register + Space, // Shader register space + ArraySize, // Number of registers used (1 for non-array resources) + OffsetFromTableStart // Offset in descriptors from the table start + ); + } +} + +PipelineResourceSignatureD3D12Impl::~PipelineResourceSignatureD3D12Impl() +{ + Destruct(); +} + +void PipelineResourceSignatureD3D12Impl::Destruct() +{ + TPipelineResourceSignatureBase::Destruct(); + + if (m_pResourceAttribs == nullptr) + return; // memory is not allocated + + auto& RawAllocator = GetRawAllocator(); + + if (m_StaticVarsMgrs != nullptr) + { + for (size_t i = 0; i < m_StaticVarIndex.size(); ++i) + { + auto Idx = m_StaticVarIndex[i]; + if (Idx >= 0) + { + m_StaticVarsMgrs[Idx].Destroy(RawAllocator); + m_StaticVarsMgrs[Idx].~ShaderVariableManagerD3D12(); + } + } + m_StaticVarIndex.fill(-1); + m_StaticVarsMgrs = nullptr; + } + + if (m_pStaticResCache != nullptr) + { + m_pStaticResCache->~ShaderResourceCacheD3D12(); + m_pStaticResCache = nullptr; + } + + for (Uint32 i = 0; i < m_Desc.NumImmutableSamplers; ++i) + { + m_ImmutableSamplers[i].~ImmutableSamplerAttribs(); + } + m_ImmutableSamplers = nullptr; + + if (void* pRawMem = m_pResourceAttribs) + { + RawAllocator.Free(pRawMem); + m_pResourceAttribs = nullptr; + } +} + +bool PipelineResourceSignatureD3D12Impl::IsCompatibleWith(const PipelineResourceSignatureD3D12Impl& Other) const +{ + if (this == &Other) + return true; + + if (GetHash() != Other.GetHash()) + return false; + + if (GetDesc().BindingIndex != Other.GetDesc().BindingIndex) + return false; + + const Uint32 LResCount = GetTotalResourceCount(); + const Uint32 RResCount = Other.GetTotalResourceCount(); + + if (LResCount != RResCount) + return false; + + for (Uint32 r = 0; r < LResCount; ++r) + { + if (!ResourcesCompatible(GetResourceAttribs(r), Other.GetResourceAttribs(r)) || + !ResourcesCompatible(GetResourceDesc(r), Other.GetResourceDesc(r))) + return false; + } + + const Uint32 LSampCount = GetDesc().NumImmutableSamplers; + const Uint32 RSampCount = Other.GetDesc().NumImmutableSamplers; + + if (LSampCount != RSampCount) + return false; + + for (Uint32 s = 0; s < LSampCount; ++s) + { + const auto& LSamp = GetDesc().ImmutableSamplers[s]; + const auto& RSamp = Other.GetDesc().ImmutableSamplers[s]; + + if (LSamp.ShaderStages != RSamp.ShaderStages || + !(LSamp.Desc == RSamp.Desc)) + return false; + } + + return true; +} + +void PipelineResourceSignatureD3D12Impl::CreateShaderResourceBinding(IShaderResourceBinding** ppShaderResourceBinding, + bool InitStaticResources) +{ + auto& SRBAllocator = m_pDevice->GetSRBAllocator(); + auto pResBindingD3D12 = NEW_RC_OBJ(SRBAllocator, "ShaderResourceBindingD3D12Impl instance", ShaderResourceBindingD3D12Impl)(this, false); + if (InitStaticResources) + pResBindingD3D12->InitializeStaticResources(nullptr); + pResBindingD3D12->QueryInterface(IID_ShaderResourceBinding, reinterpret_cast<IObject**>(ppShaderResourceBinding)); +} + +Uint32 PipelineResourceSignatureD3D12Impl::GetStaticVariableCount(SHADER_TYPE ShaderType) const +{ + const auto VarMngrInd = GetStaticVariableCountHelper(ShaderType, m_StaticVarIndex); + if (VarMngrInd < 0) + return 0; + + auto& StaticVarMgr = m_StaticVarsMgrs[VarMngrInd]; + return StaticVarMgr.GetVariableCount(); +} + +IShaderResourceVariable* PipelineResourceSignatureD3D12Impl::GetStaticVariableByName(SHADER_TYPE ShaderType, const Char* Name) +{ + const auto VarMngrInd = GetStaticVariableByNameHelper(ShaderType, Name, m_StaticVarIndex); + if (VarMngrInd < 0) + return nullptr; + + auto& StaticVarMgr = m_StaticVarsMgrs[VarMngrInd]; + return StaticVarMgr.GetVariable(Name); +} + +IShaderResourceVariable* PipelineResourceSignatureD3D12Impl::GetStaticVariableByIndex(SHADER_TYPE ShaderType, Uint32 Index) +{ + const auto VarMngrInd = GetStaticVariableByIndexHelper(ShaderType, Index, m_StaticVarIndex); + if (VarMngrInd < 0) + return nullptr; + + auto& StaticVarMgr = m_StaticVarsMgrs[VarMngrInd]; + return StaticVarMgr.GetVariable(Index); +} + +void PipelineResourceSignatureD3D12Impl::BindStaticResources(Uint32 ShaderFlags, + IResourceMapping* pResMapping, + Uint32 Flags) +{ + const auto PipelineType = GetPipelineType(); + for (Uint32 ShaderInd = 0; ShaderInd < m_StaticVarIndex.size(); ++ShaderInd) + { + const auto VarMngrInd = m_StaticVarIndex[ShaderInd]; + if (VarMngrInd >= 0) + { + // ShaderInd is the shader type pipeline index here + const auto ShaderType = GetShaderTypeFromPipelineIndex(ShaderInd, PipelineType); + if (ShaderFlags & ShaderType) + { + m_StaticVarsMgrs[VarMngrInd].BindResources(pResMapping, Flags); + } + } + } +} + +size_t PipelineResourceSignatureD3D12Impl::CalculateHash() const +{ + if (m_Desc.NumResources == 0 && m_Desc.NumImmutableSamplers == 0) + return 0; + + size_t Hash = ComputeHash(m_Desc.NumResources, m_Desc.NumImmutableSamplers, m_Desc.BindingIndex); + + for (Uint32 i = 0; i < m_Desc.NumResources; ++i) + { + const auto& Res = m_Desc.Resources[i]; + const auto& Attr = m_pResourceAttribs[i]; + + HashCombine(Hash, Res.ArraySize, Uint32{Res.ShaderStages}, Uint32{Res.VarType}, Uint32{Res.Flags}, + Attr.BindPoint, Attr.Space, Attr.SRBRootIndex, Attr.SRBOffsetFromTableStart, Attr.IsImmutableSamplerAssigned()); + } + + for (Uint32 i = 0; i < m_Desc.NumImmutableSamplers; ++i) + { + HashCombine(Hash, Uint32{m_Desc.ImmutableSamplers[i].ShaderStages}, m_Desc.ImmutableSamplers[i].Desc); + } + + return Hash; +} + +std::vector<Uint32, STDAllocatorRawMem<Uint32>> PipelineResourceSignatureD3D12Impl::GetCacheTableSizes() const +{ + // Get root table size for every root index + // m_RootParams keeps root tables sorted by the array index, not the root index + // Root views are treated as one-descriptor tables + std::vector<Uint32, STDAllocatorRawMem<Uint32>> CacheTableSizes(m_RootParams.GetNumRootTables() + m_RootParams.GetNumRootViews(), 0, STD_ALLOCATOR_RAW_MEM(Uint32, GetRawAllocator(), "Allocator for vector<Uint32>")); + for (Uint32 rt = 0; rt < m_RootParams.GetNumRootTables(); ++rt) + { + auto& RootParam = m_RootParams.GetRootTable(rt); + CacheTableSizes[RootParam.GetLocalRootIndex()] = RootParam.GetDescriptorTableSize(); + } + + for (Uint32 rv = 0; rv < m_RootParams.GetNumRootViews(); ++rv) + { + auto& RootParam = m_RootParams.GetRootView(rv); + CacheTableSizes[RootParam.GetLocalRootIndex()] = 1; + } + + return CacheTableSizes; +} + +void PipelineResourceSignatureD3D12Impl::InitSRBResourceCache(ShaderResourceCacheD3D12& ResourceCache, + IMemoryAllocator& CacheMemAllocator, + const char* DbgPipelineName) const +{ + auto CacheTableSizes = GetCacheTableSizes(); + + // Initialize resource cache to hold root tables + ResourceCache.Initialize(CacheMemAllocator, static_cast<Uint32>(CacheTableSizes.size()), CacheTableSizes.data()); + + // Allocate space in GPU-visible descriptor heap for static and mutable variables only + Uint32 TotalSrvCbvUavDescriptors = m_TotalSrvCbvUavSlots[ROOT_TYPE_STATIC]; + Uint32 TotalSamplerDescriptors = m_TotalSamplerSlots[ROOT_TYPE_STATIC]; + + DescriptorHeapAllocation CbcSrvUavHeapSpace, SamplerHeapSpace; + if (TotalSrvCbvUavDescriptors) + { + CbcSrvUavHeapSpace = GetDevice()->AllocateGPUDescriptors(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, TotalSrvCbvUavDescriptors); + DEV_CHECK_ERR(!CbcSrvUavHeapSpace.IsNull(), + "Failed to allocate ", TotalSrvCbvUavDescriptors, " GPU-visible CBV/SRV/UAV descriptor", + (TotalSrvCbvUavDescriptors > 1 ? "s" : ""), + ". Consider increasing GPUDescriptorHeapSize[0] in EngineD3D12CreateInfo."); + } + VERIFY_EXPR(TotalSrvCbvUavDescriptors == 0 && CbcSrvUavHeapSpace.IsNull() || CbcSrvUavHeapSpace.GetNumHandles() == TotalSrvCbvUavDescriptors); + + if (TotalSamplerDescriptors) + { + SamplerHeapSpace = GetDevice()->AllocateGPUDescriptors(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, TotalSamplerDescriptors); + DEV_CHECK_ERR(!SamplerHeapSpace.IsNull(), + "Failed to allocate ", TotalSamplerDescriptors, " GPU-visible Sampler descriptor", + (TotalSamplerDescriptors > 1 ? "s" : ""), + ". Consider using immutable samplers in the Pipeline State Object or " + "increasing GPUDescriptorHeapSize[1] in EngineD3D12CreateInfo."); + } + VERIFY_EXPR(TotalSamplerDescriptors == 0 && SamplerHeapSpace.IsNull() || SamplerHeapSpace.GetNumHandles() == TotalSamplerDescriptors); + + // Iterate through all root static/mutable tables and assign start offsets. The tables are tightly packed, so + // start offset of table N+1 is start offset of table N plus the size of table N. + // Root tables with dynamic resources as well as root views are not assigned space in GPU-visible allocation + // (root views are simply not processed) + Uint32 SrvCbvUavTblStartOffset = 0; + Uint32 SamplerTblStartOffset = 0; + for (Uint32 rt = 0; rt < m_RootParams.GetNumRootTables(); ++rt) + { + auto& RootParam = m_RootParams.GetRootTable(rt); + const auto& D3D12RootParam = static_cast<const D3D12_ROOT_PARAMETER&>(RootParam); + auto& RootTableCache = ResourceCache.GetRootTable(RootParam.GetLocalRootIndex()); + const bool IsDynamic = RootParam.GetRootType() == ROOT_TYPE_DYNAMIC; + + VERIFY_EXPR(D3D12RootParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE); + + auto TableSize = RootParam.GetDescriptorTableSize(); + VERIFY(TableSize > 0, "Unexpected empty descriptor table"); + + auto HeapType = HeapTypeFromRangeType(D3D12RootParam.DescriptorTable.pDescriptorRanges[0].RangeType); + +#ifdef DILIGENT_DEBUG + RootTableCache.SetDebugAttribs(TableSize, HeapType, IsDynamic); +#endif + + // Space for dynamic variables is allocated at every draw call + if (!IsDynamic) + { + if (HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV) + { + RootTableCache.m_TableStartOffset = SrvCbvUavTblStartOffset; + SrvCbvUavTblStartOffset += TableSize; + } + else + { + RootTableCache.m_TableStartOffset = SamplerTblStartOffset; + SamplerTblStartOffset += TableSize; + } + } + else + { + // AZ TODO: optimization: break on first dynamic resource + + VERIFY_EXPR(RootTableCache.m_TableStartOffset == ShaderResourceCacheD3D12::InvalidDescriptorOffset); + } + } + +#ifdef DILIGENT_DEBUG + for (Uint32 rv = 0; rv < m_RootParams.GetNumRootViews(); ++rv) + { + auto& RootParam = m_RootParams.GetRootView(rv); + const auto& D3D12RootParam = static_cast<const D3D12_ROOT_PARAMETER&>(RootParam); + auto& RootTableCache = ResourceCache.GetRootTable(RootParam.GetLocalRootIndex()); + const bool IsDynamic = RootParam.GetRootType() == ROOT_TYPE_DYNAMIC; + + // Root views are not assigned valid table start offset + VERIFY_EXPR(RootTableCache.m_TableStartOffset == ShaderResourceCacheD3D12::InvalidDescriptorOffset); + + VERIFY_EXPR(D3D12RootParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_CBV); + RootTableCache.SetDebugAttribs(1, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, IsDynamic); + } +#endif + + VERIFY_EXPR(SrvCbvUavTblStartOffset == TotalSrvCbvUavDescriptors); + VERIFY_EXPR(SamplerTblStartOffset == TotalSamplerDescriptors); + + ResourceCache.SetDescriptorHeapSpace(std::move(CbcSrvUavHeapSpace), std::move(SamplerHeapSpace)); +} + +void PipelineResourceSignatureD3D12Impl::InitializeStaticSRBResources(ShaderResourceCacheD3D12& DstResourceCache) const +{ + if (m_pStaticResCache == nullptr) + return; + + // SrcResourceCache contains only static resources. + // DstResourceCache contains static, mutable and dynamic resources. + const auto& SrcResourceCache = *m_pStaticResCache; + const auto ResIdxRange = GetResourceIndexRange(SHADER_RESOURCE_VARIABLE_TYPE_STATIC); + auto* d3d12Device = GetDevice()->GetD3D12Device(); + const auto SrcCacheType = SrcResourceCache.GetContentType(); + const auto DstCacheType = DstResourceCache.GetContentType(); + + auto& DstBoundDynamicCBsCounter = DstResourceCache.GetBoundDynamicCBsCounter(); + + for (Uint32 r = ResIdxRange.first; r < ResIdxRange.second; ++r) + { + const auto& ResDesc = GetResourceDesc(r); + const auto& Attr = GetResourceAttribs(r); + VERIFY_EXPR(ResDesc.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC); + + const auto DstRootIndex = Attr.RootIndex(DstCacheType); + const auto& SrcRootTable = SrcResourceCache.GetRootTable(Attr.RootIndex(SrcCacheType)); + auto& DstRootTable = DstResourceCache.GetRootTable(DstRootIndex); + + for (Uint32 ArrInd = 0; ArrInd < ResDesc.ArraySize; ++ArrInd) + { + const auto SrcCacheOffset = Attr.OffsetFromTableStart(SrcCacheType) + ArrInd; + const auto DstCacheOffset = Attr.OffsetFromTableStart(DstCacheType) + ArrInd; + const bool IsSampler = (ResDesc.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER); + + const auto& SrcRes = SrcRootTable.GetResource(SrcCacheOffset, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + if (!SrcRes.pObject) + LOG_ERROR_MESSAGE("No resource is assigned to static shader variable '", GetShaderResourcePrintName(ResDesc, ArrInd), "' in pipeline resource signature '", m_Desc.Name, "'."); + + auto& DstRes = DstRootTable.GetResource(DstCacheOffset, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + if (DstRes.pObject != SrcRes.pObject) + { + DEV_CHECK_ERR(DstRes.pObject == nullptr, "Static resource has already been initialized, and the resource to be assigned from the shader does not match previously assigned resource"); + + if (SrcRes.Type == SHADER_RESOURCE_TYPE_CONSTANT_BUFFER) + { + if (DstRes.pObject && DstRes.pObject.RawPtr<const BufferD3D12Impl>()->GetDesc().Usage == USAGE_DYNAMIC) + { + VERIFY_EXPR(DstBoundDynamicCBsCounter > 0); + --DstBoundDynamicCBsCounter; + } + if (SrcRes.pObject && SrcRes.pObject.RawPtr<const BufferD3D12Impl>()->GetDesc().Usage == USAGE_DYNAMIC) + { + ++DstBoundDynamicCBsCounter; + } + } + + DstRes.pObject = SrcRes.pObject; + DstRes.Type = SrcRes.Type; + DstRes.CPUDescriptorHandle = SrcRes.CPUDescriptorHandle; + + if (IsSampler) + { + auto ShdrVisibleSamplerHeapCPUDescriptorHandle = DstResourceCache.GetShaderVisibleTableCPUDescriptorHandle<D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER>(DstRootIndex, DstCacheOffset); + VERIFY_EXPR(ShdrVisibleSamplerHeapCPUDescriptorHandle.ptr != 0); + + if (ShdrVisibleSamplerHeapCPUDescriptorHandle.ptr != 0) + { + VERIFY_EXPR(SrcRes.CPUDescriptorHandle.ptr != 0); + d3d12Device->CopyDescriptorsSimple(1, ShdrVisibleSamplerHeapCPUDescriptorHandle, SrcRes.CPUDescriptorHandle, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); + } + } + else + { + auto ShdrVisibleHeapCPUDescriptorHandle = DstResourceCache.GetShaderVisibleTableCPUDescriptorHandle<D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV>(DstRootIndex, DstCacheOffset); + VERIFY_EXPR(ShdrVisibleHeapCPUDescriptorHandle.ptr != 0 || DstRes.Type == SHADER_RESOURCE_TYPE_CONSTANT_BUFFER); + + // Root views are not assigned space in the GPU-visible descriptor heap allocation + if (ShdrVisibleHeapCPUDescriptorHandle.ptr != 0 && SrcRes.CPUDescriptorHandle.ptr != 0) + { + VERIFY_EXPR(SrcRes.CPUDescriptorHandle.ptr != 0); + d3d12Device->CopyDescriptorsSimple(1, ShdrVisibleHeapCPUDescriptorHandle, SrcRes.CPUDescriptorHandle, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + } + } + } + else + { + VERIFY_EXPR(DstRes.pObject == SrcRes.pObject); + VERIFY_EXPR(DstRes.Type == SrcRes.Type); + VERIFY_EXPR(DstRes.CPUDescriptorHandle.ptr == SrcRes.CPUDescriptorHandle.ptr); + } + } + } +} + +void PipelineResourceSignatureD3D12Impl::TransitionResources(ShaderResourceCacheD3D12& ResourceCache, + CommandContext& Ctx, + bool PerformResourceTransitions, + bool ValidateStates) const +{ + m_RootParams.ProcessRootTables( + [&](Uint32 RootInd, + const RootParameter& RootTable, + const D3D12_ROOT_PARAMETER& D3D12Param, + bool IsResourceTable, + D3D12_DESCRIPTOR_HEAP_TYPE dbgHeapType) // + { + ProcessCachedTableResources( + RootInd, D3D12Param, ResourceCache, dbgHeapType, + [&](UINT OffsetFromTableStart, + const D3D12_DESCRIPTOR_RANGE& range, + ShaderResourceCacheD3D12::Resource& Res) // + { + // AZ TODO: optimize + if (PerformResourceTransitions) + { + TransitionResource(Ctx, Res, range.RangeType); + } +#ifdef DILIGENT_DEVELOPMENT + else if (ValidateStates) + { + DvpVerifyResourceState(Res, range.RangeType); + } +#endif + } // + ); + } // + ); +} + +void PipelineResourceSignatureD3D12Impl::CommitRootTables(ShaderResourceCacheD3D12& ResourceCache, + CommandContext& CmdCtx, + DeviceContextD3D12Impl* pDeviceCtx, + Uint32 DeviceCtxId, + bool IsCompute, + Uint32 FirstRootIndex) +{ + auto* pd3d12Device = GetDevice()->GetD3D12Device(); + + Uint32 NumDynamicCbvSrvUavDescriptors = m_TotalSrvCbvUavSlots[ROOT_TYPE_DYNAMIC]; + Uint32 NumDynamicSamplerDescriptors = m_TotalSamplerSlots[ROOT_TYPE_DYNAMIC]; + //VERIFY_EXPR(NumDynamicCbvSrvUavDescriptors > 0 || NumDynamicSamplerDescriptors > 0); + + DescriptorHeapAllocation DynamicCbvSrvUavDescriptors, DynamicSamplerDescriptors; + if (NumDynamicCbvSrvUavDescriptors > 0) + { + DynamicCbvSrvUavDescriptors = CmdCtx.AllocateDynamicGPUVisibleDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, NumDynamicCbvSrvUavDescriptors); + DEV_CHECK_ERR(DynamicCbvSrvUavDescriptors.GetDescriptorHeap() != nullptr, + "Failed to allocate ", NumDynamicCbvSrvUavDescriptors, " dynamic GPU-visible CBV/SRV/UAV descriptor", + (NumDynamicCbvSrvUavDescriptors > 1 ? "s" : ""), + ". Consider increasing GPUDescriptorHeapDynamicSize[0] in EngineD3D12CreateInfo " + "or optimizing dynamic resource utilization by using static or mutable shader resource variables instead."); + } + + if (NumDynamicSamplerDescriptors > 0) + { + DynamicSamplerDescriptors = CmdCtx.AllocateDynamicGPUVisibleDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, NumDynamicSamplerDescriptors); + DEV_CHECK_ERR(DynamicSamplerDescriptors.GetDescriptorHeap() != nullptr, + "Failed to allocate ", NumDynamicSamplerDescriptors, " dynamic GPU-visible Sampler descriptor", + (NumDynamicSamplerDescriptors > 1 ? "s" : ""), + ". Consider using immutable samplers in the Pipeline State Object, increasing GPUDescriptorHeapDynamicSize[1] in " + "EngineD3D12CreateInfo, or optimizing dynamic resource utilization by using static or mutable shader resource variables instead."); + } + + CommandContext::ShaderDescriptorHeaps Heaps(ResourceCache.GetSrvCbvUavDescriptorHeap(), ResourceCache.GetSamplerDescriptorHeap()); + if (Heaps.pSamplerHeap == nullptr) + Heaps.pSamplerHeap = DynamicSamplerDescriptors.GetDescriptorHeap(); + + if (Heaps.pSrvCbvUavHeap == nullptr) + Heaps.pSrvCbvUavHeap = DynamicCbvSrvUavDescriptors.GetDescriptorHeap(); + + if (NumDynamicCbvSrvUavDescriptors > 0) + VERIFY(DynamicCbvSrvUavDescriptors.GetDescriptorHeap() == Heaps.pSrvCbvUavHeap, "Inconsistent CbvSrvUav descriptor heaps"); + if (NumDynamicSamplerDescriptors > 0) + VERIFY(DynamicSamplerDescriptors.GetDescriptorHeap() == Heaps.pSamplerHeap, "Inconsistent Sampler descriptor heaps"); + + if (Heaps) + CmdCtx.SetDescriptorHeaps(Heaps); + + // Offset to the beginning of the current dynamic CBV_SRV_UAV/SAMPLER table from + // the start of the allocation + Uint32 DynamicCbvSrvUavTblOffset = 0; + Uint32 DynamicSamplerTblOffset = 0; + + m_RootParams.ProcessRootTables( + [&](Uint32 RootInd, + const RootParameter& RootTable, + const D3D12_ROOT_PARAMETER& D3D12Param, + bool IsResourceTable, + D3D12_DESCRIPTOR_HEAP_TYPE dbgHeapType) // + { + D3D12_GPU_DESCRIPTOR_HANDLE RootTableGPUDescriptorHandle; + + bool IsDynamicTable = RootTable.GetRootType() == ROOT_TYPE_DYNAMIC; + if (IsDynamicTable) + { + if (IsResourceTable) + RootTableGPUDescriptorHandle = DynamicCbvSrvUavDescriptors.GetGpuHandle(DynamicCbvSrvUavTblOffset); + else + RootTableGPUDescriptorHandle = DynamicSamplerDescriptors.GetGpuHandle(DynamicSamplerTblOffset); + } + else + { + RootTableGPUDescriptorHandle = IsResourceTable ? + ResourceCache.GetShaderVisibleTableGPUDescriptorHandle<D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV>(RootInd) : + ResourceCache.GetShaderVisibleTableGPUDescriptorHandle<D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER>(RootInd); + VERIFY(RootTableGPUDescriptorHandle.ptr != 0, "Unexpected null GPU descriptor handle"); + } + + if (IsCompute) + CmdCtx.GetCommandList()->SetComputeRootDescriptorTable(FirstRootIndex + RootInd, RootTableGPUDescriptorHandle); + else + CmdCtx.GetCommandList()->SetGraphicsRootDescriptorTable(FirstRootIndex + RootInd, RootTableGPUDescriptorHandle); + + ProcessCachedTableResources( + RootInd, D3D12Param, ResourceCache, dbgHeapType, + [&](UINT OffsetFromTableStart, + const D3D12_DESCRIPTOR_RANGE& range, + ShaderResourceCacheD3D12::Resource& Res) // + { + if (IsDynamicTable) + { + if (IsResourceTable) + { + VERIFY(DynamicCbvSrvUavTblOffset < NumDynamicCbvSrvUavDescriptors, "Not enough space in the descriptor heap allocation"); + + if (Res.CPUDescriptorHandle.ptr != 0) + { + pd3d12Device->CopyDescriptorsSimple(1, DynamicCbvSrvUavDescriptors.GetCpuHandle(DynamicCbvSrvUavTblOffset), Res.CPUDescriptorHandle, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + } +#ifdef DILIGENT_DEVELOPMENT + else + { + LOG_ERROR_MESSAGE("No valid CbvSrvUav descriptor handle found for root parameter ", RootInd, ", descriptor slot ", OffsetFromTableStart); + } +#endif + + ++DynamicCbvSrvUavTblOffset; + } + else + { + VERIFY(DynamicSamplerTblOffset < NumDynamicSamplerDescriptors, "Not enough space in the descriptor heap allocation"); + + if (Res.CPUDescriptorHandle.ptr != 0) + { + pd3d12Device->CopyDescriptorsSimple(1, DynamicSamplerDescriptors.GetCpuHandle(DynamicSamplerTblOffset), Res.CPUDescriptorHandle, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); + } +#ifdef DILIGENT_DEVELOPMENT + else + { + LOG_ERROR_MESSAGE("No valid sampler descriptor handle found for root parameter ", RootInd, ", descriptor slot ", OffsetFromTableStart); + } +#endif + + ++DynamicSamplerTblOffset; + } + } + } // + ); + } // + ); + + VERIFY_EXPR(DynamicCbvSrvUavTblOffset == NumDynamicCbvSrvUavDescriptors); + VERIFY_EXPR(DynamicSamplerTblOffset == NumDynamicSamplerDescriptors); + + + for (Uint32 rv = 0; rv < m_RootParams.GetNumRootViews(); ++rv) + { + auto& RootView = m_RootParams.GetRootView(rv); + auto RootInd = RootView.GetLocalRootIndex(); + + auto& Res = ResourceCache.GetRootTable(RootInd).GetResource(0, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + if (auto* pBuffToTransition = Res.pObject.RawPtr<BufferD3D12Impl>()) + { + bool IsDynamic = pBuffToTransition->GetDesc().Usage == USAGE_DYNAMIC; + if (!IsDynamic) + { + D3D12_GPU_VIRTUAL_ADDRESS CBVAddress = pBuffToTransition->GetGPUAddress(DeviceCtxId, pDeviceCtx); + if (IsCompute) + CmdCtx.GetCommandList()->SetComputeRootConstantBufferView(FirstRootIndex + RootInd, CBVAddress); + else + CmdCtx.GetCommandList()->SetGraphicsRootConstantBufferView(FirstRootIndex + RootInd, CBVAddress); + } + } + } +} + +void PipelineResourceSignatureD3D12Impl::CommitRootViews(ShaderResourceCacheD3D12& ResourceCache, + CommandContext& CmdCtx, + DeviceContextD3D12Impl* pDeviceCtx, + Uint32 DeviceCtxId, + bool IsCompute, + Uint32 FirstRootIndex) +{ + for (Uint32 rv = 0; rv < m_RootParams.GetNumRootViews(); ++rv) + { + auto& RootView = m_RootParams.GetRootView(rv); + auto RootInd = RootView.GetLocalRootIndex(); + + auto& Res = ResourceCache.GetRootTable(RootInd).GetResource(0, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + if (auto* pBuffToTransition = Res.pObject.RawPtr<BufferD3D12Impl>()) + { + bool IsDynamic = pBuffToTransition->GetDesc().Usage == USAGE_DYNAMIC; + if (IsDynamic) + { + D3D12_GPU_VIRTUAL_ADDRESS CBVAddress = pBuffToTransition->GetGPUAddress(DeviceCtxId, pDeviceCtx); + if (IsCompute) + CmdCtx.GetCommandList()->SetComputeRootConstantBufferView(FirstRootIndex + RootInd, CBVAddress); + else + CmdCtx.GetCommandList()->SetGraphicsRootConstantBufferView(FirstRootIndex + RootInd, CBVAddress); + } + } + } +} + + +namespace +{ + +struct BindResourceHelper +{ + ShaderResourceCacheD3D12::Resource& DstRes; + const PipelineResourceDesc& ResDesc; + const PipelineResourceSignatureD3D12Impl::ResourceAttribs& Attribs; + const Uint32 ArrayIndex; + D3D12_CPU_DESCRIPTOR_HANDLE ShdrVisibleHeapCPUDescriptorHandle; + PipelineResourceSignatureD3D12Impl const& Signature; + ShaderResourceCacheD3D12& ResourceCache; + +#ifdef DILIGENT_DEBUG + bool dbgIsDynamic = false; + bool dbgIsRootView = false; +#endif + + void BindResource(IDeviceObject* pObj) const; + +private: + void CacheCB(IDeviceObject* pBuffer) const; + void CacheSampler(IDeviceObject* pBuffer) const; + void CacheAccelStruct(IDeviceObject* pBuffer) const; + + template <typename TResourceViewType, ///< ResType of the view (ITextureViewD3D12 or IBufferViewD3D12) + typename TViewTypeEnum, ///< ResType of the expected view type enum (TEXTURE_VIEW_TYPE or BUFFER_VIEW_TYPE) + typename TBindSamplerProcType> ///< ResType of the procedure to set sampler + void CacheResourceView(IDeviceObject* pBufferView, + TViewTypeEnum dbgExpectedViewType, + TBindSamplerProcType BindSamplerProc) const; + + ID3D12Device* GetD3D12Device() const { return Signature.GetDevice()->GetD3D12Device(); } +}; + + +void BindResourceHelper::CacheCB(IDeviceObject* pBuffer) const +{ + // http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-cache#Binding-Objects-to-Shader-Variables + + // We cannot use ValidatedCast<> here as the resource retrieved from the + // resource mapping can be of wrong type + RefCntAutoPtr<BufferD3D12Impl> pBuffD3D12{pBuffer, IID_BufferD3D12}; +#ifdef DILIGENT_DEVELOPMENT + VerifyConstantBufferBinding(ResDesc.Name, ResDesc.ArraySize, ResDesc.VarType, ResDesc.Flags, ArrayIndex, + pBuffer, pBuffD3D12.RawPtr(), DstRes.pObject.RawPtr()); +#endif + if (pBuffD3D12) + { + if (ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && DstRes.pObject != nullptr) + { + // Do not update resource if one is already bound unless it is dynamic. This may be + // dangerous as CopyDescriptorsSimple() may interfere with GPU reading the same descriptor. + return; + } + + DstRes.Type = ResDesc.ResourceType; + DstRes.CPUDescriptorHandle = pBuffD3D12->GetCBVHandle(); + VERIFY(DstRes.CPUDescriptorHandle.ptr != 0 || pBuffD3D12->GetDesc().Usage == USAGE_DYNAMIC, "No relevant CBV CPU descriptor handle"); + + if (ShdrVisibleHeapCPUDescriptorHandle.ptr != 0) + { + // Dynamic resources are assigned descriptor in the GPU-visible heap at every draw call, and + // the descriptor is copied by the RootSignature when resources are committed + VERIFY(DstRes.pObject == nullptr, "Static and mutable resource descriptors must be copied only once"); + VERIFY_EXPR(DstRes.CPUDescriptorHandle.ptr != 0); + + GetD3D12Device()->CopyDescriptorsSimple(1, ShdrVisibleHeapCPUDescriptorHandle, DstRes.CPUDescriptorHandle, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + } + else + { + VERIFY(dbgIsRootView || dbgIsDynamic, "Descriptor in root table can be used only in dynamic tables."); + } + + auto& BoundDynamicCBsCounter = ResourceCache.GetBoundDynamicCBsCounter(); + if (DstRes.pObject != nullptr && DstRes.pObject.RawPtr<const BufferD3D12Impl>()->GetDesc().Usage == USAGE_DYNAMIC) + { + VERIFY(BoundDynamicCBsCounter > 0, "There is a dynamic CB bound in the resource cache, but the dynamic CB counter is zero"); + --BoundDynamicCBsCounter; + } + if (pBuffD3D12->GetDesc().Usage == USAGE_DYNAMIC) + ++BoundDynamicCBsCounter; + DstRes.pObject = std::move(pBuffD3D12); + } +} + +void BindResourceHelper::CacheSampler(IDeviceObject* pSampler) const +{ + RefCntAutoPtr<ISamplerD3D12> pSamplerD3D12{pSampler, IID_SamplerD3D12}; + if (pSamplerD3D12) + { + if (ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && DstRes.pObject != nullptr) + { + if (DstRes.pObject != pSampler) + { + auto VarTypeStr = GetShaderVariableTypeLiteralName(ResDesc.VarType); + LOG_ERROR_MESSAGE("Non-null sampler is already bound to ", VarTypeStr, " shader variable '", GetShaderResourcePrintName(ResDesc, ArrayIndex), + "'. Attempting to bind another sampler is an error and will be ignored. ", + "Use another shader resource binding instance or label the variable as dynamic."); + } + + // Do not update resource if one is already bound unless it is dynamic. This may be + // dangerous as CopyDescriptorsSimple() may interfere with GPU reading the same descriptor. + return; + } + + DstRes.Type = SHADER_RESOURCE_TYPE_SAMPLER; + + DstRes.CPUDescriptorHandle = pSamplerD3D12->GetCPUDescriptorHandle(); + VERIFY(DstRes.CPUDescriptorHandle.ptr != 0, "No relevant D3D12 sampler descriptor handle"); + + if (ShdrVisibleHeapCPUDescriptorHandle.ptr != 0) + { + // Dynamic resources are assigned descriptor in the GPU-visible heap at every draw call, and + // the descriptor is copied by the RootSignature when resources are committed + VERIFY(DstRes.pObject == nullptr, "Static and mutable resource descriptors must be copied only once"); + + GetD3D12Device()->CopyDescriptorsSimple(1, ShdrVisibleHeapCPUDescriptorHandle, DstRes.CPUDescriptorHandle, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); + } + + DstRes.pObject = std::move(pSamplerD3D12); + } + else + { + LOG_ERROR_MESSAGE("Failed to bind object '", pSampler->GetDesc().Name, "' to variable '", GetShaderResourcePrintName(ResDesc, ArrayIndex), "'." + "Incorect object type: sampler is expected."); + } +} + +void BindResourceHelper::CacheAccelStruct(IDeviceObject* pTLAS) const +{ + RefCntAutoPtr<ITopLevelASD3D12> pTLASD3D12{pTLAS, IID_TopLevelASD3D12}; + if (pTLASD3D12) + { + if (ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && DstRes.pObject != nullptr) + { + // Do not update resource if one is already bound unless it is dynamic. This may be + // dangerous as CopyDescriptorsSimple() may interfere with GPU reading the same descriptor. + return; + } + + DstRes.Type = SHADER_RESOURCE_TYPE_ACCEL_STRUCT; + DstRes.CPUDescriptorHandle = pTLASD3D12->GetCPUDescriptorHandle(); + VERIFY(DstRes.CPUDescriptorHandle.ptr != 0, "No relevant D3D12 resource"); + + if (ShdrVisibleHeapCPUDescriptorHandle.ptr != 0) + { + // Dynamic resources are assigned descriptor in the GPU-visible heap at every draw call, and + // the descriptor is copied by the RootSignature when resources are committed + VERIFY(DstRes.pObject == nullptr, "Static and mutable resource descriptors must be copied only once"); + + GetD3D12Device()->CopyDescriptorsSimple(1, ShdrVisibleHeapCPUDescriptorHandle, DstRes.CPUDescriptorHandle, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + } + + DstRes.pObject = std::move(pTLASD3D12); + } +} + +template <typename TResourceViewType> +struct ResourceViewTraits +{}; + +template <> +struct ResourceViewTraits<ITextureViewD3D12> +{ + static const INTERFACE_ID& IID; + + //static bool VerifyView(ITextureViewD3D12* pViewD3D12, const D3DShaderResourceAttribs& Attribs) + //{ + // return true; + //} +}; +const INTERFACE_ID& ResourceViewTraits<ITextureViewD3D12>::IID = IID_TextureViewD3D12; + +template <> +struct ResourceViewTraits<IBufferViewD3D12> +{ + static const INTERFACE_ID& IID; + + //static bool VerifyView(IBufferViewD3D12* pViewD3D12, const D3DShaderResourceAttribs& Attribs) + //{ + // return VerifyBufferViewModeD3D(pViewD3D12, Attribs); + //} +}; +const INTERFACE_ID& ResourceViewTraits<IBufferViewD3D12>::IID = IID_BufferViewD3D12; + + +template <typename TResourceViewType, ///< ResType of the view (ITextureViewD3D12 or IBufferViewD3D12) + typename TViewTypeEnum, ///< ResType of the expected view type enum (TEXTURE_VIEW_TYPE or BUFFER_VIEW_TYPE) + typename TBindSamplerProcType> ///< ResType of the procedure to set sampler +void BindResourceHelper::CacheResourceView(IDeviceObject* pView, + TViewTypeEnum dbgExpectedViewType, + TBindSamplerProcType BindSamplerProc) const +{ + // We cannot use ValidatedCast<> here as the resource retrieved from the + // resource mapping can be of wrong type + RefCntAutoPtr<TResourceViewType> pViewD3D12{pView, ResourceViewTraits<TResourceViewType>::IID}; +#ifdef DILIGENT_DEVELOPMENT + VerifyResourceViewBinding(ResDesc.Name, ResDesc.ArraySize, ResDesc.VarType, ArrayIndex, + pView, pViewD3D12.RawPtr(), + {dbgExpectedViewType}, RESOURCE_DIM_UNDEFINED, + false, // IsMultisample + DstRes.pObject.RawPtr()); + //ResourceViewTraits<TResourceViewType>::VerifyView(pViewD3D12, Attribs); +#endif + if (pViewD3D12) + { + if (ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && DstRes.pObject != nullptr) + { + // Do not update resource if one is already bound unless it is dynamic. This may be + // dangerous as CopyDescriptorsSimple() may interfere with GPU reading the same descriptor. + return; + } + + DstRes.Type = ResDesc.ResourceType; + DstRes.CPUDescriptorHandle = pViewD3D12->GetCPUDescriptorHandle(); + VERIFY(DstRes.CPUDescriptorHandle.ptr != 0, "No relevant D3D12 view"); + + if (ShdrVisibleHeapCPUDescriptorHandle.ptr != 0) + { + // Dynamic resources are assigned descriptor in the GPU-visible heap at every draw call, and + // the descriptor is copied by the RootSignature when resources are committed + VERIFY(DstRes.pObject == nullptr, "Static and mutable resource descriptors must be copied only once"); + + GetD3D12Device()->CopyDescriptorsSimple(1, ShdrVisibleHeapCPUDescriptorHandle, DstRes.CPUDescriptorHandle, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + } + + BindSamplerProc(pViewD3D12); + + DstRes.pObject = std::move(pViewD3D12); + } +} + +void BindResourceHelper::BindResource(IDeviceObject* pObj) const +{ + VERIFY_EXPR(ArrayIndex < ResDesc.ArraySize); + +#ifdef DILIGENT_DEBUG + using CacheContentType = PipelineResourceSignatureD3D12Impl::CacheContentType; + + if (ResourceCache.GetContentType() == CacheContentType::Signature) + { + VERIFY(ShdrVisibleHeapCPUDescriptorHandle.ptr == 0, "Static shader resources of a shader should not be assigned shader visible descriptor space"); + } + else if (ResourceCache.GetContentType() == CacheContentType::SRB) + { + if (ResDesc.ResourceType == SHADER_RESOURCE_TYPE_CONSTANT_BUFFER && ResDesc.ArraySize == 1) + { + VERIFY(ShdrVisibleHeapCPUDescriptorHandle.ptr == 0, "Non-array constant buffers are bound as root views and should not be assigned shader visible descriptor space"); + } + else + { + if (ResDesc.VarType == SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) + VERIFY(ShdrVisibleHeapCPUDescriptorHandle.ptr == 0, "Dynamic resources of a shader resource binding should be assigned shader visible descriptor space at every draw call"); + else + VERIFY(ShdrVisibleHeapCPUDescriptorHandle.ptr != 0, "Non-dynamics resources of a shader resource binding must be assigned shader visible descriptor space"); + } + } + else + { + UNEXPECTED("Unknown content type"); + } +#endif + + if (pObj) + { + static_assert(SHADER_RESOURCE_TYPE_LAST == SHADER_RESOURCE_TYPE_ACCEL_STRUCT, "Please update this function to handle the new resource type"); + switch (ResDesc.ResourceType) + { + case SHADER_RESOURCE_TYPE_CONSTANT_BUFFER: + CacheCB(pObj); + break; + + case SHADER_RESOURCE_TYPE_TEXTURE_SRV: + CacheResourceView<ITextureViewD3D12>( + pObj, TEXTURE_VIEW_SHADER_RESOURCE, + [&](ITextureViewD3D12* pTexView) // + { + if (Attribs.IsCombinedWithSampler()) + { + auto& SamplerResDesc = Signature.GetResourceDesc(Attribs.SamplerInd); + auto& SamplerAttribs = Signature.GetResourceAttribs(Attribs.SamplerInd); + VERIFY_EXPR(SamplerResDesc.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER); + + if (!SamplerAttribs.IsImmutableSamplerAssigned()) + { + auto* pSampler = pTexView->GetSampler(); + if (pSampler) + { + VERIFY_EXPR(ResDesc.ArraySize == SamplerResDesc.ArraySize || SamplerResDesc.ArraySize == 1); + const auto CacheType = ResourceCache.GetContentType(); + const auto SamplerArrInd = SamplerResDesc.ArraySize > 1 ? ArrayIndex : 0; + const auto RootIndex = SamplerAttribs.RootIndex(CacheType); + const auto OffsetFromTableStart = SamplerAttribs.OffsetFromTableStart(CacheType) + SamplerArrInd; + auto& SampleDstRes = ResourceCache.GetRootTable(RootIndex).GetResource(OffsetFromTableStart, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); + + BindResourceHelper SeparateSampler{ + SampleDstRes, + SamplerResDesc, + SamplerAttribs, + SamplerArrInd, + ResourceCache.GetShaderVisibleTableCPUDescriptorHandle<D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER>(RootIndex, OffsetFromTableStart), + Signature, + ResourceCache}; + SeparateSampler.BindResource(pSampler); + } + else + { + LOG_ERROR_MESSAGE("Failed to bind sampler to variable '", SamplerResDesc.Name, ". Sampler is not set in the texture view '", pTexView->GetDesc().Name, '\''); + } + } + } + }); + break; + + case SHADER_RESOURCE_TYPE_TEXTURE_UAV: + CacheResourceView<ITextureViewD3D12>(pObj, TEXTURE_VIEW_UNORDERED_ACCESS, [](ITextureViewD3D12*) {}); + break; + + case SHADER_RESOURCE_TYPE_BUFFER_SRV: + CacheResourceView<IBufferViewD3D12>(pObj, BUFFER_VIEW_SHADER_RESOURCE, [](IBufferViewD3D12*) {}); + break; + + case SHADER_RESOURCE_TYPE_BUFFER_UAV: + CacheResourceView<IBufferViewD3D12>(pObj, BUFFER_VIEW_UNORDERED_ACCESS, [](IBufferViewD3D12*) {}); + break; + + case SHADER_RESOURCE_TYPE_SAMPLER: + DEV_CHECK_ERR(Signature.IsUsingSeparateSamplers(), "Samplers should not be set directly when using combined texture samplers"); + CacheSampler(pObj); + break; + + case SHADER_RESOURCE_TYPE_ACCEL_STRUCT: + CacheAccelStruct(pObj); + break; + + default: UNEXPECTED("Unknown resource type ", static_cast<Int32>(ResDesc.ResourceType)); + } + } + else + { + if (DstRes.pObject != nullptr && ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) + LOG_ERROR_MESSAGE("Shader variable '", ResDesc.Name, "' is not dynamic but is being reset to null. This is an error and may cause unpredicted behavior. ", + "Use another shader resource binding instance or label the variable as dynamic if you need to bind another resource."); + + DstRes = ShaderResourceCacheD3D12::Resource{}; + if (Attribs.IsCombinedWithSampler()) + { + auto& SamplerResDesc = Signature.GetResourceDesc(Attribs.SamplerInd); + auto& SamplerAttribs = Signature.GetResourceAttribs(Attribs.SamplerInd); + VERIFY_EXPR(SamplerResDesc.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER); + + const auto CacheType = ResourceCache.GetContentType(); + auto SamplerArrInd = SamplerResDesc.ArraySize > 1 ? ArrayIndex : 0; + const auto RootIndex = SamplerAttribs.RootIndex(CacheType); + const auto OffsetFromTableStart = SamplerAttribs.OffsetFromTableStart(CacheType) + SamplerArrInd; + auto& DstSam = ResourceCache.GetRootTable(RootIndex).GetResource(OffsetFromTableStart, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); + + if (DstSam.pObject != nullptr && SamplerResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) + LOG_ERROR_MESSAGE("Sampler variable '", SamplerResDesc.Name, "' is not dynamic but is being reset to null. This is an error and may cause unpredicted behavior. ", + "Use another shader resource binding instance or label the variable as dynamic if you need to bind another sampler."); + + DstSam = ShaderResourceCacheD3D12::Resource{}; + } + } +} + +} // namespace + + +void PipelineResourceSignatureD3D12Impl::BindResource(IDeviceObject* pObj, + Uint32 ArrayIndex, + Uint32 ResIndex, + ShaderResourceCacheD3D12& ResourceCache) const +{ + const auto& ResDesc = GetResourceDesc(ResIndex); + const auto& Attribs = GetResourceAttribs(ResIndex); + const bool IsSampler = (ResDesc.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER); + const auto CacheType = ResourceCache.GetContentType(); + const auto RootIndex = Attribs.RootIndex(CacheType); + const auto OffsetFromTableStart = Attribs.OffsetFromTableStart(CacheType) + ArrayIndex; + + VERIFY_EXPR(ArrayIndex < ResDesc.ArraySize); + + auto& RootTable = ResourceCache.GetRootTable(RootIndex); + auto& DstRes = RootTable.GetResource(OffsetFromTableStart, IsSampler ? D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER : D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + + auto ShdrVisibleHeapCPUDescriptorHandle = IsSampler ? + ResourceCache.GetShaderVisibleTableCPUDescriptorHandle<D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER>(RootIndex, OffsetFromTableStart) : + ResourceCache.GetShaderVisibleTableCPUDescriptorHandle<D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV>(RootIndex, OffsetFromTableStart); + + BindResourceHelper Helper{ + DstRes, + ResDesc, + Attribs, + ArrayIndex, + ShdrVisibleHeapCPUDescriptorHandle, + *this, + ResourceCache}; + +#ifdef DILIGENT_DEBUG + Helper.dbgIsDynamic = RootTable.IsDynamic(); + Helper.dbgIsRootView = Attribs.IsRootView(); +#endif + + Helper.BindResource(pObj); +} + +bool PipelineResourceSignatureD3D12Impl::IsBound(Uint32 ArrayIndex, + Uint32 ResIndex, + ShaderResourceCacheD3D12& ResourceCache) const +{ + const auto& ResDesc = GetResourceDesc(ResIndex); + const auto& Attribs = GetResourceAttribs(ResIndex); + const auto CacheType = ResourceCache.GetContentType(); + const auto RootIndex = Attribs.RootIndex(CacheType); + const auto OffsetFromTableStart = Attribs.OffsetFromTableStart(CacheType) + ArrayIndex; + + VERIFY_EXPR(ArrayIndex < ResDesc.ArraySize); + + if (RootIndex < ResourceCache.GetNumRootTables()) + { + const auto& RootTable = ResourceCache.GetRootTable(RootIndex); + if (OffsetFromTableStart + ArrayIndex < RootTable.GetSize()) + { + const auto& CachedRes = + RootTable.GetResource(OffsetFromTableStart + ArrayIndex, + ResDesc.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER ? D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER : D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + if (CachedRes.pObject != nullptr) + { + VERIFY(CachedRes.CPUDescriptorHandle.ptr != 0 || CachedRes.pObject.RawPtr<BufferD3D12Impl>()->GetDesc().Usage == USAGE_DYNAMIC, "No relevant descriptor handle"); + return true; + } + } + } + + return false; +} + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp index a32facda..9cfc7c7d 100644 --- a/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp @@ -28,6 +28,7 @@ #include "pch.h" #include <array> #include <sstream> +#include <d3dcompiler.h> #include "PipelineStateD3D12Impl.hpp" #include "ShaderD3D12Impl.hpp" @@ -40,6 +41,7 @@ #include "StringTools.hpp" #include "ShaderVariableD3D12.hpp" #include "DynamicLinearAllocator.hpp" +#include "DXBCUtils.hpp" #include "DXCompiler.hpp" #include "dxc/dxcapi.h" @@ -102,14 +104,9 @@ private: std::array<D3D12_PRIMITIVE_TOPOLOGY_TYPE, PRIMITIVE_TOPOLOGY_NUM_TOPOLOGIES> m_Map; }; -using TBindingMapPerStage = std::array<IDXCompiler::TResourceBindingMap, MAX_SHADERS_IN_PIPELINE>; - void BuildRTPipelineDescription(const RayTracingPipelineStateCreateInfo& CreateInfo, std::vector<D3D12_STATE_SUBOBJECT>& Subobjects, - std::vector<CComPtr<IDxcBlob>>& ShaderBlobs, - DynamicLinearAllocator& TempPool, - IDXCompiler* compiler, - const TBindingMapPerStage& BindingMapPerStage) noexcept(false) + DynamicLinearAllocator& TempPool) noexcept(false) { #define LOG_PSO_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of ray tracing PSO '", (CreateInfo.PSODesc.Name ? CreateInfo.PSODesc.Name : ""), "' is invalid: ", ##__VA_ARGS__) @@ -124,15 +121,10 @@ void BuildRTPipelineDescription(const RayTracingPipelineStateCreateInfo& CreateI auto it_inserted = UniqueShaders.emplace(pShader, nullptr); if (it_inserted.second) { - auto& LibDesc = *TempPool.Construct<D3D12_DXIL_LIBRARY_DESC>(); - auto& ExportDesc = *TempPool.Construct<D3D12_EXPORT_DESC>(); - auto* pShaderD3D12 = ValidatedCast<ShaderD3D12Impl>(pShader); - Uint32 ShaderIdx = GetShaderTypePipelineIndex(pShaderD3D12->GetDesc().ShaderType, PIPELINE_TYPE_RAY_TRACING); - auto& BindingMap = BindingMapPerStage[ShaderIdx]; - - CComPtr<IDxcBlob> pBlob; - if (!compiler->RemapResourceBindings(BindingMap, reinterpret_cast<IDxcBlob*>(pShaderD3D12->GetShaderByteCode()), &pBlob)) - LOG_ERROR_AND_THROW("Failed to remap resource bindings in shader '", pShaderD3D12->GetDesc().Name, "'."); + auto& LibDesc = *TempPool.Construct<D3D12_DXIL_LIBRARY_DESC>(); + auto& ExportDesc = *TempPool.Construct<D3D12_EXPORT_DESC>(); + auto* pShaderD3D12 = ValidatedCast<ShaderD3D12Impl>(pShader); + auto* pBlob = pShaderD3D12->GetShaderByteCode(); LibDesc.DXILLibrary.BytecodeLength = pBlob->GetBufferSize(); LibDesc.DXILLibrary.pShaderBytecode = pBlob->GetBufferPointer(); @@ -152,7 +144,6 @@ void BuildRTPipelineDescription(const RayTracingPipelineStateCreateInfo& CreateI } Subobjects.push_back({D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY, &LibDesc}); - ShaderBlobs.push_back(pBlob); it_inserted.first->second = ExportDesc.Name; return ExportDesc.Name; @@ -161,8 +152,6 @@ void BuildRTPipelineDescription(const RayTracingPipelineStateCreateInfo& CreateI return it_inserted.first->second; }; - ShaderBlobs.reserve(CreateInfo.GeneralShaderCount + CreateInfo.TriangleHitShaderCount + CreateInfo.ProceduralHitShaderCount); - for (Uint32 i = 0; i < CreateInfo.GeneralShaderCount; ++i) { const auto& GeneralShader = CreateInfo.pGeneralShaders[i]; @@ -276,70 +265,76 @@ void GetShaderIdentifiers(ID3D12DeviceChild* pSO, } } -TBindingMapPerStage ExtractResourceBindingMap(const RootSignatureBuilder& RootSig, - const std::array<Int8, MAX_SHADERS_IN_PIPELINE>& ResourceLayoutIndex, - const ShaderResourceLayoutD3D12* pResourceLayouts, - const ShaderResourceLayoutD3D12* pStaticLayouts) noexcept(false) +void GetShaderResourceTypeAndFlags(const D3DShaderResourceAttribs& Attribs, + SHADER_RESOURCE_TYPE& OutType, + PIPELINE_RESOURCE_FLAGS& OutFlags) { - TBindingMapPerStage BindingMapPerStage; - - const auto ExtractResources = [&](const ShaderResourceLayoutD3D12* pLayouts) // - { - for (Uint32 ShaderIdx = 0; ShaderIdx < ResourceLayoutIndex.size(); ++ShaderIdx) - { - const auto LayoutIdx = ResourceLayoutIndex[ShaderIdx]; - if (LayoutIdx < 0) - continue; - - auto& BindingMap = BindingMapPerStage[ShaderIdx]; - const auto& ResLayout = pLayouts[LayoutIdx]; - - const auto TotalResCount = ResLayout.GetTotalResourceCount(); - for (Uint32 i = 0; i < TotalResCount; ++i) - { - const auto& Attribs = ResLayout.GetResource(i).Attribs; - VERIFY_EXPR(Attribs.Name != nullptr && Attribs.Name[0] != '\0'); - - auto Iter = BindingMap.emplace(HashMapStringKey{Attribs.Name}, Attribs.BindPoint).first; - VERIFY(Iter->second == Attribs.BindPoint, - "Resource '", Attribs.Name, "' was assigned incosistent bind points in different resource layouts. This is a bug."); - } - } - }; - // Gather resource bind points - ExtractResources(pResourceLayouts); - ExtractResources(pStaticLayouts); - - // Gather static sampler bind points - for (size_t i = 0; i < RootSig.GetImmutableSamplerCount(); ++i) - { - const auto& ImtblSmplr = RootSig.GetImmutableSamplers()[i]; - const Uint32 ShaderIdx = GetShaderTypePipelineIndex(ImtblSmplr.ShaderType, PIPELINE_TYPE_RAY_TRACING); - const auto LayoutIdx = ResourceLayoutIndex[ShaderIdx]; - if (LayoutIdx < 0) - continue; - - if (ImtblSmplr.SamplerName.empty()) - { - UNEXPECTED("Immutable sampler name is empty"); - continue; - } - - auto& BindingMap = BindingMapPerStage[ShaderIdx]; - auto Iter = BindingMap.emplace(HashMapStringKey{ImtblSmplr.SamplerName.c_str()}, ImtblSmplr.ShaderRegister).first; - VERIFY(Iter->second == ImtblSmplr.ShaderRegister, - "Static sampler '", ImtblSmplr.SamplerName, "' was assigned incosistent bind points in different resource layouts. This is a bug."); + OutFlags = PIPELINE_RESOURCE_FLAG_UNKNOWN; + + switch (static_cast<Uint32>(Attribs.GetInputType())) + { + case D3D_SIT_CBUFFER: + OutType = SHADER_RESOURCE_TYPE_CONSTANT_BUFFER; + break; + case D3D_SIT_TBUFFER: + UNSUPPORTED("TBuffers are not supported"); + OutType = SHADER_RESOURCE_TYPE_TEXTURE_SRV; + break; + case D3D_SIT_TEXTURE: + OutType = (Attribs.GetSRVDimension() == D3D_SRV_DIMENSION_BUFFER ? SHADER_RESOURCE_TYPE_BUFFER_SRV : SHADER_RESOURCE_TYPE_TEXTURE_SRV); + break; + case D3D_SIT_SAMPLER: + OutType = SHADER_RESOURCE_TYPE_SAMPLER; + break; + case D3D_SIT_UAV_RWTYPED: + OutType = (Attribs.GetSRVDimension() == D3D_SRV_DIMENSION_BUFFER ? SHADER_RESOURCE_TYPE_BUFFER_UAV : SHADER_RESOURCE_TYPE_TEXTURE_UAV); + break; + case D3D_SIT_STRUCTURED: + case D3D_SIT_BYTEADDRESS: + OutType = SHADER_RESOURCE_TYPE_BUFFER_SRV; + break; + case D3D_SIT_UAV_RWSTRUCTURED: + case D3D_SIT_UAV_RWBYTEADDRESS: + case D3D_SIT_UAV_APPEND_STRUCTURED: + case D3D_SIT_UAV_CONSUME_STRUCTURED: + case D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER: + OutType = SHADER_RESOURCE_TYPE_BUFFER_UAV; + break; + case D3D_SIT_RTACCELERATIONSTRUCTURE: + OutType = SHADER_RESOURCE_TYPE_ACCEL_STRUCT; + break; + default: + UNEXPECTED("Unknown HLSL resource type"); + OutType = SHADER_RESOURCE_TYPE_UNKNOWN; + break; } - - return BindingMapPerStage; } +void VerifyResourceMerge(const D3DShaderResourceAttribs& ExistingRes, + const D3DShaderResourceAttribs& NewResAttribs) +{ + DEV_CHECK_ERR(ExistingRes.GetInputType() == NewResAttribs.GetInputType(), + "Shader variable '", NewResAttribs.Name, + "' exists in multiple shaders from the same shader stage, but its input type is not consistent between " + "shaders. All variables with the same name from the same shader stage must have the same input type."); + + DEV_CHECK_ERR(ExistingRes.GetSRVDimension() == NewResAttribs.GetSRVDimension(), + "Shader variable '", NewResAttribs.Name, + "' exists in multiple shaders from the same shader stage, but its SRV dimension is not consistent between " + "shaders. All variables with the same name from the same shader stage must have the same SRV dimension."); + + DEV_CHECK_ERR(ExistingRes.BindCount == NewResAttribs.BindCount, + "Shader variable '", NewResAttribs.Name, + "' exists in multiple shaders from the same shader stage, but its array size is not consistent between " + "shaders. All variables with the same name from the same shader stage must have the same array size."); +} } // namespace PipelineStateD3D12Impl::ShaderStageInfo::ShaderStageInfo(ShaderD3D12Impl* _pShader) : Type{_pShader->GetDesc().ShaderType}, - Shaders{_pShader} + Shaders{_pShader}, + ByteCodes{_pShader->GetShaderByteCode()} { } @@ -363,71 +358,336 @@ void PipelineStateD3D12Impl::ShaderStageInfo::Append(ShaderD3D12Impl* pShader) } Shaders.push_back(pShader); + ByteCodes.push_back(pShader->GetShaderByteCode()); } size_t PipelineStateD3D12Impl::ShaderStageInfo::Count() const { + VERIFY_EXPR(Shaders.size() == ByteCodes.size()); return Shaders.size(); } +void PipelineStateD3D12Impl::CreateDefaultResourceSignature(const PipelineStateCreateInfo& CreateInfo, + TShaderStages& ShaderStages, + LocalRootSignatureD3D12* pLocalRootSig, + IPipelineResourceSignature** ppImplicitSignature) +{ + struct UniqueResource + { + D3DShaderResourceAttribs const* Attribs = nullptr; + Uint32 DescIndex = ~0u; + }; + using ResourceNameToIndex_t = std::unordered_map<HashMapStringKey, UniqueResource, HashMapStringKey::Hasher>; + + std::vector<PipelineResourceDesc> Resources; + ResourceNameToIndex_t UniqueNames; + const char* pCombinedSamplerSuffix = nullptr; + const auto& LayoutDesc = CreateInfo.PSODesc.ResourceLayout; + + for (auto& Stage : ShaderStages) + { + UniqueNames.clear(); + for (auto* pShader : Stage.Shaders) + { + const auto DefaultVarType = LayoutDesc.DefaultVariableType; + auto& ShaderResources = *pShader->GetShaderResources(); + const auto HandleResource = [&](const D3DShaderResourceAttribs& Res, Uint32) // + { + if (pLocalRootSig != nullptr && pLocalRootSig->IsShaderRecord(Res)) + return; + + auto IterAndAssigned = UniqueNames.emplace(HashMapStringKey{Res.Name}, UniqueResource{&Res, static_cast<Uint32>(Resources.size())}); + if (IterAndAssigned.second) + { + SHADER_RESOURCE_TYPE Type; + PIPELINE_RESOURCE_FLAGS Flags; + GetShaderResourceTypeAndFlags(Res, Type, Flags); + + // Backward compatibility: only CBV with array size == 1 will be placed as root view. + if ((Type == SHADER_RESOURCE_TYPE_CONSTANT_BUFFER && Res.BindCount > 1) || + Type == SHADER_RESOURCE_TYPE_BUFFER_SRV || + Type == SHADER_RESOURCE_TYPE_BUFFER_UAV) + { + Flags |= PIPELINE_RESOURCE_FLAG_NO_DYNAMIC_BUFFERS; + } + + if (Res.BindCount == 0) + { + LOG_ERROR_AND_THROW("Is shader '", pShader->GetDesc().Name, "' resource '", Res.Name, "' uses runtime sized array, ", + "you must explicitlly set resource signature to specify array size"); + } + + Resources.emplace_back(Stage.Type, Res.Name, Res.BindCount, Type, DefaultVarType, Flags); + } + else + { + VerifyResourceMerge(*IterAndAssigned.first->second.Attribs, Res); + } + }; + + ShaderResources.ProcessResources(HandleResource, HandleResource, HandleResource, HandleResource, HandleResource, HandleResource, HandleResource); + + // merge combined sampler suffixes + if (ShaderResources.IsUsingCombinedTextureSamplers() && ShaderResources.GetNumSamplers() > 0) + { + if (pCombinedSamplerSuffix != nullptr) + { + if (strcmp(pCombinedSamplerSuffix, ShaderResources.GetCombinedSamplerSuffix()) != 0) + LOG_ERROR_AND_THROW("CombinedSamplerSuffix is not compatible between shaders"); + } + else + { + pCombinedSamplerSuffix = ShaderResources.GetCombinedSamplerSuffix(); + } + } + + for (Uint32 i = 0; i < LayoutDesc.NumVariables; ++i) + { + const auto& Var = LayoutDesc.Variables[i]; + if (Var.ShaderStages & Stage.Type) + { + auto Iter = UniqueNames.find(HashMapStringKey{Var.Name}); + if (Iter != UniqueNames.end()) + { + auto& Res = Resources[Iter->second.DescIndex]; + Res.VarType = Var.Type; + + // apply new variable type to sampler too + if (ShaderResources.IsUsingCombinedTextureSamplers() && Res.ResourceType == SHADER_RESOURCE_TYPE_TEXTURE_SRV) + { + String SampName = String{Var.Name} + ShaderResources.GetCombinedSamplerSuffix(); + auto SampIter = UniqueNames.find(HashMapStringKey{SampName.c_str()}); + if (SampIter != UniqueNames.end()) + Resources[SampIter->second.DescIndex].VarType = Var.Type; + } + } + } + } + } + } + + if (Resources.size()) + { + PipelineResourceSignatureDesc ResSignDesc; + ResSignDesc.Resources = Resources.data(); + ResSignDesc.NumResources = static_cast<Uint32>(Resources.size()); + ResSignDesc.ImmutableSamplers = LayoutDesc.ImmutableSamplers; + ResSignDesc.NumImmutableSamplers = LayoutDesc.NumImmutableSamplers; + ResSignDesc.BindingIndex = 0; + ResSignDesc.SRBAllocationGranularity = CreateInfo.PSODesc.SRBAllocationGranularity; + ResSignDesc.UseCombinedTextureSamplers = pCombinedSamplerSuffix != nullptr; + ResSignDesc.CombinedSamplerSuffix = pCombinedSamplerSuffix; + + GetDevice()->CreatePipelineResourceSignature(ResSignDesc, ppImplicitSignature, true); + + if (*ppImplicitSignature == nullptr) + LOG_ERROR_AND_THROW("Failed to create resource signature for pipeline state"); + } +} + +void PipelineStateD3D12Impl::InitRootSignature(const PipelineStateCreateInfo& CreateInfo, + TShaderStages& ShaderStages, + LocalRootSignatureD3D12* pLocalRootSig) +{ + const Uint32 SignatureCount = CreateInfo.ResourceSignaturesCount; + RefCntAutoPtr<IPipelineResourceSignature> pImplicitSignature; + + if (SignatureCount == 0 || CreateInfo.ppResourceSignatures == nullptr) + { + CreateDefaultResourceSignature(CreateInfo, ShaderStages, pLocalRootSig, &pImplicitSignature); + + if (pImplicitSignature != nullptr) + { + VERIFY_EXPR(pImplicitSignature->GetDesc().BindingIndex == 0); + m_Signatures[0] = ValidatedCast<PipelineResourceSignatureD3D12Impl>(pImplicitSignature.RawPtr()); + m_SignatureCount = 1; + } + } + else + { + const auto PipelineType = CreateInfo.PSODesc.PipelineType; + for (Uint32 i = 0; i < SignatureCount; ++i) + { + auto* pSignature = ValidatedCast<PipelineResourceSignatureD3D12Impl>(CreateInfo.ppResourceSignatures[i]); + VERIFY(pSignature != nullptr, "Pipeline resource signature at index ", i, " is null. This error should've been caught by ValidatePipelineResourceSignatures."); + + const Uint8 Index = pSignature->GetDesc().BindingIndex; + +#ifdef DILIGENT_DEBUG + VERIFY(Index < m_Signatures.size(), + "Pipeline resource signature specifies binding index ", Uint32{Index}, " that exceeds the limit (", m_Signatures.size() - 1, + "). This error should've been caught by ValidatePipelineResourceSignatureDesc."); + + VERIFY(m_Signatures[Index] == nullptr, + "Pipeline resource signature '", pSignature->GetDesc().Name, "' at index ", Uint32{Index}, + " conflicts with another resource signature '", m_Signatures[Index]->GetDesc().Name, + "' that uses the same index. This error should've been caught by ValidatePipelineResourceSignatures."); + + for (Uint32 s = 0, StageCount = pSignature->GetNumActiveShaderStages(); s < StageCount; ++s) + { + const auto ShaderType = pSignature->GetActiveShaderStageType(s); + VERIFY(IsConsistentShaderType(ShaderType, PipelineType), + "Pipeline resource signature '", pSignature->GetDesc().Name, "' at index ", Uint32{Index}, + " has shader stage '", GetShaderTypeLiteralName(ShaderType), "' that is not compatible with pipeline type '", + GetPipelineTypeString(PipelineType), "'."); + } +#endif + + m_SignatureCount = std::max<Uint8>(m_SignatureCount, Index + 1); + m_Signatures[Index] = pSignature; + } + } + + m_RootSig = GetDevice()->GetRootSignatureCache().GetRootSig(m_Signatures.data(), m_SignatureCount); + if (!m_RootSig) + LOG_ERROR_AND_THROW("Failed to create root signature"); + + // Verify that pipeline layout is compatible with shader resources and + // remap resource bindings. + auto* compiler = GetDevice()->GetDxCompiler(); + + for (size_t s = 0; s < ShaderStages.size(); ++s) + { + const auto& Shaders = ShaderStages[s].Shaders; + auto& ByteCodes = ShaderStages[s].ByteCodes; + const auto ShaderType = ShaderStages[s].Type; + + ResourceBinding::TMap ResourceMap; + for (Uint32 Sig = 0, SigCount = GetSignatureCount(); Sig < SigCount; ++Sig) + { + auto* pSignature = GetSignature(Sig); + if (pSignature != nullptr) + { + const Uint32 FirstSpace = pSignature->GetBaseRegisterSpace(); + + for (Uint32 r = 0, ResCount = pSignature->GetTotalResourceCount(); r < ResCount; ++r) + { + const auto& ResDesc = pSignature->GetResourceDesc(r); + const auto& Attribs = pSignature->GetResourceAttribs(r); + + if (ResDesc.ShaderStages & ShaderType) + { + auto IsUnique = ResourceMap.emplace(HashMapStringKey{ResDesc.Name}, ResourceBinding::BindInfo{Attribs.BindPoint, Attribs.Space + FirstSpace}).second; + VERIFY(IsUnique, "resource name must be unique"); + } + } + + for (Uint32 samp = 0, SampCount = pSignature->GetImmutableSamplerCount(); samp < SampCount; ++samp) + { + const auto& ImtblSam = pSignature->GetImmutableSamplerDesc(samp); + const auto& SampAttr = pSignature->GetImmutableSamplerAttribs(samp); + ResourceBinding::BindInfo BindInfo{SampAttr.ShaderRegister, SampAttr.RegisterSpace + FirstSpace}; + + if (ImtblSam.ShaderStages & ShaderType) + { + auto IsUnique = ResourceMap.emplace(HashMapStringKey{ImtblSam.SamplerOrTextureName}, BindInfo).second; + if (!IsUnique && pSignature->IsUsingCombinedSamplers()) + { + // add sampler with suffix + String SampName{ImtblSam.SamplerOrTextureName}; + SampName += pSignature->GetCombinedSamplerSuffix(); + ResourceMap.emplace(HashMapStringKey{SampName}, BindInfo); + } + } + } + } + } + + // AZ TODO: add local root signature to ResourceMap + + for (size_t i = 0; i < Shaders.size(); ++i) + { + auto* pShader = Shaders[i]; + auto& pBytecode = ByteCodes[i]; + CComPtr<ID3DBlob> pBlob; + + if (IsDXILBytecode(pBytecode->GetBufferPointer(), pBytecode->GetBufferSize())) + { + if (!compiler) + LOG_ERROR_AND_THROW("DXC compiler is not exists, can not remap resource bindings"); + + if (!compiler->RemapResourceBindings(ResourceMap, reinterpret_cast<IDxcBlob*>(pBytecode.p), reinterpret_cast<IDxcBlob**>(&pBlob))) + LOG_ERROR_AND_THROW("Failed to remap resource bindings in shader '", pShader->GetDesc().Name, "'."); + } + else + { + D3DCreateBlob(pBytecode->GetBufferSize(), &pBlob); + memcpy(pBlob->GetBufferPointer(), pBytecode->GetBufferPointer(), pBytecode->GetBufferSize()); + + if (!DXBCUtils::RemapResourceBindings(ResourceMap, pBlob->GetBufferPointer(), pBlob->GetBufferSize())) + LOG_ERROR_AND_THROW("Failed to remap resource bindings in shader '", pShader->GetDesc().Name, "'."); + } + pBytecode = pBlob; + + // AZ TODO +#if 0 //def DILIGENT_DEVELOPMENT + const auto& pShaderResources = pShader->GetShaderResources(); + m_ShaderResources.emplace_back(pShaderResources); + + // Check compatibility between shader resources and resource signature. + const auto HandleResource = [&](const D3DShaderResourceAttribs& Res, Uint32) // + { + if (pLocalRootSig != nullptr && pLocalRootSig->IsShaderRecord(Res)) + return; + + ResourceInfo Info = {}; + if (!m_RootSig->GetResource(Res.Name, Info)) + { + // error + } + + if (Res.BindCount == 0) + { + if ((Info.Flags & PIPELINE_RESOURCE_FLAG_RUNTIME_ARRAY) != 0) + { + // error + } + } + else if (Info.Flags & PIPELINE_RESOURCE_FLAG_RUNTIME_ARRAY) + { + // warning + } + }; + pShaderResources->ProcessResources(HandleResource, HandleResource, HandleResource, HandleResource, HandleResource, HandleResource, HandleResource); +#endif + } + } +} + template <typename PSOCreateInfoType> void PipelineStateD3D12Impl::InitInternalObjects(const PSOCreateInfoType& CreateInfo, - RootSignatureBuilder& RootSigBuilder, TShaderStages& ShaderStages, - LocalRootSignature* pLocalRoot) + LocalRootSignatureD3D12* pLocalRootSig) { - m_ResourceLayoutIndex.fill(-1); - ExtractShaders<ShaderD3D12Impl>(CreateInfo, ShaderStages); FixedLinearAllocator MemPool{GetRawAllocator()}; - const auto NumShaderStages = GetNumShaderStages(); - VERIFY_EXPR(NumShaderStages > 0 && NumShaderStages == ShaderStages.size()); - - MemPool.AddSpace<ShaderResourceCacheD3D12>(NumShaderStages); - MemPool.AddSpace<ShaderResourceLayoutD3D12>(NumShaderStages * 2); - MemPool.AddSpace<ShaderVariableManagerD3D12>(NumShaderStages); - ReserveSpaceForPipelineDesc(CreateInfo, MemPool); MemPool.Reserve(); - m_pStaticResourceCaches = MemPool.ConstructArray<ShaderResourceCacheD3D12>(NumShaderStages, ShaderResourceCacheD3D12::DbgCacheContentType::StaticShaderResources); - - // The memory is now owned by PipelineStateD3D12Impl and will be freed by Destruct(). - auto* Ptr = MemPool.ReleaseOwnership(); - VERIFY_EXPR(Ptr == m_pStaticResourceCaches); - (void)Ptr; - - auto* const pd3d12Device = GetDevice()->GetD3D12Device(); - m_pShaderResourceLayouts = MemPool.ConstructArray<ShaderResourceLayoutD3D12>(NumShaderStages * 2, std::ref(*this), pd3d12Device); - - m_pStaticVarManagers = MemPool.Allocate<ShaderVariableManagerD3D12>(NumShaderStages); - for (Uint32 s = 0; s < NumShaderStages; ++s) - new (m_pStaticVarManagers + s) ShaderVariableManagerD3D12{*this, GetStaticShaderResCache(s)}; + m_pRawMem = MemPool.ReleaseOwnership(); InitializePipelineDesc(CreateInfo, MemPool); // It is important to construct all objects before initializing them because if an exception is thrown, // destructors will be called for all objects - InitResourceLayouts(CreateInfo, RootSigBuilder, ShaderStages, pLocalRoot); + InitRootSignature(CreateInfo, ShaderStages, pLocalRootSig); } PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* pRefCounters, RenderDeviceD3D12Impl* pDeviceD3D12, const GraphicsPipelineStateCreateInfo& CreateInfo) : - TPipelineStateBase{pRefCounters, pDeviceD3D12, CreateInfo}, - m_SRBMemAllocator{GetRawAllocator()} + TPipelineStateBase{pRefCounters, pDeviceD3D12, CreateInfo} { try { - RootSignatureBuilder RootSigBuilder{m_RootSig, CreateInfo.PSODesc.ResourceLayout}; - TShaderStages ShaderStages; - InitInternalObjects(CreateInfo, RootSigBuilder, ShaderStages); + TShaderStages ShaderStages; + InitInternalObjects(CreateInfo, ShaderStages); auto* pd3d12Device = pDeviceD3D12->GetD3D12Device(); if (m_Desc.PipelineType == PIPELINE_TYPE_GRAPHICS) @@ -438,13 +698,11 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* for (const auto& Stage : ShaderStages) { - VERIFY_EXPR(Stage.Shaders.size() == 1); - auto* pShaderD3D12 = Stage.Shaders[0]; - auto ShaderType = pShaderD3D12->GetDesc().ShaderType; - VERIFY_EXPR(ShaderType == Stage.Type); + VERIFY_EXPR(Stage.Count() == 1); + const auto& pByteCode = Stage.ByteCodes[0]; D3D12_SHADER_BYTECODE* pd3d12ShaderBytecode = nullptr; - switch (ShaderType) + switch (Stage.Type) { // clang-format off case SHADER_TYPE_VERTEX: pd3d12ShaderBytecode = &d3d12PSODesc.VS; break; @@ -455,13 +713,12 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* // clang-format on default: UNEXPECTED("Unexpected shader type"); } - auto* pByteCode = pShaderD3D12->GetShaderByteCode(); pd3d12ShaderBytecode->pShaderBytecode = pByteCode->GetBufferPointer(); pd3d12ShaderBytecode->BytecodeLength = pByteCode->GetBufferSize(); } - d3d12PSODesc.pRootSignature = m_RootSig.GetD3D12RootSignature(); + d3d12PSODesc.pRootSignature = m_RootSig->GetD3D12RootSignature(); memset(&d3d12PSODesc.StreamOutput, 0, sizeof(d3d12PSODesc.StreamOutput)); @@ -542,13 +799,11 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* for (const auto& Stage : ShaderStages) { - VERIFY_EXPR(Stage.Shaders.size() == 1); - auto* pShaderD3D12 = Stage.Shaders[0]; - auto ShaderType = pShaderD3D12->GetDesc().ShaderType; - VERIFY_EXPR(ShaderType == Stage.Type); + VERIFY_EXPR(Stage.Count() == 1); + const auto& pByteCode = Stage.ByteCodes[0]; D3D12_SHADER_BYTECODE* pd3d12ShaderBytecode = nullptr; - switch (ShaderType) + switch (Stage.Type) { // clang-format off case SHADER_TYPE_AMPLIFICATION: pd3d12ShaderBytecode = &d3d12PSODesc.AS; break; @@ -557,13 +812,12 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* // clang-format on default: UNEXPECTED("Unexpected shader type"); } - auto* pByteCode = pShaderD3D12->GetShaderByteCode(); pd3d12ShaderBytecode->pShaderBytecode = pByteCode->GetBufferPointer(); pd3d12ShaderBytecode->BytecodeLength = pByteCode->GetBufferSize(); } - d3d12PSODesc.pRootSignature = m_RootSig.GetD3D12RootSignature(); + d3d12PSODesc.pRootSignature = m_RootSig->GetD3D12RootSignature(); BlendStateDesc_To_D3D12_BLEND_DESC(GraphicsPipeline.BlendDesc, *d3d12PSODesc.BlendState); d3d12PSODesc.SampleMask = GraphicsPipeline.SampleMask; @@ -610,10 +864,6 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* if (*m_Desc.Name != 0) { m_pd3d12PSO->SetName(WidenString(m_Desc.Name).c_str()); - String RootSignatureDesc("Root signature for PSO '"); - RootSignatureDesc.append(m_Desc.Name); - RootSignatureDesc.push_back('\''); - m_RootSig.GetD3D12RootSignature()->SetName(WidenString(RootSignatureDesc).c_str()); } } catch (...) @@ -626,22 +876,20 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* pRefCounters, RenderDeviceD3D12Impl* pDeviceD3D12, const ComputePipelineStateCreateInfo& CreateInfo) : - TPipelineStateBase{pRefCounters, pDeviceD3D12, CreateInfo}, - m_SRBMemAllocator{GetRawAllocator()} + TPipelineStateBase{pRefCounters, pDeviceD3D12, CreateInfo} { try { - RootSignatureBuilder RootSigBuilder{m_RootSig, CreateInfo.PSODesc.ResourceLayout}; - TShaderStages ShaderStages; - InitInternalObjects(CreateInfo, RootSigBuilder, ShaderStages); + TShaderStages ShaderStages; + InitInternalObjects(CreateInfo, ShaderStages); auto* pd3d12Device = pDeviceD3D12->GetD3D12Device(); D3D12_COMPUTE_PIPELINE_STATE_DESC d3d12PSODesc = {}; VERIFY_EXPR(ShaderStages[0].Type == SHADER_TYPE_COMPUTE); - VERIFY_EXPR(ShaderStages[0].Shaders.size() == 1); - auto* pByteCode = ShaderStages[0].Shaders[0]->GetShaderByteCode(); + VERIFY_EXPR(ShaderStages[0].Count() == 1); + const auto& pByteCode = ShaderStages[0].ByteCodes[0]; d3d12PSODesc.CS.pShaderBytecode = pByteCode->GetBufferPointer(); d3d12PSODesc.CS.BytecodeLength = pByteCode->GetBufferSize(); @@ -656,7 +904,7 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* // The only valid bit is D3D12_PIPELINE_STATE_FLAG_TOOL_DEBUG, which can only be set on WARP devices. d3d12PSODesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; - d3d12PSODesc.pRootSignature = m_RootSig.GetD3D12RootSignature(); + d3d12PSODesc.pRootSignature = m_RootSig->GetD3D12RootSignature(); HRESULT hr = pd3d12Device->CreateComputePipelineState(&d3d12PSODesc, IID_PPV_ARGS(&m_pd3d12PSO)); if (FAILED(hr)) @@ -665,10 +913,6 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* if (*m_Desc.Name != 0) { m_pd3d12PSO->SetName(WidenString(m_Desc.Name).c_str()); - String RootSignatureDesc("Root signature for PSO '"); - RootSignatureDesc.append(m_Desc.Name); - RootSignatureDesc.push_back('\''); - m_RootSig.GetD3D12RootSignature()->SetName(WidenString(RootSignatureDesc).c_str()); } } catch (...) @@ -681,32 +925,21 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* pRefCounters, RenderDeviceD3D12Impl* pDeviceD3D12, const RayTracingPipelineStateCreateInfo& CreateInfo) : - TPipelineStateBase{pRefCounters, pDeviceD3D12, CreateInfo}, - m_SRBMemAllocator{GetRawAllocator()} + TPipelineStateBase{pRefCounters, pDeviceD3D12, CreateInfo} { try { - LocalRootSignature LocalRootSig{CreateInfo.pShaderRecordName, CreateInfo.RayTracingPipeline.ShaderRecordSize}; - TShaderStages ShaderStages; - RootSignatureBuilder RootSigBuilder{m_RootSig, CreateInfo.PSODesc.ResourceLayout}; - InitInternalObjects(CreateInfo, RootSigBuilder, ShaderStages, &LocalRootSig); + LocalRootSignatureD3D12 LocalRootSig{CreateInfo.pShaderRecordName, CreateInfo.RayTracingPipeline.ShaderRecordSize}; + TShaderStages ShaderStages; + InitInternalObjects(CreateInfo, ShaderStages, &LocalRootSig); auto* pd3d12Device = pDeviceD3D12->GetD3D12Device5(); - const auto* const pStaticResLayouts = m_pShaderResourceLayouts + GetNumShaderStages(); - // Extract bindings (shader registers) assigned during the layout initialization, - // for every shader stage. - const auto BindingMapPerStage = - ExtractResourceBindingMap(RootSigBuilder, m_ResourceLayoutIndex, m_pShaderResourceLayouts, pStaticResLayouts); - DynamicLinearAllocator TempPool{GetRawAllocator(), 4 << 10}; std::vector<D3D12_STATE_SUBOBJECT> Subobjects; - std::vector<CComPtr<IDxcBlob>> ShaderBlobs; - // Create ray-tracing pipeline and remap shader registers (including static samplers) using the bind points assigned during the - // resource layout initialization. - BuildRTPipelineDescription(CreateInfo, Subobjects, ShaderBlobs, TempPool, pDeviceD3D12->GetDxCompiler(), BindingMapPerStage); + BuildRTPipelineDescription(CreateInfo, Subobjects, TempPool); - D3D12_GLOBAL_ROOT_SIGNATURE GlobalRoot = {m_RootSig.GetD3D12RootSignature()}; + D3D12_GLOBAL_ROOT_SIGNATURE GlobalRoot = {m_RootSig->GetD3D12RootSignature()}; Subobjects.push_back({D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE, &GlobalRoot}); D3D12_LOCAL_ROOT_SIGNATURE LocalRoot = {LocalRootSig.Create(pd3d12Device)}; @@ -729,10 +962,6 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* if (*m_Desc.Name != 0) { m_pd3d12PSO->SetName(WidenString(m_Desc.Name).c_str()); - String RootSignatureDesc("Root signature for PSO '"); - RootSignatureDesc.append(m_Desc.Name); - RootSignatureDesc.push_back('\''); - m_RootSig.GetD3D12RootSignature()->SetName(WidenString(RootSignatureDesc).c_str()); } } catch (...) @@ -751,30 +980,14 @@ void PipelineStateD3D12Impl::Destruct() { TPipelineStateBase::Destruct(); - auto& ShaderResLayoutAllocator = GetRawAllocator(); - for (Uint32 s = 0; s < GetNumShaderStages(); ++s) - { - if (m_pStaticVarManagers != nullptr) - { - m_pStaticVarManagers[s].Destroy(GetRawAllocator()); - m_pStaticVarManagers[s].~ShaderVariableManagerD3D12(); - } + m_Signatures.fill({}); + m_RootSig.Release(); - if (m_pShaderResourceLayouts != nullptr) - { - m_pShaderResourceLayouts[s].~ShaderResourceLayoutD3D12(); - m_pShaderResourceLayouts[GetNumShaderStages() + s].~ShaderResourceLayoutD3D12(); - } - - if (m_pStaticResourceCaches != nullptr) - { - m_pStaticResourceCaches[s].~ShaderResourceCacheD3D12(); - } - } - // All internal objects are allocated in contiguous chunks of memory. - if (auto* pRawMem = m_pStaticResourceCaches) + auto& RawAllocator = GetRawAllocator(); + if (m_pRawMem) { - ShaderResLayoutAllocator.Free(pRawMem); + RawAllocator.Free(m_pRawMem); + m_pRawMem = nullptr; } if (m_pd3d12PSO) @@ -784,98 +997,6 @@ void PipelineStateD3D12Impl::Destruct() } } -void PipelineStateD3D12Impl::InitResourceLayouts(const PipelineStateCreateInfo& CreateInfo, - RootSignatureBuilder& RootSigBuilder, - TShaderStages& ShaderStages, - LocalRootSignature* pLocalRoot) -{ - auto* const pd3d12Device = GetDevice()->GetD3D12Device(); - const auto& ResourceLayout = m_Desc.ResourceLayout; - -#ifdef DILIGENT_DEVELOPMENT - { - std::vector<const ShaderResources*> Resources; - for (size_t s = 0; s < ShaderStages.size(); ++s) - { - for (auto* pShader : ShaderStages[s].Shaders) - { - Resources.push_back(pShader->GetShaderResources().get()); - } - } - ShaderResources::DvpVerifyResourceLayout(ResourceLayout, Resources.data(), static_cast<Uint32>(Resources.size()), - (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_VARIABLES) == 0, - (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_IMMUTABLE_SAMPLERS) == 0); - } -#endif - - for (size_t s = 0; s < ShaderStages.size(); ++s) - { - auto Shaders = ShaderStages[s].Shaders; - auto ShaderType = ShaderStages[s].Type; - auto ShaderInd = GetShaderTypePipelineIndex(ShaderType, m_Desc.PipelineType); - - m_ResourceLayoutIndex[ShaderInd] = static_cast<Int8>(s); - - // Initialize all-resources layout - m_pShaderResourceLayouts[s].Initialize( - m_Desc.PipelineType, - ResourceLayout, - Shaders, - GetRawAllocator(), - RootSigBuilder, - pLocalRoot // - ); - - // Initialize static resource layout and the cache. We must do this after - // general layout is initialized, because we will use the bind points that - // may have been assigned (for ray tracing shaders). - const SHADER_RESOURCE_VARIABLE_TYPE StaticVarType[] = {SHADER_RESOURCE_VARIABLE_TYPE_STATIC}; - m_pShaderResourceLayouts[GetNumShaderStages() + s].InitializeStaticReourceLayout( - m_pShaderResourceLayouts[s], - GetRawAllocator(), - m_pStaticResourceCaches[s] // - ); - - m_pStaticVarManagers[s].Initialize( - GetStaticShaderResLayout(static_cast<Uint32>(s)), - GetRawAllocator(), - nullptr, - 0 // - ); - } - RootSigBuilder.Finalize(pd3d12Device); - - if (m_Desc.SRBAllocationGranularity > 1) - { - std::array<size_t, MAX_SHADERS_IN_PIPELINE> ShaderVarMgrDataSizes = {}; - for (Uint32 s = 0; s < GetNumShaderStages(); ++s) - { - std::array<SHADER_RESOURCE_VARIABLE_TYPE, 2> AllowedVarTypes = - { - SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, - SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC // - }; - Uint32 NumVariablesUnused = 0; - - ShaderVarMgrDataSizes[s] = ShaderVariableManagerD3D12::GetRequiredMemorySize(m_pShaderResourceLayouts[s], AllowedVarTypes.data(), static_cast<Uint32>(AllowedVarTypes.size()), NumVariablesUnused); - } - - auto CacheMemorySize = RootSigBuilder.GetResourceCacheRequiredMemSize(); - m_SRBMemAllocator.Initialize(m_Desc.SRBAllocationGranularity, GetNumShaderStages(), ShaderVarMgrDataSizes.data(), 1, &CacheMemorySize); - } - - m_ShaderResourceLayoutHash = RootSigBuilder.GetHash(); -} - -void PipelineStateD3D12Impl::CreateShaderResourceBinding(IShaderResourceBinding** ppShaderResourceBinding, bool InitStaticResources) -{ - auto& SRBAllocator = m_pDevice->GetSRBAllocator(); - auto* pResBindingD3D12 = NEW_RC_OBJ(SRBAllocator, "ShaderResourceBindingD3D12Impl instance", ShaderResourceBindingD3D12Impl)(this, false); - if (InitStaticResources) - pResBindingD3D12->InitializeStaticResources(nullptr); - pResBindingD3D12->QueryInterface(IID_ShaderResourceBinding, reinterpret_cast<IObject**>(ppShaderResourceBinding)); -} - bool PipelineStateD3D12Impl::IsCompatibleWith(const IPipelineState* pPSO) const { VERIFY_EXPR(pPSO != nullptr); @@ -883,179 +1004,7 @@ bool PipelineStateD3D12Impl::IsCompatibleWith(const IPipelineState* pPSO) const if (pPSO == this) return true; - const PipelineStateD3D12Impl* pPSOD3D12 = ValidatedCast<const PipelineStateD3D12Impl>(pPSO); - if (m_ShaderResourceLayoutHash != pPSOD3D12->m_ShaderResourceLayoutHash) - return false; - - auto IsSameRootSignature = m_RootSig.IsSameAs(pPSOD3D12->m_RootSig); - -#ifdef DILIGENT_DEBUG - { - bool IsCompatibleShaders = true; - if (GetNumShaderStages() != pPSOD3D12->GetNumShaderStages()) - IsCompatibleShaders = false; - - if (IsCompatibleShaders) - { - for (Uint32 s = 0; s < GetNumShaderStages(); ++s) - { - if (GetShaderStageType(s) != pPSOD3D12->GetShaderStageType(s)) - { - IsCompatibleShaders = false; - break; - } - - const auto& Res0 = GetShaderResLayout(s); - const auto& Res1 = pPSOD3D12->GetShaderResLayout(s); - if (!Res0.IsCompatibleWith(Res1)) - { - IsCompatibleShaders = false; - break; - } - } - } - - if (IsCompatibleShaders) - VERIFY(IsSameRootSignature, "Compatible shaders must have same root signatures"); - } -#endif - - return IsSameRootSignature; -} - -ShaderResourceCacheD3D12* PipelineStateD3D12Impl::CommitAndTransitionShaderResources(class DeviceContextD3D12Impl* pDeviceCtx, - class CommandContext& CmdCtx, - CommitAndTransitionResourcesAttribs& Attrib) const -{ -#ifdef DILIGENT_DEVELOPMENT - if (Attrib.pShaderResourceBinding == nullptr && ContainsShaderResources()) - { - LOG_ERROR_MESSAGE("Pipeline state '", m_Desc.Name, "' requires shader resource binding object to ", - (Attrib.CommitResources ? "commit" : "transition"), " resources, but none is provided."); - } -#endif - - auto* pResBindingD3D12Impl = ValidatedCast<ShaderResourceBindingD3D12Impl>(Attrib.pShaderResourceBinding); - if (pResBindingD3D12Impl == nullptr) - { - if (Attrib.CommitResources) - { - if (m_Desc.IsAnyGraphicsPipeline()) - CmdCtx.AsGraphicsContext().SetGraphicsRootSignature(GetD3D12RootSignature()); - else - CmdCtx.AsComputeContext().SetComputeRootSignature(GetD3D12RootSignature()); - } - return nullptr; - } - -#ifdef DILIGENT_DEVELOPMENT - if (IsIncompatibleWith(pResBindingD3D12Impl->GetPipelineState())) - { - LOG_ERROR_MESSAGE("Shader resource binding is incompatible with the pipeline state '", m_Desc.Name, "'. Operation will be ignored."); - return nullptr; - } - - if (Attrib.CommitResources) - { - if ((m_RootSig.GetTotalSrvCbvUavSlots(SHADER_RESOURCE_VARIABLE_TYPE_STATIC) != 0 || - m_RootSig.GetTotalRootViews(SHADER_RESOURCE_VARIABLE_TYPE_STATIC) != 0) && - !pResBindingD3D12Impl->StaticResourcesInitialized()) - { - LOG_ERROR_MESSAGE("Static resources have not been initialized in the shader resource binding object being committed for PSO '", m_Desc.Name, "'. Please call IShaderResourceBinding::InitializeStaticResources()."); - } - - pResBindingD3D12Impl->dvpVerifyResourceBindings(this); - } -#endif - - auto& ResourceCache = pResBindingD3D12Impl->GetResourceCache(); - if (Attrib.CommitResources) - { - if (m_Desc.IsAnyGraphicsPipeline()) - CmdCtx.AsGraphicsContext().SetGraphicsRootSignature(GetD3D12RootSignature()); - else - CmdCtx.AsComputeContext().SetComputeRootSignature(GetD3D12RootSignature()); - - if (Attrib.TransitionResources) - { - (m_RootSig.*m_RootSig.TransitionAndCommitDescriptorHandles)(m_pDevice, ResourceCache, CmdCtx, !m_Desc.IsAnyGraphicsPipeline(), Attrib.ValidateStates); - } - else - { - (m_RootSig.*m_RootSig.CommitDescriptorHandles)(m_pDevice, ResourceCache, CmdCtx, !m_Desc.IsAnyGraphicsPipeline(), Attrib.ValidateStates); - } - } - else - { - VERIFY(Attrib.TransitionResources, "Resources should be transitioned or committed or both"); - m_RootSig.TransitionResources(ResourceCache, CmdCtx); - } - - // Process only non-dynamic buffers at this point. Dynamic buffers will be handled by the Draw/Dispatch command. - m_RootSig.CommitRootViews(ResourceCache, - CmdCtx, - !m_Desc.IsAnyGraphicsPipeline(), - Attrib.CtxId, - pDeviceCtx, - Attrib.CommitResources, // CommitViews - false, // ProcessDynamicBuffers - true, // ProcessNonDynamicBuffers - Attrib.TransitionResources, - Attrib.ValidateStates); - - return &ResourceCache; -} - - -bool PipelineStateD3D12Impl::ContainsShaderResources() const -{ - for (auto VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1)) - { - if (m_RootSig.GetTotalSrvCbvUavSlots(VarType) != 0 || - m_RootSig.GetTotalRootViews(VarType) != 0) - return true; - } - return false; -} - -void PipelineStateD3D12Impl::BindStaticResources(Uint32 ShaderFlags, IResourceMapping* pResourceMapping, Uint32 Flags) -{ - for (Uint32 s = 0; s < GetNumShaderStages(); ++s) - { - const auto ShaderType = GetStaticShaderResLayout(s).GetShaderType(); - if ((ShaderFlags & ShaderType) != 0) - m_pStaticVarManagers[s].BindResources(pResourceMapping, Flags); - } -} - -Uint32 PipelineStateD3D12Impl::GetStaticVariableCount(SHADER_TYPE ShaderType) const -{ - const auto LayoutInd = GetStaticVariableCountHelper(ShaderType, m_ResourceLayoutIndex); - if (LayoutInd < 0) - return 0; - - VERIFY_EXPR(static_cast<Uint32>(LayoutInd) < GetNumShaderStages()); - return m_pStaticVarManagers[LayoutInd].GetVariableCount(); -} - -IShaderResourceVariable* PipelineStateD3D12Impl::GetStaticVariableByName(SHADER_TYPE ShaderType, const Char* Name) -{ - const auto LayoutInd = GetStaticVariableByNameHelper(ShaderType, Name, m_ResourceLayoutIndex); - if (LayoutInd < 0) - return nullptr; - - VERIFY_EXPR(static_cast<Uint32>(LayoutInd) < GetNumShaderStages()); - return m_pStaticVarManagers[LayoutInd].GetVariable(Name); -} - -IShaderResourceVariable* PipelineStateD3D12Impl::GetStaticVariableByIndex(SHADER_TYPE ShaderType, Uint32 Index) -{ - const auto LayoutInd = GetStaticVariableByIndexHelper(ShaderType, Index, m_ResourceLayoutIndex); - if (LayoutInd < 0) - return nullptr; - - VERIFY_EXPR(static_cast<Uint32>(LayoutInd) < GetNumShaderStages()); - return m_pStaticVarManagers[LayoutInd].GetVariable(Index); + return (m_RootSig == ValidatedCast<const PipelineStateD3D12Impl>(pPSO)->m_RootSig); } } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp index 8b22a8c3..b8667f78 100644 --- a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp @@ -46,6 +46,7 @@ #include "BottomLevelASD3D12Impl.hpp" #include "TopLevelASD3D12Impl.hpp" #include "ShaderBindingTableD3D12Impl.hpp" +#include "PipelineResourceSignatureD3D12Impl.hpp" #include "EngineMemory.h" namespace Diligent @@ -141,7 +142,8 @@ RenderDeviceD3D12Impl::RenderDeviceD3D12Impl(IReferenceCounters* pRefCo sizeof(FramebufferD3D12Impl), sizeof(BottomLevelASD3D12Impl), sizeof(TopLevelASD3D12Impl), - sizeof(ShaderBindingTableD3D12Impl) + sizeof(ShaderBindingTableD3D12Impl), + sizeof(PipelineResourceSignatureD3D12Impl) } }, m_pd3d12Device {pd3d12Device}, @@ -159,14 +161,16 @@ RenderDeviceD3D12Impl::RenderDeviceD3D12Impl(IReferenceCounters* pRefCo {RawMemAllocator, *this, EngineCI.GPUDescriptorHeapSize[0], EngineCI.GPUDescriptorHeapDynamicSize[0], D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE}, {RawMemAllocator, *this, EngineCI.GPUDescriptorHeapSize[1], EngineCI.GPUDescriptorHeapDynamicSize[1], D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE} }, - m_ContextPool (STD_ALLOCATOR_RAW_MEM(PooledCommandContext, GetRawAllocator(), "Allocator for vector<PooledCommandContext>")), - m_DynamicMemoryManager{GetRawAllocator(), *this, EngineCI.NumDynamicHeapPagesToReserve, EngineCI.DynamicHeapPageSize}, - m_MipsGenerator {pd3d12Device}, - m_QueryMgr {pd3d12Device, EngineCI.QueryPoolSizes}, - m_pDxCompiler {CreateDXCompiler(DXCompilerTarget::Direct3D12, EngineCI.pDxCompilerPath)} + m_ContextPool (STD_ALLOCATOR_RAW_MEM(PooledCommandContext, GetRawAllocator(), "Allocator for vector<PooledCommandContext>")), + m_DynamicMemoryManager {GetRawAllocator(), *this, EngineCI.NumDynamicHeapPagesToReserve, EngineCI.DynamicHeapPageSize}, + m_MipsGenerator {pd3d12Device}, + m_QueryMgr {pd3d12Device, EngineCI.QueryPoolSizes}, + m_pDxCompiler {CreateDXCompiler(DXCompilerTarget::Direct3D12, EngineCI.pDxCompilerPath)}, + m_RootSignatureAllocator{GetRawAllocator(), sizeof(RootSignatureD3D12), 128}, + m_RootSignatureCache {*this} // clang-format on { - static_assert(sizeof(DeviceObjectSizes) == sizeof(size_t) * 15, "Please add new objects to DeviceObjectSizes constructor"); + static_assert(sizeof(DeviceObjectSizes) == sizeof(size_t) * 16, "Please add new objects to DeviceObjectSizes constructor"); // set device properties { @@ -310,12 +314,14 @@ RenderDeviceD3D12Impl::RenderDeviceD3D12Impl(IReferenceCounters* pRefCo } } -#define CHECK_REQUIRED_FEATURE(Feature, FeatureName) \ - do \ - { \ - if (EngineCI.Features.Feature == DEVICE_FEATURE_STATE_ENABLED && \ - m_DeviceCaps.Features.Feature != DEVICE_FEATURE_STATE_ENABLED) \ - LOG_ERROR_AND_THROW(FeatureName, "not supported by this device"); \ + m_DeviceCaps.Features.ShaderResourceRuntimeArray = DEVICE_FEATURE_STATE_ENABLED; + +#define CHECK_REQUIRED_FEATURE(Feature, FeatureName) \ + do \ + { \ + if (EngineCI.Features.Feature == DEVICE_FEATURE_STATE_ENABLED && \ + m_DeviceCaps.Features.Feature != DEVICE_FEATURE_STATE_ENABLED) \ + LOG_ERROR_AND_THROW(FeatureName, " not supported by this device"); \ } while (false) // clang-format off @@ -333,7 +339,7 @@ RenderDeviceD3D12Impl::RenderDeviceD3D12Impl(IReferenceCounters* pRefCo #undef CHECK_REQUIRED_FEATURE #if defined(_MSC_VER) && defined(_WIN64) - static_assert(sizeof(DeviceFeatures) == 32, "Did you add a new feature to DeviceFeatures? Please handle its satus here."); + static_assert(sizeof(DeviceFeatures) == 33, "Did you add a new feature to DeviceFeatures? Please handle its satus here."); #endif auto& TexCaps = m_DeviceCaps.TexCaps; @@ -815,6 +821,25 @@ void RenderDeviceD3D12Impl::CreateSBT(const ShaderBindingTableDesc& Desc, }); } +void RenderDeviceD3D12Impl::CreatePipelineResourceSignature(const PipelineResourceSignatureDesc& Desc, + IPipelineResourceSignature** ppSignature) +{ + CreatePipelineResourceSignature(Desc, ppSignature, false); +} + +void RenderDeviceD3D12Impl::CreatePipelineResourceSignature(const PipelineResourceSignatureDesc& Desc, + IPipelineResourceSignature** ppSignature, + bool IsDeviceInternal) +{ + CreateDeviceObject("PipelineResourceSignature", Desc, ppSignature, + [&]() // + { + PipelineResourceSignatureD3D12Impl* pPRSD3D12(NEW_RC_OBJ(m_PipeResSignAllocator, "PipelineResourceSignatureD3D12Impl instance", PipelineResourceSignatureD3D12Impl)(this, Desc, IsDeviceInternal)); + pPRSD3D12->QueryInterface(IID_PipelineResourceSignature, reinterpret_cast<IObject**>(ppSignature)); + OnCreateDeviceObject(pPRSD3D12); + }); +} + DescriptorHeapAllocation RenderDeviceD3D12Impl::AllocateDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE Type, UINT Count /*= 1*/) { VERIFY(Type >= D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV && Type < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES, "Invalid heap type"); @@ -827,4 +852,10 @@ DescriptorHeapAllocation RenderDeviceD3D12Impl::AllocateGPUDescriptors(D3D12_DES return m_GPUDescriptorHeaps[Type].Allocate(Count); } +void RenderDeviceD3D12Impl::CreateRootSignature(const RefCntAutoPtr<PipelineResourceSignatureD3D12Impl>* ppSignatures, Uint32 SignatureCount, RootSignatureD3D12** ppRootSig) +{ + RootSignatureD3D12* pRootSigD3D12(NEW_RC_OBJ(m_RootSignatureAllocator, "RootSignatureD3D12 instance", RootSignatureD3D12)(this, ppSignatures, SignatureCount)); + *ppRootSig = pRootSigD3D12; +} + } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp b/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp index 8281d2c3..75e833b1 100644 --- a/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp +++ b/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp @@ -28,8 +28,6 @@ #include "pch.h" #include "RootSignature.hpp" -#include "ShaderResourceLayoutD3D12.hpp" -#include "ShaderD3D12Impl.hpp" #include "CommandContext.hpp" #include "RenderDeviceD3D12Impl.hpp" #include "TextureD3D12Impl.hpp" @@ -40,400 +38,146 @@ namespace Diligent { -static constexpr auto RAY_TRACING_SHADER_TYPES = - SHADER_TYPE_RAY_GEN | - SHADER_TYPE_RAY_MISS | - SHADER_TYPE_RAY_CLOSEST_HIT | - SHADER_TYPE_RAY_ANY_HIT | - SHADER_TYPE_RAY_INTERSECTION | - SHADER_TYPE_CALLABLE; - -RootSignature::RootParamsManager::RootParamsManager(IMemoryAllocator& MemAllocator) : - m_MemAllocator{MemAllocator}, - m_pMemory{nullptr, STDDeleter<void, IMemoryAllocator>(MemAllocator)} -{} - -size_t RootSignature::RootParamsManager::GetRequiredMemorySize(Uint32 NumExtraRootTables, - Uint32 NumExtraRootViews, - Uint32 NumExtraDescriptorRanges) const -{ - return sizeof(RootParameter) * (m_NumRootTables + NumExtraRootTables + m_NumRootViews + NumExtraRootViews) + sizeof(D3D12_DESCRIPTOR_RANGE) * (m_TotalDescriptorRanges + NumExtraDescriptorRanges); -} - -D3D12_DESCRIPTOR_RANGE* RootSignature::RootParamsManager::Extend(Uint32 NumExtraRootTables, - Uint32 NumExtraRootViews, - Uint32 NumExtraDescriptorRanges, - Uint32 RootTableToAddRanges) +RootSignatureD3D12::RootSignatureD3D12(IReferenceCounters* pRefCounters, + RenderDeviceD3D12Impl* pDeviceD3D12Impl, + const RefCntAutoPtr<PipelineResourceSignatureD3D12Impl>* ppSignatures, + Uint32 SignatureCount) : + ObjectBase<IObject>{pRefCounters}, + m_SignatureCount{static_cast<Uint8>(SignatureCount)}, + m_pDeviceD3D12Impl{pDeviceD3D12Impl} { - VERIFY(NumExtraRootTables > 0 || NumExtraRootViews > 0 || NumExtraDescriptorRanges > 0, "At least one root table, root view or descriptor range must be added"); - auto MemorySize = GetRequiredMemorySize(NumExtraRootTables, NumExtraRootViews, NumExtraDescriptorRanges); - VERIFY_EXPR(MemorySize > 0); - auto* pNewMemory = ALLOCATE_RAW(m_MemAllocator, "Memory buffer for root tables, root views & descriptor ranges", MemorySize); - memset(pNewMemory, 0, MemorySize); + VERIFY(m_SignatureCount == SignatureCount, "Signature count (", SignatureCount, ") exceeds maximum representable value"); - // Note: this order is more efficient than views->tables->ranges - auto* pNewRootTables = reinterpret_cast<RootParameter*>(pNewMemory); - auto* pNewRootViews = pNewRootTables + (m_NumRootTables + NumExtraRootTables); - auto* pCurrDescriptorRangePtr = reinterpret_cast<D3D12_DESCRIPTOR_RANGE*>(pNewRootViews + m_NumRootViews + NumExtraRootViews); - - // Copy existing root tables to new memory - for (Uint32 rt = 0; rt < m_NumRootTables; ++rt) + for (Uint32 i = 0; i < SignatureCount; ++i) { - const auto& SrcTbl = GetRootTable(rt); - auto& D3D12SrcTbl = static_cast<const D3D12_ROOT_PARAMETER&>(SrcTbl).DescriptorTable; - auto NumRanges = D3D12SrcTbl.NumDescriptorRanges; - if (rt == RootTableToAddRanges) + m_Signatures[i] = ppSignatures[i]; + + if (ppSignatures[i] != nullptr) { - VERIFY(NumExtraRootTables == 0 || NumExtraRootTables == 1, "Up to one descriptor table can be extended at a time"); - NumRanges += NumExtraDescriptorRanges; + VERIFY(ppSignatures[i]->GetDesc().BindingIndex == i, "Signature placed to another binding index"); } - new (pNewRootTables + rt) RootParameter(SrcTbl, NumRanges, pCurrDescriptorRangePtr); - pCurrDescriptorRangePtr += NumRanges; } - // Copy existing root views to new memory - for (Uint32 rv = 0; rv < m_NumRootViews; ++rv) + if (m_SignatureCount > 0) { - const auto& SrcView = GetRootView(rv); - new (pNewRootViews + rv) RootParameter(SrcView); + HashCombine(m_Hash, m_SignatureCount); + for (Uint32 i = 0; i < m_SignatureCount; ++i) + { + if (m_Signatures[i] != nullptr) + HashCombine(m_Hash, m_Signatures[i]->GetHash()); + else + HashCombine(m_Hash, 0); + } } - - m_pMemory.reset(pNewMemory); - m_NumRootTables += NumExtraRootTables; - m_NumRootViews += NumExtraRootViews; - m_TotalDescriptorRanges += NumExtraDescriptorRanges; - m_pRootTables = m_NumRootTables != 0 ? pNewRootTables : nullptr; - m_pRootViews = m_NumRootViews != 0 ? pNewRootViews : nullptr; - - return pCurrDescriptorRangePtr; } -void RootSignature::RootParamsManager::AddRootView(D3D12_ROOT_PARAMETER_TYPE ParameterType, - Uint32 RootIndex, - UINT Register, - D3D12_SHADER_VISIBILITY Visibility, - SHADER_RESOURCE_VARIABLE_TYPE VarType) +RootSignatureD3D12::~RootSignatureD3D12() { - auto* pRangePtr = Extend(0, 1, 0); - VERIFY_EXPR((char*)pRangePtr == (char*)m_pMemory.get() + GetRequiredMemorySize(0, 0, 0)); - new (m_pRootViews + m_NumRootViews - 1) RootParameter(ParameterType, RootIndex, Register, 0u, Visibility, VarType); + m_pDeviceD3D12Impl->GetRootSignatureCache().OnDestroyRootSig(this); } -void RootSignature::RootParamsManager::AddRootTable(Uint32 RootIndex, - D3D12_SHADER_VISIBILITY Visibility, - SHADER_RESOURCE_VARIABLE_TYPE VarType, - Uint32 NumRangesInNewTable) +void RootSignatureD3D12::Finalize() { - auto* pRangePtr = Extend(1, 0, NumRangesInNewTable); - VERIFY_EXPR((char*)(pRangePtr + NumRangesInNewTable) == (char*)m_pMemory.get() + GetRequiredMemorySize(0, 0, 0)); - new (m_pRootTables + m_NumRootTables - 1) RootParameter(D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, RootIndex, NumRangesInNewTable, pRangePtr, Visibility, VarType); -} + VERIFY(m_pd3d12RootSignature == nullptr, "This root signature is already initialized"); -void RootSignature::RootParamsManager::AddDescriptorRanges(Uint32 RootTableInd, Uint32 NumExtraRanges) -{ - auto* pRangePtr = Extend(0, 0, NumExtraRanges, RootTableInd); - VERIFY_EXPR((char*)pRangePtr == (char*)m_pMemory.get() + GetRequiredMemorySize(0, 0, 0)); -} + D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc = {}; + rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; -bool RootSignature::RootParamsManager::operator==(const RootParamsManager& RootParams) const -{ - if (m_NumRootTables != RootParams.m_NumRootTables || - m_NumRootViews != RootParams.m_NumRootViews) - return false; + Uint32 TotalParams = 0; + Uint32 TotalD3D12StaticSamplers = 0; - for (Uint32 rv = 0; rv < m_NumRootViews; ++rv) + for (Uint32 s = 0; s < m_SignatureCount; ++s) { - const auto& RV0 = GetRootView(rv); - const auto& RV1 = RootParams.GetRootView(rv); - if (RV0 != RV1) - return false; - } - - for (Uint32 rv = 0; rv < m_NumRootTables; ++rv) - { - const auto& RT0 = GetRootTable(rv); - const auto& RT1 = RootParams.GetRootTable(rv); - if (RT0 != RT1) - return false; - } - - return true; -} - -size_t RootSignature::RootParamsManager::GetHash() const -{ - size_t hash = ComputeHash(m_NumRootTables, m_NumRootViews); - for (Uint32 rv = 0; rv < m_NumRootViews; ++rv) - HashCombine(hash, GetRootView(rv).GetHash()); - - for (Uint32 rv = 0; rv < m_NumRootTables; ++rv) - HashCombine(hash, GetRootTable(rv).GetHash()); - - return hash; -} - - -RootSignatureBuilder::RootSignatureBuilder(RootSignature& RootSig, - const PipelineResourceLayoutDesc& PipelineResLayout) : - m_RootSig{RootSig}, - m_PipelineResLayout{PipelineResLayout}, - m_ImmutableSamplers(STD_ALLOCATOR_RAW_MEM(ImmutableSamplerAttribs, GetRawAllocator(), "Allocator for vector<ImmutableSamplerAttribs>")) -{ -} - - -void RootSignatureBuilder::InitImmutableSampler(SHADER_TYPE ShaderType, - const char* SamplerName, - const char* SamplerSuffix, - const D3DShaderResourceAttribs& SamplerAttribs) -{ - auto FindExistingSampler = [&]() -> const ImmutableSamplerAttribs* { - for (const auto& ImtblSmplr : m_ImmutableSamplers) + auto& pSignature = m_Signatures[s]; + if (pSignature != nullptr) { - if (ImtblSmplr.ShaderType == ShaderType && ImtblSmplr.SamplerName == SamplerName) - { - return &ImtblSmplr; - } - } - return nullptr; - }; + auto& RootParams = pSignature->m_RootParams; - if (ShaderType & RAY_TRACING_SHADER_TYPES) - { - if (const auto* pImtblSmplr = FindExistingSampler()) - { - // The sampler has already been initialized when processing another - // shader from the same shader stage. - DEV_CHECK_ERR(pImtblSmplr->ArraySize == SamplerAttribs.BindCount, "Immutable sampler '", SamplerName, - "' has already been found, but its previous array size (", pImtblSmplr->ArraySize, - ") does not match the new array size (", SamplerAttribs.BindCount, ")"); - return; - } - } - else - { - VERIFY(FindExistingSampler() == nullptr, "Multiple samplers with the same name in one stage are only expected in ray tracing shaders"); - } + m_FirstRootIndex[s] = TotalParams; + TotalParams += RootParams.GetNumRootTables() + RootParams.GetNumRootViews(); - bool SamplerFound = false; - for (Uint32 SrcImtblSmplrId = 0; SrcImtblSmplrId < m_PipelineResLayout.NumImmutableSamplers; ++SrcImtblSmplrId) - { - const auto& ImtblSamDesc = m_PipelineResLayout.ImmutableSamplers[SrcImtblSmplrId]; - if ((ImtblSamDesc.ShaderStages & ShaderType) != 0 && - StreqSuff(SamplerName, ImtblSamDesc.SamplerOrTextureName, SamplerSuffix)) - { - UINT ShaderRegister = SamplerAttribs.BindPoint; - if (ShaderType & RAY_TRACING_SHADER_TYPES) + for (Uint32 samp = 0, SampCount = pSignature->GetImmutableSamplerCount(); samp < SampCount; ++samp) { - // For ray tracing shaders, use the next available sampler register. - // The bindings will be remapped in the DXIL byte code. - ShaderRegister = m_NumResources[D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER]; - m_NumResources[D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER] += SamplerAttribs.BindCount; - } - - m_ImmutableSamplers.emplace_back( - ImtblSamDesc.Desc, - SamplerName, - ShaderRegister, - SamplerAttribs.BindCount, - 0, // Register space - ShaderType); + const auto& ImtblSam = pSignature->GetImmutableSamplerAttribs(samp); + VERIFY_EXPR(ImtblSam.IsAssigned()); - SamplerFound = true; - break; + TotalD3D12StaticSamplers += ImtblSam.ArraySize; + } } } - DEV_CHECK_ERR(SamplerFound, "Unable to find immutable sampler \'", SamplerName, '\''); -} - - -// http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-layout#Initializing-Shader-Resource-Layouts-and-Root-Signature-in-a-Pipeline-State-Object -void RootSignatureBuilder::AllocateResourceSlot(SHADER_TYPE ShaderType, - PIPELINE_TYPE PipelineType, - const D3DShaderResourceAttribs& ShaderResAttribs, - SHADER_RESOURCE_VARIABLE_TYPE VariableType, - D3D12_DESCRIPTOR_RANGE_TYPE RangeType, - Uint32& BindPoint, // in/out parameter - Uint32& RootIndex, // Output parameter - Uint32& OffsetFromTableStart // Output parameter -) -{ - const auto ShaderVisibility = ShaderTypeToD3D12ShaderVisibility(ShaderType); - auto& RootParams = m_RootSig.m_RootParams; - - if (ShaderType & RAY_TRACING_SHADER_TYPES) - { - // For ray tracing shaders, original bind points are ignored and - // will be remapped later by the PSO constructor. - BindPoint = m_NumResources[RangeType]; - m_NumResources[RangeType] += ShaderResAttribs.BindCount; - } - else - { - // Use original bind point - BindPoint = ShaderResAttribs.BindPoint; - } + std::vector<D3D12_ROOT_PARAMETER, STDAllocatorRawMem<D3D12_ROOT_PARAMETER>> D3D12Parameters(TotalParams, D3D12_ROOT_PARAMETER{}, STD_ALLOCATOR_RAW_MEM(D3D12_ROOT_PARAMETER, GetRawAllocator(), "Allocator for vector<D3D12_ROOT_PARAMETER>")); + std::vector<D3D12_STATIC_SAMPLER_DESC, STDAllocatorRawMem<D3D12_STATIC_SAMPLER_DESC>> D3D12StaticSamplers(STD_ALLOCATOR_RAW_MEM(D3D12_STATIC_SAMPLER_DESC, GetRawAllocator(), "Allocator for vector<D3D12_STATIC_SAMPLER_DESC>")); + D3D12StaticSamplers.reserve(TotalD3D12StaticSamplers); - if (RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_CBV && ShaderResAttribs.BindCount == 1) + for (Uint32 sig = 0; sig < m_SignatureCount; ++sig) { - // Allocate single CBV directly in the root signature - - // Get the next available root index past all allocated tables and root views - RootIndex = RootParams.GetNumRootTables() + RootParams.GetNumRootViews(); - OffsetFromTableStart = 0; + auto& pSignature = m_Signatures[sig]; + const auto FirstRootIndex = m_FirstRootIndex[sig]; - // Add new root view to existing root parameters - RootParams.AddRootView(D3D12_ROOT_PARAMETER_TYPE_CBV, RootIndex, BindPoint, ShaderVisibility, VariableType); - } - else - { - const auto ShaderInd = GetShaderTypePipelineIndex(ShaderType, PipelineType); - // Use the same table for static and mutable resources. Treat both as static - const auto RootTableType = (VariableType == SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) ? SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC : SHADER_RESOURCE_VARIABLE_TYPE_STATIC; - const auto TableIndKey = ShaderInd * SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES + RootTableType; - // Get the table array index (this is not the root index!) - auto& RootTableArrayInd = ((RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER) ? m_RootSig.m_SamplerRootTablesMap : m_RootSig.m_SrvCbvUavRootTablesMap)[TableIndKey]; - if (RootTableArrayInd == RootSignature::InvalidRootTableIndex) + if (pSignature != nullptr) { - // Root table has not been assigned to this combination yet - - // Get the next available root index past all allocated tables and root views - RootIndex = RootParams.GetNumRootTables() + RootParams.GetNumRootViews(); - VERIFY_EXPR(RootParams.GetNumRootTables() < 255); - RootTableArrayInd = static_cast<Uint8>(RootParams.GetNumRootTables()); - // Add root table with one single-descriptor range - RootParams.AddRootTable(RootIndex, ShaderVisibility, RootTableType, 1); - } - else - { - // Add a new single-descriptor range to the existing table at index RootTableArrayInd - RootParams.AddDescriptorRanges(RootTableArrayInd, 1); - } - - // Reference to either existing or just added table - auto& CurrParam = RootParams.GetRootTable(RootTableArrayInd); - RootIndex = CurrParam.GetRootIndex(); - - const auto& d3d12RootParam = static_cast<const D3D12_ROOT_PARAMETER&>(CurrParam); - - VERIFY(d3d12RootParam.ShaderVisibility == ShaderVisibility, "Shader visibility is not correct"); - - // Descriptors are tightly packed, so the next descriptor offset is the - // current size of the table - OffsetFromTableStart = CurrParam.GetDescriptorTableSize(); - - // New just added range is the last range in the descriptor table - Uint32 NewDescriptorRangeIndex = d3d12RootParam.DescriptorTable.NumDescriptorRanges - 1; - CurrParam.SetDescriptorRange(NewDescriptorRangeIndex, - RangeType, // Range type (CBV, SRV, UAV or SAMPLER) - BindPoint, // Shader register - ShaderResAttribs.BindCount, // Number of registers used (1 for non-array resources) - 0, // Register space. Always 0 for now - OffsetFromTableStart // Offset in descriptors from the table start - ); - } -} - -void RootSignatureBuilder::Finalize(ID3D12Device* pd3d12Device) -{ - auto& RootParams = m_RootSig.m_RootParams; - auto& TotalSamplerSlots = m_RootSig.m_TotalSamplerSlots; - auto& TotalSrvCbvUavSlots = m_RootSig.m_TotalSrvCbvUavSlots; - auto& TotalRootViews = m_RootSig.m_TotalRootViews; - auto& d3d12RootSignature = m_RootSig.m_pd3d12RootSignature; - - for (Uint32 rt = 0; rt < RootParams.GetNumRootTables(); ++rt) - { - const auto& RootTbl = RootParams.GetRootTable(rt); - const auto& d3d12RootParam = static_cast<const D3D12_ROOT_PARAMETER&>(RootTbl); - VERIFY_EXPR(d3d12RootParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE); - - auto TableSize = RootTbl.GetDescriptorTableSize(); - VERIFY(d3d12RootParam.DescriptorTable.NumDescriptorRanges > 0 && TableSize > 0, "Unexpected empty descriptor table"); - auto IsSamplerTable = d3d12RootParam.DescriptorTable.pDescriptorRanges[0].RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; - auto VarType = RootTbl.GetShaderVariableType(); - (IsSamplerTable ? TotalSamplerSlots : TotalSrvCbvUavSlots)[VarType] += TableSize; - } - - for (Uint32 rv = 0; rv < RootParams.GetNumRootViews(); ++rv) - { - const auto& RootView = RootParams.GetRootView(rv); - ++TotalRootViews[RootView.GetShaderVariableType()]; - } - -#ifdef DILIGENT_DEBUG - dbgVerifyRootParameters(); -#endif + auto& RootParams = pSignature->m_RootParams; + for (Uint32 rt = 0; rt < RootParams.GetNumRootTables(); ++rt) + { + const auto& RootTable = RootParams.GetRootTable(rt); + const D3D12_ROOT_PARAMETER& SrcParam = RootTable; + const Uint32 RootIndex = FirstRootIndex + RootTable.GetLocalRootIndex(); + VERIFY(SrcParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE && SrcParam.DescriptorTable.NumDescriptorRanges > 0, "Non-empty descriptor table is expected"); + D3D12Parameters[RootIndex] = SrcParam; + } - D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc; - rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; + for (Uint32 rv = 0; rv < RootParams.GetNumRootViews(); ++rv) + { + const auto& RootView = RootParams.GetRootView(rv); + const D3D12_ROOT_PARAMETER& SrcParam = RootView; + const Uint32 RootIndex = FirstRootIndex + RootView.GetLocalRootIndex(); + VERIFY(SrcParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_CBV, "Root CBV is expected"); + D3D12Parameters[RootIndex] = SrcParam; + } - auto TotalParams = RootParams.GetNumRootTables() + RootParams.GetNumRootViews(); + for (Uint32 samp = 0, SampCount = pSignature->GetImmutableSamplerCount(); samp < SampCount; ++samp) + { + const auto& SampAttr = pSignature->GetImmutableSamplerAttribs(samp); + const auto& ImtblSam = pSignature->GetImmutableSamplerDesc(samp); + const auto& SamDesc = ImtblSam.Desc; - std::vector<D3D12_ROOT_PARAMETER, STDAllocatorRawMem<D3D12_ROOT_PARAMETER>> D3D12Parameters(TotalParams, D3D12_ROOT_PARAMETER{}, STD_ALLOCATOR_RAW_MEM(D3D12_ROOT_PARAMETER, GetRawAllocator(), "Allocator for vector<D3D12_ROOT_PARAMETER>")); - for (Uint32 rt = 0; rt < RootParams.GetNumRootTables(); ++rt) - { - const auto& RootTable = RootParams.GetRootTable(rt); - const D3D12_ROOT_PARAMETER& SrcParam = RootTable; - VERIFY(SrcParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE && SrcParam.DescriptorTable.NumDescriptorRanges > 0, "Non-empty descriptor table is expected"); - D3D12Parameters[RootTable.GetRootIndex()] = SrcParam; - } - for (Uint32 rv = 0; rv < RootParams.GetNumRootViews(); ++rv) - { - const auto& RootView = RootParams.GetRootView(rv); - const D3D12_ROOT_PARAMETER& SrcParam = RootView; - VERIFY(SrcParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_CBV, "Root CBV is expected"); - D3D12Parameters[RootView.GetRootIndex()] = SrcParam; + for (UINT ArrInd = 0; ArrInd < SampAttr.ArraySize; ++ArrInd) + { + D3D12StaticSamplers.emplace_back( + D3D12_STATIC_SAMPLER_DESC // + { + FilterTypeToD3D12Filter(SamDesc.MinFilter, SamDesc.MagFilter, SamDesc.MipFilter), + TexAddressModeToD3D12AddressMode(SamDesc.AddressU), + TexAddressModeToD3D12AddressMode(SamDesc.AddressV), + TexAddressModeToD3D12AddressMode(SamDesc.AddressW), + SamDesc.MipLODBias, + SamDesc.MaxAnisotropy, + ComparisonFuncToD3D12ComparisonFunc(SamDesc.ComparisonFunc), + BorderColorToD3D12StaticBorderColor(SamDesc.BorderColor), + SamDesc.MinLOD, + SamDesc.MaxLOD, + SampAttr.ShaderRegister + ArrInd, + SampAttr.RegisterSpace, + ShaderTypeToD3D12ShaderVisibility(ImtblSam.ShaderStages) // + } // + ); + } + } + } } - rootSignatureDesc.NumParameters = static_cast<UINT>(D3D12Parameters.size()); rootSignatureDesc.pParameters = D3D12Parameters.size() ? D3D12Parameters.data() : nullptr; - UINT TotalD3D12StaticSamplers = 0; - for (const auto& ImtblSam : m_ImmutableSamplers) - { - TotalD3D12StaticSamplers += ImtblSam.ArraySize; - } rootSignatureDesc.NumStaticSamplers = TotalD3D12StaticSamplers; rootSignatureDesc.pStaticSamplers = nullptr; - std::vector<D3D12_STATIC_SAMPLER_DESC, STDAllocatorRawMem<D3D12_STATIC_SAMPLER_DESC>> D3D12StaticSamplers(STD_ALLOCATOR_RAW_MEM(D3D12_STATIC_SAMPLER_DESC, GetRawAllocator(), "Allocator for vector<D3D12_STATIC_SAMPLER_DESC>")); - D3D12StaticSamplers.reserve(TotalD3D12StaticSamplers); - if (!m_ImmutableSamplers.empty()) + if (!D3D12StaticSamplers.empty()) { - for (size_t s = 0; s < m_ImmutableSamplers.size(); ++s) - { - const auto& ImtblSmplr = m_ImmutableSamplers[s]; - const auto& SamDesc = ImtblSmplr.Desc; - for (UINT ArrInd = 0; ArrInd < ImtblSmplr.ArraySize; ++ArrInd) - { - D3D12StaticSamplers.emplace_back( - D3D12_STATIC_SAMPLER_DESC // - { - FilterTypeToD3D12Filter(SamDesc.MinFilter, SamDesc.MagFilter, SamDesc.MipFilter), - TexAddressModeToD3D12AddressMode(SamDesc.AddressU), - TexAddressModeToD3D12AddressMode(SamDesc.AddressV), - TexAddressModeToD3D12AddressMode(SamDesc.AddressW), - SamDesc.MipLODBias, - SamDesc.MaxAnisotropy, - ComparisonFuncToD3D12ComparisonFunc(SamDesc.ComparisonFunc), - BorderColorToD3D12StaticBorderColor(SamDesc.BorderColor), - SamDesc.MinLOD, - SamDesc.MaxLOD, - ImtblSmplr.ShaderRegister + ArrInd, - ImtblSmplr.RegisterSpace, - ShaderTypeToD3D12ShaderVisibility(ImtblSmplr.ShaderType) // - } // - ); - } - } rootSignatureDesc.pStaticSamplers = D3D12StaticSamplers.data(); - VERIFY_EXPR(D3D12StaticSamplers.size() == TotalD3D12StaticSamplers); } - CComPtr<ID3DBlob> signature; CComPtr<ID3DBlob> error; @@ -444,789 +188,135 @@ void RootSignatureBuilder::Finalize(ID3D12Device* pd3d12Device) } CHECK_D3D_RESULT_THROW(hr, "Failed to serialize root signature"); - hr = pd3d12Device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), __uuidof(d3d12RootSignature), reinterpret_cast<void**>(static_cast<ID3D12RootSignature**>(&d3d12RootSignature))); - CHECK_D3D_RESULT_THROW(hr, "Failed to create root signature"); - - bool bHasDynamicDescriptors = TotalSrvCbvUavSlots[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC] != 0 || TotalSamplerSlots[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC] != 0; - if (bHasDynamicDescriptors) - { - m_RootSig.CommitDescriptorHandles = &RootSignature::CommitDescriptorHandlesInternal_SMD<false>; - m_RootSig.TransitionAndCommitDescriptorHandles = &RootSignature::CommitDescriptorHandlesInternal_SMD<true>; - } - else - { - m_RootSig.CommitDescriptorHandles = &RootSignature::CommitDescriptorHandlesInternal_SM<false>; - m_RootSig.TransitionAndCommitDescriptorHandles = &RootSignature::CommitDescriptorHandlesInternal_SM<true>; - } -} - - -#ifdef DILIGENT_DEBUG -void RootSignatureBuilder::dbgVerifyRootParameters() const -{ - auto& RootParams = m_RootSig.m_RootParams; - auto& TotalSamplerSlots = m_RootSig.m_TotalSamplerSlots; - auto& TotalSrvCbvUavSlots = m_RootSig.m_TotalSrvCbvUavSlots; - auto& TotalRootViews = m_RootSig.m_TotalRootViews; - - Uint32 dbgTotalSrvCbvUavSlots = 0; - Uint32 dbgTotalSamplerSlots = 0; - for (Uint32 rt = 0; rt < RootParams.GetNumRootTables(); ++rt) - { - auto& RootTable = RootParams.GetRootTable(rt); - auto& Param = static_cast<const D3D12_ROOT_PARAMETER&>(RootTable); - VERIFY(Param.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Root parameter is expected to be a descriptor table"); - auto& Table = Param.DescriptorTable; - VERIFY(Table.NumDescriptorRanges > 0, "Descriptor table is expected to be non-empty"); - VERIFY(Table.pDescriptorRanges[0].OffsetInDescriptorsFromTableStart == 0, "Descriptor table is expected to start at 0 offset"); - bool IsResourceTable = Table.pDescriptorRanges[0].RangeType != D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; - for (Uint32 r = 0; r < Table.NumDescriptorRanges; ++r) - { - const auto& range = Table.pDescriptorRanges[r]; - if (IsResourceTable) - { - // clang-format off - VERIFY(range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV || - range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_CBV || - range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_UAV, - "Resource type is expected to be SRV, CBV or UAV"); - // clang-format on - dbgTotalSrvCbvUavSlots += range.NumDescriptors; - } - else - { - VERIFY(range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, "Resource type is expected to be sampler"); - dbgTotalSamplerSlots += range.NumDescriptors; - } - - if (r > 0) - { - VERIFY(Table.pDescriptorRanges[r].OffsetInDescriptorsFromTableStart == Table.pDescriptorRanges[r - 1].OffsetInDescriptorsFromTableStart + Table.pDescriptorRanges[r - 1].NumDescriptors, "Ranges in a descriptor table are expected to be consequtive"); - } - } - } - - Uint32 dbgTotalRootViews = 0; - for (Uint32 rv = 0; rv < RootParams.GetNumRootViews(); ++rv) - { - auto& RootView = RootParams.GetRootView(rv); - auto& Param = static_cast<const D3D12_ROOT_PARAMETER&>(RootView); - VERIFY(Param.ParameterType == D3D12_ROOT_PARAMETER_TYPE_CBV, "Root parameter is expected to be a CBV"); - ++dbgTotalRootViews; - } - - // clang-format off - VERIFY(dbgTotalSrvCbvUavSlots == - TotalSrvCbvUavSlots[SHADER_RESOURCE_VARIABLE_TYPE_STATIC] + - TotalSrvCbvUavSlots[SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE] + - TotalSrvCbvUavSlots[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC], "Unexpected number of SRV CBV UAV resource slots"); - VERIFY(dbgTotalSamplerSlots == - TotalSamplerSlots[SHADER_RESOURCE_VARIABLE_TYPE_STATIC] + - TotalSamplerSlots[SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE] + - TotalSamplerSlots[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC], "Unexpected number of sampler slots"); - VERIFY(dbgTotalRootViews == - TotalRootViews[SHADER_RESOURCE_VARIABLE_TYPE_STATIC] + - TotalRootViews[SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE] + - TotalRootViews[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC], "Unexpected number of root views"); - // clang-format on -} -#endif + auto* pd3d12Device = m_pDeviceD3D12Impl->GetD3D12Device(); -size_t RootSignatureBuilder::GetResourceCacheRequiredMemSize() const -{ - auto CacheTableSizes = m_RootSig.GetCacheTableSizes(); - return ShaderResourceCacheD3D12::GetRequiredMemorySize(static_cast<Uint32>(CacheTableSizes.size()), CacheTableSizes.data()); + hr = pd3d12Device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), __uuidof(m_pd3d12RootSignature), reinterpret_cast<void**>(static_cast<ID3D12RootSignature**>(&m_pd3d12RootSignature))); + CHECK_D3D_RESULT_THROW(hr, "Failed to create root signature"); } -RootSignature::RootSignature() : - m_RootParams{GetRawAllocator()}, - m_MemAllocator{GetRawAllocator()} -{ - m_SrvCbvUavRootTablesMap.fill(InvalidRootTableIndex); - m_SamplerRootTablesMap.fill(InvalidRootTableIndex); -} -// clang-format off -static D3D12_DESCRIPTOR_HEAP_TYPE RangeType2HeapTypeMap[] -{ - D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, //D3D12_DESCRIPTOR_RANGE_TYPE_SRV = 0 - D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, //D3D12_DESCRIPTOR_RANGE_TYPE_UAV = ( D3D12_DESCRIPTOR_RANGE_TYPE_SRV + 1 ) - D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, //D3D12_DESCRIPTOR_RANGE_TYPE_CBV = ( D3D12_DESCRIPTOR_RANGE_TYPE_UAV + 1 ) - D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER //D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER = ( D3D12_DESCRIPTOR_RANGE_TYPE_CBV + 1 ) -}; -// clang-format on -D3D12_DESCRIPTOR_HEAP_TYPE HeapTypeFromRangeType(D3D12_DESCRIPTOR_RANGE_TYPE RangeType) +LocalRootSignatureD3D12::LocalRootSignatureD3D12(const char* pCBName, Uint32 ShaderRecordSize) : + m_pName{pCBName}, + m_ShaderRecordSize{ShaderRecordSize} { - VERIFY_EXPR(RangeType >= D3D12_DESCRIPTOR_RANGE_TYPE_SRV && RangeType <= D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER); - auto HeapType = RangeType2HeapTypeMap[RangeType]; - -#ifdef DILIGENT_DEBUG - switch (RangeType) - { - // clang-format off - case D3D12_DESCRIPTOR_RANGE_TYPE_CBV: VERIFY_EXPR(HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); break; - case D3D12_DESCRIPTOR_RANGE_TYPE_SRV: VERIFY_EXPR(HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); break; - case D3D12_DESCRIPTOR_RANGE_TYPE_UAV: VERIFY_EXPR(HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); break; - case D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER: VERIFY_EXPR(HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); break; - // clang-format on - default: UNEXPECTED("Unexpected descriptor range type"); break; - } -#endif - return HeapType; + VERIFY_EXPR((m_pName != nullptr) == (m_ShaderRecordSize > 0)); } -std::vector<Uint32, STDAllocatorRawMem<Uint32>> RootSignature::GetCacheTableSizes() const +bool LocalRootSignatureD3D12::IsShaderRecord(const D3DShaderResourceAttribs& CB) { - // Get root table size for every root index - // m_RootParams keeps root tables sorted by the array index, not the root index - // Root views are treated as one-descriptor tables - std::vector<Uint32, STDAllocatorRawMem<Uint32>> CacheTableSizes(m_RootParams.GetNumRootTables() + m_RootParams.GetNumRootViews(), 0, STD_ALLOCATOR_RAW_MEM(Uint32, GetRawAllocator(), "Allocator for vector<Uint32>")); - for (Uint32 rt = 0; rt < m_RootParams.GetNumRootTables(); ++rt) - { - auto& RootParam = m_RootParams.GetRootTable(rt); - CacheTableSizes[RootParam.GetRootIndex()] = RootParam.GetDescriptorTableSize(); - } - - for (Uint32 rv = 0; rv < m_RootParams.GetNumRootViews(); ++rv) + if (m_ShaderRecordSize > 0 && + CB.GetInputType() == D3D_SIT_CBUFFER && + strcmp(m_pName, CB.Name) == 0) { - auto& RootParam = m_RootParams.GetRootView(rv); - CacheTableSizes[RootParam.GetRootIndex()] = 1; + return true; } - - return CacheTableSizes; + return false; } -//http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-cache#Initializing-the-Cache-for-Shader-Resource-Binding-Object -void RootSignature::InitResourceCache(RenderDeviceD3D12Impl* pDeviceD3D12Impl, - ShaderResourceCacheD3D12& ResourceCache, - IMemoryAllocator& CacheMemAllocator) const +ID3D12RootSignature* LocalRootSignatureD3D12::Create(ID3D12Device* pDevice) { - auto CacheTableSizes = GetCacheTableSizes(); - // Initialize resource cache to hold root tables - ResourceCache.Initialize(CacheMemAllocator, static_cast<Uint32>(CacheTableSizes.size()), CacheTableSizes.data()); - - // Allocate space in GPU-visible descriptor heap for static and mutable variables only - Uint32 TotalSrvCbvUavDescriptors = - m_TotalSrvCbvUavSlots[SHADER_RESOURCE_VARIABLE_TYPE_STATIC] + - m_TotalSrvCbvUavSlots[SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE]; - Uint32 TotalSamplerDescriptors = - m_TotalSamplerSlots[SHADER_RESOURCE_VARIABLE_TYPE_STATIC] + - m_TotalSamplerSlots[SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE]; - - DescriptorHeapAllocation CbcSrvUavHeapSpace, SamplerHeapSpace; - if (TotalSrvCbvUavDescriptors) - { - CbcSrvUavHeapSpace = pDeviceD3D12Impl->AllocateGPUDescriptors(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, TotalSrvCbvUavDescriptors); - DEV_CHECK_ERR(!CbcSrvUavHeapSpace.IsNull(), - "Failed to allocate ", TotalSrvCbvUavDescriptors, " GPU-visible CBV/SRV/UAV descriptor", - (TotalSrvCbvUavDescriptors > 1 ? "s" : ""), - ". Consider increasing GPUDescriptorHeapSize[0] in EngineD3D12CreateInfo."); - } - VERIFY_EXPR(TotalSrvCbvUavDescriptors == 0 && CbcSrvUavHeapSpace.IsNull() || CbcSrvUavHeapSpace.GetNumHandles() == TotalSrvCbvUavDescriptors); - - if (TotalSamplerDescriptors) - { - SamplerHeapSpace = pDeviceD3D12Impl->AllocateGPUDescriptors(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, TotalSamplerDescriptors); - DEV_CHECK_ERR(!SamplerHeapSpace.IsNull(), - "Failed to allocate ", TotalSamplerDescriptors, " GPU-visible Sampler descriptor", - (TotalSamplerDescriptors > 1 ? "s" : ""), - ". Consider using immutable samplers in the Pipeline State Object or " - "increasing GPUDescriptorHeapSize[1] in EngineD3D12CreateInfo."); - } - VERIFY_EXPR(TotalSamplerDescriptors == 0 && SamplerHeapSpace.IsNull() || SamplerHeapSpace.GetNumHandles() == TotalSamplerDescriptors); - - // Iterate through all root static/mutable tables and assign start offsets. The tables are tightly packed, so - // start offset of table N+1 is start offset of table N plus the size of table N. - // Root tables with dynamic resources as well as root views are not assigned space in GPU-visible allocation - // (root views are simply not processed) - Uint32 SrvCbvUavTblStartOffset = 0; - Uint32 SamplerTblStartOffset = 0; - for (Uint32 rt = 0; rt < m_RootParams.GetNumRootTables(); ++rt) - { - auto& RootParam = m_RootParams.GetRootTable(rt); - const auto& D3D12RootParam = static_cast<const D3D12_ROOT_PARAMETER&>(RootParam); - auto& RootTableCache = ResourceCache.GetRootTable(RootParam.GetRootIndex()); - - VERIFY_EXPR(D3D12RootParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE); - - auto TableSize = RootParam.GetDescriptorTableSize(); - VERIFY(TableSize > 0, "Unexpected empty descriptor table"); + if (m_ShaderRecordSize == 0 || m_BindPoint == InvalidBindPoint) + return nullptr; - auto HeapType = HeapTypeFromRangeType(D3D12RootParam.DescriptorTable.pDescriptorRanges[0].RangeType); + VERIFY(m_pd3d12RootSignature == nullptr, "This root signature is already created"); -#ifdef DILIGENT_DEBUG - RootTableCache.SetDebugAttribs(TableSize, HeapType, D3D12ShaderVisibilityToShaderType(D3D12RootParam.ShaderVisibility)); -#endif + D3D12_ROOT_SIGNATURE_DESC d3d12RootSignatureDesc = {}; + D3D12_ROOT_PARAMETER d3d12Params = {}; - // Space for dynamic variables is allocated at every draw call - if (RootParam.GetShaderVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) - { - if (HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV) - { - RootTableCache.m_TableStartOffset = SrvCbvUavTblStartOffset; - SrvCbvUavTblStartOffset += TableSize; - } - else - { - RootTableCache.m_TableStartOffset = SamplerTblStartOffset; - SamplerTblStartOffset += TableSize; - } - } - else - { - VERIFY_EXPR(RootTableCache.m_TableStartOffset == ShaderResourceCacheD3D12::InvalidDescriptorOffset); - } - } + d3d12Params.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; + d3d12Params.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + d3d12Params.Constants.Num32BitValues = m_ShaderRecordSize / 4; + d3d12Params.Constants.RegisterSpace = 0; + d3d12Params.Constants.ShaderRegister = m_BindPoint; -#ifdef DILIGENT_DEBUG - for (Uint32 rv = 0; rv < m_RootParams.GetNumRootViews(); ++rv) - { - auto& RootParam = m_RootParams.GetRootView(rv); - const auto& D3D12RootParam = static_cast<const D3D12_ROOT_PARAMETER&>(RootParam); - auto& RootTableCache = ResourceCache.GetRootTable(RootParam.GetRootIndex()); - // Root views are not assigned valid table start offset - VERIFY_EXPR(RootTableCache.m_TableStartOffset == ShaderResourceCacheD3D12::InvalidDescriptorOffset); + d3d12RootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_LOCAL_ROOT_SIGNATURE; + d3d12RootSignatureDesc.NumParameters = 1; + d3d12RootSignatureDesc.pParameters = &d3d12Params; - VERIFY_EXPR(D3D12RootParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_CBV); - RootTableCache.SetDebugAttribs(1, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12ShaderVisibilityToShaderType(D3D12RootParam.ShaderVisibility)); - } -#endif + CComPtr<ID3DBlob> signature; + auto hr = D3D12SerializeRootSignature(&d3d12RootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, nullptr); + CHECK_D3D_RESULT_THROW(hr, "Failed to serialize local root signature"); - VERIFY_EXPR(SrvCbvUavTblStartOffset == TotalSrvCbvUavDescriptors); - VERIFY_EXPR(SamplerTblStartOffset == TotalSamplerDescriptors); + hr = pDevice->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_pd3d12RootSignature)); + CHECK_D3D_RESULT_THROW(hr, "Failed to create D3D12 local root signature"); - ResourceCache.SetDescriptorHeapSpace(std::move(CbcSrvUavHeapSpace), std::move(SamplerHeapSpace)); + return m_pd3d12RootSignature; } -__forceinline void TransitionResource(CommandContext& Ctx, - ShaderResourceCacheD3D12::Resource& Res, - D3D12_DESCRIPTOR_RANGE_TYPE RangeType) -{ - static_assert(static_cast<int>(CachedResourceType::NumTypes) == 7, "Please update this function to handle the new resource type"); - switch (Res.Type) - { - case CachedResourceType::CBV: - { - VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_CBV, "Unexpected descriptor range type"); - // Not using QueryInterface() for the sake of efficiency - auto* pBuffToTransition = Res.pObject.RawPtr<BufferD3D12Impl>(); - if (pBuffToTransition->IsInKnownState() && !pBuffToTransition->CheckState(RESOURCE_STATE_CONSTANT_BUFFER)) - Ctx.TransitionResource(pBuffToTransition, RESOURCE_STATE_CONSTANT_BUFFER); - } - break; - - case CachedResourceType::BufSRV: - { - VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV, "Unexpected descriptor range type"); - auto* pBuffViewD3D12 = Res.pObject.RawPtr<BufferViewD3D12Impl>(); - auto* pBuffToTransition = pBuffViewD3D12->GetBuffer<BufferD3D12Impl>(); - if (pBuffToTransition->IsInKnownState() && !pBuffToTransition->CheckState(RESOURCE_STATE_SHADER_RESOURCE)) - Ctx.TransitionResource(pBuffToTransition, RESOURCE_STATE_SHADER_RESOURCE); - } - break; - - case CachedResourceType::BufUAV: - { - VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_UAV, "Unexpected descriptor range type"); - auto* pBuffViewD3D12 = Res.pObject.RawPtr<BufferViewD3D12Impl>(); - auto* pBuffToTransition = pBuffViewD3D12->GetBuffer<BufferD3D12Impl>(); - if (pBuffToTransition->IsInKnownState()) - { - // We must always call TransitionResource() even when the state is already - // RESOURCE_STATE_UNORDERED_ACCESS as in this case UAV barrier must be executed - Ctx.TransitionResource(pBuffToTransition, RESOURCE_STATE_UNORDERED_ACCESS); - } - } - break; - - case CachedResourceType::TexSRV: - { - VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV, "Unexpected descriptor range type"); - auto* pTexViewD3D12 = Res.pObject.RawPtr<TextureViewD3D12Impl>(); - auto* pTexToTransition = pTexViewD3D12->GetTexture<TextureD3D12Impl>(); - if (pTexToTransition->IsInKnownState() && !pTexToTransition->CheckAnyState(RESOURCE_STATE_SHADER_RESOURCE | RESOURCE_STATE_INPUT_ATTACHMENT)) - Ctx.TransitionResource(pTexToTransition, RESOURCE_STATE_SHADER_RESOURCE); - } - break; - - case CachedResourceType::TexUAV: - { - VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_UAV, "Unexpected descriptor range type"); - auto* pTexViewD3D12 = Res.pObject.RawPtr<TextureViewD3D12Impl>(); - auto* pTexToTransition = pTexViewD3D12->GetTexture<TextureD3D12Impl>(); - if (pTexToTransition->IsInKnownState()) - { - // We must always call TransitionResource() even when the state is already - // RESOURCE_STATE_UNORDERED_ACCESS as in this case UAV barrier must be executed - Ctx.TransitionResource(pTexToTransition, RESOURCE_STATE_UNORDERED_ACCESS); - } - } - break; - - case CachedResourceType::Sampler: - VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, "Unexpected descriptor range type"); - break; - - case CachedResourceType::AccelStruct: - { - VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV, "Unexpected descriptor range type"); - auto* pTLASD3D12 = Res.pObject.RawPtr<TopLevelASD3D12Impl>(); - if (pTLASD3D12->IsInKnownState()) - Ctx.TransitionResource(pTLASD3D12, RESOURCE_STATE_RAY_TRACING); - } - break; - - default: - // Resource not bound - VERIFY(Res.Type == CachedResourceType::Unknown, "Unexpected resource type"); - VERIFY(Res.pObject == nullptr && Res.CPUDescriptorHandle.ptr == 0, "Bound resource is unexpected"); - } -} -#ifdef DILIGENT_DEVELOPMENT -void RootSignature::DvpVerifyResourceState(const ShaderResourceCacheD3D12::Resource& Res, - D3D12_DESCRIPTOR_RANGE_TYPE RangeType) +bool RootSignatureCacheD3D12::RootSignatureCompare::operator()(const RootSignatureD3D12* lhs, const RootSignatureD3D12* rhs) const noexcept { - static_assert(static_cast<int>(CachedResourceType::NumTypes) == 7, "Please update this function to handle the new resource type"); - switch (Res.Type) - { - case CachedResourceType::CBV: - { - VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_CBV, "Unexpected descriptor range type"); - // Not using QueryInterface() for the sake of efficiency - const auto* pBufferD3D12 = Res.pObject.RawPtr<const BufferD3D12Impl>(); - if (pBufferD3D12->IsInKnownState() && !pBufferD3D12->CheckState(RESOURCE_STATE_CONSTANT_BUFFER)) - { - LOG_ERROR_MESSAGE("Buffer '", pBufferD3D12->GetDesc().Name, "' must be in RESOURCE_STATE_CONSTANT_BUFFER state. Actual state: ", - GetResourceStateString(pBufferD3D12->GetState()), - ". Call IDeviceContext::TransitionShaderResources(), use RESOURCE_STATE_TRANSITION_MODE_TRANSITION " - "when calling IDeviceContext::CommitShaderResources() or explicitly transition the buffer state " - "with IDeviceContext::TransitionResourceStates()."); - } - } - break; - - case CachedResourceType::BufSRV: - { - VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV, "Unexpected descriptor range type"); - const auto* pBuffViewD3D12 = Res.pObject.RawPtr<const BufferViewD3D12Impl>(); - const auto* pBufferD3D12 = pBuffViewD3D12->GetBuffer<const BufferD3D12Impl>(); - if (pBufferD3D12->IsInKnownState() && !pBufferD3D12->CheckState(RESOURCE_STATE_SHADER_RESOURCE)) - { - LOG_ERROR_MESSAGE("Buffer '", pBufferD3D12->GetDesc().Name, "' must be in RESOURCE_STATE_SHADER_RESOURCE state. Actual state: ", - GetResourceStateString(pBufferD3D12->GetState()), - ". Call IDeviceContext::TransitionShaderResources(), use RESOURCE_STATE_TRANSITION_MODE_TRANSITION " - "when calling IDeviceContext::CommitShaderResources() or explicitly transition the buffer state " - "with IDeviceContext::TransitionResourceStates()."); - } - } - break; - - case CachedResourceType::BufUAV: - { - VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_UAV, "Unexpected descriptor range type"); - const auto* pBuffViewD3D12 = Res.pObject.RawPtr<const BufferViewD3D12Impl>(); - const auto* pBufferD3D12 = pBuffViewD3D12->GetBuffer<const BufferD3D12Impl>(); - if (pBufferD3D12->IsInKnownState() && !pBufferD3D12->CheckState(RESOURCE_STATE_UNORDERED_ACCESS)) - { - LOG_ERROR_MESSAGE("Buffer '", pBufferD3D12->GetDesc().Name, "' must be in RESOURCE_STATE_UNORDERED_ACCESS state. Actual state: ", - GetResourceStateString(pBufferD3D12->GetState()), - ". Call IDeviceContext::TransitionShaderResources(), use RESOURCE_STATE_TRANSITION_MODE_TRANSITION " - "when calling IDeviceContext::CommitShaderResources() or explicitly transition the buffer state " - "with IDeviceContext::TransitionResourceStates()."); - } - } - break; - - case CachedResourceType::TexSRV: - { - VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV, "Unexpected descriptor range type"); - const auto* pTexViewD3D12 = Res.pObject.RawPtr<const TextureViewD3D12Impl>(); - const auto* pTexD3D12 = pTexViewD3D12->GetTexture<TextureD3D12Impl>(); - if (pTexD3D12->IsInKnownState() && !pTexD3D12->CheckAnyState(RESOURCE_STATE_SHADER_RESOURCE | RESOURCE_STATE_INPUT_ATTACHMENT)) - { - LOG_ERROR_MESSAGE("Texture '", pTexD3D12->GetDesc().Name, "' must be in RESOURCE_STATE_SHADER_RESOURCE state. Actual state: ", - GetResourceStateString(pTexD3D12->GetState()), - ". Call IDeviceContext::TransitionShaderResources(), use RESOURCE_STATE_TRANSITION_MODE_TRANSITION " - "when calling IDeviceContext::CommitShaderResources() or explicitly transition the texture state " - "with IDeviceContext::TransitionResourceStates()."); - } - } - break; + const Uint32 LSigCount = lhs->GetSignatureCount(); + const Uint32 RSigCount = rhs->GetSignatureCount(); - case CachedResourceType::TexUAV: - { - VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_UAV, "Unexpected descriptor range type"); - const auto* pTexViewD3D12 = Res.pObject.RawPtr<const TextureViewD3D12Impl>(); - const auto* pTexD3D12 = pTexViewD3D12->GetTexture<const TextureD3D12Impl>(); - if (pTexD3D12->IsInKnownState() && !pTexD3D12->CheckState(RESOURCE_STATE_UNORDERED_ACCESS)) - { - LOG_ERROR_MESSAGE("Texture '", pTexD3D12->GetDesc().Name, "' must be in RESOURCE_STATE_UNORDERED_ACCESS state. Actual state: ", - GetResourceStateString(pTexD3D12->GetState()), - ". Call IDeviceContext::TransitionShaderResources(), use RESOURCE_STATE_TRANSITION_MODE_TRANSITION " - "when calling IDeviceContext::CommitShaderResources() or explicitly transition the texture state " - "with IDeviceContext::TransitionResourceStates()."); - } - } - break; - - case CachedResourceType::Sampler: - VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, "Unexpected descriptor range type"); - break; - - case CachedResourceType::AccelStruct: - { - VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV, "Unexpected descriptor range type"); - const auto* pTLASD3D12 = Res.pObject.RawPtr<const TopLevelASD3D12Impl>(); - if (pTLASD3D12->IsInKnownState() && !pTLASD3D12->CheckState(RESOURCE_STATE_RAY_TRACING)) - { - LOG_ERROR_MESSAGE("TLAS '", pTLASD3D12->GetDesc().Name, "' must be in RESOURCE_STATE_RAY_TRACING state. Actual state: ", - GetResourceStateString(pTLASD3D12->GetState()), - ". Call IDeviceContext::TransitionShaderResources(), use RESOURCE_STATE_TRANSITION_MODE_TRANSITION " - "when calling IDeviceContext::CommitShaderResources() or explicitly transition the TLAS state " - "with IDeviceContext::TransitionResourceStates()."); - } - } - break; - - default: - // Resource not bound - VERIFY(Res.Type == CachedResourceType::Unknown, "Unexpected resource type"); - VERIFY(Res.pObject == nullptr && Res.CPUDescriptorHandle.ptr == 0, "Bound resource is unexpected"); - } -} -#endif // DILIGENT_DEVELOPMENT + if (LSigCount != RSigCount) + return false; -template <class TOperation> -__forceinline void RootSignature::RootParamsManager::ProcessRootTables(TOperation Operation) const -{ - for (Uint32 rt = 0; rt < m_NumRootTables; ++rt) + for (Uint32 i = 0; i < LSigCount; ++i) { - auto& RootTable = GetRootTable(rt); - auto RootInd = RootTable.GetRootIndex(); - const D3D12_ROOT_PARAMETER& D3D12Param = RootTable; - - VERIFY_EXPR(D3D12Param.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE); + auto* pLSig = lhs->GetSignature(i); + auto* pRSig = rhs->GetSignature(i); - auto& d3d12Table = D3D12Param.DescriptorTable; - VERIFY(d3d12Table.NumDescriptorRanges > 0 && RootTable.GetDescriptorTableSize() > 0, "Unexepected empty descriptor table"); - bool IsResourceTable = d3d12Table.pDescriptorRanges[0].RangeType != D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; - D3D12_DESCRIPTOR_HEAP_TYPE dbgHeapType = D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; -#ifdef DILIGENT_DEBUG - dbgHeapType = IsResourceTable ? D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV : D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; -#endif - Operation(RootInd, RootTable, D3D12Param, IsResourceTable, dbgHeapType); - } -} - -template <class TOperation> -__forceinline void ProcessCachedTableResources(Uint32 RootInd, - const D3D12_ROOT_PARAMETER& D3D12Param, - ShaderResourceCacheD3D12& ResourceCache, - D3D12_DESCRIPTOR_HEAP_TYPE dbgHeapType, - TOperation Operation) -{ - for (UINT r = 0; r < D3D12Param.DescriptorTable.NumDescriptorRanges; ++r) - { - const auto& range = D3D12Param.DescriptorTable.pDescriptorRanges[r]; - for (UINT d = 0; d < range.NumDescriptors; ++d) - { - SHADER_TYPE dbgShaderType = SHADER_TYPE_UNKNOWN; -#ifdef DILIGENT_DEBUG - dbgShaderType = D3D12ShaderVisibilityToShaderType(D3D12Param.ShaderVisibility); -#endif - VERIFY(dbgHeapType == HeapTypeFromRangeType(range.RangeType), "Mistmatch between descriptor heap type and descriptor range type"); + if (pLSig == pRSig) + continue; - auto OffsetFromTableStart = range.OffsetInDescriptorsFromTableStart + d; - auto& Res = ResourceCache.GetRootTable(RootInd).GetResource(OffsetFromTableStart, dbgHeapType, dbgShaderType); + if ((pLSig == nullptr) != (pRSig == nullptr)) + return false; - Operation(OffsetFromTableStart, range, Res); - } + if (!pLSig->IsCompatibleWith(*pRSig)) + return false; } + return true; } +RootSignatureCacheD3D12::RootSignatureCacheD3D12(RenderDeviceD3D12Impl& DeviceD3D12Impl) : + m_DeviceD3D12Impl{DeviceD3D12Impl} +{} -template <bool PerformResourceTransitions> -void RootSignature::CommitDescriptorHandlesInternal_SMD(RenderDeviceD3D12Impl* pRenderDeviceD3D12, - ShaderResourceCacheD3D12& ResourceCache, - CommandContext& Ctx, - bool IsCompute, - bool ValidateStates) const +RootSignatureCacheD3D12::~RootSignatureCacheD3D12() { - auto* pd3d12Device = pRenderDeviceD3D12->GetD3D12Device(); - - Uint32 NumDynamicCbvSrvUavDescriptors = m_TotalSrvCbvUavSlots[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC]; - Uint32 NumDynamicSamplerDescriptors = m_TotalSamplerSlots[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC]; - VERIFY_EXPR(NumDynamicCbvSrvUavDescriptors > 0 || NumDynamicSamplerDescriptors > 0); - - DescriptorHeapAllocation DynamicCbvSrvUavDescriptors, DynamicSamplerDescriptors; - if (NumDynamicCbvSrvUavDescriptors > 0) - { - DynamicCbvSrvUavDescriptors = Ctx.AllocateDynamicGPUVisibleDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, NumDynamicCbvSrvUavDescriptors); - DEV_CHECK_ERR(DynamicCbvSrvUavDescriptors.GetDescriptorHeap() != nullptr, - "Failed to allocate ", NumDynamicCbvSrvUavDescriptors, " dynamic GPU-visible CBV/SRV/UAV descriptor", - (NumDynamicCbvSrvUavDescriptors > 1 ? "s" : ""), - ". Consider increasing GPUDescriptorHeapDynamicSize[0] in EngineD3D12CreateInfo " - "or optimizing dynamic resource utilization by using static or mutable shader resource variables instead."); - } - - if (NumDynamicSamplerDescriptors > 0) - { - DynamicSamplerDescriptors = Ctx.AllocateDynamicGPUVisibleDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, NumDynamicSamplerDescriptors); - DEV_CHECK_ERR(DynamicSamplerDescriptors.GetDescriptorHeap() != nullptr, - "Failed to allocate ", NumDynamicSamplerDescriptors, " dynamic GPU-visible Sampler descriptor", - (NumDynamicSamplerDescriptors > 1 ? "s" : ""), - ". Consider using immutable samplers in the Pipeline State Object, increasing GPUDescriptorHeapDynamicSize[1] in " - "EngineD3D12CreateInfo, or optimizing dynamic resource utilization by using static or mutable shader resource variables instead."); - } - - CommandContext::ShaderDescriptorHeaps Heaps(ResourceCache.GetSrvCbvUavDescriptorHeap(), ResourceCache.GetSamplerDescriptorHeap()); - if (Heaps.pSamplerHeap == nullptr) - Heaps.pSamplerHeap = DynamicSamplerDescriptors.GetDescriptorHeap(); - - if (Heaps.pSrvCbvUavHeap == nullptr) - Heaps.pSrvCbvUavHeap = DynamicCbvSrvUavDescriptors.GetDescriptorHeap(); - - if (NumDynamicCbvSrvUavDescriptors > 0) - VERIFY(DynamicCbvSrvUavDescriptors.GetDescriptorHeap() == Heaps.pSrvCbvUavHeap, "Inconsistent CbvSrvUav descriptor heaps"); - if (NumDynamicSamplerDescriptors > 0) - VERIFY(DynamicSamplerDescriptors.GetDescriptorHeap() == Heaps.pSamplerHeap, "Inconsistent Sampler descriptor heaps"); - - if (Heaps) - Ctx.SetDescriptorHeaps(Heaps); - - // Offset to the beginning of the current dynamic CBV_SRV_UAV/SAMPLER table from - // the start of the allocation - Uint32 DynamicCbvSrvUavTblOffset = 0; - Uint32 DynamicSamplerTblOffset = 0; - - m_RootParams.ProcessRootTables( - [&](Uint32 RootInd, - const RootParameter& RootTable, - const D3D12_ROOT_PARAMETER& D3D12Param, - bool IsResourceTable, - D3D12_DESCRIPTOR_HEAP_TYPE dbgHeapType) // - { - D3D12_GPU_DESCRIPTOR_HANDLE RootTableGPUDescriptorHandle; - - bool IsDynamicTable = RootTable.GetShaderVariableType() == SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC; - if (IsDynamicTable) - { - if (IsResourceTable) - RootTableGPUDescriptorHandle = DynamicCbvSrvUavDescriptors.GetGpuHandle(DynamicCbvSrvUavTblOffset); - else - RootTableGPUDescriptorHandle = DynamicSamplerDescriptors.GetGpuHandle(DynamicSamplerTblOffset); - } - else - { - RootTableGPUDescriptorHandle = IsResourceTable ? - ResourceCache.GetShaderVisibleTableGPUDescriptorHandle<D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV>(RootInd) : - ResourceCache.GetShaderVisibleTableGPUDescriptorHandle<D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER>(RootInd); - VERIFY(RootTableGPUDescriptorHandle.ptr != 0, "Unexpected null GPU descriptor handle"); - } - - if (IsCompute) - Ctx.GetCommandList()->SetComputeRootDescriptorTable(RootInd, RootTableGPUDescriptorHandle); - else - Ctx.GetCommandList()->SetGraphicsRootDescriptorTable(RootInd, RootTableGPUDescriptorHandle); - - ProcessCachedTableResources( - RootInd, D3D12Param, ResourceCache, dbgHeapType, - [&](UINT OffsetFromTableStart, - const D3D12_DESCRIPTOR_RANGE& range, - ShaderResourceCacheD3D12::Resource& Res) // - { - if (PerformResourceTransitions) - { - TransitionResource(Ctx, Res, range.RangeType); - } -#ifdef DILIGENT_DEVELOPMENT - else if (ValidateStates) - { - DvpVerifyResourceState(Res, range.RangeType); - } -#endif - - if (IsDynamicTable) - { - if (IsResourceTable) - { - VERIFY(DynamicCbvSrvUavTblOffset < NumDynamicCbvSrvUavDescriptors, "Not enough space in the descriptor heap allocation"); - - if (Res.CPUDescriptorHandle.ptr != 0) - { - pd3d12Device->CopyDescriptorsSimple(1, DynamicCbvSrvUavDescriptors.GetCpuHandle(DynamicCbvSrvUavTblOffset), Res.CPUDescriptorHandle, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); - } -#ifdef DILIGENT_DEVELOPMENT - else - { - LOG_ERROR_MESSAGE("No valid CbvSrvUav descriptor handle found for root parameter ", RootInd, ", descriptor slot ", OffsetFromTableStart); - } -#endif - - ++DynamicCbvSrvUavTblOffset; - } - else - { - VERIFY(DynamicSamplerTblOffset < NumDynamicSamplerDescriptors, "Not enough space in the descriptor heap allocation"); - - if (Res.CPUDescriptorHandle.ptr != 0) - { - pd3d12Device->CopyDescriptorsSimple(1, DynamicSamplerDescriptors.GetCpuHandle(DynamicSamplerTblOffset), Res.CPUDescriptorHandle, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); - } -#ifdef DILIGENT_DEVELOPMENT - else - { - LOG_ERROR_MESSAGE("No valid sampler descriptor handle found for root parameter ", RootInd, ", descriptor slot ", OffsetFromTableStart); - } -#endif - - ++DynamicSamplerTblOffset; - } - } - } // - ); - } // - ); - - VERIFY_EXPR(DynamicCbvSrvUavTblOffset == NumDynamicCbvSrvUavDescriptors); - VERIFY_EXPR(DynamicSamplerTblOffset == NumDynamicSamplerDescriptors); + std::lock_guard<std::mutex> Lock{m_RootSigCacheGuard}; + VERIFY(m_RootSigCache.empty(), "All pipeline layouts must be released"); } -template <bool PerformResourceTransitions> -void RootSignature::CommitDescriptorHandlesInternal_SM(RenderDeviceD3D12Impl* pRenderDeviceD3D12, - ShaderResourceCacheD3D12& ResourceCache, - CommandContext& Ctx, - bool IsCompute, - bool ValidateStates) const +RefCntAutoPtr<RootSignatureD3D12> RootSignatureCacheD3D12::GetRootSig(const RefCntAutoPtr<PipelineResourceSignatureD3D12Impl>* ppSignatures, Uint32 SignatureCount) { - VERIFY_EXPR(m_TotalSrvCbvUavSlots[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC] == 0 && m_TotalSamplerSlots[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC] == 0); - - CommandContext::ShaderDescriptorHeaps Heaps(ResourceCache.GetSrvCbvUavDescriptorHeap(), ResourceCache.GetSamplerDescriptorHeap()); - if (Heaps) - Ctx.SetDescriptorHeaps(Heaps); - - m_RootParams.ProcessRootTables( - [&](Uint32 RootInd, const RootParameter& RootTable, const D3D12_ROOT_PARAMETER& D3D12Param, bool IsResourceTable, D3D12_DESCRIPTOR_HEAP_TYPE dbgHeapType) { - VERIFY(RootTable.GetShaderVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC, "Unexpected dynamic resource"); - - D3D12_GPU_DESCRIPTOR_HANDLE RootTableGPUDescriptorHandle = IsResourceTable ? - ResourceCache.GetShaderVisibleTableGPUDescriptorHandle<D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV>(RootInd) : - ResourceCache.GetShaderVisibleTableGPUDescriptorHandle<D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER>(RootInd); - VERIFY(RootTableGPUDescriptorHandle.ptr != 0, "Unexpected null GPU descriptor handle"); - - if (IsCompute) - Ctx.GetCommandList()->SetComputeRootDescriptorTable(RootInd, RootTableGPUDescriptorHandle); - else - Ctx.GetCommandList()->SetGraphicsRootDescriptorTable(RootInd, RootTableGPUDescriptorHandle); - - if (PerformResourceTransitions) - { - ProcessCachedTableResources( - RootInd, D3D12Param, ResourceCache, dbgHeapType, - [&](UINT OffsetFromTableStart, - const D3D12_DESCRIPTOR_RANGE& range, - ShaderResourceCacheD3D12::Resource& Res) // - { - TransitionResource(Ctx, Res, range.RangeType); - } // - ); - } -#ifdef DILIGENT_DEVELOPMENT - else if (ValidateStates) - { - ProcessCachedTableResources( - RootInd, D3D12Param, ResourceCache, dbgHeapType, - [&](UINT OffsetFromTableStart, - const D3D12_DESCRIPTOR_RANGE& range, - const ShaderResourceCacheD3D12::Resource& Res) // - { - DvpVerifyResourceState(Res, range.RangeType); - } // - ); - } -#endif - } // - ); -} + RootSignatureD3D12* pNewRootSig = nullptr; + m_DeviceD3D12Impl.CreateRootSignature(ppSignatures, SignatureCount, &pNewRootSig); + if (pNewRootSig == nullptr) + return {}; -void RootSignature::TransitionResources(ShaderResourceCacheD3D12& ResourceCache, - CommandContext& Ctx) const -{ - m_RootParams.ProcessRootTables( - [&](Uint32 RootInd, - const RootParameter& RootTable, - const D3D12_ROOT_PARAMETER& D3D12Param, - bool IsResourceTable, - D3D12_DESCRIPTOR_HEAP_TYPE dbgHeapType) // - { - ProcessCachedTableResources( - RootInd, D3D12Param, ResourceCache, dbgHeapType, - [&](UINT OffsetFromTableStart, - const D3D12_DESCRIPTOR_RANGE& range, - ShaderResourceCacheD3D12::Resource& Res) // - { - TransitionResource(Ctx, Res, range.RangeType); - } // - ); - } // - ); -} + RefCntAutoPtr<RootSignatureD3D12> Result; + bool Inserted = false; + { + std::lock_guard<std::mutex> Lock{m_RootSigCacheGuard}; + auto IterAndFlag = m_RootSigCache.insert(pNewRootSig); + Inserted = IterAndFlag.second; -LocalRootSignature::LocalRootSignature(const char* pCBName, Uint32 ShaderRecordSize) : - m_pName{pCBName}, - m_ShaderRecordSize{ShaderRecordSize} -{ - VERIFY_EXPR((m_pName != nullptr) == (m_ShaderRecordSize > 0)); -} + if (Inserted) + pNewRootSig->Finalize(); -bool LocalRootSignature::SetOrMerge(const D3DShaderResourceAttribs& CB) -{ - if (m_ShaderRecordSize > 0 && - CB.GetInputType() == D3D_SIT_CBUFFER && - strcmp(m_pName, CB.Name) == 0) - { - if (m_BindPoint == InvalidBindPoint) - m_BindPoint = CB.BindPoint; + Result = *IterAndFlag.first; + } - VERIFY_EXPR(CB.BindCount == 1); - VERIFY_EXPR(m_BindPoint == CB.BindPoint); + // Destroy outside of mutex scope. + if (!Inserted) + pNewRootSig->~RootSignatureD3D12(); - return true; - } - return false; + return Result; } -ID3D12RootSignature* LocalRootSignature::Create(ID3D12Device* pDevice) +void RootSignatureCacheD3D12::OnDestroyRootSig(RootSignatureD3D12* pRootSig) { - if (m_ShaderRecordSize == 0 || m_BindPoint == InvalidBindPoint) - return nullptr; - - D3D12_ROOT_SIGNATURE_DESC d3d12RootSignatureDesc = {}; - D3D12_ROOT_PARAMETER d3d12Params = {}; - - d3d12Params.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; - d3d12Params.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; - d3d12Params.Constants.Num32BitValues = m_ShaderRecordSize / 4; - d3d12Params.Constants.RegisterSpace = 0; - d3d12Params.Constants.ShaderRegister = m_BindPoint; - - d3d12RootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_LOCAL_ROOT_SIGNATURE; - d3d12RootSignatureDesc.NumParameters = 1; - d3d12RootSignatureDesc.pParameters = &d3d12Params; + std::lock_guard<std::mutex> Lock{m_RootSigCacheGuard}; - CComPtr<ID3DBlob> signature; - auto hr = D3D12SerializeRootSignature(&d3d12RootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, nullptr); - CHECK_D3D_RESULT_THROW(hr, "Failed to serialize local root signature"); - - hr = pDevice->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_pd3d12RootSignature)); - CHECK_D3D_RESULT_THROW(hr, "Failed to create D3D12 local root signature"); - - return m_pd3d12RootSignature; + auto Iter = m_RootSigCache.find(pRootSig); + if (Iter != m_RootSigCache.end() && *Iter == pRootSig) + m_RootSigCache.erase(Iter); } } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderResourceBindingD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderResourceBindingD3D12Impl.cpp index 2116d4f9..6f23e288 100644 --- a/Graphics/GraphicsEngineD3D12/src/ShaderResourceBindingD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/ShaderResourceBindingD3D12Impl.cpp @@ -27,31 +27,29 @@ #include "pch.h" #include "ShaderResourceBindingD3D12Impl.hpp" -#include "PipelineStateD3D12Impl.hpp" -#include "ShaderD3D12Impl.hpp" #include "RenderDeviceD3D12Impl.hpp" #include "FixedLinearAllocator.hpp" namespace Diligent { -ShaderResourceBindingD3D12Impl::ShaderResourceBindingD3D12Impl(IReferenceCounters* pRefCounters, - PipelineStateD3D12Impl* pPSO, - bool IsPSOInternal) : +ShaderResourceBindingD3D12Impl::ShaderResourceBindingD3D12Impl(IReferenceCounters* pRefCounters, + PipelineResourceSignatureD3D12Impl* pPRS, + bool IsDeviceInternal) : // clang-format off TBase { pRefCounters, - pPSO, - IsPSOInternal + pPRS, + IsDeviceInternal }, - m_ShaderResourceCache{ShaderResourceCacheD3D12::DbgCacheContentType::SRBResources}, - m_NumShaders {static_cast<decltype(m_NumShaders)>(pPSO->GetNumShaderStages())} + m_ShaderResourceCache{ShaderResourceCacheD3D12::CacheContentType::SRB}, + m_NumShaders {static_cast<decltype(m_NumShaders)>(pPRS->GetNumActiveShaderStages())} // clang-format on { try { - m_ResourceLayoutIndex.fill(-1); + m_ShaderVarIndex.fill(-1); FixedLinearAllocator MemPool{GetRawAllocator()}; MemPool.AddSpace<ShaderVariableManagerD3D12>(m_NumShaders); @@ -66,28 +64,28 @@ ShaderResourceBindingD3D12Impl::ShaderResourceBindingD3D12Impl(IReferenceCounter // It is important to construct all objects before initializing them because if an exception is thrown, // destructors will be called for all objects - auto* pRenderDeviceD3D12Impl = ValidatedCast<RenderDeviceD3D12Impl>(pPSO->GetDevice()); - auto& ResCacheDataAllocator = pPSO->GetSRBMemoryAllocator().GetResourceCacheDataAllocator(0); - pPSO->GetRootSignature().InitResourceCache(pRenderDeviceD3D12Impl, m_ShaderResourceCache, ResCacheDataAllocator); + auto& SRBMemAllocator = pPRS->GetSRBMemoryAllocator(); + auto& ResourceCacheDataAllocator = SRBMemAllocator.GetResourceCacheDataAllocator(0); + pPRS->InitSRBResourceCache(m_ShaderResourceCache, ResourceCacheDataAllocator, pPRS->GetDesc().Name); for (Uint32 s = 0; s < m_NumShaders; ++s) { - const auto ShaderType = pPSO->GetShaderStageType(s); - const auto& SrcLayout = pPSO->GetShaderResLayout(s); - const auto ShaderInd = GetShaderTypePipelineIndex(ShaderType, pPSO->GetDesc().PipelineType); + const auto ShaderType = pPRS->GetActiveShaderStageType(s); + const auto ShaderInd = GetShaderTypePipelineIndex(ShaderType, pPRS->GetPipelineType()); - auto& VarDataAllocator = pPSO->GetSRBMemoryAllocator().GetShaderVariableDataAllocator(s); + auto& VarDataAllocator = SRBMemAllocator.GetShaderVariableDataAllocator(s); // http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-layout#Initializing-Resource-Layouts-in-a-Shader-Resource-Binding-Object const SHADER_RESOURCE_VARIABLE_TYPE AllowedVarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC}; m_pShaderVarMgrs[s].Initialize( - SrcLayout, + *pPRS, VarDataAllocator, AllowedVarTypes, - _countof(AllowedVarTypes) // + _countof(AllowedVarTypes), + ShaderType // ); - m_ResourceLayoutIndex[ShaderInd] = static_cast<Int8>(s); + m_ShaderVarIndex[ShaderInd] = static_cast<Int8>(s); } } catch (...) @@ -107,7 +105,7 @@ void ShaderResourceBindingD3D12Impl::Destruct() { if (m_pShaderVarMgrs != nullptr) { - auto& SRBMemAllocator = m_pPSO->GetSRBMemoryAllocator(); + auto& SRBMemAllocator = GetSignature()->GetSRBMemoryAllocator(); for (Uint32 s = 0; s < m_NumShaders; ++s) { auto& VarDataAllocator = SRBMemAllocator.GetShaderVariableDataAllocator(s); @@ -120,17 +118,17 @@ void ShaderResourceBindingD3D12Impl::Destruct() void ShaderResourceBindingD3D12Impl::BindResources(Uint32 ShaderFlags, IResourceMapping* pResMapping, Uint32 Flags) { - const auto PipelineType = m_pPSO->GetDesc().PipelineType; - for (Int32 ShaderInd = 0; ShaderInd < static_cast<Int32>(m_ResourceLayoutIndex.size()); ++ShaderInd) + const auto PipelineType = GetPipelineType(); + for (Int32 ShaderInd = 0; ShaderInd < static_cast<Int32>(m_ShaderVarIndex.size()); ++ShaderInd) { - auto ResLayoutInd = m_ResourceLayoutIndex[ShaderInd]; - if (ResLayoutInd >= 0) + auto VarMngrInd = m_ShaderVarIndex[ShaderInd]; + if (VarMngrInd >= 0) { // ShaderInd is the shader type pipeline index here const auto ShaderType = GetShaderTypeFromPipelineIndex(ShaderInd, PipelineType); if (ShaderFlags & ShaderType) { - m_pShaderVarMgrs[ResLayoutInd].BindResources(pResMapping, Flags); + m_pShaderVarMgrs[VarMngrInd].BindResources(pResMapping, Flags); } } } @@ -138,101 +136,66 @@ void ShaderResourceBindingD3D12Impl::BindResources(Uint32 ShaderFlags, IResource IShaderResourceVariable* ShaderResourceBindingD3D12Impl::GetVariableByName(SHADER_TYPE ShaderType, const char* Name) { - auto ResLayoutInd = GetVariableByNameHelper(ShaderType, Name, m_ResourceLayoutIndex); - if (ResLayoutInd < 0) + auto VarMngrInd = GetVariableByNameHelper(ShaderType, Name, m_ShaderVarIndex); + if (VarMngrInd < 0) return nullptr; - VERIFY_EXPR(static_cast<Uint32>(ResLayoutInd) < Uint32{m_NumShaders}); - return m_pShaderVarMgrs[ResLayoutInd].GetVariable(Name); + VERIFY_EXPR(static_cast<Uint32>(VarMngrInd) < Uint32{m_NumShaders}); + return m_pShaderVarMgrs[VarMngrInd].GetVariable(Name); } Uint32 ShaderResourceBindingD3D12Impl::GetVariableCount(SHADER_TYPE ShaderType) const { - auto ResLayoutInd = GetVariableCountHelper(ShaderType, m_ResourceLayoutIndex); - if (ResLayoutInd < 0) + auto VarMngrInd = GetVariableCountHelper(ShaderType, m_ShaderVarIndex); + if (VarMngrInd < 0) return 0; - VERIFY_EXPR(static_cast<Uint32>(ResLayoutInd) < Uint32{m_NumShaders}); - return m_pShaderVarMgrs[ResLayoutInd].GetVariableCount(); + VERIFY_EXPR(static_cast<Uint32>(VarMngrInd) < Uint32{m_NumShaders}); + return m_pShaderVarMgrs[VarMngrInd].GetVariableCount(); } IShaderResourceVariable* ShaderResourceBindingD3D12Impl::GetVariableByIndex(SHADER_TYPE ShaderType, Uint32 Index) { - auto ResLayoutInd = GetVariableByIndexHelper(ShaderType, Index, m_ResourceLayoutIndex); - if (ResLayoutInd < 0) + auto VarMngrInd = GetVariableByIndexHelper(ShaderType, Index, m_ShaderVarIndex); + if (VarMngrInd < 0) return nullptr; - VERIFY_EXPR(static_cast<Uint32>(ResLayoutInd) < Uint32{m_NumShaders}); - return m_pShaderVarMgrs[ResLayoutInd].GetVariable(Index); -} - - -#ifdef DILIGENT_DEVELOPMENT -void ShaderResourceBindingD3D12Impl::dvpVerifyResourceBindings(const PipelineStateD3D12Impl* pPSO) const -{ - auto* pRefPSO = GetPipelineState<const PipelineStateD3D12Impl>(); - if (pPSO->IsIncompatibleWith(pRefPSO)) - { - LOG_ERROR("Shader resource binding is incompatible with the pipeline state \"", pPSO->GetDesc().Name, '\"'); - return; - } - for (Uint32 l = 0; l < m_NumShaders; ++l) - { - // Use reference layout from pipeline state that contains all shader resource types - const auto& ShaderResLayout = pRefPSO->GetShaderResLayout(l); - ShaderResLayout.dvpVerifyBindings(m_ShaderResourceCache); - } -# ifdef DILIGENT_DEBUG - m_ShaderResourceCache.DbgVerifyBoundDynamicCBsCounter(); -# endif + VERIFY_EXPR(static_cast<Uint32>(VarMngrInd) < Uint32{m_NumShaders}); + return m_pShaderVarMgrs[VarMngrInd].GetVariable(Index); } -#endif - -void ShaderResourceBindingD3D12Impl::InitializeStaticResources(const IPipelineState* pPSO) +void ShaderResourceBindingD3D12Impl::InitializeStaticResources(const IPipelineState* pPipelineState) { if (StaticResourcesInitialized()) { - LOG_WARNING_MESSAGE("Static resources have already been initialized in this shader " - "resource binding object. The operation will be ignored."); + LOG_WARNING_MESSAGE("Static resources have already been initialized in this shader resource binding object. The operation will be ignored."); return; } - if (pPSO == nullptr) + if (pPipelineState == nullptr) { - pPSO = GetPipelineState(); + InitializeStaticResourcesWithSignature(nullptr); } else { - DEV_CHECK_ERR(pPSO->IsCompatibleWith(GetPipelineState()), "The pipeline state is not compatible with this SRB"); - } - - auto* pPSO12 = ValidatedCast<const PipelineStateD3D12Impl>(pPSO); - auto NumShaders = pPSO12->GetNumShaderStages(); - // Copy static resources - for (Uint32 s = 0; s < NumShaders; ++s) - { - const auto& ShaderResLayout = pPSO12->GetShaderResLayout(s); - auto& StaticResLayout = pPSO12->GetStaticShaderResLayout(s); - auto& StaticResCache = pPSO12->GetStaticShaderResCache(s); - -#ifdef DILIGENT_DEVELOPMENT - if (!StaticResLayout.dvpVerifyBindings(StaticResCache)) + auto* pSign = pPipelineState->GetResourceSignature(GetBindingIndex()); + if (pSign == nullptr) { - LOG_ERROR_MESSAGE("Static resources in SRB of PSO '", pPSO12->GetDesc().Name, - "' will not be successfully initialized because not all static resource bindings in shader type '", - GetShaderTypeLiteralName(pPSO12->GetShaderStageType(s)), - "' are valid. Please make sure you bind all static resources to PSO before calling InitializeStaticResources() " - "directly or indirectly by passing InitStaticResources=true to CreateShaderResourceBinding() method."); + LOG_ERROR_MESSAGE("Shader resource binding is not compatible with pipeline state."); + return; } -#endif - StaticResLayout.CopyStaticResourceDesriptorHandles(StaticResCache, ShaderResLayout, m_ShaderResourceCache); + + InitializeStaticResourcesWithSignature(pSign); } +} -#ifdef DILIGENT_DEBUG - m_ShaderResourceCache.DbgVerifyBoundDynamicCBsCounter(); -#endif +void ShaderResourceBindingD3D12Impl::InitializeStaticResourcesWithSignature(const IPipelineResourceSignature* pResourceSignature) +{ + if (pResourceSignature == nullptr) + pResourceSignature = GetPipelineResourceSignature(); + auto* pPRSD3D12 = ValidatedCast<const PipelineResourceSignatureD3D12Impl>(pResourceSignature); + pPRSD3D12->InitializeStaticSRBResources(m_ShaderResourceCache); m_bStaticResourcesInitialized = true; } diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderResourceCacheD3D12.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderResourceCacheD3D12.cpp index 95e43d16..828bdca3 100644 --- a/Graphics/GraphicsEngineD3D12/src/ShaderResourceCacheD3D12.cpp +++ b/Graphics/GraphicsEngineD3D12/src/ShaderResourceCacheD3D12.cpp @@ -99,7 +99,7 @@ ShaderResourceCacheD3D12::~ShaderResourceCacheD3D12() } } -#ifdef DILIGENT_DEBUG +#if 0 //def DILIGENT_DEBUG void ShaderResourceCacheD3D12::DbgVerifyBoundDynamicCBsCounter() const { Uint32 NumDynamicCBsBound = 0; diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderResourceLayoutD3D12.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderResourceLayoutD3D12.cpp deleted file mode 100644 index 7cc95e6c..00000000 --- a/Graphics/GraphicsEngineD3D12/src/ShaderResourceLayoutD3D12.cpp +++ /dev/null @@ -1,1247 +0,0 @@ -/* - * Copyright 2019-2021 Diligent Graphics LLC - * Copyright 2015-2019 Egor Yusov - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * In no event and under no legal theory, whether in tort (including negligence), - * contract, or otherwise, unless required by applicable law (such as deliberate - * and grossly negligent acts) or agreed to in writing, shall any Contributor be - * liable for any damages, including any direct, indirect, special, incidental, - * or consequential damages of any character arising as a result of this License or - * out of the use or inability to use the software (including but not limited to damages - * for loss of goodwill, work stoppage, computer failure or malfunction, or any and - * all other commercial damages or losses), even if such Contributor has been advised - * of the possibility of such damages. - */ - -#include "pch.h" - -#include "ShaderResourceLayoutD3D12.hpp" -#include "ShaderResourceCacheD3D12.hpp" -#include "BufferD3D12Impl.hpp" -#include "BufferViewD3D12.h" -#include "TextureD3D12Impl.hpp" -#include "TextureViewD3D12Impl.hpp" -#include "SamplerD3D12Impl.hpp" -#include "ShaderD3D12Impl.hpp" -#include "RootSignature.hpp" -#include "PipelineStateD3D12Impl.hpp" -#include "ShaderResourceVariableBase.hpp" -#include "ShaderVariableD3DBase.hpp" -#include "FixedLinearAllocator.hpp" -#include "TopLevelASD3D12.h" - -namespace Diligent -{ - -ShaderResourceLayoutD3D12::~ShaderResourceLayoutD3D12() -{ - for (Uint32 r = 0; r < GetTotalResourceCount(); ++r) - GetResource(r).~D3D12Resource(); -} - -D3D12_DESCRIPTOR_RANGE_TYPE GetDescriptorRangeType(CachedResourceType ResType) -{ - class ResTypeToD3D12DescrRangeType - { - public: - ResTypeToD3D12DescrRangeType() - { - // clang-format off - m_Map[(size_t)CachedResourceType::CBV] = D3D12_DESCRIPTOR_RANGE_TYPE_CBV; - m_Map[(size_t)CachedResourceType::TexSRV] = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; - m_Map[(size_t)CachedResourceType::BufSRV] = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; - m_Map[(size_t)CachedResourceType::TexUAV] = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; - m_Map[(size_t)CachedResourceType::BufUAV] = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; - m_Map[(size_t)CachedResourceType::Sampler] = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; - m_Map[(size_t)CachedResourceType::AccelStruct] = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; - // clang-format on - } - - D3D12_DESCRIPTOR_RANGE_TYPE operator[](CachedResourceType ResType) const - { - auto Ind = static_cast<size_t>(ResType); - VERIFY(Ind >= 0 && Ind < (size_t)CachedResourceType::NumTypes, "Unexpected resource type"); - return m_Map[Ind]; - } - - private: - std::array<D3D12_DESCRIPTOR_RANGE_TYPE, static_cast<size_t>(CachedResourceType::NumTypes)> m_Map; - }; - - static const ResTypeToD3D12DescrRangeType ResTypeToDescrRangeTypeMap; - return ResTypeToDescrRangeTypeMap[ResType]; -} - - -StringPool ShaderResourceLayoutD3D12::AllocateMemory(IMemoryAllocator& Allocator, - const std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES>& CbvSrvUavCount, - const std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES>& SamplerCount, - size_t StringPoolSize) -{ - m_CbvSrvUavOffsets[0] = 0; - for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; - VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; - VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1)) - { - VERIFY(m_CbvSrvUavOffsets[VarType] + CbvSrvUavCount[VarType] <= std::numeric_limits<Uint16>::max(), "Offset is not representable in 16 bits"); - m_CbvSrvUavOffsets[VarType + 1] = static_cast<Uint16>(m_CbvSrvUavOffsets[VarType] + CbvSrvUavCount[VarType]); - VERIFY_EXPR(GetCbvSrvUavCount(VarType) == CbvSrvUavCount[VarType]); - } - - m_SamplersOffsets[0] = m_CbvSrvUavOffsets[SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES]; - for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; - VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; - VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1)) - { - VERIFY(m_SamplersOffsets[VarType] + SamplerCount[VarType] <= std::numeric_limits<Uint16>::max(), "Offset is not representable in 16 bits"); - m_SamplersOffsets[VarType + 1] = static_cast<Uint16>(m_SamplersOffsets[VarType] + SamplerCount[VarType]); - VERIFY_EXPR(GetSamplerCount(VarType) == SamplerCount[VarType]); - } - - FixedLinearAllocator MemPool{Allocator}; - MemPool.AddSpace<D3D12Resource>(GetTotalResourceCount()); - MemPool.AddSpace<char>(StringPoolSize); - - MemPool.Reserve(); - - auto* pResources = MemPool.Allocate<D3D12Resource>(GetTotalResourceCount()); - auto* pStringPoolData = MemPool.ConstructArray<char>(StringPoolSize); - - m_ResourceBuffer = std::unique_ptr<void, STDDeleterRawMem<void>>(MemPool.Release(), Allocator); - VERIFY_EXPR(pResources == nullptr || m_ResourceBuffer.get() == pResources); - VERIFY_EXPR(pStringPoolData == GetStringPoolData()); - - StringPool stringPool; - stringPool.AssignMemory(pStringPoolData, StringPoolSize); - return stringPool; -} - - -// http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-layout#Initializing-Shader-Resource-Layouts-and-Root-Signature-in-a-Pipeline-State-Object -// http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-cache#Initializing-Shader-Resource-Layouts-in-a-Pipeline-State -void ShaderResourceLayoutD3D12::Initialize(PIPELINE_TYPE PipelineType, - const PipelineResourceLayoutDesc& ResourceLayout, - const std::vector<ShaderD3D12Impl*>& Shaders, - IMemoryAllocator& LayoutDataAllocator, - class RootSignatureBuilder& RootSgnBldr, - LocalRootSignature* pLocalRootSig) -{ - VERIFY_EXPR(!Shaders.empty()); - - m_IsUsingSeparateSamplers = !Shaders[0]->GetShaderResources()->IsUsingCombinedTextureSamplers(); - m_ShaderType = Shaders[0]->GetDesc().ShaderType; - - std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES> CbvSrvUavCount = {}; - std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES> SamplerCount = {}; - - // Mapping from the resource name to its index in m_ResourceBuffer that is used - // to de-duplicate resources. - std::unordered_map<HashMapStringKey, Uint32, HashMapStringKey::Hasher> ResourceNameToIndex; - - // Construct shader or shader group name - const auto ShaderName = GetShaderGroupName(Shaders); - - // Start calculating the pool size required to keep all strings in the layout - size_t StringPoolSize = StringPool::GetRequiredReserveSize(ShaderName); - - static constexpr Uint32 InvalidResourceIndex = ~0u; - - // Count resources to calculate the required memory size. - for (auto* pShader : Shaders) // Iterate over all shaders in the stage. - { - const auto& ShaderRes = *pShader->GetShaderResources(); - VERIFY_EXPR(ShaderRes.GetShaderType() == m_ShaderType); - - auto AddResource = [&](const D3DShaderResourceAttribs& Res, Uint32 /*Index*/ = 0) // - { - const auto IsNewResource = ResourceNameToIndex.emplace(HashMapStringKey{Res.Name}, InvalidResourceIndex).second; - if (IsNewResource) - { - const auto VarType = ShaderRes.FindVariableType(Res, ResourceLayout); - StringPoolSize += StringPool::GetRequiredReserveSize(Res.Name); - if (Res.GetInputType() == D3D_SIT_SAMPLER) - ++SamplerCount[VarType]; - else - ++CbvSrvUavCount[VarType]; - } - return IsNewResource; - }; - - ShaderRes.ProcessResources( - [&](const auto& CB, Uint32) // - { - if (pLocalRootSig != nullptr && pLocalRootSig->SetOrMerge(CB)) - return; - - AddResource(CB); - }, - [&](const D3DShaderResourceAttribs& Sam, Uint32) // - { - constexpr bool LogImtblSamplerArrayError = true; - - const auto ImtblSamplerInd = ShaderRes.FindImmutableSampler(Sam, ResourceLayout, LogImtblSamplerArrayError); - // Skip immutable samplers - if (ImtblSamplerInd >= 0) - return; - - AddResource(Sam); - }, - [&](const D3DShaderResourceAttribs& TexSRV, Uint32) // - { - if (AddResource(TexSRV)) - { -#if DILIGENT_DEVELOPMENT - if (TexSRV.IsCombinedWithSampler()) - { - const auto& SamplerAttribs = ShaderRes.GetCombinedSampler(TexSRV); - const auto SamplerVarType = ShaderRes.FindVariableType(SamplerAttribs, ResourceLayout); - const auto TexSrvVarType = ShaderRes.FindVariableType(TexSRV, ResourceLayout); - DEV_CHECK_ERR(SamplerVarType == TexSrvVarType, - "The type (", GetShaderVariableTypeLiteralName(TexSrvVarType), ") of texture SRV variable '", TexSRV.Name, - "' is not consistent with the type (", GetShaderVariableTypeLiteralName(SamplerVarType), - ") of the sampler '", SamplerAttribs.Name, "' that is assigned to it"); - } -#endif - } - }, - AddResource, - AddResource, - AddResource, - AddResource // - ); - } - - auto stringPool = AllocateMemory(LayoutDataAllocator, CbvSrvUavCount, SamplerCount, StringPoolSize); - - stringPool.CopyString(ShaderName); - - std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES> CurrCbvSrvUav = {}; - std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES> CurrSampler = {}; - - for (auto* pShader : Shaders) - { - const auto& ShaderRes = *pShader->GetShaderResources(); - - auto InitResource = [&](const D3DShaderResourceAttribs& Attribs, - CachedResourceType ResType, - Uint32 SamplerId = D3DShaderResourceAttribs::InvalidSamplerId) // - { - const auto VarType = ShaderRes.FindVariableType(Attribs, ResourceLayout); - - auto ResIter = ResourceNameToIndex.find(HashMapStringKey{Attribs.Name}); - VERIFY(ResIter != ResourceNameToIndex.end(), - "Resource '", Attribs.Name, - "' is not found in ResourceNameToIndex map. This should never happen as " - "all resources are added to the map when they are being counted."); - - if (ResIter->second == InvalidResourceIndex) - { - Uint32 RootIndex = D3D12Resource::InvalidRootIndex; - Uint32 Offset = D3D12Resource::InvalidOffset; - Uint32 BindPoint = D3DShaderResourceAttribs::InvalidBindPoint; - - D3D12_DESCRIPTOR_RANGE_TYPE DescriptorRangeType = GetDescriptorRangeType(ResType); - - RootSgnBldr.AllocateResourceSlot(GetShaderType(), PipelineType, Attribs, VarType, DescriptorRangeType, BindPoint, RootIndex, Offset); - VERIFY(RootIndex <= D3D12Resource::MaxRootIndex, "Root index excceeds allowed limit"); - VERIFY(RootIndex != D3D12Resource::InvalidRootIndex, "Root index must be valid"); - VERIFY(BindPoint <= D3DShaderResourceAttribs::MaxBindPoint, "Bind point excceeds allowed limit"); - VERIFY(Offset != D3D12Resource::InvalidOffset, "Offset must be valid"); - - // Immutable samplers are never copied, and SamplerId == InvalidSamplerId - Uint32 ResOffset = (ResType == CachedResourceType::Sampler) ? - GetSamplerOffset(VarType, CurrSampler[VarType]++) : - GetSrvCbvUavOffset(VarType, CurrCbvSrvUav[VarType]++); - ResIter->second = ResOffset; - auto& NewResource = GetResource(ResOffset); - ::new (&NewResource) D3D12Resource // - { - *this, - stringPool, - Attribs, - SamplerId, - VarType, - ResType, - BindPoint, - RootIndex, - Offset // - }; - } - else - { - // Merge with existing - auto& ExistingRes = GetResource(ResIter->second); - VERIFY(ExistingRes.VariableType == VarType, - "The type of variable '", Attribs.Name, "' does not match the type determined for previous shaders. This appears to be a bug."); - - DEV_CHECK_ERR(ExistingRes.Attribs.GetInputType() == Attribs.GetInputType(), - "Shader variable '", Attribs.Name, - "' exists in multiple shaders from the same shader stage, but its input type is not consistent between " - "shaders. All variables with the same name from the same shader stage must have the same input type."); - - DEV_CHECK_ERR(ExistingRes.Attribs.GetSRVDimension() == Attribs.GetSRVDimension(), - "Shader variable '", Attribs.Name, - "' exists in multiple shaders from the same shader stage, but its SRV dimension is not consistent between " - "shaders. All variables with the same name from the same shader stage must have the same SRV dimension."); - - DEV_CHECK_ERR(ExistingRes.Attribs.BindCount == Attribs.BindCount, - "Shader variable '", Attribs.Name, - "' exists in multiple shaders from the same shader stage, but its array size is not consistent between " - "shaders. All variables with the same name from the same shader stage must have the same array size."); - } - }; - - ShaderRes.ProcessResources( - [&](const D3DShaderResourceAttribs& CB, Uint32) // - { - if (pLocalRootSig != nullptr && pLocalRootSig->SetOrMerge(CB)) - return; - - InitResource(CB, CachedResourceType::CBV); - }, - [&](const D3DShaderResourceAttribs& Sam, Uint32) // - { - // The errors (if any) have already been logged when counting the resources - constexpr bool LogImtblSamplerArrayError = false; - - const auto ImtblSamplerInd = ShaderRes.FindImmutableSampler(Sam, ResourceLayout, LogImtblSamplerArrayError); - if (ImtblSamplerInd >= 0) - { - // Note that there may be multiple immutable samplers with the same name in different ray tracing shaders - // that are assigned to different registers. InitImmutableSampler() handles this by allocating new - // register only first time the sampler is encountered. All bindings will be remapped afterwards. - RootSgnBldr.InitImmutableSampler(ShaderRes.GetShaderType(), Sam.Name, ShaderRes.GetCombinedSamplerSuffix(), Sam); - } - else - { - InitResource(Sam, CachedResourceType::Sampler); - } - }, - [&](const D3DShaderResourceAttribs& TexSRV, Uint32) // - { - static_assert(SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES == 3, "Unexpected number of shader variable types"); - VERIFY(CurrSampler[SHADER_RESOURCE_VARIABLE_TYPE_STATIC] + CurrSampler[SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE] + CurrSampler[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC] == GetTotalSamplerCount(), "All samplers must be initialized before texture SRVs"); - - Uint32 SamplerId = D3DShaderResourceAttribs::InvalidSamplerId; - if (TexSRV.IsCombinedWithSampler()) - { - const auto& SamplerAttribs = ShaderRes.GetCombinedSampler(TexSRV); - const auto SamplerVarType = ShaderRes.FindVariableType(SamplerAttribs, ResourceLayout); - const auto TexSrvVarType = ShaderRes.FindVariableType(TexSRV, ResourceLayout); - DEV_CHECK_ERR(SamplerVarType == TexSrvVarType, - "The type (", GetShaderVariableTypeLiteralName(TexSrvVarType), ") of texture SRV variable '", TexSRV.Name, - "' is not consistent with the type (", GetShaderVariableTypeLiteralName(SamplerVarType), - ") of the sampler '", SamplerAttribs.Name, "' that is assigned to it"); - - // The errors (if any) have already been logged when counting the resources - constexpr bool LogImtblSamplerArrayError = false; - const auto ImtblSamplerInd = ShaderRes.FindImmutableSampler(SamplerAttribs, ResourceLayout, LogImtblSamplerArrayError); - if (ImtblSamplerInd >= 0) - { - SamplerId = D3DShaderResourceAttribs::InvalidSamplerId; - // Immutable samplers are never copied, and should not be found in resources - DEV_CHECK_ERR(FindSamplerByName(SamplerAttribs.Name) == D3DShaderResourceAttribs::InvalidSamplerId, - "Immutable sampler '", SamplerAttribs.Name, "' was found among shader resources. This seems to be a bug"); - } - else - { - SamplerId = FindSamplerByName(SamplerAttribs.Name); - DEV_CHECK_ERR(SamplerId != D3DShaderResourceAttribs::InvalidSamplerId, - "Unable to find sampler '", SamplerAttribs.Name, "' assigned to texture SRV '", TexSRV.Name, - "' in the list of already created shader resources. This seems to be a bug."); - } - } - InitResource(TexSRV, CachedResourceType::TexSRV, SamplerId); - }, - [&](const D3DShaderResourceAttribs& TexUAV, Uint32) // - { - InitResource(TexUAV, CachedResourceType::TexUAV); - }, - [&](const D3DShaderResourceAttribs& BufSRV, Uint32) // - { - InitResource(BufSRV, CachedResourceType::BufSRV); - }, - [&](const D3DShaderResourceAttribs& BufUAV, Uint32) // - { - InitResource(BufUAV, CachedResourceType::BufUAV); - }, - [&](const D3DShaderResourceAttribs& AccelStruct, Uint32) // - { - InitResource(AccelStruct, CachedResourceType::AccelStruct); - } // - ); - } - -#ifdef DILIGENT_DEBUG - VERIFY_EXPR(stringPool.GetRemainingSize() == 0); - for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1)) - { - VERIFY(CurrCbvSrvUav[VarType] == CbvSrvUavCount[VarType], "Not all Srv/Cbv/Uavs are initialized, which result in a crash when dtor is called"); - VERIFY(CurrSampler[VarType] == SamplerCount[VarType], "Not all Samplers are initialized, which result in a crash when dtor is called"); - } -#endif -} - -void ShaderResourceLayoutD3D12::InitializeStaticReourceLayout(const ShaderResourceLayoutD3D12& SrcLayout, - IMemoryAllocator& LayoutDataAllocator, - ShaderResourceCacheD3D12& ResourceCache) -{ - m_IsUsingSeparateSamplers = SrcLayout.m_IsUsingSeparateSamplers; - m_ShaderType = SrcLayout.m_ShaderType; - - const auto AllowedTypeBits = GetAllowedTypeBit(SHADER_RESOURCE_VARIABLE_TYPE_STATIC); - const auto* const ShaderName = SrcLayout.GetShaderName(); - - std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES> CbvSrvUavCount = {}; - std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES> SamplerCount = {}; - - size_t StringPoolSize = StringPool::GetRequiredReserveSize(ShaderName); - - for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; - VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; - VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1)) - { - if (!IsAllowedType(VarType, AllowedTypeBits)) - continue; - - CbvSrvUavCount[VarType] = SrcLayout.GetCbvSrvUavCount(VarType); - SamplerCount[VarType] = SrcLayout.GetSamplerCount(VarType); - - for (Uint32 i = 0; i < CbvSrvUavCount[VarType]; ++i) - StringPoolSize += StringPool::GetRequiredReserveSize(SrcLayout.GetSrvCbvUav(VarType, i).Attribs.Name); - for (Uint32 i = 0; i < SamplerCount[VarType]; ++i) - StringPoolSize += StringPool::GetRequiredReserveSize(SrcLayout.GetSampler(VarType, i).Attribs.Name); - } - - auto stringPool = AllocateMemory(LayoutDataAllocator, CbvSrvUavCount, SamplerCount, StringPoolSize); - stringPool.CopyString(ShaderName); - - std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES> CurrCbvSrvUav = {}; - std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES> CurrSampler = {}; - - std::array<Uint32, D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER + 1> StaticResCacheTblSizes = {}; - - auto InitResource = [&](const D3D12Resource& SrcRes, - Uint32 SamplerId = D3DShaderResourceAttribs::InvalidSamplerId) // - { - const auto ResType = SrcRes.GetResType(); - const auto VarType = SrcRes.GetVariableType(); - - const Uint32 ResOffset = (ResType == CachedResourceType::Sampler) ? - GetSamplerOffset(VarType, CurrSampler[VarType]++) : - GetSrvCbvUavOffset(VarType, CurrCbvSrvUav[VarType]++); - - // http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-layout#Initializing-Special-Resource-Layout-for-Managing-Static-Shader-Resources - // Use artifial root signature: - // SRVs at root index D3D12_DESCRIPTOR_RANGE_TYPE_SRV (0) - // UAVs at root index D3D12_DESCRIPTOR_RANGE_TYPE_UAV (1) - // CBVs at root index D3D12_DESCRIPTOR_RANGE_TYPE_CBV (2) - // Samplers at root index D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER (3) - const Uint32 RootIndex = GetDescriptorRangeType(ResType); - const Uint32 Offset = StaticResCacheTblSizes[RootIndex]; - - auto& NewResource = GetResource(ResOffset); - ::new (&NewResource) D3D12Resource // - { - *this, - stringPool, - SrcRes.Attribs, - SamplerId, - VarType, - ResType, - SrcRes.Attribs.BindPoint, - RootIndex, - Offset // - }; - - StaticResCacheTblSizes[RootIndex] += NewResource.Attribs.BindCount; - }; - - // Process samplers first - for (Uint32 s = 0; s < SrcLayout.GetTotalSamplerCount(); ++s) - { - const auto& SrcSmplr = SrcLayout.GetSampler(s); - if (IsAllowedType(SrcSmplr.GetVariableType(), AllowedTypeBits)) - { - InitResource(SrcSmplr); - } - } - - // Process SRVs, CBVs, UAVs - for (Uint32 res = 0; res < SrcLayout.GetTotalSrvCbvUavCount(); ++res) - { - const auto& SrcRes = SrcLayout.GetSrvCbvUav(res); - const auto VarType = SrcRes.GetVariableType(); - if (!IsAllowedType(VarType, AllowedTypeBits)) - continue; - - Uint32 SamplerId = D3DShaderResourceAttribs::InvalidSamplerId; - if (SrcRes.Attribs.IsCombinedWithSampler()) - { - // If source resource is combined with the sampler, there must also be - // a corresponding sampler in this layout. - - const auto& SrcAssignedSmplr = SrcLayout.GetAssignedSampler(SrcRes); - VERIFY(SrcAssignedSmplr.GetVariableType() == SrcRes.GetVariableType(), - "The type of the sampler does not match the type of the texture it is assigned to. This is likely a bug."); - - SamplerId = FindSamplerByName(SrcAssignedSmplr.Attribs.Name); - VERIFY(SamplerId != D3DShaderResourceAttribs::InvalidSamplerId, - "Unable to find sampler '", SrcAssignedSmplr.Attribs.Name, "' among resources. This seems to be a bug."); - } - - InitResource(SrcRes, SamplerId); - } - -#ifdef DILIGENT_DEBUG - VERIFY_EXPR(stringPool.GetRemainingSize() == 0); - for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1)) - { - VERIFY(CurrCbvSrvUav[VarType] == CbvSrvUavCount[VarType], "Not all Srv/Cbv/Uavs are initialized, which result in a crash when dtor is called"); - VERIFY(CurrSampler[VarType] == SamplerCount[VarType], "Not all Samplers are initialized, which result in a crash when dtor is called"); - } -#endif - - // Initialize resource cache to store static resources - // http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-cache#Initializing-the-Cache-for-Static-Shader-Resources - // http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-cache#Initializing-Shader-Objects - ResourceCache.Initialize(GetRawAllocator(), static_cast<Uint32>(StaticResCacheTblSizes.size()), StaticResCacheTblSizes.data()); -#ifdef DILIGENT_DEBUG - ResourceCache.GetRootTable(D3D12_DESCRIPTOR_RANGE_TYPE_SRV).SetDebugAttribs(StaticResCacheTblSizes[D3D12_DESCRIPTOR_RANGE_TYPE_SRV], D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, GetShaderType()); - ResourceCache.GetRootTable(D3D12_DESCRIPTOR_RANGE_TYPE_UAV).SetDebugAttribs(StaticResCacheTblSizes[D3D12_DESCRIPTOR_RANGE_TYPE_UAV], D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, GetShaderType()); - ResourceCache.GetRootTable(D3D12_DESCRIPTOR_RANGE_TYPE_CBV).SetDebugAttribs(StaticResCacheTblSizes[D3D12_DESCRIPTOR_RANGE_TYPE_CBV], D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, GetShaderType()); - ResourceCache.GetRootTable(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER).SetDebugAttribs(StaticResCacheTblSizes[D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER], D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, GetShaderType()); -#endif -} - -void ShaderResourceLayoutD3D12::D3D12Resource::CacheCB(IDeviceObject* pBuffer, - ShaderResourceCacheD3D12::Resource& DstRes, - Uint32 ArrayInd, - D3D12_CPU_DESCRIPTOR_HANDLE ShdrVisibleHeapCPUDescriptorHandle, - Uint32& BoundDynamicCBsCounter) const -{ - // http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-cache#Binding-Objects-to-Shader-Variables - - // We cannot use ValidatedCast<> here as the resource retrieved from the - // resource mapping can be of wrong type - RefCntAutoPtr<BufferD3D12Impl> pBuffD3D12{pBuffer, IID_BufferD3D12}; -#ifdef DILIGENT_DEVELOPMENT - VerifyConstantBufferBinding(Attribs, GetVariableType(), ArrayInd, pBuffer, pBuffD3D12.RawPtr(), DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName()); -#endif - if (pBuffD3D12) - { - if (GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && DstRes.pObject != nullptr) - { - // Do not update resource if one is already bound unless it is dynamic. This may be - // dangerous as CopyDescriptorsSimple() may interfere with GPU reading the same descriptor. - return; - } - - DstRes.Type = GetResType(); - DstRes.CPUDescriptorHandle = pBuffD3D12->GetCBVHandle(); - VERIFY(DstRes.CPUDescriptorHandle.ptr != 0 || pBuffD3D12->GetDesc().Usage == USAGE_DYNAMIC, "No relevant CBV CPU descriptor handle"); - - if (ShdrVisibleHeapCPUDescriptorHandle.ptr != 0) - { - // Dynamic resources are assigned descriptor in the GPU-visible heap at every draw call, and - // the descriptor is copied by the RootSignature when resources are committed - VERIFY(DstRes.pObject == nullptr, "Static and mutable resource descriptors must be copied only once"); - - ID3D12Device* pd3d12Device = ParentResLayout.m_pd3d12Device; - pd3d12Device->CopyDescriptorsSimple(1, ShdrVisibleHeapCPUDescriptorHandle, DstRes.CPUDescriptorHandle, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); - } - - if (DstRes.pObject != nullptr && DstRes.pObject.RawPtr<const BufferD3D12Impl>()->GetDesc().Usage == USAGE_DYNAMIC) - { - VERIFY(BoundDynamicCBsCounter > 0, "There is a dynamic CB bound in the resource cache, but the dynamic CB counter is zero"); - --BoundDynamicCBsCounter; - } - if (pBuffD3D12->GetDesc().Usage == USAGE_DYNAMIC) - ++BoundDynamicCBsCounter; - DstRes.pObject = std::move(pBuffD3D12); - } -} - -template <typename TResourceViewType> -struct ResourceViewTraits -{}; - -template <> -struct ResourceViewTraits<ITextureViewD3D12> -{ - static const INTERFACE_ID& IID; - - static bool VerifyView(ITextureViewD3D12* pViewD3D12, const D3DShaderResourceAttribs& Attribs, const char* ShaderName) - { - return true; - } -}; -const INTERFACE_ID& ResourceViewTraits<ITextureViewD3D12>::IID = IID_TextureViewD3D12; - -template <> -struct ResourceViewTraits<IBufferViewD3D12> -{ - static const INTERFACE_ID& IID; - - static bool VerifyView(IBufferViewD3D12* pViewD3D12, const D3DShaderResourceAttribs& Attribs, const char* ShaderName) - { - return VerifyBufferViewModeD3D(pViewD3D12, Attribs, ShaderName); - } -}; -const INTERFACE_ID& ResourceViewTraits<IBufferViewD3D12>::IID = IID_BufferViewD3D12; - -template <typename TResourceViewType, ///< ResType of the view (ITextureViewD3D12 or IBufferViewD3D12) - typename TViewTypeEnum, ///< ResType of the expected view type enum (TEXTURE_VIEW_TYPE or BUFFER_VIEW_TYPE) - typename TBindSamplerProcType> ///< ResType of the procedure to set sampler -void ShaderResourceLayoutD3D12::D3D12Resource::CacheResourceView(IDeviceObject* pView, - ShaderResourceCacheD3D12::Resource& DstRes, - Uint32 ArrayIndex, - D3D12_CPU_DESCRIPTOR_HANDLE ShdrVisibleHeapCPUDescriptorHandle, - TViewTypeEnum dbgExpectedViewType, - TBindSamplerProcType BindSamplerProc) const -{ - // We cannot use ValidatedCast<> here as the resource retrieved from the - // resource mapping can be of wrong type - RefCntAutoPtr<TResourceViewType> pViewD3D12{pView, ResourceViewTraits<TResourceViewType>::IID}; -#ifdef DILIGENT_DEVELOPMENT - VerifyResourceViewBinding(Attribs, GetVariableType(), ArrayIndex, pView, pViewD3D12.RawPtr(), {dbgExpectedViewType}, DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName()); - ResourceViewTraits<TResourceViewType>::VerifyView(pViewD3D12, Attribs, ParentResLayout.GetShaderName()); -#endif - if (pViewD3D12) - { - if (GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && DstRes.pObject != nullptr) - { - // Do not update resource if one is already bound unless it is dynamic. This may be - // dangerous as CopyDescriptorsSimple() may interfere with GPU reading the same descriptor. - return; - } - - DstRes.Type = GetResType(); - DstRes.CPUDescriptorHandle = pViewD3D12->GetCPUDescriptorHandle(); - VERIFY(DstRes.CPUDescriptorHandle.ptr != 0, "No relevant D3D12 view"); - - if (ShdrVisibleHeapCPUDescriptorHandle.ptr != 0) - { - // Dynamic resources are assigned descriptor in the GPU-visible heap at every draw call, and - // the descriptor is copied by the RootSignature when resources are committed - VERIFY(DstRes.pObject == nullptr, "Static and mutable resource descriptors must be copied only once"); - - ID3D12Device* pd3d12Device = ParentResLayout.m_pd3d12Device; - pd3d12Device->CopyDescriptorsSimple(1, ShdrVisibleHeapCPUDescriptorHandle, DstRes.CPUDescriptorHandle, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); - } - - BindSamplerProc(pViewD3D12); - - DstRes.pObject = std::move(pViewD3D12); - } -} - -void ShaderResourceLayoutD3D12::D3D12Resource::CacheSampler(IDeviceObject* pSampler, - ShaderResourceCacheD3D12::Resource& DstSam, - Uint32 ArrayIndex, - D3D12_CPU_DESCRIPTOR_HANDLE ShdrVisibleHeapCPUDescriptorHandle) const -{ - VERIFY(Attribs.IsValidBindPoint(), "Invalid bind point"); - VERIFY_EXPR(ArrayIndex < Attribs.BindCount); - - RefCntAutoPtr<ISamplerD3D12> pSamplerD3D12{pSampler, IID_SamplerD3D12}; - if (pSamplerD3D12) - { - if (GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && DstSam.pObject != nullptr) - { - if (DstSam.pObject != pSampler) - { - auto VarTypeStr = GetShaderVariableTypeLiteralName(GetVariableType()); - LOG_ERROR_MESSAGE("Non-null sampler is already bound to ", VarTypeStr, " shader variable '", Attribs.GetPrintName(ArrayIndex), - "' in shader '", ParentResLayout.GetShaderName(), "'. Attempting to bind another sampler is an error and will " - "be ignored. Use another shader resource binding instance or label the variable as dynamic."); - } - - // Do not update resource if one is already bound unless it is dynamic. This may be - // dangerous as CopyDescriptorsSimple() may interfere with GPU reading the same descriptor. - return; - } - - DstSam.Type = CachedResourceType::Sampler; - - DstSam.CPUDescriptorHandle = pSamplerD3D12->GetCPUDescriptorHandle(); - VERIFY(DstSam.CPUDescriptorHandle.ptr != 0, "No relevant D3D12 sampler descriptor handle"); - - if (ShdrVisibleHeapCPUDescriptorHandle.ptr != 0) - { - // Dynamic resources are assigned descriptor in the GPU-visible heap at every draw call, and - // the descriptor is copied by the RootSignature when resources are committed - VERIFY(DstSam.pObject == nullptr, "Static and mutable resource descriptors must be copied only once"); - - ID3D12Device* pd3d12Device = ParentResLayout.m_pd3d12Device; - pd3d12Device->CopyDescriptorsSimple(1, ShdrVisibleHeapCPUDescriptorHandle, DstSam.CPUDescriptorHandle, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); - } - - DstSam.pObject = std::move(pSamplerD3D12); - } - else - { - LOG_ERROR_MESSAGE("Failed to bind object '", pSampler->GetDesc().Name, "' to variable '", Attribs.GetPrintName(ArrayIndex), - "' in shader '", ParentResLayout.GetShaderName(), "'. Incorect object type: sampler is expected."); - } -} - -void ShaderResourceLayoutD3D12::D3D12Resource::CacheAccelStruct(IDeviceObject* pTLAS, - ShaderResourceCacheD3D12::Resource& DstRes, - Uint32 ArrayIndex, - D3D12_CPU_DESCRIPTOR_HANDLE ShdrVisibleHeapCPUDescriptorHandle) const -{ - VERIFY(Attribs.IsValidBindPoint(), "Invalid bind point"); - VERIFY_EXPR(ArrayIndex < Attribs.BindCount); - - RefCntAutoPtr<ITopLevelASD3D12> pTLASD3D12{pTLAS, IID_TopLevelASD3D12}; - if (pTLASD3D12) - { - if (GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && DstRes.pObject != nullptr) - { - // Do not update resource if one is already bound unless it is dynamic. This may be - // dangerous as CopyDescriptorsSimple() may interfere with GPU reading the same descriptor. - return; - } - - DstRes.Type = GetResType(); - DstRes.CPUDescriptorHandle = pTLASD3D12->GetCPUDescriptorHandle(); - VERIFY(DstRes.CPUDescriptorHandle.ptr != 0, "No relevant D3D12 resource"); - - if (ShdrVisibleHeapCPUDescriptorHandle.ptr != 0) - { - // Dynamic resources are assigned descriptor in the GPU-visible heap at every draw call, and - // the descriptor is copied by the RootSignature when resources are committed - VERIFY(DstRes.pObject == nullptr, "Static and mutable resource descriptors must be copied only once"); - - ID3D12Device* pd3d12Device = ParentResLayout.m_pd3d12Device; - pd3d12Device->CopyDescriptorsSimple(1, ShdrVisibleHeapCPUDescriptorHandle, DstRes.CPUDescriptorHandle, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); - } - - DstRes.pObject = std::move(pTLASD3D12); - } -} - - -Uint32 ShaderResourceLayoutD3D12::FindSamplerByName(const char* SamplerName) const -{ - const auto SamplerCount = GetTotalSamplerCount(); - for (Uint32 SamplerId = 0; SamplerId < SamplerCount; ++SamplerId) - { - const auto& Sampler = GetSampler(SamplerId); - if (strcmp(Sampler.Attribs.Name, SamplerName) == 0) - { - VERIFY(SamplerId <= D3DShaderResourceAttribs::MaxSamplerId, "Sampler index excceeds allowed limit"); - return SamplerId; - } - } - - return D3DShaderResourceAttribs::InvalidSamplerId; -} - -const ShaderResourceLayoutD3D12::D3D12Resource& ShaderResourceLayoutD3D12::GetAssignedSampler(const D3D12Resource& TexSrv) const -{ - VERIFY(TexSrv.GetResType() == CachedResourceType::TexSRV, "Unexpected resource type: texture SRV is expected"); - VERIFY(TexSrv.Attribs.IsCombinedWithSampler(), "Texture SRV has no associated sampler"); - const auto& SamInfo = GetSampler(TexSrv.Attribs.GetCombinedSamplerId()); - VERIFY(SamInfo.GetVariableType() == TexSrv.GetVariableType(), "Inconsistent texture and sampler variable types"); - //VERIFY(StreqSuff(SamInfo.Name, TexSrv.Name, GetCombinedSamplerSuffix()), "Sampler name '", SamInfo.Name, "' does not match texture name '", TexSrv.Name, '\''); - return SamInfo; -} - -ShaderResourceLayoutD3D12::D3D12Resource& ShaderResourceLayoutD3D12::GetAssignedSampler(const D3D12Resource& TexSrv) -{ - return const_cast<D3D12Resource&>(const_cast<const ShaderResourceLayoutD3D12*>(this)->GetAssignedSampler(TexSrv)); -} - - -void ShaderResourceLayoutD3D12::D3D12Resource::BindResource(IDeviceObject* pObj, - Uint32 ArrayIndex, - ShaderResourceCacheD3D12& ResourceCache) const -{ - VERIFY_EXPR(ArrayIndex < Attribs.BindCount); - - const bool IsSampler = GetResType() == CachedResourceType::Sampler; - auto DescriptorHeapType = IsSampler ? D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER : D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; - auto& DstRes = ResourceCache.GetRootTable(RootIndex).GetResource(OffsetFromTableStart + ArrayIndex, DescriptorHeapType, ParentResLayout.GetShaderType()); - - auto ShdrVisibleHeapCPUDescriptorHandle = IsSampler ? - ResourceCache.GetShaderVisibleTableCPUDescriptorHandle<D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER>(RootIndex, OffsetFromTableStart + ArrayIndex) : - ResourceCache.GetShaderVisibleTableCPUDescriptorHandle<D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV>(RootIndex, OffsetFromTableStart + ArrayIndex); - -#ifdef DILIGENT_DEBUG - { - if (ResourceCache.DbgGetContentType() == ShaderResourceCacheD3D12::DbgCacheContentType::StaticShaderResources) - { - VERIFY(ShdrVisibleHeapCPUDescriptorHandle.ptr == 0, "Static shader resources of a shader should not be assigned shader visible descriptor space"); - } - else if (ResourceCache.DbgGetContentType() == ShaderResourceCacheD3D12::DbgCacheContentType::SRBResources) - { - if (GetResType() == CachedResourceType::CBV && Attribs.BindCount == 1) - { - VERIFY(ShdrVisibleHeapCPUDescriptorHandle.ptr == 0, "Non-array constant buffers are bound as root views and should not be assigned shader visible descriptor space"); - } - else - { - if (GetVariableType() == SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) - VERIFY(ShdrVisibleHeapCPUDescriptorHandle.ptr == 0, "Dynamic resources of a shader resource binding should be assigned shader visible descriptor space at every draw call"); - else - VERIFY(ShdrVisibleHeapCPUDescriptorHandle.ptr != 0, "Non-dynamics resources of a shader resource binding must be assigned shader visible descriptor space"); - } - } - else - { - UNEXPECTED("Unknown content type"); - } - } -#endif - - if (pObj) - { - static_assert(static_cast<int>(CachedResourceType::NumTypes) == 7, "Please update this function to handle the new resource type"); - switch (GetResType()) - { - case CachedResourceType::CBV: - CacheCB(pObj, DstRes, ArrayIndex, ShdrVisibleHeapCPUDescriptorHandle, ResourceCache.GetBoundDynamicCBsCounter()); - break; - - case CachedResourceType::TexSRV: - CacheResourceView<ITextureViewD3D12>( - pObj, DstRes, ArrayIndex, ShdrVisibleHeapCPUDescriptorHandle, TEXTURE_VIEW_SHADER_RESOURCE, - [&](ITextureViewD3D12* pTexView) // - { - if (Attribs.IsCombinedWithSampler()) - { - auto& Sam = ParentResLayout.GetAssignedSampler(*this); - //VERIFY( !Sam.IsImmutableSampler(), "Immutable samplers should never be assigned space in the cache" ); - VERIFY_EXPR(Attribs.BindCount == Sam.Attribs.BindCount || Sam.Attribs.BindCount == 1); - auto SamplerArrInd = Sam.Attribs.BindCount > 1 ? ArrayIndex : 0; - - auto ShdrVisibleSamplerHeapCPUDescriptorHandle = ResourceCache.GetShaderVisibleTableCPUDescriptorHandle<D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER>(Sam.RootIndex, Sam.OffsetFromTableStart + SamplerArrInd); - - auto& DstSam = ResourceCache.GetRootTable(Sam.RootIndex).GetResource(Sam.OffsetFromTableStart + SamplerArrInd, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, ParentResLayout.GetShaderType()); -#ifdef DILIGENT_DEBUG - { - if (ResourceCache.DbgGetContentType() == ShaderResourceCacheD3D12::DbgCacheContentType::StaticShaderResources) - { - VERIFY(ShdrVisibleSamplerHeapCPUDescriptorHandle.ptr == 0, "Static shader resources of a shader should not be assigned shader visible descriptor space"); - } - else if (ResourceCache.DbgGetContentType() == ShaderResourceCacheD3D12::DbgCacheContentType::SRBResources) - { - if (GetVariableType() == SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) - VERIFY(ShdrVisibleSamplerHeapCPUDescriptorHandle.ptr == 0, "Dynamic resources of a shader resource binding should be assigned shader visible descriptor space at every draw call"); - else - VERIFY(ShdrVisibleSamplerHeapCPUDescriptorHandle.ptr != 0 || pTexView == nullptr, "Non-dynamics resources of a shader resource binding must be assigned shader visible descriptor space"); - } - else - { - UNEXPECTED("Unknown content type"); - } - } -#endif - auto* pSampler = pTexView->GetSampler(); - if (pSampler) - { - Sam.CacheSampler(pSampler, DstSam, SamplerArrInd, ShdrVisibleSamplerHeapCPUDescriptorHandle); - } - else - { - LOG_ERROR_MESSAGE("Failed to bind sampler to variable '", Sam.Attribs.Name, ". Sampler is not set in the texture view '", pTexView->GetDesc().Name, '\''); - } - } - }); - break; - - case CachedResourceType::TexUAV: - CacheResourceView<ITextureViewD3D12>(pObj, DstRes, ArrayIndex, ShdrVisibleHeapCPUDescriptorHandle, TEXTURE_VIEW_UNORDERED_ACCESS, [](ITextureViewD3D12*) {}); - break; - - case CachedResourceType::BufSRV: - CacheResourceView<IBufferViewD3D12>(pObj, DstRes, ArrayIndex, ShdrVisibleHeapCPUDescriptorHandle, BUFFER_VIEW_SHADER_RESOURCE, [](IBufferViewD3D12*) {}); - break; - - case CachedResourceType::BufUAV: - CacheResourceView<IBufferViewD3D12>(pObj, DstRes, ArrayIndex, ShdrVisibleHeapCPUDescriptorHandle, BUFFER_VIEW_UNORDERED_ACCESS, [](IBufferViewD3D12*) {}); - break; - - case CachedResourceType::Sampler: - DEV_CHECK_ERR(ParentResLayout.IsUsingSeparateSamplers(), "Samplers should not be set directly when using combined texture samplers"); - CacheSampler(pObj, DstRes, ArrayIndex, ShdrVisibleHeapCPUDescriptorHandle); - break; - - case CachedResourceType::AccelStruct: - CacheAccelStruct(pObj, DstRes, ArrayIndex, ShdrVisibleHeapCPUDescriptorHandle); - break; - - default: UNEXPECTED("Unknown resource type ", static_cast<Int32>(GetResType())); - } - } - else - { - if (DstRes.pObject != nullptr && GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) - LOG_ERROR_MESSAGE("Shader variable '", Attribs.Name, "' in shader '", ParentResLayout.GetShaderName(), "' is not dynamic but is being reset to null. This is an error and may cause unpredicted behavior. Use another shader resource binding instance or label the variable as dynamic if you need to bind another resource."); - - DstRes = ShaderResourceCacheD3D12::Resource{}; - if (Attribs.IsCombinedWithSampler()) - { - auto& Sam = ParentResLayout.GetAssignedSampler(*this); - D3D12_CPU_DESCRIPTOR_HANDLE NullHandle = {0}; - auto SamplerArrInd = Sam.Attribs.BindCount > 1 ? ArrayIndex : 0; - auto& DstSam = ResourceCache.GetRootTable(Sam.RootIndex).GetResource(Sam.OffsetFromTableStart + SamplerArrInd, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, ParentResLayout.GetShaderType()); - if (DstSam.pObject != nullptr && Sam.GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) - LOG_ERROR_MESSAGE("Sampler variable '", Sam.Attribs.Name, "' in shader '", ParentResLayout.GetShaderName(), "' is not dynamic but is being reset to null. This is an error and may cause unpredicted behavior. Use another shader resource binding instance or label the variable as dynamic if you need to bind another sampler."); - DstSam = ShaderResourceCacheD3D12::Resource{}; - } - } -} - -bool ShaderResourceLayoutD3D12::D3D12Resource::IsBound(Uint32 ArrayIndex, const ShaderResourceCacheD3D12& ResourceCache) const -{ - VERIFY_EXPR(ArrayIndex < Attribs.BindCount); - - if (RootIndex < ResourceCache.GetNumRootTables()) - { - const auto& RootTable = ResourceCache.GetRootTable(RootIndex); - if (OffsetFromTableStart + ArrayIndex < RootTable.GetSize()) - { - const auto& CachedRes = - RootTable.GetResource(OffsetFromTableStart + ArrayIndex, - GetResType() == CachedResourceType::Sampler ? D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER : D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, - ParentResLayout.GetShaderType()); - if (CachedRes.pObject != nullptr) - { - VERIFY(CachedRes.CPUDescriptorHandle.ptr != 0 || CachedRes.pObject.RawPtr<BufferD3D12Impl>()->GetDesc().Usage == USAGE_DYNAMIC, "No relevant descriptor handle"); - return true; - } - } - } - - return false; -} - -void ShaderResourceLayoutD3D12::CopyStaticResourceDesriptorHandles(const ShaderResourceCacheD3D12& SrcCache, - const ShaderResourceLayoutD3D12& DstLayout, - ShaderResourceCacheD3D12& DstCache) const -{ - // Static shader resources are stored as follows: - // CBVs at root index D3D12_DESCRIPTOR_RANGE_TYPE_CBV, - // SRVs at root index D3D12_DESCRIPTOR_RANGE_TYPE_SRV, - // UAVs at root index D3D12_DESCRIPTOR_RANGE_TYPE_UAV, and - // Samplers at root index D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER - - { - const auto CbvSrvUavCount = DstLayout.GetCbvSrvUavCount(SHADER_RESOURCE_VARIABLE_TYPE_STATIC); - VERIFY(GetCbvSrvUavCount(SHADER_RESOURCE_VARIABLE_TYPE_STATIC) == CbvSrvUavCount, - "The number of static resources in the source cache (", GetCbvSrvUavCount(SHADER_RESOURCE_VARIABLE_TYPE_STATIC), - ") is not consistent with the number of static resources in destination cache (", CbvSrvUavCount, ")"); - auto& DstBoundDynamicCBsCounter = DstCache.GetBoundDynamicCBsCounter(); - for (Uint32 r = 0; r < CbvSrvUavCount; ++r) - { - // Get resource attributes - const auto& DstResInfo = DstLayout.GetSrvCbvUav(SHADER_RESOURCE_VARIABLE_TYPE_STATIC, r); - const auto& SrcResInfo = GetSrvCbvUav(SHADER_RESOURCE_VARIABLE_TYPE_STATIC, r); - VERIFY(strcmp(SrcResInfo.Attribs.Name, DstResInfo.Attribs.Name) == 0, "Src resource name ('", SrcResInfo.Attribs.Name, "') does match the dst resource name '(", DstResInfo.Attribs.Name, "'). This is a bug."); - VERIFY(SrcResInfo.Attribs.IsCompatibleWith(DstResInfo.Attribs), "Src resource is incompatible with the dst resource. This is a bug."); - - // Source resource in the static resource cache is in the root table at index RangeType - // D3D12_DESCRIPTOR_RANGE_TYPE_SRV = 0, - // D3D12_DESCRIPTOR_RANGE_TYPE_UAV = 1 - // D3D12_DESCRIPTOR_RANGE_TYPE_CBV = 2 - VERIFY(SrcResInfo.RootIndex == static_cast<Uint32>(GetDescriptorRangeType(DstResInfo.GetResType())), "Unexpected root index for the source resource. This is a bug."); - const auto& SrcRootTable = SrcCache.GetRootTable(SrcResInfo.RootIndex); - auto& DstRootTable = DstCache.GetRootTable(DstResInfo.RootIndex); - for (Uint32 ArrInd = 0; ArrInd < DstResInfo.Attribs.BindCount; ++ArrInd) - { - const auto& SrcRes = SrcRootTable.GetResource(SrcResInfo.OffsetFromTableStart + ArrInd, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, GetShaderType()); - if (!SrcRes.pObject) - LOG_ERROR_MESSAGE("No resource is assigned to static shader variable '", DstResInfo.Attribs.GetPrintName(ArrInd), "' in shader '", GetShaderName(), "'."); - - auto& DstRes = DstRootTable.GetResource(DstResInfo.OffsetFromTableStart + ArrInd, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, GetShaderType()); - - if (DstRes.pObject != SrcRes.pObject) - { - DEV_CHECK_ERR(DstRes.pObject == nullptr, "Static resource has already been initialized, and the resource to be assigned from the shader does not match previously assigned resource"); - - if (SrcRes.Type == CachedResourceType::CBV) - { - if (DstRes.pObject && DstRes.pObject.RawPtr<const BufferD3D12Impl>()->GetDesc().Usage == USAGE_DYNAMIC) - { - VERIFY_EXPR(DstBoundDynamicCBsCounter > 0); - --DstBoundDynamicCBsCounter; - } - if (SrcRes.pObject && SrcRes.pObject.RawPtr<const BufferD3D12Impl>()->GetDesc().Usage == USAGE_DYNAMIC) - { - ++DstBoundDynamicCBsCounter; - } - } - - DstRes.pObject = SrcRes.pObject; - DstRes.Type = SrcRes.Type; - DstRes.CPUDescriptorHandle = SrcRes.CPUDescriptorHandle; - - auto ShdrVisibleHeapCPUDescriptorHandle = - DstCache.GetShaderVisibleTableCPUDescriptorHandle<D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV>( - DstResInfo.RootIndex, - DstResInfo.OffsetFromTableStart + ArrInd); - VERIFY_EXPR(ShdrVisibleHeapCPUDescriptorHandle.ptr != 0 || DstRes.Type == CachedResourceType::CBV); - // Root views are not assigned space in the GPU-visible descriptor heap allocation - if (ShdrVisibleHeapCPUDescriptorHandle.ptr != 0) - { - m_pd3d12Device->CopyDescriptorsSimple(1, ShdrVisibleHeapCPUDescriptorHandle, SrcRes.CPUDescriptorHandle, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); - } - } - else - { - VERIFY_EXPR(DstRes.pObject == SrcRes.pObject); - VERIFY_EXPR(DstRes.Type == SrcRes.Type); - VERIFY_EXPR(DstRes.CPUDescriptorHandle.ptr == SrcRes.CPUDescriptorHandle.ptr); - } - } - - VERIFY(DstResInfo.Attribs.IsCombinedWithSampler() == SrcResInfo.Attribs.IsCombinedWithSampler(), - "When source resource is combined with the sampler, destination resource must also be combined with the sampler and vice versa"); - if (DstResInfo.Attribs.IsCombinedWithSampler()) - { -#ifdef DILIGENT_DEBUG - const auto& DstSamInfo = DstLayout.GetAssignedSampler(DstResInfo); - const auto& SrcSamInfo = GetAssignedSampler(SrcResInfo); - VERIFY(strcmp(SrcSamInfo.Attribs.Name, DstSamInfo.Attribs.Name) == 0, "Src sampler name ('", SrcSamInfo.Attribs.Name, "') does match the dst sampler name '(", DstSamInfo.Attribs.Name, "'). This is a bug."); - VERIFY(DstSamInfo.Attribs.IsCompatibleWith(SrcSamInfo.Attribs), "Source sampler is incompatible with destination sampler"); - - //VERIFY(!SamInfo.IsImmutableSampler(), "Immutable samplers should never be assigned space in the cache"); - - VERIFY(DstSamInfo.Attribs.IsValidBindPoint(), "Sampler bind point must be valid"); - VERIFY_EXPR(DstSamInfo.Attribs.BindCount == DstResInfo.Attribs.BindCount || DstSamInfo.Attribs.BindCount == 1); -#endif - } - } - } - - { - const auto SamplerCount = DstLayout.GetSamplerCount(SHADER_RESOURCE_VARIABLE_TYPE_STATIC); - VERIFY(GetSamplerCount(SHADER_RESOURCE_VARIABLE_TYPE_STATIC) == SamplerCount, - "The number of static-type samplers in the source cache (", GetSamplerCount(SHADER_RESOURCE_VARIABLE_TYPE_STATIC), - ") is not consistent with the number of static-type samplers in destination cache (", SamplerCount, ")"); - for (Uint32 s = 0; s < SamplerCount; ++s) - { - const auto& DstSamInfo = DstLayout.GetSampler(SHADER_RESOURCE_VARIABLE_TYPE_STATIC, s); - const auto& SrcSamInfo = GetSampler(SHADER_RESOURCE_VARIABLE_TYPE_STATIC, s); - VERIFY(strcmp(SrcSamInfo.Attribs.Name, DstSamInfo.Attribs.Name) == 0, "Src sampler name ('", SrcSamInfo.Attribs.Name, "') does match the dst sampler name '(", DstSamInfo.Attribs.Name, "'). This is a bug."); - VERIFY(SrcSamInfo.Attribs.IsCompatibleWith(DstSamInfo.Attribs), "Src sampler is incompatible with the dst sampler. This is a bug."); - - // Source sampler in the static resource cache is in the root table at index 3 - // (D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER = 3) - VERIFY(SrcSamInfo.RootIndex == static_cast<Uint32>(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER), "Unexpected root index for the source sampler. This is a bug."); - const auto& SrcRootTable = SrcCache.GetRootTable(SrcSamInfo.RootIndex); - auto& DstRootTable = DstCache.GetRootTable(DstSamInfo.RootIndex); - for (Uint32 ArrInd = 0; ArrInd < DstSamInfo.Attribs.BindCount; ++ArrInd) - { - const auto& SrcSampler = SrcRootTable.GetResource(SrcSamInfo.OffsetFromTableStart + ArrInd, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, GetShaderType()); - if (!SrcSampler.pObject) - LOG_ERROR_MESSAGE("No sampler assigned to static shader variable '", DstSamInfo.Attribs.GetPrintName(ArrInd), "' in shader '", GetShaderName(), "'."); - auto& DstSampler = DstRootTable.GetResource(DstSamInfo.OffsetFromTableStart + ArrInd, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, GetShaderType()); - - if (DstSampler.pObject != SrcSampler.pObject) - { - DEV_CHECK_ERR(DstSampler.pObject == nullptr, "Static-type sampler has already been initialized, and the sampler to be assigned from the shader does not match previously assigned resource"); - - DstSampler.pObject = SrcSampler.pObject; - DstSampler.Type = SrcSampler.Type; - DstSampler.CPUDescriptorHandle = SrcSampler.CPUDescriptorHandle; - - auto ShdrVisibleSamplerHeapCPUDescriptorHandle = - DstCache.GetShaderVisibleTableCPUDescriptorHandle<D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER>( - DstSamInfo.RootIndex, - DstSamInfo.OffsetFromTableStart + ArrInd); - VERIFY_EXPR(ShdrVisibleSamplerHeapCPUDescriptorHandle.ptr != 0); - if (ShdrVisibleSamplerHeapCPUDescriptorHandle.ptr != 0) - { - m_pd3d12Device->CopyDescriptorsSimple(1, ShdrVisibleSamplerHeapCPUDescriptorHandle, SrcSampler.CPUDescriptorHandle, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); - } - } - else - { - VERIFY_EXPR(DstSampler.pObject == SrcSampler.pObject); - VERIFY_EXPR(DstSampler.Type == SrcSampler.Type); - VERIFY_EXPR(DstSampler.CPUDescriptorHandle.ptr == SrcSampler.CPUDescriptorHandle.ptr); - } - } - } - } -} - - -#ifdef DILIGENT_DEVELOPMENT -bool ShaderResourceLayoutD3D12::dvpVerifyBindings(const ShaderResourceCacheD3D12& ResourceCache) const -{ - bool BindingsOK = true; - for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1)) - { - for (Uint32 r = 0; r < GetCbvSrvUavCount(VarType); ++r) - { - const auto& res = GetSrvCbvUav(VarType, r); - VERIFY(res.GetVariableType() == VarType, "Unexpected variable type"); - - for (Uint32 ArrInd = 0; ArrInd < res.Attribs.BindCount; ++ArrInd) - { - const auto& CachedRes = ResourceCache.GetRootTable(res.RootIndex).GetResource(res.OffsetFromTableStart + ArrInd, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, GetShaderType()); - if (CachedRes.pObject) - VERIFY(CachedRes.Type == res.GetResType(), "Inconsistent cached resource types"); - else - VERIFY(CachedRes.Type == CachedResourceType::Unknown, "Unexpected cached resource types"); - - if (!CachedRes.pObject || - // Dynamic buffers do not have CPU descriptor handle as they do not keep D3D12 buffer, and space is allocated from the GPU ring buffer - CachedRes.CPUDescriptorHandle.ptr == 0 && !(CachedRes.Type == CachedResourceType::CBV && CachedRes.pObject.RawPtr<const BufferD3D12Impl>()->GetDesc().Usage == USAGE_DYNAMIC)) - { - LOG_ERROR_MESSAGE("No resource is bound to ", GetShaderVariableTypeLiteralName(res.GetVariableType()), " variable '", res.Attribs.GetPrintName(ArrInd), "' in shader '", GetShaderName(), "'"); - BindingsOK = false; - } - - if (res.Attribs.BindCount > 1 && res.Attribs.IsCombinedWithSampler()) - { - // Verify that if single sampler is used for all texture array elements, all samplers set in the resource views are consistent - const auto& SamInfo = GetAssignedSampler(res); - if (SamInfo.Attribs.BindCount == 1) - { - const auto& CachedSampler = ResourceCache.GetRootTable(SamInfo.RootIndex).GetResource(SamInfo.OffsetFromTableStart, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, GetShaderType()); - // Conversion must always succeed as the type is verified when resource is bound to the variable - if (const auto* pTexView = CachedRes.pObject.RawPtr<const TextureViewD3D12Impl>()) - { - const auto* pSampler = pTexView->GetSampler(); - if (pSampler != nullptr && CachedSampler.pObject != nullptr && CachedSampler.pObject != pSampler) - { - LOG_ERROR_MESSAGE("All elements of texture array '", res.Attribs.Name, "' in shader '", GetShaderName(), "' share the same sampler. However, the sampler set in view for element ", ArrInd, " does not match bound sampler. This may cause incorrect behavior on GL platform."); - } - } - } - } - -# ifdef DILIGENT_DEBUG - { - const auto ShdrVisibleHeapCPUDescriptorHandle = ResourceCache.GetShaderVisibleTableCPUDescriptorHandle<D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV>(res.RootIndex, res.OffsetFromTableStart + ArrInd); - if (ResourceCache.DbgGetContentType() == ShaderResourceCacheD3D12::DbgCacheContentType::StaticShaderResources) - { - VERIFY(ShdrVisibleHeapCPUDescriptorHandle.ptr == 0, "Static shader resources of a shader should not be assigned shader visible descriptor space"); - } - else if (ResourceCache.DbgGetContentType() == ShaderResourceCacheD3D12::DbgCacheContentType::SRBResources) - { - if (res.GetResType() == CachedResourceType::CBV && res.Attribs.BindCount == 1) - { - VERIFY(ShdrVisibleHeapCPUDescriptorHandle.ptr == 0, "Non-array constant buffers are bound as root views and should not be assigned shader visible descriptor space"); - } - else - { - if (res.GetVariableType() == SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) - VERIFY(ShdrVisibleHeapCPUDescriptorHandle.ptr == 0, "Dynamic resources of a shader resource binding should be assigned shader visible descriptor space at every draw call"); - else - VERIFY(ShdrVisibleHeapCPUDescriptorHandle.ptr != 0, "Non-dynamics resources of a shader resource binding must be assigned shader visible descriptor space"); - } - } - else - { - UNEXPECTED("Unknown content type"); - } - } -# endif - } - - if (res.Attribs.IsCombinedWithSampler()) - { - VERIFY(res.GetResType() == CachedResourceType::TexSRV, "Sampler can only be assigned to a texture SRV"); - const auto& SamInfo = GetAssignedSampler(res); - //VERIFY(!SamInfo.IsImmutableSampler(), "Immutable samplers should never be assigned space in the cache" ); - VERIFY(SamInfo.Attribs.IsValidBindPoint(), "Sampler bind point must be valid"); - - for (Uint32 ArrInd = 0; ArrInd < SamInfo.Attribs.BindCount; ++ArrInd) - { - const auto& CachedSampler = ResourceCache.GetRootTable(SamInfo.RootIndex).GetResource(SamInfo.OffsetFromTableStart + ArrInd, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, GetShaderType()); - if (CachedSampler.pObject) - VERIFY(CachedSampler.Type == CachedResourceType::Sampler, "Incorrect cached sampler type"); - else - VERIFY(CachedSampler.Type == CachedResourceType::Unknown, "Unexpected cached sampler type"); - if (!CachedSampler.pObject || CachedSampler.CPUDescriptorHandle.ptr == 0) - { - LOG_ERROR_MESSAGE("No sampler is assigned to texture variable '", res.Attribs.GetPrintName(ArrInd), "' in shader '", GetShaderName(), "'"); - BindingsOK = false; - } - -# ifdef DILIGENT_DEBUG - { - const auto ShdrVisibleHeapCPUDescriptorHandle = ResourceCache.GetShaderVisibleTableCPUDescriptorHandle<D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER>(SamInfo.RootIndex, SamInfo.OffsetFromTableStart + ArrInd); - if (ResourceCache.DbgGetContentType() == ShaderResourceCacheD3D12::DbgCacheContentType::StaticShaderResources) - { - VERIFY(ShdrVisibleHeapCPUDescriptorHandle.ptr == 0, "Static shader resources of a shader should not be assigned shader visible descriptor space"); - } - else if (ResourceCache.DbgGetContentType() == ShaderResourceCacheD3D12::DbgCacheContentType::SRBResources) - { - if (SamInfo.GetVariableType() == SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) - VERIFY(ShdrVisibleHeapCPUDescriptorHandle.ptr == 0, "Dynamic resources of a shader resource binding should be assigned shader visible descriptor space at every draw call"); - else - VERIFY(ShdrVisibleHeapCPUDescriptorHandle.ptr != 0, "Non-dynamics resources of a shader resource binding must be assigned shader visible descriptor space"); - } - else - { - UNEXPECTED("Unknown content type"); - } - } -# endif - } - } - } - - for (Uint32 s = 0; s < GetSamplerCount(VarType); ++s) - { - const auto& sam = GetSampler(VarType, s); - VERIFY(sam.GetVariableType() == VarType, "Unexpected sampler variable type"); - - for (Uint32 ArrInd = 0; ArrInd < sam.Attribs.BindCount; ++ArrInd) - { - const auto& CachedSampler = ResourceCache.GetRootTable(sam.RootIndex).GetResource(sam.OffsetFromTableStart + ArrInd, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, GetShaderType()); - if (CachedSampler.pObject) - VERIFY(CachedSampler.Type == CachedResourceType::Sampler, "Incorrect cached sampler type"); - else - VERIFY(CachedSampler.Type == CachedResourceType::Unknown, "Unexpected cached sampler type"); - if (!CachedSampler.pObject || CachedSampler.CPUDescriptorHandle.ptr == 0) - { - LOG_ERROR_MESSAGE("No sampler is bound to sampler variable '", sam.Attribs.GetPrintName(ArrInd), "' in shader '", GetShaderName(), "'"); - BindingsOK = false; - } - } - } - } - - return BindingsOK; -} -#endif - -bool ShaderResourceLayoutD3D12::IsCompatibleWith(const ShaderResourceLayoutD3D12& ResLayout) const -{ - if (GetTotalResourceCount() != ResLayout.GetTotalResourceCount()) - return false; - - for (Uint32 i = 0; i < GetTotalResourceCount(); ++i) - { - const auto& lRes = GetResource(i); - const auto& rRes = ResLayout.GetResource(i); - - if (!lRes.Attribs.IsCompatibleWith(rRes.Attribs)) - return false; - } - - return true; -} - -} // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderResourcesD3D12.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderResourcesD3D12.cpp index 9f2113de..8092e9d5 100644 --- a/Graphics/GraphicsEngineD3D12/src/ShaderResourcesD3D12.cpp +++ b/Graphics/GraphicsEngineD3D12/src/ShaderResourcesD3D12.cpp @@ -33,69 +33,9 @@ #include "ShaderBase.hpp" #include "DXCompiler.hpp" -#include "dxc/DxilContainer/DxilContainer.h" - namespace Diligent { -static bool IsDXILBytecode(ID3DBlob* pBytecodeBlob) -{ - const auto* data_begin = reinterpret_cast<const uint8_t*>(pBytecodeBlob->GetBufferPointer()); - const auto* data_end = data_begin + pBytecodeBlob->GetBufferSize(); - const auto* ptr = data_begin; - - if (ptr + sizeof(hlsl::DxilContainerHeader) > data_end) - { - // No space for the container header - return false; - } - - // A DXIL container is composed of a header, a sequence of part lengths, and a sequence of parts. - // https://github.com/microsoft/DirectXShaderCompiler/blob/master/docs/DXIL.rst#dxil-container-format - const auto& ContainerHeader = *reinterpret_cast<const hlsl::DxilContainerHeader*>(ptr); - if (ContainerHeader.HeaderFourCC != hlsl::DFCC_Container) - { - // Incorrect FourCC - return false; - } - - if (ContainerHeader.Version.Major != hlsl::DxilContainerVersionMajor) - { - LOG_WARNING_MESSAGE("Unable to parse DXIL container: the container major version is ", Uint32{ContainerHeader.Version.Major}, - " while ", Uint32{hlsl::DxilContainerVersionMajor}, " is expected"); - return false; - } - - // The header is followed by uint32_t PartOffset[PartCount]; - // The offset is to a DxilPartHeader. - ptr += sizeof(hlsl::DxilContainerHeader); - if (ptr + sizeof(uint32_t) * ContainerHeader.PartCount > data_end) - { - // No space for offsets - return false; - } - - const auto* PartOffsets = reinterpret_cast<const uint32_t*>(ptr); - for (uint32_t part = 0; part < ContainerHeader.PartCount; ++part) - { - const auto Offset = PartOffsets[part]; - if (data_begin + Offset + sizeof(hlsl::DxilPartHeader) > data_end) - { - // No space for the part header - return false; - } - - const auto& PartHeader = *reinterpret_cast<const hlsl::DxilPartHeader*>(data_begin + Offset); - if (PartHeader.PartFourCC == hlsl::DFCC_DXIL) - { - // We found DXIL part - return true; - } - } - - return false; -} - ShaderResourcesD3D12::ShaderResourcesD3D12(ID3DBlob* pShaderBytecode, const ShaderDesc& ShdrDesc, const char* CombinedSamplerSuffix, @@ -117,7 +57,7 @@ ShaderResourcesD3D12::ShaderResourcesD3D12(ID3DBlob* pShaderBytecode, }; CComPtr<ID3D12ShaderReflection> pShaderReflection; - if (IsDXILBytecode(pShaderBytecode)) + if (IsDXILBytecode(pShaderBytecode->GetBufferPointer(), pShaderBytecode->GetBufferSize())) { VERIFY(pDXCompiler != nullptr, "DXC is not initialized"); pDXCompiler->GetD3D12ShaderReflection(reinterpret_cast<IDxcBlob*>(pShaderBytecode), &pShaderReflection); diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderVariableD3D12.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderVariableD3D12.cpp index 70bbe9e4..53eb1f9b 100644 --- a/Graphics/GraphicsEngineD3D12/src/ShaderVariableD3D12.cpp +++ b/Graphics/GraphicsEngineD3D12/src/ShaderVariableD3D12.cpp @@ -29,35 +29,51 @@ #include "ShaderVariableD3D12.hpp" #include "ShaderResourceVariableBase.hpp" +#include "RenderDeviceD3D12Impl.hpp" namespace Diligent { -size_t ShaderVariableManagerD3D12::GetRequiredMemorySize(const ShaderResourceLayoutD3D12& Layout, - const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, - Uint32 NumAllowedTypes, - Uint32& NumVariables) +size_t ShaderVariableManagerD3D12::GetRequiredMemorySize(const PipelineResourceSignatureD3D12Impl& Signature, + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes, + SHADER_TYPE ShaderType, + Uint32& NumVariables) { - NumVariables = 0; - Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); + NumVariables = 0; + const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); + const bool UsingSeparateSamplers = Signature.IsUsingSeparateSamplers(); + for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1)) { if (IsAllowedType(VarType, AllowedTypeBits)) { - NumVariables += Layout.GetCbvSrvUavCount(VarType); - if (Layout.IsUsingSeparateSamplers()) - NumVariables += Layout.GetSamplerCount(VarType); + const auto ResIdxRange = Signature.GetResourceIndexRange(VarType); + for (Uint32 r = ResIdxRange.first; r < ResIdxRange.second; ++r) + { + const auto& Res = Signature.GetResourceDesc(r); + VERIFY_EXPR(Res.VarType == VarType); + + if (!(Res.ShaderStages & ShaderType)) + continue; + + if (!UsingSeparateSamplers && Res.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER) + continue; + + ++NumVariables; + } } } return NumVariables * sizeof(ShaderVariableD3D12Impl); } -// Creates shader variable for every resource from SrcLayout whose type is one AllowedVarTypes -void ShaderVariableManagerD3D12::Initialize(const ShaderResourceLayoutD3D12& SrcLayout, - IMemoryAllocator& Allocator, - const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, - Uint32 NumAllowedTypes) +// Creates shader variable for every resource from Signature whose type is one AllowedVarTypes +void ShaderVariableManagerD3D12::Initialize(const PipelineResourceSignatureD3D12Impl& Signature, + IMemoryAllocator& Allocator, + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes, + SHADER_TYPE ShaderType) { #ifdef DILIGENT_DEBUG m_pDbgAllocator = &Allocator; @@ -65,7 +81,7 @@ void ShaderVariableManagerD3D12::Initialize(const ShaderResourceLayoutD3D12& const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); VERIFY_EXPR(m_NumVariables == 0); - auto MemSize = GetRequiredMemorySize(SrcLayout, AllowedVarTypes, NumAllowedTypes, m_NumVariables); + auto MemSize = GetRequiredMemorySize(Signature, AllowedVarTypes, NumAllowedTypes, ShaderType, m_NumVariables); if (m_NumVariables == 0) return; @@ -73,32 +89,33 @@ void ShaderVariableManagerD3D12::Initialize(const ShaderResourceLayoutD3D12& auto* pRawMem = ALLOCATE_RAW(Allocator, "Raw memory buffer for shader variables", MemSize); m_pVariables = reinterpret_cast<ShaderVariableD3D12Impl*>(pRawMem); - Uint32 VarInd = 0; + Uint32 VarInd = 0; + const bool UsingSeparateSamplers = Signature.IsUsingSeparateSamplers(); + for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1)) { - if (!IsAllowedType(VarType, AllowedTypeBits)) - continue; - - Uint32 NumResources = SrcLayout.GetCbvSrvUavCount(VarType); - for (Uint32 r = 0; r < NumResources; ++r) - { - const auto& SrcRes = SrcLayout.GetSrvCbvUav(VarType, r); - ::new (m_pVariables + VarInd) ShaderVariableD3D12Impl{*this, SrcRes}; - ++VarInd; - } - - if (SrcLayout.IsUsingSeparateSamplers()) + if (IsAllowedType(VarType, AllowedTypeBits)) { - Uint32 NumSamplers = SrcLayout.GetSamplerCount(VarType); - for (Uint32 r = 0; r < NumSamplers; ++r) + const auto ResIdxRange = Signature.GetResourceIndexRange(VarType); + for (Uint32 r = ResIdxRange.first; r < ResIdxRange.second; ++r) { - const auto& SrcSampler = SrcLayout.GetSampler(VarType, r); - ::new (m_pVariables + VarInd) ShaderVariableD3D12Impl{*this, SrcSampler}; + const auto& Res = Signature.GetResourceDesc(r); + VERIFY_EXPR(Res.VarType == VarType); + + if (!(Res.ShaderStages & ShaderType)) + continue; + + if (!UsingSeparateSamplers && Res.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER) + continue; + + ::new (m_pVariables + VarInd) ShaderVariableD3D12Impl{*this, r}; ++VarInd; } } } VERIFY_EXPR(VarInd == m_NumVariables); + + m_pSignature = &Signature; } ShaderVariableManagerD3D12::~ShaderVariableManagerD3D12() @@ -124,8 +141,9 @@ ShaderVariableD3D12Impl* ShaderVariableManagerD3D12::GetVariable(const Char* Nam ShaderVariableD3D12Impl* pVar = nullptr; for (Uint32 v = 0; v < m_NumVariables; ++v) { - auto& Var = m_pVariables[v]; - if (strcmp(Var.m_Resource.Attribs.Name, Name) == 0) + auto& Var = m_pVariables[v]; + const auto& Res = Var.GetDesc(); + if (strcmp(Res.Name, Name) == 0) { pVar = &Var; break; @@ -176,31 +194,67 @@ void ShaderVariableManagerD3D12::BindResources(IResourceMapping* pResourceMappin for (Uint32 v = 0; v < m_NumVariables; ++v) { auto& Var = m_pVariables[v]; - const auto& Res = Var.m_Resource; + const auto& Res = Var.GetDesc(); - if ((Flags & (1 << Res.GetVariableType())) == 0) + if ((Flags & (1u << Res.VarType)) == 0) continue; - for (Uint32 ArrInd = 0; ArrInd < Res.Attribs.BindCount; ++ArrInd) + for (Uint32 ArrInd = 0; ArrInd < Res.ArraySize; ++ArrInd) { - if ((Flags & BIND_SHADER_RESOURCES_KEEP_EXISTING) && Res.IsBound(ArrInd, m_ResourceCache)) + if ((Flags & BIND_SHADER_RESOURCES_KEEP_EXISTING) && Var.IsBound(ArrInd)) continue; + const auto* VarName = Res.Name; RefCntAutoPtr<IDeviceObject> pObj; - VERIFY_EXPR(pResourceMapping != nullptr); - pResourceMapping->GetResource(Res.Attribs.Name, &pObj, ArrInd); + pResourceMapping->GetResource(VarName, &pObj, ArrInd); if (pObj) { - // Call non-virtual function - Res.BindResource(pObj, ArrInd, m_ResourceCache); + Var.BindResource(pObj, ArrInd); } else { - if ((Flags & BIND_SHADER_RESOURCES_VERIFY_ALL_RESOLVED) && !Res.IsBound(ArrInd, m_ResourceCache)) - LOG_ERROR_MESSAGE("Unable to bind resource to shader variable '", Res.Attribs.GetPrintName(ArrInd), "': resource is not found in the resource mapping"); + if ((Flags & BIND_SHADER_RESOURCES_VERIFY_ALL_RESOLVED) && !Var.IsBound(ArrInd)) + { + LOG_ERROR_MESSAGE("Unable to bind resource to shader variable '", + GetShaderResourcePrintName(Res, ArrInd), + "': resource is not found in the resource mapping. " + "Do not use BIND_SHADER_RESOURCES_VERIFY_ALL_RESOLVED flag to suppress the message if this is not an issue."); + } } } } } + + +void ShaderVariableD3D12Impl::Set(IDeviceObject* pObject) +{ + BindResource(pObject, 0); +} + +void ShaderVariableD3D12Impl::SetArray(IDeviceObject* const* ppObjects, Uint32 FirstElement, Uint32 NumElements) +{ + const auto& ResDesc = GetDesc(); + VerifyAndCorrectSetArrayArguments(ResDesc.Name, ResDesc.ArraySize, FirstElement, NumElements); + + for (Uint32 Elem = 0; Elem < NumElements; ++Elem) + BindResource(ppObjects[Elem], FirstElement + Elem); +} + +bool ShaderVariableD3D12Impl::IsBound(Uint32 ArrayIndex) const +{ + auto* pSignature = m_ParentManager.m_pSignature; + auto& ResourceCache = m_ParentManager.m_ResourceCache; + + return pSignature->IsBound(ArrayIndex, m_ResIndex, ResourceCache); +} + +void ShaderVariableD3D12Impl::BindResource(IDeviceObject* pObj, Uint32 ArrayIndex) const +{ + auto* pSignature = m_ParentManager.m_pSignature; + auto& ResourceCache = m_ParentManager.m_ResourceCache; + + pSignature->BindResource(pObj, ArrayIndex, m_ResIndex, ResourceCache); +} + } // namespace Diligent |
