From 0a151467462765d271bb4a49c6e0b2fda6a8ce5d Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Sat, 30 Jul 2022 22:50:10 +0200 Subject: [PATCH] [dxvk] Use unordered map to look up base pipelines No reason to use a linear list here. The object is always locked when we access this list, so we don't need the lock-free one here. --- src/dxvk/dxvk_graphics.cpp | 53 ++++++++++++++++++-------------------- src/dxvk/dxvk_graphics.h | 42 +++++++++++++++--------------- src/dxvk/dxvk_shader.h | 4 +++ 3 files changed, 50 insertions(+), 49 deletions(-) diff --git a/src/dxvk/dxvk_graphics.cpp b/src/dxvk/dxvk_graphics.cpp index b29f6e63..4d6dc1df 100644 --- a/src/dxvk/dxvk_graphics.cpp +++ b/src/dxvk/dxvk_graphics.cpp @@ -541,7 +541,7 @@ namespace dxvk { this->destroyPipeline(instance.fastHandle.load()); for (const auto& instance : m_basePipelines) - this->destroyPipeline(instance.handle); + this->destroyPipeline(instance.second); } @@ -654,19 +654,10 @@ namespace dxvk { VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT); } - if (!fastHandle) { - // If that didn't succeed, link a pipeline using the - // pre-compiled fragment and vertex shader libraries. - DxvkGraphicsPipelineVertexInputState viState(m_device, state, m_shaders.vs.ptr()); - DxvkGraphicsPipelineFragmentOutputState foState(m_device, state, m_shaders.fs.ptr()); - - DxvkGraphicsPipelineBaseInstanceKey key; - key.viLibrary = m_manager->createVertexInputLibrary(viState); - key.foLibrary = m_manager->createFragmentOutputLibrary(foState); - key.args.depthClipEnable = state.rs.depthClipEnable(); - - baseHandle = this->createBaseInstance(key)->handle; - } + // If that didn't succeed, link a pipeline using the + // pre-compiled fragment and vertex shader libraries. + if (!fastHandle) + baseHandle = this->getBasePipeline(state); } else { // Create optimized variant right away, no choice fastHandle = this->createOptimizedPipeline(state, 0); @@ -692,20 +683,6 @@ namespace dxvk { } - DxvkGraphicsPipelineBaseInstance* DxvkGraphicsPipeline::createBaseInstance( - const DxvkGraphicsPipelineBaseInstanceKey& key) { - for (auto& instance : m_basePipelines) { - if (instance.key.viLibrary == key.viLibrary - && instance.key.foLibrary == key.foLibrary - && instance.key.args == key.args) - return &instance; - } - - VkPipeline handle = createBasePipeline(key); - return &(*m_basePipelines.emplace(key, handle)); - } - - bool DxvkGraphicsPipeline::canCreateBasePipeline( const DxvkGraphicsPipelineStateInfo& state) const { if (!m_vsLibrary || !m_fsLibrary) @@ -751,6 +728,26 @@ namespace dxvk { } + VkPipeline DxvkGraphicsPipeline::getBasePipeline( + const DxvkGraphicsPipelineStateInfo& state) { + DxvkGraphicsPipelineVertexInputState viState(m_device, state, m_shaders.vs.ptr()); + DxvkGraphicsPipelineFragmentOutputState foState(m_device, state, m_shaders.fs.ptr()); + + DxvkGraphicsPipelineBaseInstanceKey key; + key.viLibrary = m_manager->createVertexInputLibrary(viState); + key.foLibrary = m_manager->createFragmentOutputLibrary(foState); + key.args.depthClipEnable = state.rs.depthClipEnable(); + + auto entry = m_basePipelines.find(key); + if (entry != m_basePipelines.end()) + return entry->second; + + VkPipeline handle = createBasePipeline(key); + m_basePipelines.insert({ key, handle }); + return handle; + } + + VkPipeline DxvkGraphicsPipeline::createBasePipeline( const DxvkGraphicsPipelineBaseInstanceKey& key) const { auto vk = m_device->vkd(); diff --git a/src/dxvk/dxvk_graphics.h b/src/dxvk/dxvk_graphics.h index d3593b41..5238d96f 100644 --- a/src/dxvk/dxvk_graphics.h +++ b/src/dxvk/dxvk_graphics.h @@ -274,26 +274,23 @@ namespace dxvk { const DxvkGraphicsPipelineVertexInputLibrary* viLibrary = nullptr; const DxvkGraphicsPipelineFragmentOutputLibrary* foLibrary = nullptr; DxvkShaderPipelineLibraryCompileArgs args; + + bool eq(const DxvkGraphicsPipelineBaseInstanceKey& other) const { + return viLibrary == other.viLibrary + && foLibrary == other.foLibrary + && args == other.args; + } + + size_t hash() const { + DxvkHashState hash; + hash.add(size_t(viLibrary)); + hash.add(size_t(foLibrary)); + hash.add(args.hash()); + return hash; + } }; - /** - * \brief Base pipeline instance - * - * Stores the key and handle of a base pipeline. - */ - struct DxvkGraphicsPipelineBaseInstance { - DxvkGraphicsPipelineBaseInstance() { } - DxvkGraphicsPipelineBaseInstance( - const DxvkGraphicsPipelineBaseInstanceKey& key_, - VkPipeline handle_) - : key(key_), handle(handle_) { } - - DxvkGraphicsPipelineBaseInstanceKey key; - VkPipeline handle = VK_NULL_HANDLE; - }; - - /** * \brief Graphics pipeline * @@ -413,7 +410,10 @@ namespace dxvk { alignas(CACHE_LINE_SIZE) dxvk::mutex m_mutex; sync::List m_pipelines; - sync::List m_basePipelines; + + std::unordered_map< + DxvkGraphicsPipelineBaseInstanceKey, + VkPipeline, DxvkHash, DxvkEq> m_basePipelines; DxvkGraphicsPipelineInstance* createInstance( const DxvkGraphicsPipelineStateInfo& state, @@ -422,12 +422,12 @@ namespace dxvk { DxvkGraphicsPipelineInstance* findInstance( const DxvkGraphicsPipelineStateInfo& state); - DxvkGraphicsPipelineBaseInstance* createBaseInstance( - const DxvkGraphicsPipelineBaseInstanceKey& key); - bool canCreateBasePipeline( const DxvkGraphicsPipelineStateInfo& state) const; + VkPipeline getBasePipeline( + const DxvkGraphicsPipelineStateInfo& state); + VkPipeline createBasePipeline( const DxvkGraphicsPipelineBaseInstanceKey& key) const; diff --git a/src/dxvk/dxvk_shader.h b/src/dxvk/dxvk_shader.h index 2def7936..5a8f327a 100644 --- a/src/dxvk/dxvk_shader.h +++ b/src/dxvk/dxvk_shader.h @@ -329,6 +329,10 @@ namespace dxvk { bool operator != (const DxvkShaderPipelineLibraryCompileArgs& other) const { return !this->operator == (other); } + + size_t hash() const { + return size_t(depthClipEnable); + } };