1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-02-06 13:54:14 +01:00

[dxvk] Go back to fence-based command list synchronization

Timeline semaphores are too unreliable on 32-bit Proton builds.
This commit is contained in:
Philip Rebohle 2022-09-04 18:05:33 +02:00
parent 439043ddb4
commit 1b66b8c9f3
4 changed files with 45 additions and 37 deletions

View File

@ -39,6 +39,12 @@ namespace dxvk {
} }
void DxvkCommandSubmission::signalFence(
VkFence fence) {
m_fence = fence;
}
void DxvkCommandSubmission::executeCommandBuffer( void DxvkCommandSubmission::executeCommandBuffer(
VkCommandBuffer commandBuffer) { VkCommandBuffer commandBuffer) {
VkCommandBufferSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO }; VkCommandBufferSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO };
@ -73,7 +79,7 @@ namespace dxvk {
VkResult vr = VK_SUCCESS; VkResult vr = VK_SUCCESS;
if (!this->isEmpty()) if (!this->isEmpty())
vr = vk->vkQueueSubmit2(queue, 1, &submitInfo, VK_NULL_HANDLE); vr = vk->vkQueueSubmit2(queue, 1, &submitInfo, m_fence);
this->reset(); this->reset();
return vr; return vr;
@ -81,6 +87,7 @@ namespace dxvk {
void DxvkCommandSubmission::reset() { void DxvkCommandSubmission::reset() {
m_fence = VK_NULL_HANDLE;
m_semaphoreWaits.clear(); m_semaphoreWaits.clear();
m_semaphoreSignals.clear(); m_semaphoreSignals.clear();
m_commandBuffers.clear(); m_commandBuffers.clear();
@ -88,7 +95,8 @@ namespace dxvk {
bool DxvkCommandSubmission::isEmpty() const { bool DxvkCommandSubmission::isEmpty() const {
return m_semaphoreWaits.empty() return m_fence == VK_NULL_HANDLE
&& m_semaphoreWaits.empty()
&& m_semaphoreSignals.empty() && m_semaphoreSignals.empty()
&& m_commandBuffers.empty(); && m_commandBuffers.empty();
} }
@ -171,6 +179,11 @@ namespace dxvk {
if (m_vkd->vkCreateSemaphore(m_vkd->device(), &semaphoreInfo, nullptr, &m_sdmaSemaphore)) if (m_vkd->vkCreateSemaphore(m_vkd->device(), &semaphoreInfo, nullptr, &m_sdmaSemaphore))
throw DxvkError("DxvkCommandList: Failed to create semaphore"); 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); m_graphicsPool = new DxvkCommandPool(device, graphicsQueue.queueFamily);
if (transferQueue.queueFamily != graphicsQueue.queueFamily) if (transferQueue.queueFamily != graphicsQueue.queueFamily)
@ -286,6 +299,9 @@ namespace dxvk {
m_commandSubmission.signalSemaphore(m_wsiSemaphores.present, m_commandSubmission.signalSemaphore(m_wsiSemaphores.present,
0, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT); 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 // 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() { void DxvkCommandList::reset() {
// Free resources and other objects // Free resources and other objects
// that are no longer in use // that are no longer in use
@ -389,6 +410,10 @@ namespace dxvk {
// Reset actual command buffers and pools // Reset actual command buffers and pools
m_graphicsPool->reset(); m_graphicsPool->reset();
m_transferPool->reset(); m_transferPool->reset();
// Reset fence
if (m_vkd->vkResetFences(m_vkd->device(), 1, &m_fence))
Logger::err("DxvkCommandList: Failed to reset fence");
} }

View File

@ -72,6 +72,13 @@ namespace dxvk {
uint64_t value, uint64_t value,
VkPipelineStageFlags2 stageMask); VkPipelineStageFlags2 stageMask);
/**
* \brief Adds a fence to signal
* \param [in] fence The fence
*/
void signalFence(
VkFence fence);
/** /**
* \brief Adds a command buffer to execute * \brief Adds a command buffer to execute
* \param [in] commandBuffer The command buffer * \param [in] commandBuffer The command buffer
@ -105,6 +112,7 @@ namespace dxvk {
private: private:
VkFence m_fence = VK_NULL_HANDLE;
std::vector<VkSemaphoreSubmitInfo> m_semaphoreWaits; std::vector<VkSemaphoreSubmitInfo> m_semaphoreWaits;
std::vector<VkSemaphoreSubmitInfo> m_semaphoreSignals; std::vector<VkSemaphoreSubmitInfo> m_semaphoreSignals;
std::vector<VkCommandBufferSubmitInfo> m_commandBuffers; std::vector<VkCommandBufferSubmitInfo> m_commandBuffers;
@ -359,6 +367,12 @@ namespace dxvk {
m_wsiSemaphores = wsiSemaphores; m_wsiSemaphores = wsiSemaphores;
} }
/**
* \brief Synchronizes with command list fence
* \returns Return value of vkWaitForFences call
*/
VkResult synchronizeFence();
/** /**
* \brief Resets the command list * \brief Resets the command list
* *
@ -996,6 +1010,7 @@ namespace dxvk {
Rc<DxvkCommandPool> m_transferPool; Rc<DxvkCommandPool> m_transferPool;
VkSemaphore m_sdmaSemaphore = VK_NULL_HANDLE; VkSemaphore m_sdmaSemaphore = VK_NULL_HANDLE;
VkFence m_fence = VK_NULL_HANDLE;
DxvkCommandSubmissionInfo m_cmd; DxvkCommandSubmissionInfo m_cmd;

View File

@ -32,8 +32,6 @@ namespace dxvk {
m_submitThread.join(); m_submitThread.join();
m_finishThread.join(); m_finishThread.join();
synchronizeSemaphore(m_semaphoreValue);
vk->vkDestroySemaphore(vk->device(), m_semaphore, nullptr); 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() { void DxvkSubmissionQueue::submitCmdLists() {
env::setThreadName("dxvk-submit"); env::setThreadName("dxvk-submit");
@ -141,12 +115,10 @@ namespace dxvk {
if (m_lastError != VK_ERROR_DEVICE_LOST) { if (m_lastError != VK_ERROR_DEVICE_LOST) {
std::lock_guard<dxvk::mutex> lock(m_mutexQueue); std::lock_guard<dxvk::mutex> lock(m_mutexQueue);
if (entry.submit.cmdList != nullptr) { if (entry.submit.cmdList != nullptr)
status = entry.submit.cmdList->submit(m_semaphore, m_semaphoreValue); 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(); status = entry.present.presenter->presentImage();
}
} else { } else {
// Don't submit anything after device loss // Don't submit anything after device loss
// so that drivers get a chance to recover // so that drivers get a chance to recover
@ -200,7 +172,7 @@ namespace dxvk {
VkResult status = m_lastError.load(); VkResult status = m_lastError.load();
if (status != VK_ERROR_DEVICE_LOST) if (status != VK_ERROR_DEVICE_LOST)
status = synchronizeSemaphore(entry.submit.semaphoreValue); status = entry.submit.cmdList->synchronizeFence();
if (status != VK_SUCCESS) { if (status != VK_SUCCESS) {
m_lastError = status; m_lastError = status;

View File

@ -33,7 +33,6 @@ namespace dxvk {
*/ */
struct DxvkSubmitInfo { struct DxvkSubmitInfo {
Rc<DxvkCommandList> cmdList; Rc<DxvkCommandList> cmdList;
uint64_t semaphoreValue;
}; };
@ -200,9 +199,6 @@ namespace dxvk {
dxvk::thread m_submitThread; dxvk::thread m_submitThread;
dxvk::thread m_finishThread; dxvk::thread m_finishThread;
VkResult synchronizeSemaphore(
uint64_t semaphoreValue);
void submitCmdLists(); void submitCmdLists();
void finishCmdLists(); void finishCmdLists();