From 4e3da45fdeab9d81601ec1d4b5174cff4c6629d6 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Fri, 25 Oct 2019 22:08:21 +0200 Subject: [PATCH] [d3d11] Recycle command lists from deferred contexts Can save a few memory allocations and deallocations at runtime. --- src/d3d11/d3d11_cmdlist.cpp | 64 +++++++++++++++++++++++++++--- src/d3d11/d3d11_cmdlist.h | 69 ++++++++++++++++++++++++++++++--- src/d3d11/d3d11_context_def.cpp | 2 +- src/d3d11/d3d11_device.cpp | 3 +- src/d3d11/d3d11_device.h | 6 +++ 5 files changed, 132 insertions(+), 12 deletions(-) diff --git a/src/d3d11/d3d11_cmdlist.cpp b/src/d3d11/d3d11_cmdlist.cpp index 25205e73c..276043ea1 100644 --- a/src/d3d11/d3d11_cmdlist.cpp +++ b/src/d3d11/d3d11_cmdlist.cpp @@ -4,10 +4,11 @@ namespace dxvk { D3D11CommandList::D3D11CommandList( - D3D11Device* pDevice, - UINT ContextFlags) - : m_device (pDevice), - m_contextFlags(ContextFlags) { } + D3D11Device* pDevice, + D3D11CommandListAllocator* pAllocator) + : m_device(pDevice), m_allocator(pAllocator) { + + } D3D11CommandList::~D3D11CommandList() { @@ -25,8 +26,14 @@ namespace dxvk { ULONG STDMETHODCALLTYPE D3D11CommandList::Release() { ULONG refCount = --m_refCount; - if (!refCount) + + if (!refCount) { + Reset(); + + m_allocator->RecycleCommandList(this); m_device->Release(); + } + return refCount; } @@ -81,6 +88,15 @@ namespace dxvk { MarkSubmitted(); } + + + void D3D11CommandList::Reset() { + m_chunks.clear(); + + m_contextFlags = 0; + m_submitted = false; + m_warned = false; + } void D3D11CommandList::MarkSubmitted() { @@ -92,4 +108,42 @@ namespace dxvk { } } + + D3D11CommandListAllocator::D3D11CommandListAllocator(D3D11Device* pDevice) + : m_device(pDevice) { + + } + + + D3D11CommandListAllocator::~D3D11CommandListAllocator() { + for (uint32_t i = 0; i < m_listCount; i++) + delete m_lists[i]; + } + + + D3D11CommandList* D3D11CommandListAllocator::AllocCommandList( + UINT ContextFlags) { + std::lock_guard lock(m_mutex); + D3D11CommandList* result = nullptr; + + if (m_listCount) + result = m_lists[--m_listCount]; + else + result = new D3D11CommandList(m_device, this); + + result->SetContextFlags(ContextFlags); + return result; + } + + + void D3D11CommandListAllocator::RecycleCommandList( + D3D11CommandList* pCommandList) { + std::lock_guard lock(m_mutex); + + if (m_listCount < m_lists.size()) + m_lists[m_listCount++] = pCommandList; + else + delete pCommandList; + } + } \ No newline at end of file diff --git a/src/d3d11/d3d11_cmdlist.h b/src/d3d11/d3d11_cmdlist.h index 58d16fe6c..78bb1315c 100644 --- a/src/d3d11/d3d11_cmdlist.h +++ b/src/d3d11/d3d11_cmdlist.h @@ -1,16 +1,21 @@ #pragma once +#include +#include + #include "d3d11_context.h" namespace dxvk { + + class D3D11CommandListAllocator; class D3D11CommandList : public D3D11DeviceChild { public: D3D11CommandList( - D3D11Device* pDevice, - UINT ContextFlags); + D3D11Device* pDevice, + D3D11CommandListAllocator* pAllocator); ~D3D11CommandList(); @@ -26,6 +31,10 @@ namespace dxvk { ID3D11Device **ppDevice) final; UINT STDMETHODCALLTYPE GetContextFlags() final; + + void SetContextFlags(UINT ContextFlags) { + m_contextFlags = ContextFlags; + } void AddChunk( DxvkCsChunkRef&& Chunk); @@ -38,9 +47,11 @@ namespace dxvk { private: - D3D11Device* const m_device; - UINT const m_contextFlags; - + D3D11Device* m_device; + D3D11CommandListAllocator* m_allocator; + + uint32_t m_contextFlags = 0; + std::vector m_chunks; std::atomic m_submitted = { false }; @@ -48,8 +59,56 @@ namespace dxvk { std::atomic m_refCount = { 0u }; + void Reset(); + void MarkSubmitted(); }; + + /** + * \brief Command list allocator + * + * Creates and recycles command list instances + * in order to reduce deferred context overhead. + */ + class D3D11CommandListAllocator { + + public: + + D3D11CommandListAllocator( + D3D11Device* pDevice); + + ~D3D11CommandListAllocator(); + + /** + * \brief Allocates a command list + * + * \param [in] ContextFlags Flags of the parent context + * \returns The command list + */ + D3D11CommandList* AllocCommandList( + UINT ContextFlags); + + /** + * \brief Recycles a command list + * + * Automatically called when the command list + * in question reaches a ref count of zero. + * \param [in] pCommandList The command list + */ + void RecycleCommandList( + D3D11CommandList* pCommandList); + + private: + + D3D11Device* m_device; + + std::mutex m_mutex; + std::array m_lists; + + uint32_t m_listCount = 0; + + }; + } \ No newline at end of file diff --git a/src/d3d11/d3d11_context_def.cpp b/src/d3d11/d3d11_context_def.cpp index 70c1d39de..d3793343a 100644 --- a/src/d3d11/d3d11_context_def.cpp +++ b/src/d3d11/d3d11_context_def.cpp @@ -309,7 +309,7 @@ namespace dxvk { Com D3D11DeferredContext::CreateCommandList() { - return new D3D11CommandList(m_parent, m_contextFlags); + return m_parent->AllocCommandList(m_contextFlags); } diff --git a/src/d3d11/d3d11_device.cpp b/src/d3d11/d3d11_device.cpp index e093f0f2d..aadbe1187 100644 --- a/src/d3d11/d3d11_device.cpp +++ b/src/d3d11/d3d11_device.cpp @@ -39,7 +39,8 @@ namespace dxvk { m_dxvkAdapter (m_dxvkDevice->adapter()), m_d3d11Formats (m_dxvkAdapter), m_d3d11Options (m_dxvkAdapter->instance()->config()), - m_dxbcOptions (m_dxvkDevice, m_d3d11Options) { + m_dxbcOptions (m_dxvkDevice, m_d3d11Options), + m_commandListAllocator(this) { m_initializer = new D3D11Initializer(this); m_context = new D3D11ImmediateContext(this, m_dxvkDevice); m_d3d10Device = new D3D10Device(this, m_context); diff --git a/src/d3d11/d3d11_device.h b/src/d3d11/d3d11_device.h index 2f42760d1..c17f2ab82 100644 --- a/src/d3d11/d3d11_device.h +++ b/src/d3d11/d3d11_device.h @@ -14,6 +14,7 @@ #include "../util/com/com_private_data.h" +#include "d3d11_cmdlist.h" #include "d3d11_counter_buffer.h" #include "d3d11_initializer.h" #include "d3d11_interfaces.h" @@ -411,6 +412,10 @@ namespace dxvk { DxvkCsChunk* chunk = m_csChunkPool.allocChunk(flags); return DxvkCsChunkRef(chunk, &m_csChunkPool); } + + D3D11CommandList* AllocCommandList(UINT ContextFlags) { + return m_commandListAllocator.AllocCommandList(ContextFlags); + } const D3D11Options* GetOptions() const { return &m_d3d11Options; @@ -465,6 +470,7 @@ namespace dxvk { D3D11StateObjectSet m_rsStateObjects; D3D11StateObjectSet m_samplerObjects; D3D11ShaderModuleSet m_shaderModules; + D3D11CommandListAllocator m_commandListAllocator; Rc CreateUAVCounterBuffer(); Rc CreateXFBCounterBuffer();