From 1b66b8c9f369d2d38d93c2dbe59b333f632a0dea Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Sun, 4 Sep 2022 18:05:33 +0200 Subject: [PATCH] [dxvk] Go back to fence-based command list synchronization Timeline semaphores are too unreliable on 32-bit Proton builds. --- src/dxvk/dxvk_cmdlist.cpp | 29 +++++++++++++++++++++++++++-- src/dxvk/dxvk_cmdlist.h | 15 +++++++++++++++ src/dxvk/dxvk_queue.cpp | 34 +++------------------------------- src/dxvk/dxvk_queue.h | 4 ---- 4 files changed, 45 insertions(+), 37 deletions(-) diff --git a/src/dxvk/dxvk_cmdlist.cpp b/src/dxvk/dxvk_cmdlist.cpp index 2026a9162..86c3acbdf 100644 --- a/src/dxvk/dxvk_cmdlist.cpp +++ b/src/dxvk/dxvk_cmdlist.cpp @@ -39,6 +39,12 @@ namespace dxvk { } + void DxvkCommandSubmission::signalFence( + VkFence fence) { + m_fence = fence; + } + + void DxvkCommandSubmission::executeCommandBuffer( VkCommandBuffer commandBuffer) { VkCommandBufferSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO }; @@ -73,7 +79,7 @@ namespace dxvk { VkResult vr = VK_SUCCESS; if (!this->isEmpty()) - vr = vk->vkQueueSubmit2(queue, 1, &submitInfo, VK_NULL_HANDLE); + vr = vk->vkQueueSubmit2(queue, 1, &submitInfo, m_fence); this->reset(); return vr; @@ -81,6 +87,7 @@ namespace dxvk { void DxvkCommandSubmission::reset() { + m_fence = VK_NULL_HANDLE; m_semaphoreWaits.clear(); m_semaphoreSignals.clear(); m_commandBuffers.clear(); @@ -88,7 +95,8 @@ namespace dxvk { bool DxvkCommandSubmission::isEmpty() const { - return m_semaphoreWaits.empty() + return m_fence == VK_NULL_HANDLE + && m_semaphoreWaits.empty() && m_semaphoreSignals.empty() && m_commandBuffers.empty(); } @@ -171,6 +179,11 @@ namespace dxvk { if (m_vkd->vkCreateSemaphore(m_vkd->device(), &semaphoreInfo, nullptr, &m_sdmaSemaphore)) throw DxvkError("DxvkCommandList: Failed to create semaphore"); + VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO }; + + if (m_vkd->vkCreateFence(m_vkd->device(), &fenceInfo, nullptr, &m_fence)) + throw DxvkError("DxvkCommandList: Failed to create fence"); + m_graphicsPool = new DxvkCommandPool(device, graphicsQueue.queueFamily); if (transferQueue.queueFamily != graphicsQueue.queueFamily) @@ -286,6 +299,9 @@ namespace dxvk { m_commandSubmission.signalSemaphore(m_wsiSemaphores.present, 0, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT); } + + // Signal synchronization fence on final submission + m_commandSubmission.signalFence(m_fence); } // Finally, submit all graphics commands of the current submission @@ -350,6 +366,11 @@ namespace dxvk { } + VkResult DxvkCommandList::synchronizeFence() { + return m_vkd->vkWaitForFences(m_vkd->device(), 1, &m_fence, VK_TRUE, ~0ull); + } + + void DxvkCommandList::reset() { // Free resources and other objects // that are no longer in use @@ -389,6 +410,10 @@ namespace dxvk { // Reset actual command buffers and pools m_graphicsPool->reset(); m_transferPool->reset(); + + // Reset fence + if (m_vkd->vkResetFences(m_vkd->device(), 1, &m_fence)) + Logger::err("DxvkCommandList: Failed to reset fence"); } diff --git a/src/dxvk/dxvk_cmdlist.h b/src/dxvk/dxvk_cmdlist.h index fc096b016..45f67c6d4 100644 --- a/src/dxvk/dxvk_cmdlist.h +++ b/src/dxvk/dxvk_cmdlist.h @@ -72,6 +72,13 @@ namespace dxvk { uint64_t value, VkPipelineStageFlags2 stageMask); + /** + * \brief Adds a fence to signal + * \param [in] fence The fence + */ + void signalFence( + VkFence fence); + /** * \brief Adds a command buffer to execute * \param [in] commandBuffer The command buffer @@ -105,6 +112,7 @@ namespace dxvk { private: + VkFence m_fence = VK_NULL_HANDLE; std::vector m_semaphoreWaits; std::vector m_semaphoreSignals; std::vector m_commandBuffers; @@ -359,6 +367,12 @@ namespace dxvk { m_wsiSemaphores = wsiSemaphores; } + /** + * \brief Synchronizes with command list fence + * \returns Return value of vkWaitForFences call + */ + VkResult synchronizeFence(); + /** * \brief Resets the command list * @@ -996,6 +1010,7 @@ namespace dxvk { Rc m_transferPool; VkSemaphore m_sdmaSemaphore = VK_NULL_HANDLE; + VkFence m_fence = VK_NULL_HANDLE; DxvkCommandSubmissionInfo m_cmd; diff --git a/src/dxvk/dxvk_queue.cpp b/src/dxvk/dxvk_queue.cpp index 2db3fdd36..520a901e3 100644 --- a/src/dxvk/dxvk_queue.cpp +++ b/src/dxvk/dxvk_queue.cpp @@ -32,8 +32,6 @@ namespace dxvk { m_submitThread.join(); m_finishThread.join(); - synchronizeSemaphore(m_semaphoreValue); - vk->vkDestroySemaphore(vk->device(), m_semaphore, nullptr); } @@ -95,30 +93,6 @@ namespace dxvk { } - VkResult DxvkSubmissionQueue::synchronizeSemaphore( - uint64_t semaphoreValue) { - auto vk = m_device->vkd(); - - VkSemaphoreWaitInfo waitInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO }; - waitInfo.semaphoreCount = 1; - waitInfo.pSemaphores = &m_semaphore; - waitInfo.pValues = &semaphoreValue; - - // 32-bit winevulkan on Proton seems to be broken here - // and returns with VK_TIMEOUT, even though the timeout - // is infinite. Work around this by spinning. - VkResult vr = VK_TIMEOUT; - - while (vr == VK_TIMEOUT) - vr = vk->vkWaitSemaphores(vk->device(), &waitInfo, ~0ull); - - if (vr) - Logger::err(str::format("Failed to synchronize with global timeline semaphore: ", vr)); - - return vr; - } - - void DxvkSubmissionQueue::submitCmdLists() { env::setThreadName("dxvk-submit"); @@ -141,12 +115,10 @@ namespace dxvk { if (m_lastError != VK_ERROR_DEVICE_LOST) { std::lock_guard lock(m_mutexQueue); - if (entry.submit.cmdList != nullptr) { + if (entry.submit.cmdList != nullptr) status = entry.submit.cmdList->submit(m_semaphore, m_semaphoreValue); - entry.submit.semaphoreValue = m_semaphoreValue; - } else if (entry.present.presenter != nullptr) { + else if (entry.present.presenter != nullptr) status = entry.present.presenter->presentImage(); - } } else { // Don't submit anything after device loss // so that drivers get a chance to recover @@ -200,7 +172,7 @@ namespace dxvk { VkResult status = m_lastError.load(); if (status != VK_ERROR_DEVICE_LOST) - status = synchronizeSemaphore(entry.submit.semaphoreValue); + status = entry.submit.cmdList->synchronizeFence(); if (status != VK_SUCCESS) { m_lastError = status; diff --git a/src/dxvk/dxvk_queue.h b/src/dxvk/dxvk_queue.h index 370c763b1..8f589b558 100644 --- a/src/dxvk/dxvk_queue.h +++ b/src/dxvk/dxvk_queue.h @@ -33,7 +33,6 @@ namespace dxvk { */ struct DxvkSubmitInfo { Rc cmdList; - uint64_t semaphoreValue; }; @@ -200,9 +199,6 @@ namespace dxvk { dxvk::thread m_submitThread; dxvk::thread m_finishThread; - VkResult synchronizeSemaphore( - uint64_t semaphoreValue); - void submitCmdLists(); void finishCmdLists();