summaryrefslogtreecommitdiffstats
path: root/Graphics/GraphicsEngineD3D12
diff options
context:
space:
mode:
authorEgor Yusov <egor.yusov@gmail.com>2018-09-16 18:49:54 +0000
committerEgor Yusov <egor.yusov@gmail.com>2018-09-16 18:49:54 +0000
commit609a63ef71c504981e38d115dafc9cbf52dfa640 (patch)
treebfe75873dca09ead4b2a7939ff3b7703ab378088 /Graphics/GraphicsEngineD3D12
parentFixed one more gcc warning (diff)
downloadDiligentCore-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')
-rw-r--r--Graphics/GraphicsEngineD3D12/CMakeLists.txt4
-rw-r--r--Graphics/GraphicsEngineD3D12/include/BufferD3D12Impl.h42
-rw-r--r--Graphics/GraphicsEngineD3D12/include/CommandListD3D12Impl.h24
-rw-r--r--Graphics/GraphicsEngineD3D12/include/D3D12DynamicHeap.h213
-rw-r--r--Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.h27
-rw-r--r--Graphics/GraphicsEngineD3D12/include/DynamicUploadHeap.h141
-rw-r--r--Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.h13
-rw-r--r--Graphics/GraphicsEngineD3D12/include/RootSignature.h8
-rw-r--r--Graphics/GraphicsEngineD3D12/interface/BufferD3D12.h4
-rw-r--r--Graphics/GraphicsEngineD3D12/src/BufferD3D12Impl.cpp57
-rw-r--r--Graphics/GraphicsEngineD3D12/src/D3D12DynamicHeap.cpp199
-rw-r--r--Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp67
-rw-r--r--Graphics/GraphicsEngineD3D12/src/DynamicUploadHeap.cpp172
-rw-r--r--Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp64
-rw-r--r--Graphics/GraphicsEngineD3D12/src/RootSignature.cpp4
-rw-r--r--Graphics/GraphicsEngineD3D12/src/SwapChainD3D12Impl.cpp1
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