diff --git a/src/dxvk/dxvk_device.cpp b/src/dxvk/dxvk_device.cpp index ecd05e43..45c08222 100644 --- a/src/dxvk/dxvk_device.cpp +++ b/src/dxvk/dxvk_device.cpp @@ -221,16 +221,13 @@ namespace dxvk { VkResult DxvkDevice::presentSwapImage( const VkPresentInfoKHR& presentInfo) { - { std::lock_guard statLock(m_statLock); - m_statCounters.addCtr(DxvkStatCounter::QueuePresentCount, 1); - } + { // Queue submissions are not thread safe + std::lock_guard queueLock(m_submissionLock); + std::lock_guard statLock(m_statLock); - this->lockSubmission(); - VkResult status = m_vkd->vkQueuePresentKHR( - m_presentQueue.queueHandle, &presentInfo); - this->unlockSubmission(); - - return status; + m_statCounters.addCtr(DxvkStatCounter::QueuePresentCount, 1); + return m_vkd->vkQueuePresentKHR(m_presentQueue.queueHandle, &presentInfo); + } } @@ -238,17 +235,41 @@ namespace dxvk { const Rc& commandList, const Rc& waitSync, const Rc& wakeSync) { - { std::lock_guard statLock(m_statLock); + VkSemaphore waitSemaphore = VK_NULL_HANDLE; + VkSemaphore wakeSemaphore = VK_NULL_HANDLE; + if (waitSync != nullptr) { + waitSemaphore = waitSync->handle(); + commandList->trackResource(waitSync); + } + + if (wakeSync != nullptr) { + wakeSemaphore = wakeSync->handle(); + commandList->trackResource(wakeSync); + } + + VkResult status; + + { // Queue submissions are not thread safe + std::lock_guard queueLock(m_submissionLock); + std::lock_guard statLock(m_statLock); + m_statCounters.merge(commandList->statCounters()); m_statCounters.addCtr(DxvkStatCounter::QueueSubmitCount, 1); + + status = commandList->submit( + m_graphicsQueue.queueHandle, + waitSemaphore, wakeSemaphore); + } + + if (status == VK_SUCCESS) { + // Add this to the set of running submissions + m_submissionQueue.submit(commandList); + } else { + Logger::err(str::format( + "DxvkDevice: Command buffer submission failed: ", + status)); } - - DxvkSubmission submission; - submission.cmdList = commandList; - submission.semWait = waitSync; - submission.semWake = wakeSync; - m_submissionQueue.submit(std::move(submission)); } diff --git a/src/dxvk/dxvk_device.h b/src/dxvk/dxvk_device.h index 0a55e2cf..95d5210f 100644 --- a/src/dxvk/dxvk_device.h +++ b/src/dxvk/dxvk_device.h @@ -327,6 +327,7 @@ namespace dxvk { * \param [in] commandList The command list to submit * \param [in] waitSync (Optional) Semaphore to wait on * \param [in] wakeSync (Optional) Semaphore to notify + * \returns Synchronization fence */ void submitCommandList( const Rc& commandList, @@ -341,8 +342,7 @@ namespace dxvk { * to lock the queue before submitting command buffers. */ void lockSubmission() { - m_submissionQueue.synchronize(); - m_submissionQueue.lock(); + m_submissionLock.lock(); } /** @@ -352,7 +352,7 @@ namespace dxvk { * itself can use them for submissions again. */ void unlockSubmission() { - m_submissionQueue.unlock(); + m_submissionLock.unlock(); } /** @@ -399,6 +399,7 @@ namespace dxvk { sync::Spinlock m_statLock; DxvkStatCounters m_statCounters; + std::mutex m_submissionLock; DxvkDeviceQueue m_graphicsQueue; DxvkDeviceQueue m_presentQueue; diff --git a/src/dxvk/dxvk_queue.cpp b/src/dxvk/dxvk_queue.cpp index 4970da6b..9dc6b315 100644 --- a/src/dxvk/dxvk_queue.cpp +++ b/src/dxvk/dxvk_queue.cpp @@ -4,130 +4,54 @@ namespace dxvk { DxvkSubmissionQueue::DxvkSubmissionQueue(DxvkDevice* device) - : m_device (device), - m_queueThread ([this] () { threadQueue(); }), - m_submitThread([this] () { threadSubmit(); }) { + : m_device(device), + m_thread([this] () { threadFunc(); }) { } DxvkSubmissionQueue::~DxvkSubmissionQueue() { - { std::unique_lock lockQueue (m_queueLock); - std::unique_lock lockSubmit(m_submitLock); - + { std::unique_lock lock(m_mutex); m_stopped.store(true); } - m_submitCondOnAdd.notify_one(); - m_submitThread.join(); - - m_queueCond.notify_one(); - m_queueThread.join(); + m_condOnAdd.notify_one(); + m_thread.join(); } - void DxvkSubmissionQueue::submit(DxvkSubmission submission) { - std::unique_lock lock(m_submitLock); - - m_submitCondOnTake.wait(lock, [this] { - return m_submitQueue.size() < MaxNumQueuedCommandBuffers; - }); - - m_submits += 1; - m_submitQueue.push(std::move(submission)); - m_submitCondOnAdd.notify_one(); - } - - - void DxvkSubmissionQueue::synchronize() { - std::unique_lock lock(m_submitLock); - - m_submitCondOnTake.wait(lock, [this] { - return m_submitQueue.size() == 0; - }); - } - - - void DxvkSubmissionQueue::threadSubmit() { - env::setThreadName(L"dxvk-submit"); - - while (!m_stopped.load()) { - DxvkSubmission submission; - - { std::unique_lock lock(m_submitLock); - - m_submitCondOnAdd.wait(lock, [this] { - return m_stopped.load() || (m_submitQueue.size() != 0); - }); - - if (m_submitQueue.size() != 0) - submission = std::move(m_submitQueue.front()); - } - - if (submission.cmdList != nullptr) { - // Make sure that the semaphores do not get deleted or - // reused before the command submission has completed - VkSemaphore waitSemaphore = VK_NULL_HANDLE; - VkSemaphore wakeSemaphore = VK_NULL_HANDLE; - - if (submission.semWait != nullptr) { - waitSemaphore = submission.semWait->handle(); - submission.cmdList->trackResource(submission.semWait); - } - - if (submission.semWake != nullptr) { - wakeSemaphore = submission.semWake->handle(); - submission.cmdList->trackResource(submission.semWake); - } - - // Protect the Vulkan queue itself from concurrent access - { std::unique_lock lock(m_externalLock); - - VkResult status = submission.cmdList->submit( - m_device->m_graphicsQueue.queueHandle, - waitSemaphore, wakeSemaphore); - - if (status != VK_SUCCESS) - Logger::err(str::format("Dxvk: Submission failed: ", status)); - } - - // Process this submission on the 'queue' thread - { std::unique_lock lock(m_queueLock); - - m_queueEntries.push(std::move(submission.cmdList)); - m_queueCond.notify_one(); - } - - // Remove submission now. We cannot do this earlier as - // the synchronize method depends on this behaviour. - { std::unique_lock lock(m_submitLock); - - if (m_submitQueue.size() != 0) - m_submitQueue.pop(); - } - } - - m_submitCondOnTake.notify_one(); + void DxvkSubmissionQueue::submit(const Rc& cmdList) { + { std::unique_lock lock(m_mutex); + + m_condOnTake.wait(lock, [this] { + return m_entries.size() < MaxNumQueuedCommandBuffers; + }); + + m_submits += 1; + m_entries.push(cmdList); + m_condOnAdd.notify_one(); } } - - - void DxvkSubmissionQueue::threadQueue() { + + + void DxvkSubmissionQueue::threadFunc() { env::setThreadName(L"dxvk-queue"); while (!m_stopped.load()) { Rc cmdList; - { std::unique_lock lock(m_queueLock); + { std::unique_lock lock(m_mutex); - m_queueCond.wait(lock, [this] { - return m_stopped.load() || (m_queueEntries.size() != 0); + m_condOnAdd.wait(lock, [this] { + return m_stopped.load() || (m_entries.size() != 0); }); - if (m_queueEntries.size() != 0) { - cmdList = std::move(m_queueEntries.front()); - m_queueEntries.pop(); + if (m_entries.size() != 0) { + cmdList = std::move(m_entries.front()); + m_entries.pop(); } + + m_condOnTake.notify_one(); } if (cmdList != nullptr) { diff --git a/src/dxvk/dxvk_queue.h b/src/dxvk/dxvk_queue.h index 1fe71447..01957002 100644 --- a/src/dxvk/dxvk_queue.h +++ b/src/dxvk/dxvk_queue.h @@ -11,12 +11,6 @@ namespace dxvk { class DxvkDevice; - - struct DxvkSubmission { - Rc cmdList; - Rc semWait; - Rc semWake; - }; /** * \brief Submission queue @@ -47,33 +41,9 @@ namespace dxvk { * to finish executing on the GPU and signal * any queries and events that are used by * the command list in question. - * \param [in] submission Command submission + * \param [in] cmdList The command list */ - void submit(DxvkSubmission submission); - - /** - * \brief Synchronizes with submission thread - * - * Waits until all submissions queued prior - * to this call are submitted to the GPU. - */ - void synchronize(); - - /** - * \brief Locks external queue lock - * Protects the Vulkan queue. - */ - void lock() { - m_externalLock.lock(); - } - - /** - * \brief Locks external queue lock - * Releases the Vulkan queue. - */ - void unlock() { - m_externalLock.unlock(); - } + void submit(const Rc& cmdList); private: @@ -81,22 +51,14 @@ namespace dxvk { std::atomic m_stopped = { false }; std::atomic m_submits = { 0u }; - - std::mutex m_externalLock; - std::mutex m_queueLock; - std::condition_variable m_queueCond; - std::queue> m_queueEntries; - dxvk::thread m_queueThread; + std::mutex m_mutex; + std::condition_variable m_condOnAdd; + std::condition_variable m_condOnTake; + std::queue> m_entries; + dxvk::thread m_thread; - std::mutex m_submitLock; - std::condition_variable m_submitCondOnAdd; - std::condition_variable m_submitCondOnTake; - std::queue m_submitQueue; - dxvk::thread m_submitThread; - - void threadSubmit(); - void threadQueue(); + void threadFunc(); };