From 3e64e1b3f56d2245e1cab5f83927ef4cb1e5a2df Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Thu, 7 Oct 2021 20:32:41 +0200 Subject: [PATCH] [dxvk] Explicitly stop state cache worker threads on device destruction Otherwise, the workers may access objects that are being destroyed an app thread. --- src/dxvk/dxvk_device.cpp | 4 ++++ src/dxvk/dxvk_pipemanager.cpp | 6 ++++++ src/dxvk/dxvk_pipemanager.h | 5 +++++ src/dxvk/dxvk_state_cache.cpp | 32 +++++++++++++++++++------------- src/dxvk/dxvk_state_cache.h | 7 ++++++- 5 files changed, 40 insertions(+), 14 deletions(-) diff --git a/src/dxvk/dxvk_device.cpp b/src/dxvk/dxvk_device.cpp index bd08a5b0..8dad4e97 100644 --- a/src/dxvk/dxvk_device.cpp +++ b/src/dxvk/dxvk_device.cpp @@ -29,6 +29,10 @@ namespace dxvk { // Wait for all pending Vulkan commands to be // executed before we destroy any resources. this->waitForIdle(); + + // Stop workers explicitly in order to prevent + // access to structures that are being destroyed. + m_objects.pipelineManager().stopWorkerThreads(); } diff --git a/src/dxvk/dxvk_pipemanager.cpp b/src/dxvk/dxvk_pipemanager.cpp index 08d8ec5f..0e112e51 100644 --- a/src/dxvk/dxvk_pipemanager.cpp +++ b/src/dxvk/dxvk_pipemanager.cpp @@ -78,5 +78,11 @@ namespace dxvk { return m_stateCache != nullptr && m_stateCache->isCompilingShaders(); } + + + void DxvkPipelineManager::stopWorkerThreads() const { + if (m_stateCache != nullptr) + m_stateCache->stopWorkerThreads(); + } } diff --git a/src/dxvk/dxvk_pipemanager.h b/src/dxvk/dxvk_pipemanager.h index 7b7fe661..f32a8913 100644 --- a/src/dxvk/dxvk_pipemanager.h +++ b/src/dxvk/dxvk_pipemanager.h @@ -89,6 +89,11 @@ namespace dxvk { * \returns \c true if shaders are being compiled */ bool isCompilingShaders() const; + + /** + * \brief Stops async compiler threads + */ + void stopWorkerThreads() const; private: diff --git a/src/dxvk/dxvk_state_cache.cpp b/src/dxvk/dxvk_state_cache.cpp index 17528ea3..acc57468 100644 --- a/src/dxvk/dxvk_state_cache.cpp +++ b/src/dxvk/dxvk_state_cache.cpp @@ -210,19 +210,7 @@ namespace dxvk { DxvkStateCache::~DxvkStateCache() { - { std::lock_guard workerLock(m_workerLock); - std::lock_guard writerLock(m_writerLock); - - m_stopThreads.store(true); - - m_workerCond.notify_all(); - m_writerCond.notify_all(); - } - - for (auto& worker : m_workerThreads) - worker.join(); - - m_writerThread.join(); + this->stopWorkerThreads(); } @@ -314,6 +302,24 @@ namespace dxvk { } + void DxvkStateCache::stopWorkerThreads() { + { std::lock_guard workerLock(m_workerLock); + std::lock_guard writerLock(m_writerLock); + + if (m_stopThreads.exchange(true)) + return; + + m_workerCond.notify_all(); + m_writerCond.notify_all(); + } + + for (auto& worker : m_workerThreads) + worker.join(); + + m_writerThread.join(); + } + + DxvkShaderKey DxvkStateCache::getShaderKey(const Rc& shader) const { return shader != nullptr ? shader->getShaderKey() : g_nullShaderKey; } diff --git a/src/dxvk/dxvk_state_cache.h b/src/dxvk/dxvk_state_cache.h index e958682c..a94dbd0e 100644 --- a/src/dxvk/dxvk_state_cache.h +++ b/src/dxvk/dxvk_state_cache.h @@ -70,7 +70,12 @@ namespace dxvk { */ void registerShader( const Rc& shader); - + + /** + * \brief Explicitly stops worker threads + */ + void stopWorkerThreads(); + /** * \brief Checks whether compiler threads are busy * \returns \c true if we're compiling shaders