[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(
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");
}

View File

@ -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<VkSemaphoreSubmitInfo> m_semaphoreWaits;
std::vector<VkSemaphoreSubmitInfo> m_semaphoreSignals;
std::vector<VkCommandBufferSubmitInfo> 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<DxvkCommandPool> m_transferPool;
VkSemaphore m_sdmaSemaphore = VK_NULL_HANDLE;
VkFence m_fence = VK_NULL_HANDLE;
DxvkCommandSubmissionInfo m_cmd;

View File

@ -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<dxvk::mutex> 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;

View File

@ -33,7 +33,6 @@ namespace dxvk {
*/
struct DxvkSubmitInfo {
Rc<DxvkCommandList> 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();