diff options
| author | Egor Yusov <egor.yusov@gmail.com> | 2018-09-16 18:49:54 +0000 |
|---|---|---|
| committer | Egor Yusov <egor.yusov@gmail.com> | 2018-09-16 18:49:54 +0000 |
| commit | 609a63ef71c504981e38d115dafc9cbf52dfa640 (patch) | |
| tree | bfe75873dca09ead4b2a7939ff3b7703ab378088 /Graphics/GraphicsEngineD3D12 | |
| parent | Fixed one more gcc warning (diff) | |
| download | DiligentCore-609a63ef71c504981e38d115dafc9cbf52dfa640.tar.gz DiligentCore-609a63ef71c504981e38d115dafc9cbf52dfa640.zip | |
Reworked dynamic memory allocation in D3D12 backend to not rely on ring buffer (fixed https://github.com/DiligentGraphics/DiligentCore/issues/23)
Diffstat (limited to 'Graphics/GraphicsEngineD3D12')
16 files changed, 567 insertions, 473 deletions
diff --git a/Graphics/GraphicsEngineD3D12/CMakeLists.txt b/Graphics/GraphicsEngineD3D12/CMakeLists.txt index 525ae9e5..9cbba22f 100644 --- a/Graphics/GraphicsEngineD3D12/CMakeLists.txt +++ b/Graphics/GraphicsEngineD3D12/CMakeLists.txt @@ -16,7 +16,7 @@ set(INCLUDE include/d3dx12_win.h include/DescriptorHeap.h include/DeviceContextD3D12Impl.h - include/DynamicUploadHeap.h + include/D3D12DynamicHeap.h include/FenceD3D12Impl.h include/GenerateMips.h include/pch.h @@ -63,7 +63,7 @@ set(SRC src/D3D12Utils.cpp src/DescriptorHeap.cpp src/DeviceContextD3D12Impl.cpp - src/DynamicUploadHeap.cpp + src/D3D12DynamicHeap.cpp src/FenceD3D12Impl.cpp src/GenerateMips.cpp src/PipelineStateD3D12Impl.cpp diff --git a/Graphics/GraphicsEngineD3D12/include/BufferD3D12Impl.h b/Graphics/GraphicsEngineD3D12/include/BufferD3D12Impl.h index 4fb0c55d..d389242d 100644 --- a/Graphics/GraphicsEngineD3D12/include/BufferD3D12Impl.h +++ b/Graphics/GraphicsEngineD3D12/include/BufferD3D12Impl.h @@ -31,7 +31,7 @@ #include "BufferBase.h" #include "BufferViewD3D12Impl.h" #include "D3D12ResourceBase.h" -#include "DynamicUploadHeap.h" +#include "D3D12DynamicHeap.h" #include "RenderDeviceD3D12Impl.h" namespace Diligent @@ -65,29 +65,10 @@ public: virtual void Unmap( IDeviceContext *pContext, MAP_TYPE MapType, Uint32 MapFlags )override; #ifdef DEVELOPMENT - void DvpVerifyDynamicAllocation(Uint32 ContextId)const; + void DvpVerifyDynamicAllocation(class DeviceContextD3D12Impl* pCtx)const; #endif - virtual ID3D12Resource *GetD3D12Buffer(size_t &DataStartByteOffset, Uint32 ContextId)override final - { - auto *pd3d12Resource = GetD3D12Resource(); - if(pd3d12Resource != nullptr) - { - VERIFY(m_Desc.Usage != USAGE_DYNAMIC || (m_Desc.BindFlags | (BIND_SHADER_RESOURCE|BIND_UNORDERED_ACCESS)) != 0, "Expected non-dynamic buffer or a buffer with SRV or UAV bind flags"); - DataStartByteOffset = 0; - return pd3d12Resource; - } - else - { - VERIFY(m_Desc.Usage == USAGE_DYNAMIC, "Dynamic buffer is expected"); - -#ifdef DEVELOPMENT - DvpVerifyDynamicAllocation(ContextId); -#endif - DataStartByteOffset = m_DynamicData[ContextId].Offset; - return m_DynamicData[ContextId].pBuffer; - } - } + virtual ID3D12Resource* GetD3D12Buffer(size_t& DataStartByteOffset, IDeviceContext* pContext)override final; virtual void* GetNativeHandle()override final { @@ -100,20 +81,7 @@ public: virtual void SetD3D12ResourceState(D3D12_RESOURCE_STATES state)override final{ SetState(state); } - D3D12_GPU_VIRTUAL_ADDRESS GetGPUAddress(Uint32 ContextId) - { - if(m_Desc.Usage == USAGE_DYNAMIC) - { -#ifdef DEVELOPMENT - DvpVerifyDynamicAllocation(ContextId); -#endif - return m_DynamicData[ContextId].GPUAddress; - } - else - { - return GetD3D12Resource()->GetGPUVirtualAddress(); - } - } + D3D12_GPU_VIRTUAL_ADDRESS GetGPUAddress(class DeviceContextD3D12Impl* pCtx); D3D12_CPU_DESCRIPTOR_HANDLE GetCBVHandle(){return m_CBVDescriptorAllocation.GetCpuHandle();} @@ -131,7 +99,7 @@ private: friend class DeviceContextD3D12Impl; // Array of dynamic allocations for every device context - std::vector<DynamicAllocation, STDAllocatorRawMem<DynamicAllocation> > m_DynamicData; + std::vector<D3D12DynamicAllocation, STDAllocatorRawMem<D3D12DynamicAllocation> > m_DynamicData; }; } diff --git a/Graphics/GraphicsEngineD3D12/include/CommandListD3D12Impl.h b/Graphics/GraphicsEngineD3D12/include/CommandListD3D12Impl.h index 6ab4bf56..e3221fe4 100644 --- a/Graphics/GraphicsEngineD3D12/include/CommandListD3D12Impl.h +++ b/Graphics/GraphicsEngineD3D12/include/CommandListD3D12Impl.h @@ -32,34 +32,40 @@ namespace Diligent { +class DeviceContextD3D12Impl; +class CommandContext; + /// Implementation of the Diligent::ICommandList interface class CommandListD3D12Impl final : public CommandListBase<ICommandList, RenderDeviceD3D12Impl> { public: using TCommandListBase = CommandListBase<ICommandList, RenderDeviceD3D12Impl>; - CommandListD3D12Impl(IReferenceCounters* pRefCounters, - RenderDeviceD3D12Impl* pDevice, - class CommandContext* pCmdContext) : + CommandListD3D12Impl(IReferenceCounters* pRefCounters, + RenderDeviceD3D12Impl* pDevice, + DeviceContextD3D12Impl* pDeferredCtx, + CommandContext* pCmdContext) : TCommandListBase(pRefCounters, pDevice), - m_pCmdContext(pCmdContext) + m_pDeferredCtx (pDeferredCtx), + m_pCmdContext (pCmdContext) { } ~CommandListD3D12Impl() { - VERIFY(m_pCmdContext == nullptr, "Destroying command list that was never executed"); + VERIFY(m_pCmdContext == nullptr && m_pDeferredCtx == nullptr, "Destroying a command list that has not been executed"); } - CommandContext* Close() + void Close(CommandContext*& pCmdContext, RefCntAutoPtr<DeviceContextD3D12Impl>& pDeferredCtx) { - CommandContext* pCmdContext = m_pCmdContext; + pCmdContext = m_pCmdContext; m_pCmdContext = nullptr; - return pCmdContext; + pDeferredCtx = std::move(m_pDeferredCtx); } private: - CommandContext* m_pCmdContext = nullptr; + RefCntAutoPtr<DeviceContextD3D12Impl> m_pDeferredCtx; + CommandContext* m_pCmdContext = nullptr; }; } diff --git a/Graphics/GraphicsEngineD3D12/include/D3D12DynamicHeap.h b/Graphics/GraphicsEngineD3D12/include/D3D12DynamicHeap.h new file mode 100644 index 00000000..74bba43f --- /dev/null +++ b/Graphics/GraphicsEngineD3D12/include/D3D12DynamicHeap.h @@ -0,0 +1,213 @@ +/* Copyright 2015-2018 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 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * 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 + +#include <mutex> +#include <map> +#include <deque> + +namespace Diligent +{ + +struct D3D12DynamicAllocation +{ + D3D12DynamicAllocation()noexcept{} + D3D12DynamicAllocation(ID3D12Resource* pBuff, + Uint64 _Offset, + Uint64 _Size, + void* _CPUAddress, + D3D12_GPU_VIRTUAL_ADDRESS _GPUAddress +#ifdef DEVELOPMENT + , Uint64 _DvpCtxFrameNumber +#endif + )noexcept : + pBuffer (pBuff), + Offset (_Offset), + Size (_Size), + CPUAddress (_CPUAddress), + GPUAddress (_GPUAddress) +#ifdef DEVELOPMENT + , DvpCtxFrameNumber(_DvpCtxFrameNumber) +#endif + {} + + ID3D12Resource* pBuffer = nullptr; // The D3D buffer associated with this memory. + Uint64 Offset = 0; // Offset from start of buffer resource + Uint64 Size = 0; // Reserved size of this allocation + void* CPUAddress = nullptr; // The CPU-writeable address + D3D12_GPU_VIRTUAL_ADDRESS GPUAddress = 0; // The GPU-visible address +#ifdef DEVELOPMENT + Uint64 DvpCtxFrameNumber = static_cast<Uint64>(-1); +#endif +}; + + +class D3D12DynamicPage +{ +public: + D3D12DynamicPage(ID3D12Device* pd3d12Device, Uint64 Size); + + D3D12DynamicPage (const D3D12DynamicPage&) = delete; + D3D12DynamicPage ( D3D12DynamicPage&&) = default; + D3D12DynamicPage& operator= (const D3D12DynamicPage&) = delete; + D3D12DynamicPage& operator= ( D3D12DynamicPage&&) = delete; + + void* GetCPUAddress(Uint64 Offset) + { + VERIFY_EXPR(m_pd3d12Buffer); + VERIFY(Offset < GetSize(), "Offset (", Offset, ") exceeds buffer size (", GetSize(), ")"); + return reinterpret_cast<Uint8*>(m_CPUVirtualAddress) + Offset; + } + + D3D12_GPU_VIRTUAL_ADDRESS GetGPUAddress(Uint64 Offset) + { + VERIFY_EXPR(m_pd3d12Buffer); + VERIFY(Offset < GetSize(), "Offset (", Offset, ") exceeds buffer size (", GetSize(), ")"); + return m_GPUVirtualAddress + Offset; + } + + ID3D12Resource* GetD3D12Buffer() + { + return m_pd3d12Buffer; + } + + Uint64 GetSize()const + { + VERIFY_EXPR(m_pd3d12Buffer); + return m_pd3d12Buffer->GetDesc().Width; + } + + bool IsValid()const { return m_pd3d12Buffer != nullptr; } + +private: + CComPtr<ID3D12Resource> m_pd3d12Buffer; + void* m_CPUVirtualAddress = nullptr; // The CPU-writeable address + D3D12_GPU_VIRTUAL_ADDRESS m_GPUVirtualAddress = 0; // The GPU-visible address +}; + + +class D3D12DynamicMemoryManager +{ +public: + D3D12DynamicMemoryManager(IMemoryAllocator& Allocator, + ID3D12Device* pd3d12Device, + Uint32 NumPagesToReserve, + Uint64 PageSize); + ~D3D12DynamicMemoryManager(); + + D3D12DynamicMemoryManager (const D3D12DynamicMemoryManager&) = delete; + D3D12DynamicMemoryManager ( D3D12DynamicMemoryManager&&) = delete; + D3D12DynamicMemoryManager& operator= (const D3D12DynamicMemoryManager&) = delete; + D3D12DynamicMemoryManager& operator= ( D3D12DynamicMemoryManager&&) = delete; + + void DiscardPages(std::vector<D3D12DynamicPage>& Pages, Uint64 FenceValue) + { + std::lock_guard<std::mutex> Lock(m_StalePagesMtx); + for(auto& Page : Pages) + m_StalePages.emplace_back(FenceValue, std::move(Page)); + } + + void ReleaseStalePages(Uint64 LastCompletedFenceValue) + { + std::lock_guard<std::mutex> AvailablePagesLock(m_AvailablePagesMtx); + std::lock_guard<std::mutex> 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 Destroy(Uint64 LastCompletedFenceValue); + + D3D12DynamicPage AllocatePage(Uint64 SizeInBytes); + +private: + CComPtr<ID3D12Device> m_pd3d12Device; + + std::mutex m_AvailablePagesMtx; + using AvailablePagesMapElemType = std::pair<Uint64, D3D12DynamicPage>; + std::multimap<Uint64, D3D12DynamicPage, std::less<Uint64>, STDAllocatorRawMem<AvailablePagesMapElemType> > 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<StalePageInfo, STDAllocatorRawMem<StalePageInfo> > m_StalePages; +}; + + +class D3D12DynamicHeap +{ +public: + D3D12DynamicHeap(D3D12DynamicMemoryManager& DynamicMemMgr, std::string HeapName, Uint64 PageSize) : + m_DynamicMemMgr (DynamicMemMgr), + m_HeapName (std::move(HeapName)), + m_PageSize (PageSize) + {} + + D3D12DynamicHeap (const D3D12DynamicHeap&) = delete; + D3D12DynamicHeap (D3D12DynamicHeap&&) = delete; + D3D12DynamicHeap& operator= (const D3D12DynamicHeap&) = delete; + D3D12DynamicHeap& operator= (D3D12DynamicHeap&&) = delete; + + ~D3D12DynamicHeap(); + + D3D12DynamicAllocation Allocate(Uint64 SizeInBytes, Uint64 Alignment, Uint64 DvpCtxFrameNumber); + void FinishFrame(Uint64 FenceValue); + + static constexpr Uint64 InvalidOffset = static_cast<Uint64>(-1); + +private: + D3D12DynamicMemoryManager& m_DynamicMemMgr; + const std::string m_HeapName; + + std::vector<D3D12DynamicPage> m_AllocatedPages; + + const Uint64 m_PageSize; + + Uint64 m_CurrOffset = InvalidOffset; + Uint64 m_AvailableSize = 0; + + Uint64 m_CurrAllocatedSize = 0; + Uint64 m_CurrUsedSize = 0; + Uint64 m_PeakAllocatedSize = 0; + Uint64 m_PeakUsedSize = 0; +}; + +} diff --git a/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.h b/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.h index ea70fc8a..84a69462 100644 --- a/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.h +++ b/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.h @@ -34,6 +34,7 @@ #include "BufferD3D12Impl.h" #include "TextureViewD3D12Impl.h" #include "PipelineStateD3D12Impl.h" +#include "D3D12DynamicHeap.h" namespace Diligent { @@ -105,7 +106,7 @@ public: ///// Number of different shader types (Vertex, Pixel, Geometry, Domain, Hull, Compute) //static constexpr int NumShaderTypes = 6; - void UpdateBufferRegion(class BufferD3D12Impl *pBuffD3D12, struct DynamicAllocation& Allocation, Uint64 DstOffset, Uint64 NumBytes); + void UpdateBufferRegion(class BufferD3D12Impl *pBuffD3D12, D3D12DynamicAllocation& Allocation, Uint64 DstOffset, Uint64 NumBytes); void UpdateBufferRegion(class BufferD3D12Impl *pBuffD3D12, const void *pData, Uint64 DstOffset, Uint64 NumBytes); void CopyBufferRegion(class BufferD3D12Impl *pSrcBuffD3D12, class BufferD3D12Impl *pDstBuffD3D12, Uint64 SrcOffset, Uint64 DstOffset, Uint64 NumBytes); void CopyTextureRegion(class TextureD3D12Impl *pSrcTexture, Uint32 SrcSubResIndex, const D3D12_BOX* pD3D12SrcBox, @@ -147,12 +148,14 @@ public: void GenerateMips(class TextureViewD3D12Impl *pTexView); - struct DynamicAllocation AllocateDynamicSpace(size_t NumBytes, size_t Alignment); + D3D12DynamicAllocation AllocateDynamicSpace(size_t NumBytes, size_t Alignment); Uint32 GetContextId()const{return m_ContextId;} size_t GetNumCommandsInCtx()const { return m_NumCommandsInCurCtx; } + Int64 GetCurrentFrameNumber()const {return m_ContextFrameNumber; } + private: void CommitD3D12IndexBuffer(VALUE_TYPE IndexType); void CommitD3D12VertexBuffers(class GraphicsContext &GraphCtx); @@ -164,13 +167,13 @@ private: struct TextureUploadSpace { - DynamicAllocation Allocation; - Uint32 AlignedOffset = 0; - Uint32 Stride = 0; - Uint32 DepthStride = 0; - Uint32 RowSize = 0; - Uint32 RowCount = 0; - Box Region; + D3D12DynamicAllocation Allocation; + Uint32 AlignedOffset = 0; + Uint32 Stride = 0; + Uint32 DepthStride = 0; + Uint32 RowSize = 0; + Uint32 RowCount = 0; + Box Region; }; TextureUploadSpace AllocateTextureUploadSpace(TEXTURE_FORMAT TexFmt, const Box& Region); @@ -188,6 +191,10 @@ private: 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<ID3D12Resource> m_CommittedD3D12IndexBuffer; VALUE_TYPE m_CommittedIBFormat = VT_UNDEFINED; Uint32 m_CommittedD3D12IndexDataStartOffset = 0; @@ -197,7 +204,7 @@ private: CComPtr<ID3D12CommandSignature> m_pDispatchIndirectSignature; GenerateMipsHelper m_MipsGenerator; - class DynamicUploadHeap* m_pUploadHeap = nullptr; + D3D12DynamicHeap m_DynamicHeap; /// Flag indicating if currently committed D3D12 vertex buffers are up to date bool m_bCommittedD3D12VBsUpToDate = false; diff --git a/Graphics/GraphicsEngineD3D12/include/DynamicUploadHeap.h b/Graphics/GraphicsEngineD3D12/include/DynamicUploadHeap.h deleted file mode 100644 index b4e73676..00000000 --- a/Graphics/GraphicsEngineD3D12/include/DynamicUploadHeap.h +++ /dev/null @@ -1,141 +0,0 @@ -/* Copyright 2015-2018 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 - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. - * - * 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 - -#include "RingBuffer.h" - -namespace Diligent -{ - -struct DynamicAllocation -{ - DynamicAllocation()noexcept{} - DynamicAllocation(ID3D12Resource* pBuff, - size_t _Offset, - size_t _Size)noexcept : - pBuffer(pBuff), - Offset (_Offset), - Size (_Size) - {} - - //CComPtr<ID3D12Resource> pBuffer; // The D3D buffer associated with this memory. - ID3D12Resource* pBuffer = nullptr; // The D3D buffer associated with this memory. - size_t Offset = 0; // Offset from start of buffer resource - size_t Size = 0; // Reserved size of this allocation - void* CPUAddress = nullptr; // The CPU-writeable address - D3D12_GPU_VIRTUAL_ADDRESS GPUAddress = 0; // The GPU-visible address -#ifdef _DEBUG - Uint64 FrameNum = static_cast<Uint64>(-1); -#endif -}; - -class GPURingBuffer : public RingBuffer -{ -public: - GPURingBuffer(size_t MaxSize, IMemoryAllocator &Allocator, ID3D12Device *pd3d12Device, bool AllowCPUAccess); - - GPURingBuffer(GPURingBuffer&& rhs)noexcept : - RingBuffer (std::move(rhs)), - m_CpuVirtualAddress (rhs.m_CpuVirtualAddress), - m_GpuVirtualAddress (rhs.m_GpuVirtualAddress), - m_pBuffer (std::move(rhs.m_pBuffer)) - { - rhs.m_CpuVirtualAddress = nullptr; - rhs.m_GpuVirtualAddress = 0; - rhs.m_pBuffer.Release(); - } - - GPURingBuffer& operator =(GPURingBuffer&& rhs)noexcept - { - Destroy(); - - static_cast<RingBuffer&>(*this) = std::move(rhs); - m_CpuVirtualAddress = rhs.m_CpuVirtualAddress; - m_GpuVirtualAddress = rhs.m_GpuVirtualAddress; - m_pBuffer = std::move(rhs.m_pBuffer); - - rhs.m_CpuVirtualAddress = 0; - rhs.m_GpuVirtualAddress = 0; - - return *this; - } - - ~GPURingBuffer(); - - DynamicAllocation Allocate(size_t SizeInBytes, size_t Alignment) - { - auto Offset = RingBuffer::Allocate(SizeInBytes, Alignment); - if (Offset != RingBuffer::InvalidOffset) - { - DynamicAllocation DynAlloc(m_pBuffer, Offset, SizeInBytes); - DynAlloc.GPUAddress = m_GpuVirtualAddress + Offset; - DynAlloc.CPUAddress = m_CpuVirtualAddress; - if(DynAlloc.CPUAddress) - DynAlloc.CPUAddress = reinterpret_cast<char*>(DynAlloc.CPUAddress) + Offset; - return DynAlloc; - } - else - { - return DynamicAllocation(nullptr, 0, 0); - } - } - - GPURingBuffer(const GPURingBuffer&) = delete; - GPURingBuffer& operator =(GPURingBuffer&) = delete; - -private: - void Destroy(); - - void* m_CpuVirtualAddress; - D3D12_GPU_VIRTUAL_ADDRESS m_GpuVirtualAddress; - CComPtr<ID3D12Resource> m_pBuffer; -}; - -class DynamicUploadHeap -{ -public: - - DynamicUploadHeap(IMemoryAllocator &Allocator, bool bIsCPUAccessible, class RenderDeviceD3D12Impl* pDevice, size_t InitialSize); - - DynamicUploadHeap (const DynamicUploadHeap&)= delete; - DynamicUploadHeap (DynamicUploadHeap&&) = delete; - DynamicUploadHeap& operator=(const DynamicUploadHeap&)= delete; - DynamicUploadHeap& operator=(DynamicUploadHeap&&) = delete; - - DynamicAllocation Allocate( size_t SizeInBytes, size_t Alignment); - - void FinishFrame(Uint64 FenceValue, Uint64 LastCompletedFenceValue); - -private: - const bool m_bIsCPUAccessible; - // When a chunk of dynamic memory is requested, the heap first tries to allocate the memory in the largest GPU buffer. - // If allocation fails, a new ring buffer is created that provides enough space and requests memory from that buffer. - // Only the largest buffer is used for allocation and all other buffers are released when GPU is done with corresponding frames - std::vector<GPURingBuffer, STDAllocatorRawMem<GPURingBuffer> > m_RingBuffers; - IMemoryAllocator &m_Allocator; - RenderDeviceD3D12Impl* m_pDeviceD3D12 = nullptr; - //std::mutex m_Mutex; -}; - -} diff --git a/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.h b/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.h index 8e63405e..cd61ad3b 100644 --- a/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.h +++ b/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.h @@ -31,7 +31,7 @@ #include "DescriptorHeap.h" #include "CommandListManager.h" #include "CommandContext.h" -#include "DynamicUploadHeap.h" +#include "D3D12DynamicHeap.h" #include "Atomics.h" #include "CommandQueueD3D12.h" #include "ResourceReleaseQueue.h" @@ -92,15 +92,14 @@ public: void IdleGPU(bool ReleaseStaleObjects); CommandContext* AllocateCommandContext(const Char *ID = ""); - void CloseAndExecuteCommandContext(CommandContext *pCtx, bool DiscardStaleObjects, std::vector<std::pair<Uint64, RefCntAutoPtr<IFence> > >* pSignalFences); + Uint64 CloseAndExecuteCommandContext(CommandContext *pCtx, bool DiscardStaleObjects, std::vector<std::pair<Uint64, RefCntAutoPtr<IFence> > >* pSignalFences); void DisposeCommandContext(CommandContext*); void SafeReleaseD3D12Object(ID3D12Object* pObj); void FinishFrame(bool ReleaseAllResources); virtual void FinishFrame()override final { FinishFrame(false); } - DynamicUploadHeap* RequestUploadHeap(); - void ReleaseUploadHeap(DynamicUploadHeap* pUploadHeap); + D3D12DynamicMemoryManager& GetDynamicMemoryManager() {return m_DynamicMemoryManager;} private: virtual void TestTextureFormat( TEXTURE_FORMAT TexFormat )override final; @@ -158,11 +157,9 @@ private: std::deque<CommandContext*, STDAllocatorRawMem<CommandContext*> > m_AvailableContexts; std::mutex m_ContextAllocationMutex; - std::mutex m_UploadHeapMutex; - typedef std::unique_ptr<DynamicUploadHeap, STDDeleterRawMem<DynamicUploadHeap> > UploadHeapPoolElemType; - std::vector< UploadHeapPoolElemType, STDAllocatorRawMem<UploadHeapPoolElemType> > m_UploadHeaps; - ResourceReleaseQueue<StaticStaleResourceWrapper<CComPtr<ID3D12Object>>> m_ReleaseQueue; + + D3D12DynamicMemoryManager m_DynamicMemoryManager; }; } diff --git a/Graphics/GraphicsEngineD3D12/include/RootSignature.h b/Graphics/GraphicsEngineD3D12/include/RootSignature.h index 132f4675..66e6002f 100644 --- a/Graphics/GraphicsEngineD3D12/include/RootSignature.h +++ b/Graphics/GraphicsEngineD3D12/include/RootSignature.h @@ -322,10 +322,10 @@ public: void TransitionResources(ShaderResourceCacheD3D12& ResourceCache, class CommandContext& Ctx)const; - void CommitRootViews(ShaderResourceCacheD3D12& ResourceCache, - class CommandContext& Ctx, - bool IsCompute, - Uint32 ContextId)const; + void CommitRootViews(ShaderResourceCacheD3D12& ResourceCache, + class CommandContext& Ctx, + bool IsCompute, + class DeviceContextD3D12Impl* pCtx)const; Uint32 GetTotalSrvCbvUavSlots(SHADER_VARIABLE_TYPE VarType)const { diff --git a/Graphics/GraphicsEngineD3D12/interface/BufferD3D12.h b/Graphics/GraphicsEngineD3D12/interface/BufferD3D12.h index 7ed44894..d4741e01 100644 --- a/Graphics/GraphicsEngineD3D12/interface/BufferD3D12.h +++ b/Graphics/GraphicsEngineD3D12/interface/BufferD3D12.h @@ -48,8 +48,8 @@ public: /// to the start of the data. This parameter /// is required for dynamic buffers, which are /// suballocated in a dynamic upload heap - /// \param [in] ContextId - Id of the context within which address of the buffer is requested. - virtual ID3D12Resource* GetD3D12Buffer(size_t &DataStartByteOffset, Uint32 ContextId) = 0; + /// \param [in] pContext - Device context within which address of the buffer is requested. + virtual ID3D12Resource* GetD3D12Buffer(size_t& DataStartByteOffset, IDeviceContext* pContext) = 0; /// Sets the buffer usage state diff --git a/Graphics/GraphicsEngineD3D12/src/BufferD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/BufferD3D12Impl.cpp index 9427c271..37c8f1fb 100644 --- a/Graphics/GraphicsEngineD3D12/src/BufferD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/BufferD3D12Impl.cpp @@ -53,14 +53,14 @@ BufferD3D12Impl :: BufferD3D12Impl(IReferenceCounters* pRefCounters, { 1 + pRenderDeviceD3D12->GetNumDeferredContexts(), std::make_pair(static_cast<MAP_TYPE>(-1), static_cast<Uint32>(-1)), - STD_ALLOCATOR_RAW_MEM(DynamicAllocation, GetRawAllocator(), "Allocator for vector<pair<MAP_TYPE,Uint32>>") + STD_ALLOCATOR_RAW_MEM(D3D12DynamicAllocation, GetRawAllocator(), "Allocator for vector<pair<MAP_TYPE,Uint32>>") }, #endif m_DynamicData { BuffDesc.Usage == USAGE_DYNAMIC ? (1 + pRenderDeviceD3D12->GetNumDeferredContexts()) : 0, - DynamicAllocation(), - STD_ALLOCATOR_RAW_MEM(DynamicAllocation, GetRawAllocator(), "Allocator for vector<DynamicAllocation>") + D3D12DynamicAllocation{}, + STD_ALLOCATOR_RAW_MEM(D3D12DynamicAllocation, GetRawAllocator(), "Allocator for vector<DynamicAllocation>") } { #define LOG_BUFFER_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Buffer \"", BuffDesc.Name ? BuffDesc.Name : "", "\": ", ##__VA_ARGS__); @@ -271,13 +271,13 @@ BufferD3D12Impl :: BufferD3D12Impl(IReferenceCounters* pRefCounters, false }, #ifdef _DEBUG - m_DbgMapType(1 + pRenderDeviceD3D12->GetNumDeferredContexts(), std::make_pair(static_cast<MAP_TYPE>(-1), static_cast<Uint32>(-1)), STD_ALLOCATOR_RAW_MEM(DynamicAllocation, GetRawAllocator(), "Allocator for vector<pair<MAP_TYPE,Uint32>>")), + m_DbgMapType(1 + pRenderDeviceD3D12->GetNumDeferredContexts(), std::make_pair(static_cast<MAP_TYPE>(-1), static_cast<Uint32>(-1)), STD_ALLOCATOR_RAW_MEM(D3D12DynamicAllocation, GetRawAllocator(), "Allocator for vector<pair<MAP_TYPE,Uint32>>")), #endif m_DynamicData { BuffDesc.Usage == USAGE_DYNAMIC ? (1 + pRenderDeviceD3D12->GetNumDeferredContexts()) : 0, - DynamicAllocation(), - STD_ALLOCATOR_RAW_MEM(DynamicAllocation, GetRawAllocator(), "Allocator for vector<DynamicAllocation>") + D3D12DynamicAllocation{}, + STD_ALLOCATOR_RAW_MEM(D3D12DynamicAllocation, GetRawAllocator(), "Allocator for vector<DynamicAllocation>") } { m_pd3d12Resource = pd3d12Buffer; @@ -496,12 +496,51 @@ void BufferD3D12Impl::CreateCBV(D3D12_CPU_DESCRIPTOR_HANDLE CBVDescriptor) pDeviceD3D12->CreateConstantBufferView( &D3D12_CBVDesc, CBVDescriptor ); } +ID3D12Resource* BufferD3D12Impl::GetD3D12Buffer(size_t& DataStartByteOffset, IDeviceContext* pContext) +{ + auto* pd3d12Resource = GetD3D12Resource(); + if(pd3d12Resource != nullptr) + { + VERIFY(m_Desc.Usage != USAGE_DYNAMIC || (m_Desc.BindFlags | (BIND_SHADER_RESOURCE|BIND_UNORDERED_ACCESS)) != 0, "Expected non-dynamic buffer or a buffer with SRV or UAV bind flags"); + DataStartByteOffset = 0; + return pd3d12Resource; + } + else + { + VERIFY(m_Desc.Usage == USAGE_DYNAMIC, "Dynamic buffer is expected"); + auto* pCtxD3D12 = ValidatedCast<DeviceContextD3D12Impl>(pContext); +#ifdef DEVELOPMENT + DvpVerifyDynamicAllocation(pCtxD3D12); +#endif + auto ContextId = pCtxD3D12->GetContextId(); + DataStartByteOffset = m_DynamicData[ContextId].Offset; + return m_DynamicData[ContextId].pBuffer; + } +} + +D3D12_GPU_VIRTUAL_ADDRESS BufferD3D12Impl::GetGPUAddress(class DeviceContextD3D12Impl* pCtx) +{ + if(m_Desc.Usage == USAGE_DYNAMIC) + { +#ifdef DEVELOPMENT + DvpVerifyDynamicAllocation(pCtx); +#endif + Uint32 ContextId = pCtx->GetContextId(); + return m_DynamicData[ContextId].GPUAddress; + } + else + { + return GetD3D12Resource()->GetGPUVirtualAddress(); + } +} + #ifdef DEVELOPMENT -void BufferD3D12Impl::DvpVerifyDynamicAllocation(Uint32 ContextId)const +void BufferD3D12Impl::DvpVerifyDynamicAllocation(DeviceContextD3D12Impl* pCtx)const { - auto CurrentFrame = ValidatedCast<RenderDeviceD3D12Impl>(GetDevice())->GetCurrentFrameNumber(); + auto ContextId = pCtx->GetContextId(); + auto CurrentFrame = pCtx->GetCurrentFrameNumber(); DEV_CHECK_ERR(m_DynamicData[ContextId].GPUAddress != 0, "Dynamic buffer '", m_Desc.Name, "' has not been mapped before its first use. Context Id: ", ContextId, ". Note: memory for dynamic buffers is allocated when a buffer is mapped."); - DEV_CHECK_ERR(m_DynamicData[ContextId].FrameNum == CurrentFrame, "Dynamic allocation of dynamic buffer '", m_Desc.Name, "' in frame ", CurrentFrame, " is out-of-date. Note: contents of all dynamic resources is discarded at the end of every frame. A buffer must be mapped before its first use in any frame."); + DEV_CHECK_ERR(m_DynamicData[ContextId].DvpCtxFrameNumber == static_cast<Uint64>(CurrentFrame), "Dynamic allocation of dynamic buffer '", m_Desc.Name, "' in frame ", CurrentFrame, " is out-of-date. Note: contents of all dynamic resources is discarded at the end of every frame. A buffer must be mapped before its first use in any frame."); VERIFY(GetState() == D3D12_RESOURCE_STATE_GENERIC_READ, "Dynamic buffers are expected to always be in D3D12_RESOURCE_STATE_GENERIC_READ state"); } #endif diff --git a/Graphics/GraphicsEngineD3D12/src/D3D12DynamicHeap.cpp b/Graphics/GraphicsEngineD3D12/src/D3D12DynamicHeap.cpp new file mode 100644 index 00000000..98b6a945 --- /dev/null +++ b/Graphics/GraphicsEngineD3D12/src/D3D12DynamicHeap.cpp @@ -0,0 +1,199 @@ +/* Copyright 2015-2018 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 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * 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 "D3D12DynamicHeap.h" +#include "RenderDeviceD3D12Impl.h" + +namespace Diligent +{ + +D3D12DynamicPage::D3D12DynamicPage(ID3D12Device* pd3d12Device, Uint64 Size) +{ + D3D12_HEAP_PROPERTIES HeapProps; + HeapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + HeapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + HeapProps.CreationNodeMask = 1; + HeapProps.VisibleNodeMask = 1; + + D3D12_RESOURCE_DESC ResourceDesc; + ResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + ResourceDesc.Alignment = 0; + ResourceDesc.Height = 1; + ResourceDesc.DepthOrArraySize = 1; + ResourceDesc.MipLevels = 1; + ResourceDesc.Format = DXGI_FORMAT_UNKNOWN; + ResourceDesc.SampleDesc.Count = 1; + ResourceDesc.SampleDesc.Quality = 0; + ResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + + D3D12_RESOURCE_STATES DefaultUsage = D3D12_RESOURCE_STATE_GENERIC_READ; + HeapProps.Type = D3D12_HEAP_TYPE_UPLOAD; + ResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE; + DefaultUsage = D3D12_RESOURCE_STATE_GENERIC_READ; + ResourceDesc.Width = Size; + + auto hr = pd3d12Device->CreateCommittedResource(&HeapProps, D3D12_HEAP_FLAG_NONE, &ResourceDesc, + DefaultUsage, nullptr, __uuidof(m_pd3d12Buffer), reinterpret_cast<void**>(static_cast<ID3D12Resource**>(&m_pd3d12Buffer)) ); + if(FAILED(hr)) + { + LOG_D3D_ERROR(hr, "Failed to create dynamic page"); + return; + } + + m_pd3d12Buffer->SetName(L"Dynamic memory page"); + + m_GPUVirtualAddress = m_pd3d12Buffer->GetGPUVirtualAddress(); + + m_pd3d12Buffer->Map(0, nullptr, &m_CPUVirtualAddress); + + 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<AvailablePagesMapElemType>")), + m_StalePages(STD_ALLOCATOR_RAW_MEM(StalePageInfo, Allocator, "Allocator for deque<StalePageInfo>")) +{ + for(Uint32 i=0; i < NumPagesToReserve; ++i) + { + D3D12DynamicPage Page(m_pd3d12Device, PageSize); + auto Size = Page.GetSize(); + m_AvailablePages.emplace(Size, std::move(Page)); + } +} + +D3D12DynamicPage D3D12DynamicMemoryManager::AllocatePage(Uint64 SizeInBytes) +{ + std::lock_guard<std::mutex> AvailablePagesLock(m_AvailablePagesMtx); + 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()) + { + VERIFY_EXPR(PageIt->first >= SizeInBytes); + D3D12DynamicPage Page(std::move(PageIt->second)); + m_AvailablePages.erase(PageIt); + return Page; + } + else + { + return D3D12DynamicPage{m_pd3d12Device, SizeInBytes}; + } +} + +void D3D12DynamicMemoryManager::Destroy(Uint64 LastCompletedFenceValue) +{ + 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()"); + Uint64 TotalAllocatedSize = 0; + for(const auto& Page : m_AvailablePages) + TotalAllocatedSize += Page.second.GetSize(); + + 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"); +} + + +D3D12DynamicHeap::~D3D12DynamicHeap() +{ + VERIFY(m_AllocatedPages.empty(), "Allocated pages have not been released which indicates FinishFrame() has not been called"); + + LOG_INFO_MESSAGE(m_HeapName, " usage stats:\n" + " Peak used/peak allocated size: ", FormatMemorySize(m_PeakUsedSize, 2, m_PeakAllocatedSize), '/', FormatMemorySize(m_PeakAllocatedSize, 2, m_PeakAllocatedSize), + ". Peak utilization: ", std::fixed, std::setprecision(1), static_cast<double>(m_PeakUsedSize) / static_cast<double>(std::max(m_PeakAllocatedSize, Uint64{1})) * 100.0, '%'); +} + +D3D12DynamicAllocation D3D12DynamicHeap::Allocate(Uint64 SizeInBytes, Uint64 Alignment, Uint64 DvpCtxFrameNumber) +{ + VERIFY_EXPR(Alignment > 0); + VERIFY(IsPowerOfTwo(Alignment), "Alignment (", Alignment, ") must be power of 2"); + + if (m_CurrOffset == InvalidOffset || SizeInBytes + (Align(m_CurrOffset, Alignment) - m_CurrOffset) > m_AvailableSize) + { + auto NewPageSize = m_PageSize; + while(NewPageSize < SizeInBytes) + NewPageSize *= 2; + + auto NewPage = m_DynamicMemMgr.AllocatePage(NewPageSize); + if (NewPage.IsValid()) + { + m_CurrOffset = 0; + m_AvailableSize = NewPage.GetSize(); + + m_CurrAllocatedSize += m_AvailableSize; + m_PeakAllocatedSize = std::max(m_PeakAllocatedSize, m_CurrAllocatedSize); + + m_AllocatedPages.emplace_back(std::move(NewPage)); + } + } + + if (m_CurrOffset != InvalidOffset && SizeInBytes + (Align(m_CurrOffset, Alignment) - m_CurrOffset) <= m_AvailableSize) + { + auto AlignedOffset = Align(m_CurrOffset, Alignment); + auto AdjustedSize = SizeInBytes + (AlignedOffset - m_CurrOffset); + VERIFY_EXPR(AdjustedSize <= m_AvailableSize); + m_AvailableSize -= AdjustedSize; + m_CurrOffset += AdjustedSize; + + m_CurrUsedSize += SizeInBytes; + m_PeakUsedSize = std::max(m_PeakUsedSize, m_CurrUsedSize); + + auto& CurrPage = m_AllocatedPages.back(); + return D3D12DynamicAllocation + { + CurrPage.GetD3D12Buffer(), + AlignedOffset, + SizeInBytes, + CurrPage.GetCPUAddress(AlignedOffset), + CurrPage.GetGPUAddress(AlignedOffset) +#ifdef DEVELOPMENT + , DvpCtxFrameNumber +#endif + }; + } + else + return D3D12DynamicAllocation{}; +} + +void D3D12DynamicHeap::FinishFrame(Uint64 FenceValue) +{ + m_DynamicMemMgr.DiscardPages(m_AllocatedPages, FenceValue); + m_AllocatedPages.clear(); + + m_CurrOffset = InvalidOffset; + m_AvailableSize = 0; + m_CurrAllocatedSize = 0; + m_CurrUsedSize = 0; +} + +} diff --git a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp index ea3b7a86..7115dde0 100644 --- a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp @@ -32,20 +32,32 @@ #include "FenceD3D12Impl.h" #include "D3D12TypeConversions.h" #include "d3dx12_win.h" -#include "DynamicUploadHeap.h" +#include "D3D12DynamicHeap.h" #include "CommandListD3D12Impl.h" #include "DXGITypeConversions.h" namespace Diligent { + static std::string GetDynamicHeapName(bool bIsDeferred, Uint32 ContextId) + { + if (bIsDeferred) + { + std::stringstream ss; + ss << "Dynamic heap of deferred context #" << ContextId; + return ss.str(); + } + else + return "Dynamic heap of immediate context"; + } + DeviceContextD3D12Impl::DeviceContextD3D12Impl( IReferenceCounters* pRefCounters, RenderDeviceD3D12Impl* pDeviceD3D12Impl, bool bIsDeferred, const EngineD3D12Attribs& Attribs, Uint32 ContextId) : TDeviceContextBase(pRefCounters, pDeviceD3D12Impl, bIsDeferred), - m_pUploadHeap(pDeviceD3D12Impl->RequestUploadHeap() ), + m_DynamicHeap(pDeviceD3D12Impl->GetDynamicMemoryManager(), GetDynamicHeapName(bIsDeferred, ContextId), Attribs.DynamicHeapPageSize), m_NumCommandsInCurCtx(0), m_NumCommandsToFlush(bIsDeferred ? std::numeric_limits<decltype(m_NumCommandsToFlush)>::max() : Attribs.NumCommandsToFlushCmdList), m_pCurrCmdCtx(pDeviceD3D12Impl->AllocateCommandContext()), @@ -199,7 +211,7 @@ namespace Diligent D3D12_INDEX_BUFFER_VIEW IBView; BufferD3D12Impl *pBuffD3D12 = static_cast<BufferD3D12Impl *>(m_pIndexBuffer.RawPtr()); - IBView.BufferLocation = pBuffD3D12->GetGPUAddress(m_ContextId) + m_IndexDataStartOffset; + IBView.BufferLocation = pBuffD3D12->GetGPUAddress(this) + m_IndexDataStartOffset; if( IndexType == VT_UINT32 ) IBView.Format = DXGI_FORMAT_R32_UINT; else @@ -220,14 +232,14 @@ namespace Diligent bool IsDynamic = pBuffD3D12->GetDesc().Usage == USAGE_DYNAMIC; #ifdef DEVELOPMENT if(IsDynamic) - pBuffD3D12->DvpVerifyDynamicAllocation(m_ContextId); + pBuffD3D12->DvpVerifyDynamicAllocation(this); #endif auto &GraphicsCtx = RequestCmdContext()->AsGraphicsContext(); // Resource transitioning must always be performed! GraphicsCtx.TransitionResource(pBuffD3D12, D3D12_RESOURCE_STATE_INDEX_BUFFER, true); size_t BuffDataStartByteOffset; - auto *pd3d12Buff = pBuffD3D12->GetD3D12Buffer(BuffDataStartByteOffset, m_ContextId); + auto *pd3d12Buff = pBuffD3D12->GetD3D12Buffer(BuffDataStartByteOffset, this); if( IsDynamic || m_CommittedD3D12IndexBuffer != pd3d12Buff || @@ -274,7 +286,7 @@ namespace Diligent { DynamicBufferPresent = true; #ifdef DEVELOPMENT - pBufferD3D12->DvpVerifyDynamicAllocation(m_ContextId); + pBufferD3D12->DvpVerifyDynamicAllocation(this); #endif } @@ -285,7 +297,7 @@ namespace Diligent // so there is no need to reference the resource here //GraphicsCtx.AddReferencedObject(pd3d12Resource); - VBView.BufferLocation = pBufferD3D12->GetGPUAddress(m_ContextId) + CurrStream.Offset; + VBView.BufferLocation = pBufferD3D12->GetGPUAddress(this) + CurrStream.Offset; VBView.StrideInBytes = Strides[Buff]; // Note that for a dynamic buffer, what we use here is the size of the buffer itself, not the upload heap buffer! VBView.SizeInBytes = pBufferD3D12->GetDesc().uiSizeInBytes - CurrStream.Offset; @@ -336,7 +348,7 @@ namespace Diligent if(m_pCommittedResourceCache != nullptr) { - m_pPipelineState->GetRootSignature().CommitRootViews(*m_pCommittedResourceCache, GraphCtx, false, m_ContextId); + m_pPipelineState->GetRootSignature().CommitRootViews(*m_pCommittedResourceCache, GraphCtx, false, this); } #ifdef _DEBUG else @@ -352,12 +364,12 @@ namespace Diligent { #ifdef DEVELOPMENT if (pIndirectDrawAttribsD3D12->GetDesc().Usage == USAGE_DYNAMIC) - pIndirectDrawAttribsD3D12->DvpVerifyDynamicAllocation(m_ContextId); + pIndirectDrawAttribsD3D12->DvpVerifyDynamicAllocation(this); #endif GraphCtx.TransitionResource(pIndirectDrawAttribsD3D12, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT); size_t BuffDataStartByteOffset; - ID3D12Resource *pd3d12ArgsBuff = pIndirectDrawAttribsD3D12->GetD3D12Buffer(BuffDataStartByteOffset, m_ContextId); + ID3D12Resource *pd3d12ArgsBuff = pIndirectDrawAttribsD3D12->GetD3D12Buffer(BuffDataStartByteOffset, this); GraphCtx.ExecuteIndirect(drawAttribs.IsIndexed ? m_pDrawIndexedIndirectSignature : m_pDrawIndirectSignature, pd3d12ArgsBuff, drawAttribs.IndirectDrawArgsOffset + BuffDataStartByteOffset); } else @@ -382,7 +394,7 @@ namespace Diligent if(m_pCommittedResourceCache != nullptr) { - m_pPipelineState->GetRootSignature().CommitRootViews(*m_pCommittedResourceCache, ComputeCtx, true, m_ContextId); + m_pPipelineState->GetRootSignature().CommitRootViews(*m_pCommittedResourceCache, ComputeCtx, true, this); } #ifdef _DEBUG else @@ -398,12 +410,12 @@ namespace Diligent { #ifdef DEVELOPMENT if(pBufferD3D12->GetDesc().Usage == USAGE_DYNAMIC) - pBufferD3D12->DvpVerifyDynamicAllocation(m_ContextId); + pBufferD3D12->DvpVerifyDynamicAllocation(this); #endif ComputeCtx.TransitionResource(pBufferD3D12, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT); size_t BuffDataStartByteOffset; - ID3D12Resource *pd3d12ArgsBuff = pBufferD3D12->GetD3D12Buffer(BuffDataStartByteOffset, m_ContextId); + ID3D12Resource *pd3d12ArgsBuff = pBufferD3D12->GetD3D12Buffer(BuffDataStartByteOffset, this); ComputeCtx.ExecuteIndirect(m_pDispatchIndirectSignature, pd3d12ArgsBuff, DispatchAttrs.DispatchArgsByteOffset + BuffDataStartByteOffset); } else @@ -491,7 +503,7 @@ namespace Diligent if (m_NumCommandsInCurCtx != 0) { m_pCurrCmdCtx->FlushResourceBarriers(); - pDeviceD3D12Impl->CloseAndExecuteCommandContext(m_pCurrCmdCtx, true, &m_PendingFences); + m_LastSubmittedFenceValue = pDeviceD3D12Impl->CloseAndExecuteCommandContext(m_pCurrCmdCtx, true, &m_PendingFences); m_PendingFences.clear(); } else @@ -518,6 +530,9 @@ namespace Diligent void DeviceContextD3D12Impl::FinishFrame(bool ForceRelease) { + //Uint64 FenceValue = ForceRelease ? std::numeric_limits<Uint64>::max() : m_pDevice.RawPtr<RenderDeviceD3D12Impl>()->GetCompletedFenceValue(); + m_DynamicHeap.FinishFrame(m_LastSubmittedFenceValue); + Atomics::AtomicIncrement(m_ContextFrameNumber); } void DeviceContextD3D12Impl::SetVertexBuffers( Uint32 StartSlot, Uint32 NumBuffersSet, IBuffer** ppBuffers, Uint32* pOffsets, Uint32 Flags ) @@ -690,18 +705,18 @@ namespace Diligent } } - DynamicAllocation DeviceContextD3D12Impl::AllocateDynamicSpace(size_t NumBytes, size_t Alignment) + D3D12DynamicAllocation DeviceContextD3D12Impl::AllocateDynamicSpace(size_t NumBytes, size_t Alignment) { - return m_pUploadHeap->Allocate(NumBytes, Alignment); + return m_DynamicHeap.Allocate(NumBytes, Alignment, m_ContextFrameNumber); } - void DeviceContextD3D12Impl::UpdateBufferRegion(class BufferD3D12Impl* pBuffD3D12, DynamicAllocation& Allocation, Uint64 DstOffset, Uint64 NumBytes) + void DeviceContextD3D12Impl::UpdateBufferRegion(BufferD3D12Impl* pBuffD3D12, D3D12DynamicAllocation& Allocation, Uint64 DstOffset, Uint64 NumBytes) { auto pCmdCtx = RequestCmdContext(); VERIFY_EXPR( static_cast<size_t>(NumBytes) == NumBytes ); pCmdCtx->TransitionResource(pBuffD3D12, D3D12_RESOURCE_STATE_COPY_DEST, true); size_t DstBuffDataStartByteOffset; - auto *pd3d12Buff = pBuffD3D12->GetD3D12Buffer(DstBuffDataStartByteOffset, m_ContextId); + auto *pd3d12Buff = pBuffD3D12->GetD3D12Buffer(DstBuffDataStartByteOffset, this); VERIFY(DstBuffDataStartByteOffset == 0, "Dst buffer must not be suballocated"); pCmdCtx->GetCommandList()->CopyBufferRegion( pd3d12Buff, DstOffset + DstBuffDataStartByteOffset, Allocation.pBuffer, Allocation.Offset, NumBytes); ++m_NumCommandsInCurCtx; @@ -712,7 +727,7 @@ namespace Diligent VERIFY(pBuffD3D12->GetDesc().Usage != USAGE_DYNAMIC, "Dynamic buffers must be updated via Map()"); VERIFY_EXPR( static_cast<size_t>(NumBytes) == NumBytes ); constexpr size_t DefaultAlginment = 16; - auto TmpSpace = m_pUploadHeap->Allocate(static_cast<size_t>(NumBytes), DefaultAlginment); + auto TmpSpace = m_DynamicHeap.Allocate(static_cast<size_t>(NumBytes), DefaultAlginment, m_ContextFrameNumber); memcpy(TmpSpace.CPUAddress, pData, static_cast<size_t>(NumBytes)); UpdateBufferRegion(pBuffD3D12, TmpSpace, DstOffset, NumBytes); } @@ -725,11 +740,11 @@ namespace Diligent pCmdCtx->TransitionResource(pSrcBuffD3D12, D3D12_RESOURCE_STATE_COPY_SOURCE); pCmdCtx->TransitionResource(pDstBuffD3D12, D3D12_RESOURCE_STATE_COPY_DEST, true); size_t DstDataStartByteOffset; - auto *pd3d12DstBuff = pDstBuffD3D12->GetD3D12Buffer(DstDataStartByteOffset, m_ContextId); + auto *pd3d12DstBuff = pDstBuffD3D12->GetD3D12Buffer(DstDataStartByteOffset, this); VERIFY(DstDataStartByteOffset == 0, "Dst buffer must not be suballocated"); size_t SrcDataStartByteOffset; - auto *pd3d12SrcBuff = pSrcBuffD3D12->GetD3D12Buffer(SrcDataStartByteOffset, m_ContextId); + auto *pd3d12SrcBuff = pSrcBuffD3D12->GetD3D12Buffer(SrcDataStartByteOffset, this); pCmdCtx->GetCommandList()->CopyBufferRegion( pd3d12DstBuff, DstOffset + DstDataStartByteOffset, pd3d12SrcBuff, SrcOffset+SrcDataStartByteOffset, NumBytes); ++m_NumCommandsInCurCtx; } @@ -841,7 +856,7 @@ namespace Diligent else if(pBufferD3D12->GetState() != D3D12_RESOURCE_STATE_GENERIC_READ) RequestCmdContext()->TransitionResource(pBufferD3D12, D3D12_RESOURCE_STATE_GENERIC_READ, true); size_t DataStartByteOffset = 0; - auto* pd3d12Buffer = pBufferD3D12->GetD3D12Buffer(DataStartByteOffset, m_ContextId); + auto* pd3d12Buffer = pBufferD3D12->GetD3D12Buffer(DataStartByteOffset, this); CopyTextureRegion(pd3d12Buffer, static_cast<Uint32>(DataStartByteOffset) + SrcOffset, SrcStride, SrcDepthStride, pBufferD3D12->GetDesc().uiSizeInBytes, TextureD3D12, DstSubResIndex, DstBox); } @@ -982,7 +997,7 @@ namespace Diligent { auto* pDeviceD3D12Impl = m_pDevice.RawPtr<RenderDeviceD3D12Impl>(); CommandListD3D12Impl* pCmdListD3D12( NEW_RC_OBJ(m_CmdListAllocator, "CommandListD3D12Impl instance", CommandListD3D12Impl) - (pDeviceD3D12Impl, m_pCurrCmdCtx) ); + (pDeviceD3D12Impl, this, m_pCurrCmdCtx) ); pCmdListD3D12->QueryInterface( IID_CommandList, reinterpret_cast<IObject**>(ppCommandList) ); m_pCurrCmdCtx = nullptr; Flush(true); @@ -1004,7 +1019,11 @@ namespace Diligent CommandListD3D12Impl* pCmdListD3D12 = ValidatedCast<CommandListD3D12Impl>(pCommandList); VERIFY_EXPR(m_PendingFences.empty()); - m_pDevice.RawPtr<RenderDeviceD3D12Impl>()->CloseAndExecuteCommandContext(pCmdListD3D12->Close(), true, nullptr); + CommandContext* pCmdContext = nullptr; + RefCntAutoPtr<DeviceContextD3D12Impl> pDeferredCtx; + pCmdListD3D12->Close(pCmdContext, pDeferredCtx); + pDeferredCtx->m_LastSubmittedFenceValue = + m_pDevice.RawPtr<RenderDeviceD3D12Impl>()->CloseAndExecuteCommandContext(pCmdContext, true, nullptr); } void DeviceContextD3D12Impl::SignalFence(IFence* pFence, Uint64 Value) diff --git a/Graphics/GraphicsEngineD3D12/src/DynamicUploadHeap.cpp b/Graphics/GraphicsEngineD3D12/src/DynamicUploadHeap.cpp deleted file mode 100644 index f884579c..00000000 --- a/Graphics/GraphicsEngineD3D12/src/DynamicUploadHeap.cpp +++ /dev/null @@ -1,172 +0,0 @@ -/* Copyright 2015-2018 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 - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. - * - * 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 "DynamicUploadHeap.h" -#include "RenderDeviceD3D12Impl.h" - -namespace Diligent -{ - GPURingBuffer::GPURingBuffer(size_t MaxSize, - IMemoryAllocator& Allocator, - ID3D12Device* pd3d12Device, - bool AllowCPUAccess) : - RingBuffer(MaxSize, Allocator), - m_CpuVirtualAddress(nullptr), - m_GpuVirtualAddress(0) - { - D3D12_HEAP_PROPERTIES HeapProps; - HeapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; - HeapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - HeapProps.CreationNodeMask = 1; - HeapProps.VisibleNodeMask = 1; - - D3D12_RESOURCE_DESC ResourceDesc; - ResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; - ResourceDesc.Alignment = 0; - ResourceDesc.Height = 1; - ResourceDesc.DepthOrArraySize = 1; - ResourceDesc.MipLevels = 1; - ResourceDesc.Format = DXGI_FORMAT_UNKNOWN; - ResourceDesc.SampleDesc.Count = 1; - ResourceDesc.SampleDesc.Quality = 0; - ResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; - - D3D12_RESOURCE_STATES DefaultUsage; - if (AllowCPUAccess) - { - HeapProps.Type = D3D12_HEAP_TYPE_UPLOAD; - ResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE; - DefaultUsage = D3D12_RESOURCE_STATE_GENERIC_READ; - } - else - { - HeapProps.Type = D3D12_HEAP_TYPE_DEFAULT; - ResourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; - DefaultUsage = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; - } - ResourceDesc.Width = MaxSize; - - auto hr = pd3d12Device->CreateCommittedResource(&HeapProps, D3D12_HEAP_FLAG_NONE, &ResourceDesc, - DefaultUsage, nullptr, __uuidof(m_pBuffer), reinterpret_cast<void**>(static_cast<ID3D12Resource**>(&m_pBuffer)) ); - if(FAILED(hr)) - LOG_ERROR("Failed to create new upload ring buffer"); - - m_pBuffer->SetName(L"Upload Ring Buffer"); - - m_GpuVirtualAddress = m_pBuffer->GetGPUVirtualAddress(); - - if (AllowCPUAccess) - { - m_pBuffer->Map(0, nullptr, &m_CpuVirtualAddress); - } - - LOG_INFO_MESSAGE("GPU ring buffer created. Size: ", FormatMemorySize(MaxSize,2), "; GPU virtual address 0x", std::hex, m_GpuVirtualAddress); - } - - void GPURingBuffer::Destroy() - { - if(m_pBuffer) - { - LOG_INFO_MESSAGE("Destroying GPU ring buffer. Size: ", FormatMemorySize(m_pBuffer->GetDesc().Width,2), "; GPU virtual address 0x", std::hex, m_GpuVirtualAddress); - } - - if (m_CpuVirtualAddress) - { - m_pBuffer->Unmap(0, nullptr); - } - m_CpuVirtualAddress = 0; - m_GpuVirtualAddress = 0; - m_pBuffer.Release(); - } - - GPURingBuffer::~GPURingBuffer() - { - Destroy(); - } - - DynamicUploadHeap::DynamicUploadHeap(IMemoryAllocator& Allocator, - bool bIsCPUAccessible, - RenderDeviceD3D12Impl* pDevice, - size_t InitialSize) : - m_Allocator(Allocator), - m_pDeviceD3D12(pDevice), - m_bIsCPUAccessible(bIsCPUAccessible), - m_RingBuffers(STD_ALLOCATOR_RAW_MEM(GPURingBuffer, GetRawAllocator(), "Allocator for vector<GPURingBuffer>")) - { - m_RingBuffers.emplace_back(InitialSize, Allocator, pDevice->GetD3D12Device(), m_bIsCPUAccessible); - } - - DynamicAllocation DynamicUploadHeap::Allocate(size_t SizeInBytes, size_t Alignment) - { - // Every device context has its own upload heap, so there is no need to lock - - //std::lock_guard<std::mutex> Lock(m_Mutex); - - // - // Deferred contexts must not update resources or map dynamic buffers - // across several frames! - // - - VERIFY_EXPR(IsPowerOfTwo(Alignment)); - // Align the allocation - auto DynAlloc = m_RingBuffers.back().Allocate(SizeInBytes, Alignment); - if (!DynAlloc.pBuffer) - { - auto NewMaxSize = m_RingBuffers.back().GetMaxSize() * 2; - while(NewMaxSize < SizeInBytes)NewMaxSize*=2; - m_RingBuffers.emplace_back(NewMaxSize, m_Allocator, m_pDeviceD3D12->GetD3D12Device(), m_bIsCPUAccessible); - DynAlloc = m_RingBuffers.back().Allocate(SizeInBytes, Alignment); - } -#ifdef _DEBUG - DynAlloc.FrameNum = m_pDeviceD3D12->GetCurrentFrameNumber(); -#endif - return DynAlloc; - } - - void DynamicUploadHeap::FinishFrame(Uint64 FenceValue, Uint64 LastCompletedFenceValue) - { - // Every device context has its own upload heap, so there is no need to lock - //std::lock_guard<std::mutex> Lock(m_Mutex); - - // - // Deferred contexts must not update resources or map dynamic buffers - // across several frames! - // - - size_t NumBuffsToDelete = 0; - for(size_t Ind = 0; Ind < m_RingBuffers.size(); ++Ind) - { - auto &RingBuff = m_RingBuffers[Ind]; - RingBuff.FinishCurrentFrame(FenceValue); - RingBuff.ReleaseCompletedFrames(LastCompletedFenceValue); - if ( NumBuffsToDelete == Ind && Ind < m_RingBuffers.size()-1 && RingBuff.IsEmpty()) - { - ++NumBuffsToDelete; - } - } - - if(NumBuffsToDelete) - m_RingBuffers.erase(m_RingBuffers.begin(), m_RingBuffers.begin()+NumBuffsToDelete); - } -} diff --git a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp index a7a4fdce..dfcd5927 100644 --- a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp @@ -83,8 +83,8 @@ RenderDeviceD3D12Impl :: RenderDeviceD3D12Impl(IReferenceCounters* pRef }, m_ContextPool(STD_ALLOCATOR_RAW_MEM(ContextPoolElemType, GetRawAllocator(), "Allocator for vector<unique_ptr<CommandContext>>")), m_AvailableContexts(STD_ALLOCATOR_RAW_MEM(CommandContext*, GetRawAllocator(), "Allocator for vector<CommandContext*>")), - m_UploadHeaps(STD_ALLOCATOR_RAW_MEM(UploadHeapPoolElemType, GetRawAllocator(), "Allocator for vector<unique_ptr<DynamicUploadHeap>>")), - m_ReleaseQueue(GetRawAllocator()) + m_ReleaseQueue(GetRawAllocator()), + m_DynamicMemoryManager(GetRawAllocator(), m_pd3d12Device, CreationAttribs.NumDynamicHeapPagesToReserve, CreationAttribs.DynamicHeapPageSize) { m_DeviceCaps.DevType = DeviceType::D3D12; m_DeviceCaps.MajorVersion = 12; @@ -104,7 +104,8 @@ RenderDeviceD3D12Impl::~RenderDeviceD3D12Impl() // Call FinishFrame() again to destroy resources in // release queues FinishFrame(true); - + + m_DynamicMemoryManager.Destroy(GetCompletedFenceValue()); m_ContextPool.clear(); } @@ -114,7 +115,7 @@ void RenderDeviceD3D12Impl::DisposeCommandContext(CommandContext* pCtx) m_AvailableContexts.push_back(pCtx); } -void RenderDeviceD3D12Impl::CloseAndExecuteCommandContext(CommandContext* pCtx, bool DiscardStaleObjects, std::vector<std::pair<Uint64, RefCntAutoPtr<IFence> > >* pSignalFences) +Uint64 RenderDeviceD3D12Impl::CloseAndExecuteCommandContext(CommandContext* pCtx, bool DiscardStaleObjects, std::vector<std::pair<Uint64, RefCntAutoPtr<IFence> > >* pSignalFences) { CComPtr<ID3D12CommandAllocator> pAllocator; auto *pCmdList = pCtx->Close(&pAllocator); @@ -185,6 +186,8 @@ void RenderDeviceD3D12Impl::CloseAndExecuteCommandContext(CommandContext* pCtx, std::lock_guard<std::mutex> LockGuard(m_ContextAllocationMutex); m_AvailableContexts.push_back(pCtx); } + + return FenceValue; } @@ -265,34 +268,10 @@ void RenderDeviceD3D12Impl::FinishFrame(bool ReleaseAllResources) Atomics::AtomicIncrement(m_NextCmdListNumber); } - { - // There is no need to lock as new heaps are only created during initialization - // time for every context - //std::lock_guard<std::mutex> LockGuard(m_UploadHeapMutex); - - // Upload heaps are 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, - // so can be performed in parallel across frame boundaries - for (auto &UploadHeap : m_UploadHeaps) - { - // Currently upload heaps are free-threaded, so other threads must not allocate - // resources at the same time. This means that all dynamic buffers must be unmaped - // in the same frame and all resources must be updated within boundaries of a single frame. - // - // worker thread 3 | pDevice->CrateTexture(InitData) | | pDevice->CrateBuffer(InitData) | | pDevice->CrateTexture(InitData) | - // - // worker thread 2 | pDfrdCtx2->UpdateResource() | || - // || - // worker thread 1 | pDfrdCtx1->Map(WRITE_DISCARD) | | pDfrdCtx1->UpdateResource() | || - // || - // main thread | pCtx->Map(WRITE_DISCARD )| | pCtx->UpdateResource() | || | Present() | - // - // - - UploadHeap->FinishFrame(NextFenceValue, CompletedFenceValue); - } - } + // 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) { @@ -314,27 +293,6 @@ void RenderDeviceD3D12Impl::FinishFrame(bool ReleaseAllResources) Atomics::AtomicIncrement(m_FrameNumber); } -DynamicUploadHeap* RenderDeviceD3D12Impl::RequestUploadHeap() -{ - std::lock_guard<std::mutex> LockGuard(m_UploadHeapMutex); - -#ifdef _DEBUG - size_t InitialSize = 1024+64; -#else - size_t InitialSize = 64<<10;//16<<20; -#endif - - auto &UploadHeapAllocator = GetRawAllocator(); - auto *pRawMem = ALLOCATE(UploadHeapAllocator, "DynamicUploadHeap instance", sizeof(DynamicUploadHeap)); - auto *pNewHeap = new (pRawMem) DynamicUploadHeap(GetRawAllocator(), true, this, InitialSize); - m_UploadHeaps.emplace_back( pNewHeap, STDDeleterRawMem<DynamicUploadHeap>(UploadHeapAllocator) ); - return pNewHeap; -} - -void RenderDeviceD3D12Impl::ReleaseUploadHeap(DynamicUploadHeap* pUploadHeap) -{ - -} CommandContext* RenderDeviceD3D12Impl::AllocateCommandContext(const Char* ID) { diff --git a/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp b/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp index e68d3682..c172ea95 100644 --- a/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp +++ b/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp @@ -1035,7 +1035,7 @@ void RootSignature::TransitionResources(ShaderResourceCacheD3D12& ResourceCache, void RootSignature::CommitRootViews(ShaderResourceCacheD3D12& ResourceCache, CommandContext& Ctx, bool IsCompute, - Uint32 ContextId)const + DeviceContextD3D12Impl* pCtx)const { for(Uint32 rv = 0; rv < m_RootParams.GetNumRootViews(); ++rv) { @@ -1054,7 +1054,7 @@ void RootSignature::CommitRootViews(ShaderResourceCacheD3D12& ResourceCache, if( !pBuffToTransition->CheckAllStates(D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER) ) Ctx.TransitionResource(pBuffToTransition, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER); - D3D12_GPU_VIRTUAL_ADDRESS CBVAddress = pBuffToTransition->GetGPUAddress(ContextId); + D3D12_GPU_VIRTUAL_ADDRESS CBVAddress = pBuffToTransition->GetGPUAddress(pCtx); if(IsCompute) Ctx.GetCommandList()->SetComputeRootConstantBufferView(RootInd, CBVAddress); else diff --git a/Graphics/GraphicsEngineD3D12/src/SwapChainD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/SwapChainD3D12Impl.cpp index f9b782f0..deab12e8 100644 --- a/Graphics/GraphicsEngineD3D12/src/SwapChainD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/SwapChainD3D12Impl.cpp @@ -127,6 +127,7 @@ void SwapChainD3D12Impl::Present(Uint32 SyncInterval) auto hr = m_pSwapChain->Present( SyncInterval, 0 ); VERIFY(SUCCEEDED(hr), "Present failed"); + pImmediateCtxD3D12->FinishFrame(false); pDeviceD3D12->FinishFrame(); #if 0 |
