From d201a1f7c67f2736371b0a23fe4b35a8e1908bfb Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Tue, 1 May 2018 16:45:28 +0200 Subject: [PATCH] [dxvk] Made pipe manager and pipeline classes thread-safe --- src/dxvk/dxvk_compute.cpp | 49 ++++++++++++++++++++++++++++------- src/dxvk/dxvk_compute.h | 7 +++++ src/dxvk/dxvk_graphics.cpp | 49 ++++++++++++++++++++++++++++------- src/dxvk/dxvk_graphics.h | 7 ++++- src/dxvk/dxvk_pipemanager.cpp | 20 +++++++++----- src/dxvk/dxvk_pipemanager.h | 3 +++ 6 files changed, 108 insertions(+), 27 deletions(-) diff --git a/src/dxvk/dxvk_compute.cpp b/src/dxvk/dxvk_compute.cpp index 5ff7962c1..80f5ac9a1 100644 --- a/src/dxvk/dxvk_compute.cpp +++ b/src/dxvk/dxvk_compute.cpp @@ -42,19 +42,50 @@ namespace dxvk { VkPipeline DxvkComputePipeline::getPipelineHandle( const DxvkComputePipelineStateInfo& state, DxvkStatCounters& stats) { - for (const PipelineStruct& pair : m_pipelines) { - if (pair.stateVector == state) - return pair.pipeline; + VkPipeline pipeline = VK_NULL_HANDLE; + + { std::lock_guard lock(m_mutex); + + if (this->findPipeline(state, pipeline)) + return pipeline; } - VkPipeline pipeline = this->compilePipeline(state, m_basePipeline); - m_pipelines.push_back({ state, pipeline }); + // If no pipeline exists with the given state vector, + // create a new one and add it to the pipeline set. + VkPipeline newPipeline = this->compilePipeline(state, m_basePipeline); - if (m_basePipeline == VK_NULL_HANDLE) - m_basePipeline = pipeline; + { std::lock_guard lock(m_mutex); + + // Discard the pipeline if another thread + // was faster compiling the same pipeline + if (this->findPipeline(state, pipeline)) { + m_vkd->vkDestroyPipeline(m_vkd->device(), newPipeline, nullptr); + return pipeline; + } + + // Add new pipeline to the set + m_pipelines.push_back({ state, newPipeline }); + + if (m_basePipeline == VK_NULL_HANDLE) + m_basePipeline = newPipeline; + + stats.addCtr(DxvkStatCounter::PipeCountCompute, 1); + return newPipeline; + } + } + + + bool DxvkComputePipeline::findPipeline( + const DxvkComputePipelineStateInfo& state, + VkPipeline& pipeline) const { + for (const PipelineStruct& pair : m_pipelines) { + if (pair.stateVector == state) { + pipeline = pair.pipeline; + return true; + } + } - stats.addCtr(DxvkStatCounter::PipeCountCompute, 1); - return pipeline; + return false; } diff --git a/src/dxvk/dxvk_compute.h b/src/dxvk/dxvk_compute.h index 335589d2f..9a2101d31 100644 --- a/src/dxvk/dxvk_compute.h +++ b/src/dxvk/dxvk_compute.h @@ -1,5 +1,7 @@ #pragma once +#include + #include "dxvk_binding.h" #include "dxvk_pipecache.h" #include "dxvk_pipelayout.h" @@ -76,10 +78,15 @@ namespace dxvk { Rc m_layout; Rc m_cs; + sync::Spinlock m_mutex; std::vector m_pipelines; VkPipeline m_basePipeline = VK_NULL_HANDLE; + bool findPipeline( + const DxvkComputePipelineStateInfo& state, + VkPipeline& pipeline) const; + VkPipeline compilePipeline( const DxvkComputePipelineStateInfo& state, VkPipeline baseHandle) const; diff --git a/src/dxvk/dxvk_graphics.cpp b/src/dxvk/dxvk_graphics.cpp index 554434d4a..32c8db247 100644 --- a/src/dxvk/dxvk_graphics.cpp +++ b/src/dxvk/dxvk_graphics.cpp @@ -78,23 +78,52 @@ namespace dxvk { VkPipeline DxvkGraphicsPipeline::getPipelineHandle( const DxvkGraphicsPipelineStateInfo& state, DxvkStatCounters& stats) { + VkPipeline pipeline = VK_NULL_HANDLE; - for (const PipelineStruct& pair : m_pipelines) { - if (pair.stateVector == state) - return pair.pipeline; + { std::lock_guard lock(m_mutex); + + if (this->findPipeline(state, pipeline)) + return pipeline; } - VkPipeline pipeline = this->validatePipelineState(state) + // If no pipeline exists with the given state vector, + // create a new one and add it to the pipeline set. + VkPipeline newPipeline = this->validatePipelineState(state) ? this->compilePipeline(state, m_basePipeline) : VK_NULL_HANDLE; - m_pipelines.push_back({ state, pipeline }); + { std::lock_guard lock(m_mutex); + + // Discard the pipeline if another thread + // was faster compiling the same pipeline + if (this->findPipeline(state, pipeline)) { + m_vkd->vkDestroyPipeline(m_vkd->device(), newPipeline, nullptr); + return pipeline; + } + + // Add new pipeline to the set + m_pipelines.push_back({ state, newPipeline }); + + if (m_basePipeline == VK_NULL_HANDLE) + m_basePipeline = newPipeline; + + stats.addCtr(DxvkStatCounter::PipeCountGraphics, 1); + return newPipeline; + } + } + + + bool DxvkGraphicsPipeline::findPipeline( + const DxvkGraphicsPipelineStateInfo& state, + VkPipeline& pipeline) const { + for (const PipelineStruct& pair : m_pipelines) { + if (pair.stateVector == state) { + pipeline = pair.pipeline; + return true; + } + } - if (m_basePipeline == VK_NULL_HANDLE) - m_basePipeline = pipeline; - - stats.addCtr(DxvkStatCounter::PipeCountGraphics, 1); - return pipeline; + return false; } diff --git a/src/dxvk/dxvk_graphics.h b/src/dxvk/dxvk_graphics.h index 8b6f56a4e..5c40928e6 100644 --- a/src/dxvk/dxvk_graphics.h +++ b/src/dxvk/dxvk_graphics.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include "dxvk_binding.h" #include "dxvk_constant_state.h" @@ -160,10 +160,15 @@ namespace dxvk { DxvkGraphicsCommonPipelineStateInfo m_common; + sync::Spinlock m_mutex; std::vector m_pipelines; VkPipeline m_basePipeline = VK_NULL_HANDLE; + bool findPipeline( + const DxvkGraphicsPipelineStateInfo& state, + VkPipeline& pipeline) const; + VkPipeline compilePipeline( const DxvkGraphicsPipelineStateInfo& state, VkPipeline baseHandle) const; diff --git a/src/dxvk/dxvk_pipemanager.cpp b/src/dxvk/dxvk_pipemanager.cpp index 7b9f554f6..d827b4db2 100644 --- a/src/dxvk/dxvk_pipemanager.cpp +++ b/src/dxvk/dxvk_pipemanager.cpp @@ -21,17 +21,19 @@ namespace dxvk { } - bool DxvkPipelineKeyEq::operator () (const DxvkComputePipelineKey& a, const DxvkComputePipelineKey& b) const { + bool DxvkPipelineKeyEq::operator () ( + const DxvkComputePipelineKey& a, + const DxvkComputePipelineKey& b) const { return a.cs == b.cs; } - bool DxvkPipelineKeyEq::operator () (const DxvkGraphicsPipelineKey& a, const DxvkGraphicsPipelineKey& b) const { - return a.vs == b.vs - && a.tcs == b.tcs - && a.tes == b.tes - && a.gs == b.gs - && a.fs == b.fs; + bool DxvkPipelineKeyEq::operator () ( + const DxvkGraphicsPipelineKey& a, + const DxvkGraphicsPipelineKey& b) const { + return a.vs == b.vs && a.tcs == b.tcs + && a.tes == b.tes && a.gs == b.gs + && a.fs == b.fs; } @@ -52,6 +54,8 @@ namespace dxvk { if (cs == nullptr) return nullptr; + std::lock_guard lock(m_mutex); + DxvkComputePipelineKey key; key.cs = cs; @@ -77,6 +81,8 @@ namespace dxvk { if (vs == nullptr) return nullptr; + std::lock_guard lock(m_mutex); + DxvkGraphicsPipelineKey key; key.vs = vs; key.tcs = tcs; diff --git a/src/dxvk/dxvk_pipemanager.h b/src/dxvk/dxvk_pipemanager.h index 3690bbd20..2400cdc9c 100644 --- a/src/dxvk/dxvk_pipemanager.h +++ b/src/dxvk/dxvk_pipemanager.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include "dxvk_compute.h" @@ -99,6 +100,8 @@ namespace dxvk { const DxvkDevice* m_device; + std::mutex m_mutex; + std::unordered_map< DxvkComputePipelineKey, Rc,