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:
parent
a4fe43462c
commit
67e2ee1b26
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user