From b7a00e32ecfa501b48e4f6ad3f02f0abb78ef3a3 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Sun, 21 Jan 2018 00:49:07 +0100 Subject: [PATCH] [dxvk] Limit size of the CS command queue Prevents memory leaks and fixes stuttering in Heaven. --- src/d3d11/d3d11_context.cpp | 3 +++ src/d3d11/d3d11_context_imm.cpp | 5 +++++ src/dxvk/dxvk_cs.cpp | 14 ++++++++------ src/dxvk/dxvk_cs.h | 4 +++- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index 1e0e07ca..6d689da2 100644 --- a/src/d3d11/d3d11_context.cpp +++ b/src/d3d11/d3d11_context.cpp @@ -565,6 +565,8 @@ namespace dxvk { if (((size == bufferSlice.length()) && (bufferSlice.buffer()->memFlags() & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT))) { auto physicalSlice = bufferSlice.buffer()->allocPhysicalSlice(); + physicalSlice.resource()->acquire(); + std::memcpy(physicalSlice.mapPtr(0), pSrcData, size); EmitCs([ @@ -572,6 +574,7 @@ namespace dxvk { cPhysicalSlice = std::move(physicalSlice) ] (DxvkContext* ctx) { ctx->invalidateBuffer(cDstBuffer, cPhysicalSlice); + cPhysicalSlice.resource()->release(); }); } else { EmitCs([ diff --git a/src/d3d11/d3d11_context_imm.cpp b/src/d3d11/d3d11_context_imm.cpp index 943fa137..4f4617af 100644 --- a/src/d3d11/d3d11_context_imm.cpp +++ b/src/d3d11/d3d11_context_imm.cpp @@ -98,6 +98,8 @@ namespace dxvk { // it as the 'new' mapped slice. This assumes that the // only way to invalidate a buffer is by mapping it. auto physicalSlice = buffer->allocPhysicalSlice(); + physicalSlice.resource()->acquire(); + resource->GetBufferInfo()->mappedSlice = physicalSlice; EmitCs([ @@ -105,6 +107,7 @@ namespace dxvk { cPhysicalSlice = physicalSlice ] (DxvkContext* ctx) { ctx->invalidateBuffer(cBuffer, cPhysicalSlice); + cPhysicalSlice.resource()->release(); }); } else if (MapType != D3D11_MAP_WRITE_NO_OVERWRITE) { // Synchronize with CS thread so that we know whether @@ -167,12 +170,14 @@ namespace dxvk { // to be preserved, copy the image's contents into the buffer. if (MapType == D3D11_MAP_WRITE_DISCARD) { physicalSlice = textureInfo->imageBuffer->allocPhysicalSlice(); + physicalSlice.resource()->acquire(); EmitCs([ cImageBuffer = textureInfo->imageBuffer, cPhysicalSlice = physicalSlice ] (DxvkContext* ctx) { ctx->invalidateBuffer(cImageBuffer, cPhysicalSlice); + cPhysicalSlice.resource()->release(); }); } else { const VkImageSubresourceLayers subresourceLayers = { diff --git a/src/dxvk/dxvk_cs.cpp b/src/dxvk/dxvk_cs.cpp index aabcaea0..b3308d95 100644 --- a/src/dxvk/dxvk_cs.cpp +++ b/src/dxvk/dxvk_cs.cpp @@ -44,6 +44,10 @@ namespace dxvk { { std::unique_lock lock(m_mutex); m_chunks.push(std::move(chunk)); m_chunksPending += 1; + + m_condOnSync.wait(lock, [this] { + return m_stopped.load() || (m_chunksPending < MaxChunksInFlight); + }); } m_condOnAdd.notify_one(); @@ -78,13 +82,11 @@ namespace dxvk { if (chunk != nullptr) { chunk->executeAll(m_context.ptr()); - const bool doNotify = [this] { - std::unique_lock lock(m_mutex); - return --m_chunksPending == 0; - }(); + { std::unique_lock lock(m_mutex); + m_chunksPending -= 1; + } - if (doNotify) - m_condOnSync.notify_one(); + m_condOnSync.notify_one(); } } } diff --git a/src/dxvk/dxvk_cs.h b/src/dxvk/dxvk_cs.h index 7e0d36e8..f7e1b641 100644 --- a/src/dxvk/dxvk_cs.h +++ b/src/dxvk/dxvk_cs.h @@ -138,7 +138,9 @@ namespace dxvk { * commands on a DXVK context. */ class DxvkCsThread { - + // Limit the number of chunks in the queue + // to prevent memory leaks, stuttering etc. + constexpr static uint32_t MaxChunksInFlight = 128; public: DxvkCsThread(const Rc& context);