diff --git a/src/dxvk/dxvk_cs.cpp b/src/dxvk/dxvk_cs.cpp index 7061f1a6..5f1b57df 100644 --- a/src/dxvk/dxvk_cs.cpp +++ b/src/dxvk/dxvk_cs.cpp @@ -119,7 +119,7 @@ namespace dxvk { { std::unique_lock lock(m_mutex); seq = ++m_chunksDispatched; - m_chunksQueued.push(std::move(chunk)); + m_chunksQueued.push_back(std::move(chunk)); } m_condOnAdd.notify_one(); @@ -152,35 +152,36 @@ namespace dxvk { void DxvkCsThread::threadFunc() { env::setThreadName("dxvk-cs"); - DxvkCsChunkRef chunk; + // Local chunk queue, we use two queues and swap between + // them in order to potentially reduce lock contention. + std::vector chunks; try { while (!m_stopped.load()) { { std::unique_lock lock(m_mutex); - if (chunk) { - m_chunksExecuted++; - m_condOnSync.notify_one(); - - chunk = DxvkCsChunkRef(); - } - - if (m_chunksQueued.size() == 0) { - m_condOnAdd.wait(lock, [this] { - return (m_chunksQueued.size() != 0) - || (m_stopped.load()); - }); - } - - if (m_chunksQueued.size() != 0) { - chunk = std::move(m_chunksQueued.front()); - m_chunksQueued.pop(); - } + + m_condOnAdd.wait(lock, [this] { + return (!m_chunksQueued.empty()) + || (m_stopped.load()); + }); + + std::swap(chunks, m_chunksQueued); } - - if (chunk) { + + for (auto& chunk : chunks) { m_context->addStatCtr(DxvkStatCounter::CsChunkCount, 1); + chunk->executeAll(m_context.ptr()); + + m_chunksExecuted += 1; + m_condOnSync.notify_one(); + + // Explicitly free chunk here to release + // references to any resources held by it + chunk = DxvkCsChunkRef(); } + + chunks.clear(); } } catch (const DxvkError& e) { Logger::err("Exception on CS thread!"); diff --git a/src/dxvk/dxvk_cs.h b/src/dxvk/dxvk_cs.h index 72691c34..98bbc698 100644 --- a/src/dxvk/dxvk_cs.h +++ b/src/dxvk/dxvk_cs.h @@ -432,7 +432,7 @@ namespace dxvk { dxvk::mutex m_mutex; dxvk::condition_variable m_condOnAdd; dxvk::condition_variable m_condOnSync; - std::queue m_chunksQueued; + std::vector m_chunksQueued; dxvk::thread m_thread; void threadFunc();