1
0
mirror of https://github.com/EduApps-CDG/OpenDX synced 2024-12-30 09:45:37 +01:00

[dxvk] Use lock-free list for graphics pipeline lookup

And use a proper mutex if we do have to synchronize,
so that we can avoid busy-waits.
This commit is contained in:
Philip Rebohle 2022-02-19 16:30:14 +01:00
parent a4fe43462c
commit 67e2ee1b26
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
2 changed files with 31 additions and 24 deletions

View File

@ -63,22 +63,25 @@ namespace dxvk {
VkPipeline DxvkGraphicsPipeline::getPipelineHandle( VkPipeline DxvkGraphicsPipeline::getPipelineHandle(
const DxvkGraphicsPipelineStateInfo& state, const DxvkGraphicsPipelineStateInfo& state,
const DxvkRenderPass* renderPass) { const DxvkRenderPass* renderPass) {
DxvkGraphicsPipelineInstance* instance = nullptr; DxvkGraphicsPipelineInstance* instance = this->findInstance(state, renderPass);
{ std::lock_guard<sync::Spinlock> lock(m_mutex); if (unlikely(!instance)) {
// Exit early if the state vector is invalid
if (!this->validatePipelineState(state))
return VK_NULL_HANDLE;
// Prevent other threads from adding new instances and check again
std::lock_guard<dxvk::mutex> lock(m_mutex);
instance = this->findInstance(state, renderPass); instance = this->findInstance(state, renderPass);
if (instance)
return instance->pipeline();
instance = this->createInstance(state, renderPass);
}
if (!instance)
return VK_NULL_HANDLE;
this->writePipelineStateToCache(state, renderPass->format()); if (!instance) {
// Keep pipeline object locked, at worst we're going to stall
// a state cache worker and the current thread needs priority.
instance = this->createInstance(state, renderPass);
this->writePipelineStateToCache(state, renderPass->format());
}
}
return instance->pipeline(); return instance->pipeline();
} }
@ -86,7 +89,13 @@ namespace dxvk {
void DxvkGraphicsPipeline::compilePipeline( void DxvkGraphicsPipeline::compilePipeline(
const DxvkGraphicsPipelineStateInfo& state, const DxvkGraphicsPipelineStateInfo& state,
const DxvkRenderPass* renderPass) { const DxvkRenderPass* renderPass) {
std::lock_guard<sync::Spinlock> lock(m_mutex); // Exit early if the state vector is invalid
if (!this->validatePipelineState(state))
return;
// Keep the object locked while compiling a pipeline since compiling
// similar pipelines concurrently is fragile on some drivers
std::lock_guard<dxvk::mutex> lock(m_mutex);
if (!this->findInstance(state, renderPass)) if (!this->findInstance(state, renderPass))
this->createInstance(state, renderPass); this->createInstance(state, renderPass);
@ -96,15 +105,10 @@ namespace dxvk {
DxvkGraphicsPipelineInstance* DxvkGraphicsPipeline::createInstance( DxvkGraphicsPipelineInstance* DxvkGraphicsPipeline::createInstance(
const DxvkGraphicsPipelineStateInfo& state, const DxvkGraphicsPipelineStateInfo& state,
const DxvkRenderPass* renderPass) { const DxvkRenderPass* renderPass) {
// If the pipeline state vector is invalid, don't try VkPipeline pipeline = this->createPipeline(state, renderPass);
// to create a new pipeline, it won't work anyway.
if (!this->validatePipelineState(state))
return nullptr;
VkPipeline newPipelineHandle = this->createPipeline(state, renderPass);
m_pipeMgr->m_numGraphicsPipelines += 1; m_pipeMgr->m_numGraphicsPipelines += 1;
return &m_pipelines.emplace_back(state, renderPass, newPipelineHandle); return &(*m_pipelines.emplace(state, renderPass, pipeline));
} }

View File

@ -2,6 +2,8 @@
#include <mutex> #include <mutex>
#include "../util/sync/sync_list.h"
#include "dxvk_bind_mask.h" #include "dxvk_bind_mask.h"
#include "dxvk_constant_state.h" #include "dxvk_constant_state.h"
#include "dxvk_graphics_state.h" #include "dxvk_graphics_state.h"
@ -80,7 +82,7 @@ namespace dxvk {
DxvkGraphicsPipelineInstance() DxvkGraphicsPipelineInstance()
: m_stateVector (), : m_stateVector (),
m_renderPass (VK_NULL_HANDLE), m_renderPass (nullptr),
m_pipeline (VK_NULL_HANDLE) { } m_pipeline (VK_NULL_HANDLE) { }
DxvkGraphicsPipelineInstance( DxvkGraphicsPipelineInstance(
@ -220,8 +222,9 @@ namespace dxvk {
DxvkGraphicsCommonPipelineStateInfo m_common; DxvkGraphicsCommonPipelineStateInfo m_common;
// List of pipeline instances, shared between threads // List of pipeline instances, shared between threads
alignas(CACHE_LINE_SIZE) sync::Spinlock m_mutex; alignas(CACHE_LINE_SIZE)
std::vector<DxvkGraphicsPipelineInstance> m_pipelines; dxvk::mutex m_mutex;
sync::List<DxvkGraphicsPipelineInstance> m_pipelines;
DxvkGraphicsPipelineInstance* createInstance( DxvkGraphicsPipelineInstance* createInstance(
const DxvkGraphicsPipelineStateInfo& state, const DxvkGraphicsPipelineStateInfo& state,