From 9286fdcd21cfa7cdbc70a42d6bd1ea2d7b907e5e Mon Sep 17 00:00:00 2001 From: Egor Yusov Date: Mon, 1 Oct 2018 23:17:55 -0700 Subject: Reworked D3D12DynamicHeap to use release queues --- .../GraphicsEngineD3D12/include/D3D12DynamicHeap.h | 61 +++++------------ .../include/DeviceContextD3D12Impl.h | 14 ++-- .../GraphicsEngineD3D12/src/D3D12DynamicHeap.cpp | 76 +++++++++++++++++----- .../src/DeviceContextD3D12Impl.cpp | 30 +++++---- .../src/RenderDeviceD3D12Impl.cpp | 12 ++-- .../src/RenderDeviceFactoryD3D12.cpp | 4 +- 6 files changed, 108 insertions(+), 89 deletions(-) (limited to 'Graphics/GraphicsEngineD3D12') diff --git a/Graphics/GraphicsEngineD3D12/include/D3D12DynamicHeap.h b/Graphics/GraphicsEngineD3D12/include/D3D12DynamicHeap.h index 74bba43f..a7d54d27 100644 --- a/Graphics/GraphicsEngineD3D12/include/D3D12DynamicHeap.h +++ b/Graphics/GraphicsEngineD3D12/include/D3D12DynamicHeap.h @@ -26,10 +26,13 @@ #include #include #include +#include namespace Diligent { +class RenderDeviceD3D12Impl; + struct D3D12DynamicAllocation { D3D12DynamicAllocation()noexcept{} @@ -110,10 +113,10 @@ private: class D3D12DynamicMemoryManager { public: - D3D12DynamicMemoryManager(IMemoryAllocator& Allocator, - ID3D12Device* pd3d12Device, - Uint32 NumPagesToReserve, - Uint64 PageSize); + D3D12DynamicMemoryManager(IMemoryAllocator& Allocator, + RenderDeviceD3D12Impl& DeviceD3D12Impl, + Uint32 NumPagesToReserve, + Uint64 PageSize); ~D3D12DynamicMemoryManager(); D3D12DynamicMemoryManager (const D3D12DynamicMemoryManager&) = delete; @@ -121,54 +124,26 @@ public: D3D12DynamicMemoryManager& operator= (const D3D12DynamicMemoryManager&) = delete; D3D12DynamicMemoryManager& operator= ( D3D12DynamicMemoryManager&&) = delete; - void DiscardPages(std::vector& Pages, Uint64 FenceValue) - { - std::lock_guard Lock(m_StalePagesMtx); - for(auto& Page : Pages) - m_StalePages.emplace_back(FenceValue, std::move(Page)); - } - - void ReleaseStalePages(Uint64 LastCompletedFenceValue) - { - std::lock_guard AvailablePagesLock(m_AvailablePagesMtx); - std::lock_guard StalePagesLock(m_StalePagesMtx); - while (!m_StalePages.empty()) - { - auto& FirstPage = m_StalePages.front(); - if (FirstPage.FenceValue <= LastCompletedFenceValue) - { - auto PageSize = FirstPage.Page.GetSize(); - m_AvailablePages.emplace(PageSize, std::move(FirstPage.Page)); - m_StalePages.pop_front(); - } - else - break; - } - } + void ReleasePages(std::vector& Pages, Uint64 QueueMask); - void Destroy(Uint64 LastCompletedFenceValue); + void Destroy(); D3D12DynamicPage AllocatePage(Uint64 SizeInBytes); +#ifdef DEVELOPMENT + int32_t GetAllocatedPageCounter()const{return m_AllocatedPageCounter;} +#endif + private: - CComPtr m_pd3d12Device; + RenderDeviceD3D12Impl& m_DeviceD3D12Impl; std::mutex m_AvailablePagesMtx; using AvailablePagesMapElemType = std::pair; std::multimap, STDAllocatorRawMem > m_AvailablePages; - std::mutex m_StalePagesMtx; - struct StalePageInfo - { - StalePageInfo(Uint64 _FenceValue, D3D12DynamicPage&& _Page) : - FenceValue(_FenceValue), - Page (std::move(_Page)) - {} - - Uint64 FenceValue; - D3D12DynamicPage Page; - }; - std::deque > m_StalePages; +#ifdef DEVELOPMENT + std::atomic_int32_t m_AllocatedPageCounter = 0; +#endif }; @@ -189,7 +164,7 @@ public: ~D3D12DynamicHeap(); D3D12DynamicAllocation Allocate(Uint64 SizeInBytes, Uint64 Alignment, Uint64 DvpCtxFrameNumber); - void FinishFrame(Uint64 FenceValue); + void ReleaseAllocatedPages(Uint64 QueueMask); static constexpr Uint64 InvalidOffset = static_cast(-1); diff --git a/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.h b/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.h index fa9f4d2c..a6dafd81 100644 --- a/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.h +++ b/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.h @@ -30,6 +30,7 @@ #include "DeviceContextD3D12.h" #include "DeviceContextBase.h" +#include "DeviceContextNextGenBase.h" #include "GenerateMips.h" #include "BufferD3D12Impl.h" #include "TextureViewD3D12Impl.h" @@ -40,16 +41,17 @@ namespace Diligent { /// Implementation of the Diligent::IDeviceContext interface -class DeviceContextD3D12Impl final : public DeviceContextBase +class DeviceContextD3D12Impl final : public DeviceContextNextGenBase< DeviceContextBase > { public: - using TDeviceContextBase = DeviceContextBase; + using TDeviceContextBase = DeviceContextNextGenBase< DeviceContextBase >; DeviceContextD3D12Impl(IReferenceCounters* pRefCounters, class RenderDeviceD3D12Impl* pDevice, bool bIsDeferred, const EngineD3D12Attribs& Attribs, - Uint32 ContextId); + Uint32 ContextId, + Uint32 CommandQueueId); ~DeviceContextD3D12Impl(); virtual void QueryInterface( const Diligent::INTERFACE_ID &IID, IObject **ppInterface )override final; @@ -188,13 +190,8 @@ private: return m_pCurrCmdCtx; } size_t m_NumCommandsInCurCtx = 0; - const Uint32 m_NumCommandsToFlush = 192; CommandContext* m_pCurrCmdCtx = nullptr; - // The fence value that was signalled last time a command list was submitted for execution - Uint64 m_LastSubmittedFenceValue = 0; - Atomics::AtomicInt64 m_ContextFrameNumber = 0; - CComPtr m_CommittedD3D12IndexBuffer; VALUE_TYPE m_CommittedIBFormat = VT_UNDEFINED; Uint32 m_CommittedD3D12IndexDataStartOffset = 0; @@ -215,7 +212,6 @@ private: class ShaderResourceCacheD3D12 *m_pCommittedResourceCache = nullptr; FixedBlockMemoryAllocator m_CmdListAllocator; - const Uint32 m_ContextId; std::vector > > m_PendingFences; diff --git a/Graphics/GraphicsEngineD3D12/src/D3D12DynamicHeap.cpp b/Graphics/GraphicsEngineD3D12/src/D3D12DynamicHeap.cpp index 98b6a945..6103e9b1 100644 --- a/Graphics/GraphicsEngineD3D12/src/D3D12DynamicHeap.cpp +++ b/Graphics/GraphicsEngineD3D12/src/D3D12DynamicHeap.cpp @@ -70,17 +70,16 @@ D3D12DynamicPage::D3D12DynamicPage(ID3D12Device* pd3d12Device, Uint64 Size) LOG_INFO_MESSAGE("Created dynamic memory page. Size: ", FormatMemorySize(Size,2), "; GPU virtual address 0x", std::hex, m_GPUVirtualAddress); } -D3D12DynamicMemoryManager::D3D12DynamicMemoryManager(IMemoryAllocator& Allocator, - ID3D12Device* pd3d12Device, - Uint32 NumPagesToReserve, - Uint64 PageSize) : - m_pd3d12Device(pd3d12Device), - m_AvailablePages(STD_ALLOCATOR_RAW_MEM(AvailablePagesMapElemType, Allocator, "Allocator for multimap")), - m_StalePages(STD_ALLOCATOR_RAW_MEM(StalePageInfo, Allocator, "Allocator for deque")) +D3D12DynamicMemoryManager::D3D12DynamicMemoryManager(IMemoryAllocator& Allocator, + RenderDeviceD3D12Impl& DeviceD3D12Impl, + Uint32 NumPagesToReserve, + Uint64 PageSize) : + m_DeviceD3D12Impl(DeviceD3D12Impl), + m_AvailablePages(STD_ALLOCATOR_RAW_MEM(AvailablePagesMapElemType, Allocator, "Allocator for multimap")) { for(Uint32 i=0; i < NumPagesToReserve; ++i) { - D3D12DynamicPage Page(m_pd3d12Device, PageSize); + D3D12DynamicPage Page(m_DeviceD3D12Impl.GetD3D12Device(), PageSize); auto Size = Page.GetSize(); m_AvailablePages.emplace(Size, std::move(Page)); } @@ -89,6 +88,9 @@ D3D12DynamicMemoryManager::D3D12DynamicMemoryManager(IMemoryAllocator& Allocato D3D12DynamicPage D3D12DynamicMemoryManager::AllocatePage(Uint64 SizeInBytes) { std::lock_guard AvailablePagesLock(m_AvailablePagesMtx); +#ifdef DEVELOPMENT + ++m_AllocatedPageCounter; +#endif auto PageIt = m_AvailablePages.lower_bound(SizeInBytes); // Returns an iterator pointing to the first element that is not less than key if (PageIt != m_AvailablePages.end()) { @@ -99,14 +101,56 @@ D3D12DynamicPage D3D12DynamicMemoryManager::AllocatePage(Uint64 SizeInBytes) } else { - return D3D12DynamicPage{m_pd3d12Device, SizeInBytes}; + return D3D12DynamicPage{m_DeviceD3D12Impl.GetD3D12Device(), SizeInBytes}; + } +} + +void D3D12DynamicMemoryManager::ReleasePages(std::vector& Pages, Uint64 QueueMask) +{ + struct StalePage + { + D3D12DynamicPage Page; + D3D12DynamicMemoryManager* Mgr; + + StalePage(D3D12DynamicPage&& _Page, D3D12DynamicMemoryManager* _Mgr)noexcept : + Page (std::move(_Page)), + Mgr (_Mgr) + { + } + + StalePage (const StalePage&) = delete; + StalePage& operator= (const StalePage&) = delete; + StalePage& operator= ( StalePage&&) = delete; + + StalePage(StalePage&& rhs)noexcept : + Page (std::move(rhs.Page)), + Mgr (rhs.Mgr) + { + rhs.Mgr = nullptr; + } + + ~StalePage() + { + if (Mgr != nullptr) + { + std::lock_guard Lock(Mgr->m_AvailablePagesMtx); +#ifdef DEVELOPMENT + --Mgr->m_AllocatedPageCounter; +#endif + auto PageSize = Page.GetSize(); + Mgr->m_AvailablePages.emplace(PageSize, std::move(Page)); + } + } + }; + for(auto& Page : Pages) + { + m_DeviceD3D12Impl.SafeReleaseDeviceObject(StalePage{std::move(Page), this}, QueueMask); } } -void D3D12DynamicMemoryManager::Destroy(Uint64 LastCompletedFenceValue) +void D3D12DynamicMemoryManager::Destroy() { - ReleaseStalePages(LastCompletedFenceValue); - DEV_CHECK_ERR(m_StalePages.empty(), "Not all stale pages have been released and are still in use. The device must be idled before calling Destroy()"); + DEV_CHECK_ERR(m_AllocatedPageCounter == 0, m_AllocatedPageCounter, " page(s) have not been returned to the manager."); Uint64 TotalAllocatedSize = 0; for(const auto& Page : m_AvailablePages) TotalAllocatedSize += Page.second.GetSize(); @@ -114,13 +158,13 @@ void D3D12DynamicMemoryManager::Destroy(Uint64 LastCompletedFenceValue) LOG_INFO_MESSAGE("Dynamic memory manager usage stats:\n" " Total allocated memory: ", FormatMemorySize(TotalAllocatedSize, 2)); - m_StalePages.clear(); m_AvailablePages.clear(); } D3D12DynamicMemoryManager::~D3D12DynamicMemoryManager() { - VERIFY(m_AvailablePages.empty() && m_StalePages.empty(), "Not all pages are destroyed. Dynamic memory manager must be explicitly destroyed with Destroy() method"); + DEV_CHECK_ERR(m_AllocatedPageCounter == 0, m_AllocatedPageCounter, " page(s) have not been released. If there are outstanding references to the pages in release queues, the app will crash when the page is returned to the manager."); + VERIFY(m_AvailablePages.empty(), "Not all pages are destroyed. Dynamic memory manager must be explicitly destroyed with Destroy() method"); } @@ -185,9 +229,9 @@ D3D12DynamicAllocation D3D12DynamicHeap::Allocate(Uint64 SizeInBytes, Uint64 Ali return D3D12DynamicAllocation{}; } -void D3D12DynamicHeap::FinishFrame(Uint64 FenceValue) +void D3D12DynamicHeap::ReleaseAllocatedPages(Uint64 QueueMask) { - m_DynamicMemMgr.DiscardPages(m_AllocatedPages, FenceValue); + m_DynamicMemMgr.ReleasePages(m_AllocatedPages, QueueMask); m_AllocatedPages.clear(); m_CurrOffset = InvalidOffset; diff --git a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp index 494c1df9..04bfa5eb 100644 --- a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp @@ -55,17 +55,24 @@ namespace Diligent RenderDeviceD3D12Impl* pDeviceD3D12Impl, bool bIsDeferred, const EngineD3D12Attribs& Attribs, - Uint32 ContextId) : - TDeviceContextBase(pRefCounters, pDeviceD3D12Impl, bIsDeferred), + Uint32 ContextId, + Uint32 CommandQueueId) : + TDeviceContextBase + { + pRefCounters, + pDeviceD3D12Impl, + ContextId, + CommandQueueId, + bIsDeferred ? std::numeric_limits::max() : Attribs.NumCommandsToFlushCmdList, + bIsDeferred + }, m_DynamicHeap(pDeviceD3D12Impl->GetDynamicMemoryManager(), GetDynamicHeapName(bIsDeferred, ContextId), Attribs.DynamicHeapPageSize), m_NumCommandsInCurCtx(0), - m_NumCommandsToFlush(bIsDeferred ? std::numeric_limits::max() : Attribs.NumCommandsToFlushCmdList), m_pCurrCmdCtx(pDeviceD3D12Impl->AllocateCommandContext()), m_CommittedIBFormat(VT_UNDEFINED), m_CommittedD3D12IndexDataStartOffset(0), m_MipsGenerator(pDeviceD3D12Impl->GetD3D12Device()), - m_CmdListAllocator(GetRawAllocator(), sizeof(CommandListD3D12Impl), 64 ), - m_ContextId(ContextId) + m_CmdListAllocator(GetRawAllocator(), sizeof(CommandListD3D12Impl), 64 ) { auto *pd3d12Device = pDeviceD3D12Impl->GetD3D12Device(); @@ -503,7 +510,7 @@ namespace Diligent if (m_NumCommandsInCurCtx != 0) { m_pCurrCmdCtx->FlushResourceBarriers(); - m_LastSubmittedFenceValue = pDeviceD3D12Impl->CloseAndExecuteCommandContext(m_pCurrCmdCtx, true, &m_PendingFences); + auto FenceValue = pDeviceD3D12Impl->CloseAndExecuteCommandContext(m_pCurrCmdCtx, true, &m_PendingFences); m_PendingFences.clear(); } else @@ -530,9 +537,9 @@ namespace Diligent void DeviceContextD3D12Impl::FinishFrame() { - //Uint64 FenceValue = ForceRelease ? std::numeric_limits::max() : m_pDevice.RawPtr()->GetCompletedFenceValue(); - m_DynamicHeap.FinishFrame(m_LastSubmittedFenceValue); - Atomics::AtomicIncrement(m_ContextFrameNumber); + VERIFY_EXPR(m_bIsDeferred || m_SubmittedBuffersCmdQueueMask == (Uint64{1}< pDeferredCtx; pCmdListD3D12->Close(pCmdContext, pDeferredCtx); - pDeferredCtx->m_LastSubmittedFenceValue = - m_pDevice.RawPtr()->CloseAndExecuteCommandContext(pCmdContext, true, nullptr); + auto FenceValue = m_pDevice.RawPtr()->CloseAndExecuteCommandContext(pCmdContext, true, nullptr); + // Set the bit in the deferred context cmd queue mask corresponding to cmd queue of this context + pDeferredCtx->m_SubmittedBuffersCmdQueueMask |= Uint64{1} << m_CommandQueueId; } void DeviceContextD3D12Impl::SignalFence(IFence* pFence, Uint64 Value) diff --git a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp index 792ad326..993f1ac2 100644 --- a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp @@ -83,7 +83,7 @@ RenderDeviceD3D12Impl :: RenderDeviceD3D12Impl(IReferenceCounters* pRef }, m_ContextPool(STD_ALLOCATOR_RAW_MEM(ContextPoolElemType, GetRawAllocator(), "Allocator for vector>")), m_AvailableContexts(STD_ALLOCATOR_RAW_MEM(CommandContext*, GetRawAllocator(), "Allocator for vector")), - m_DynamicMemoryManager(GetRawAllocator(), m_pd3d12Device, CreationAttribs.NumDynamicHeapPagesToReserve, CreationAttribs.DynamicHeapPageSize) + m_DynamicMemoryManager(GetRawAllocator(), *this, CreationAttribs.NumDynamicHeapPagesToReserve, CreationAttribs.DynamicHeapPageSize) { m_DeviceCaps.DevType = DeviceType::D3D12; m_DeviceCaps.MajorVersion = 12; @@ -104,8 +104,8 @@ RenderDeviceD3D12Impl::~RenderDeviceD3D12Impl() // release queues FinishFrame(true); - // TODO: Rework - m_DynamicMemoryManager.Destroy(GetCompletedFenceValue(0)); + DEV_CHECK_ERR(m_DynamicMemoryManager.GetAllocatedPageCounter() == 0, "All allocated dynamic pages must have been returned to the manager at this point."); + m_DynamicMemoryManager.Destroy(); m_ContextPool.clear(); DestroyCommandQueues(); @@ -204,6 +204,7 @@ void RenderDeviceD3D12Impl::IdleGPU(bool ReleaseStaleObjects) void RenderDeviceD3D12Impl::FinishFrame(bool ReleaseAllResources) { + // TODO: remove { if (auto pImmediateCtx = m_wpImmediateContext.Lock()) { @@ -234,11 +235,6 @@ void RenderDeviceD3D12Impl::FinishFrame(bool ReleaseAllResources) PurgeReleaseQueues(ReleaseAllResources); - // Dynamic memory is used to update resource contents as well as to allocate - // space for dynamic resources. - // Initial resource data is uploaded using temporary one-time upload buffers - m_DynamicMemoryManager.ReleaseStalePages(CompletedFenceValue); - for(Uint32 CPUHeap=0; CPUHeap < _countof(m_CPUDescriptorHeaps); ++CPUHeap) { // This is OK if other thread disposes descriptor heap allocation at this time diff --git a/Graphics/GraphicsEngineD3D12/src/RenderDeviceFactoryD3D12.cpp b/Graphics/GraphicsEngineD3D12/src/RenderDeviceFactoryD3D12.cpp index 4dc46ff0..c79679fc 100644 --- a/Graphics/GraphicsEngineD3D12/src/RenderDeviceFactoryD3D12.cpp +++ b/Graphics/GraphicsEngineD3D12/src/RenderDeviceFactoryD3D12.cpp @@ -309,7 +309,7 @@ void EngineFactoryD3D12Impl::AttachToD3D12Device(void* pd3d1 RenderDeviceD3D12Impl *pRenderDeviceD3D12( NEW_RC_OBJ(RawMemAllocator, "RenderDeviceD3D12Impl instance", RenderDeviceD3D12Impl)(RawMemAllocator, EngineAttribs, d3d12Device, CommandQueueCount, ppCommandQueues, NumDeferredContexts ) ); pRenderDeviceD3D12->QueryInterface(IID_RenderDevice, reinterpret_cast(ppDevice) ); - RefCntAutoPtr pImmediateCtxD3D12( NEW_RC_OBJ(RawMemAllocator, "DeviceContextD3D12Impl instance", DeviceContextD3D12Impl)(pRenderDeviceD3D12, false, EngineAttribs, 0) ); + RefCntAutoPtr pImmediateCtxD3D12( NEW_RC_OBJ(RawMemAllocator, "DeviceContextD3D12Impl instance", DeviceContextD3D12Impl)(pRenderDeviceD3D12, false, EngineAttribs, 0, 0) ); // We must call AddRef() (implicitly through QueryInterface()) because pRenderDeviceD3D12 will // keep a weak reference to the context pImmediateCtxD3D12->QueryInterface(IID_DeviceContext, reinterpret_cast(ppContexts) ); @@ -317,7 +317,7 @@ void EngineFactoryD3D12Impl::AttachToD3D12Device(void* pd3d1 for (Uint32 DeferredCtx = 0; DeferredCtx < NumDeferredContexts; ++DeferredCtx) { - RefCntAutoPtr pDeferredCtxD3D12( NEW_RC_OBJ(RawMemAllocator, "DeviceContextD3D12Impl instance", DeviceContextD3D12Impl)(pRenderDeviceD3D12, true, EngineAttribs, 1+DeferredCtx) ); + RefCntAutoPtr pDeferredCtxD3D12( NEW_RC_OBJ(RawMemAllocator, "DeviceContextD3D12Impl instance", DeviceContextD3D12Impl)(pRenderDeviceD3D12, true, EngineAttribs, 1+DeferredCtx, 0) ); // We must call AddRef() (implicitly through QueryInterface()) because pRenderDeviceD3D12 will // keep a weak reference to the context pDeferredCtxD3D12->QueryInterface(IID_DeviceContext, reinterpret_cast(ppContexts + 1 + DeferredCtx) ); -- cgit v1.2.3