mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-01-31 14:52:11 +01:00
[dxvk] Use timeline semaphores for GPU synchronization
Ditches the old fence and binary semaphore code.
This commit is contained in:
parent
1ee60048c0
commit
27539fc838
@ -174,18 +174,6 @@ namespace dxvk {
|
||||
const auto& graphicsQueue = m_device->queues().graphics;
|
||||
const auto& transferQueue = m_device->queues().transfer;
|
||||
|
||||
VkSemaphoreCreateInfo semaphoreInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
|
||||
|
||||
if (m_vkd->vkCreateSemaphore(m_vkd->device(), &semaphoreInfo, nullptr, &m_bindSemaphore)
|
||||
|| m_vkd->vkCreateSemaphore(m_vkd->device(), &semaphoreInfo, nullptr, &m_postSemaphore)
|
||||
|| 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)
|
||||
@ -197,16 +185,12 @@ namespace dxvk {
|
||||
|
||||
DxvkCommandList::~DxvkCommandList() {
|
||||
this->reset();
|
||||
|
||||
m_vkd->vkDestroySemaphore(m_vkd->device(), m_bindSemaphore, nullptr);
|
||||
m_vkd->vkDestroySemaphore(m_vkd->device(), m_postSemaphore, nullptr);
|
||||
m_vkd->vkDestroySemaphore(m_vkd->device(), m_sdmaSemaphore, nullptr);
|
||||
|
||||
m_vkd->vkDestroyFence(m_vkd->device(), m_fence, nullptr);
|
||||
}
|
||||
|
||||
|
||||
VkResult DxvkCommandList::submit() {
|
||||
VkResult DxvkCommandList::submit(
|
||||
const DxvkTimelineSemaphores& semaphores,
|
||||
DxvkTimelineSemaphoreValues& timelines) {
|
||||
VkResult status = VK_SUCCESS;
|
||||
|
||||
const auto& graphics = m_device->queues().graphics;
|
||||
@ -236,18 +220,16 @@ namespace dxvk {
|
||||
if (sparseBind) {
|
||||
// Sparse binding needs to serialize command execution, so wait
|
||||
// for any prior submissions, then block any subsequent ones
|
||||
m_commandSubmission.signalSemaphore(m_bindSemaphore, 0, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT);
|
||||
sparseBind->waitSemaphore(semaphores.graphics, timelines.graphics);
|
||||
sparseBind->waitSemaphore(semaphores.transfer, timelines.transfer);
|
||||
|
||||
if ((status = m_commandSubmission.submit(m_device, graphics.queueHandle)))
|
||||
return status;
|
||||
|
||||
sparseBind->waitSemaphore(m_bindSemaphore, 0);
|
||||
sparseBind->signalSemaphore(m_postSemaphore, 0);
|
||||
sparseBind->signalSemaphore(semaphores.graphics, ++timelines.graphics);
|
||||
|
||||
if ((status = sparseBind->submit(m_device, sparse.queueHandle)))
|
||||
return status;
|
||||
|
||||
m_commandSubmission.waitSemaphore(m_postSemaphore, 0, VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT);
|
||||
m_commandSubmission.waitSemaphore(semaphores.graphics,
|
||||
timelines.graphics, VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT);
|
||||
}
|
||||
|
||||
// Submit transfer commands as necessary
|
||||
@ -257,12 +239,14 @@ namespace dxvk {
|
||||
// If we had either a transfer command or a semaphore wait, submit to the
|
||||
// transfer queue so that all subsequent commands get stalled as necessary.
|
||||
if (m_device->hasDedicatedTransferQueue() && !m_commandSubmission.isEmpty()) {
|
||||
m_commandSubmission.signalSemaphore(m_sdmaSemaphore, 0, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT);
|
||||
m_commandSubmission.signalSemaphore(semaphores.transfer,
|
||||
++timelines.transfer, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT);
|
||||
|
||||
if ((status = m_commandSubmission.submit(m_device, transfer.queueHandle)))
|
||||
return status;
|
||||
|
||||
m_commandSubmission.waitSemaphore(m_sdmaSemaphore, 0, VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT);
|
||||
m_commandSubmission.waitSemaphore(semaphores.transfer,
|
||||
timelines.transfer, VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT);
|
||||
}
|
||||
|
||||
// We promise to never do weird stuff to WSI images on
|
||||
@ -291,14 +275,25 @@ 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);
|
||||
}
|
||||
|
||||
m_commandSubmission.signalSemaphore(semaphores.graphics,
|
||||
++timelines.graphics, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT);
|
||||
|
||||
// Finally, submit all graphics commands of the current submission
|
||||
if ((status = m_commandSubmission.submit(m_device, graphics.queueHandle)))
|
||||
return status;
|
||||
|
||||
// If there are WSI semaphores involved, do another submit only
|
||||
// containing a timeline semaphore signal so that we can be sure
|
||||
// that they are safe to use afterwards.
|
||||
if ((m_wsiSemaphores.present || m_wsiSemaphores.acquire) && isLast) {
|
||||
m_commandSubmission.signalSemaphore(semaphores.graphics,
|
||||
++timelines.graphics, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT);
|
||||
|
||||
if ((status = m_commandSubmission.submit(m_device, graphics.queueHandle)))
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
return VK_SUCCESS;
|
||||
@ -358,11 +353,6 @@ 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
|
||||
@ -395,10 +385,6 @@ 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");
|
||||
}
|
||||
|
||||
|
||||
|
@ -18,6 +18,26 @@
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief Timeline semaphore pair
|
||||
*
|
||||
* One semaphore for each queue.
|
||||
*/
|
||||
struct DxvkTimelineSemaphores {
|
||||
VkSemaphore graphics = VK_NULL_HANDLE;
|
||||
VkSemaphore transfer = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Timeline semaphore values
|
||||
*/
|
||||
struct DxvkTimelineSemaphoreValues {
|
||||
uint64_t graphics = 0u;
|
||||
uint64_t transfer = 0u;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Command buffer flags
|
||||
*
|
||||
@ -195,9 +215,14 @@ namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief Submits command list
|
||||
*
|
||||
* \param [in] semaphores Timeline semaphore pair
|
||||
* \param [in] timelines Timeline semaphore values
|
||||
* \returns Submission status
|
||||
*/
|
||||
VkResult submit();
|
||||
VkResult submit(
|
||||
const DxvkTimelineSemaphores& semaphores,
|
||||
DxvkTimelineSemaphoreValues& timelines);
|
||||
|
||||
/**
|
||||
* \brief Stat counters
|
||||
@ -341,12 +366,6 @@ namespace dxvk {
|
||||
m_wsiSemaphores = wsiSemaphores;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Synchronizes with command list fence
|
||||
* \returns Return value of vkWaitForFences call
|
||||
*/
|
||||
VkResult synchronizeFence();
|
||||
|
||||
/**
|
||||
* \brief Resets the command list
|
||||
*
|
||||
@ -1047,11 +1066,6 @@ namespace dxvk {
|
||||
Rc<DxvkCommandPool> m_graphicsPool;
|
||||
Rc<DxvkCommandPool> m_transferPool;
|
||||
|
||||
VkSemaphore m_bindSemaphore = VK_NULL_HANDLE;
|
||||
VkSemaphore m_postSemaphore = VK_NULL_HANDLE;
|
||||
VkSemaphore m_sdmaSemaphore = VK_NULL_HANDLE;
|
||||
VkFence m_fence = VK_NULL_HANDLE;
|
||||
|
||||
DxvkCommandSubmissionInfo m_cmd;
|
||||
|
||||
PresenterSync m_wsiSemaphores = { };
|
||||
|
@ -141,10 +141,12 @@ namespace dxvk {
|
||||
if (m_callback)
|
||||
m_callback(true);
|
||||
|
||||
if (entry.submit.cmdList != nullptr)
|
||||
entry.result = entry.submit.cmdList->submit();
|
||||
else if (entry.present.presenter != nullptr)
|
||||
if (entry.submit.cmdList != nullptr) {
|
||||
entry.result = entry.submit.cmdList->submit(m_semaphores, m_timelines);
|
||||
entry.timelines = m_timelines;
|
||||
} else if (entry.present.presenter != nullptr) {
|
||||
entry.result = entry.present.presenter->presentImage(entry.present.presentMode, entry.present.frameId);
|
||||
}
|
||||
|
||||
if (m_callback)
|
||||
m_callback(false);
|
||||
@ -182,6 +184,8 @@ namespace dxvk {
|
||||
void DxvkSubmissionQueue::finishCmdLists() {
|
||||
env::setThreadName("dxvk-queue");
|
||||
|
||||
auto vk = m_device->vkd();
|
||||
|
||||
while (!m_stopped.load()) {
|
||||
std::unique_lock<dxvk::mutex> lock(m_mutex);
|
||||
|
||||
@ -205,8 +209,17 @@ namespace dxvk {
|
||||
if (entry.submit.cmdList != nullptr) {
|
||||
VkResult status = m_lastError.load();
|
||||
|
||||
if (status != VK_ERROR_DEVICE_LOST)
|
||||
status = entry.submit.cmdList->synchronizeFence();
|
||||
if (status != VK_ERROR_DEVICE_LOST) {
|
||||
std::array<VkSemaphore, 2> semaphores = { m_semaphores.graphics, m_semaphores.transfer };
|
||||
std::array<uint64_t, 2> timelines = { entry.timelines.graphics, entry.timelines.transfer };
|
||||
|
||||
VkSemaphoreWaitInfo waitInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO };
|
||||
waitInfo.semaphoreCount = semaphores.size();
|
||||
waitInfo.pSemaphores = semaphores.data();
|
||||
waitInfo.pValues = timelines.data();
|
||||
|
||||
status = vk->vkWaitSemaphores(vk->device(), &waitInfo, ~0ull);
|
||||
}
|
||||
|
||||
if (status != VK_SUCCESS) {
|
||||
m_lastError = status;
|
||||
|
@ -56,26 +56,7 @@ namespace dxvk {
|
||||
DxvkSubmitStatus* status;
|
||||
DxvkSubmitInfo submit;
|
||||
DxvkPresentInfo present;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Timeline semaphore pair
|
||||
*
|
||||
* One semaphore for each queue.
|
||||
*/
|
||||
struct DxvkTimelineSemaphores {
|
||||
VkSemaphore graphics = VK_NULL_HANDLE;
|
||||
VkSemaphore transfer = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Timeline semaphore values
|
||||
*/
|
||||
struct DxvkTimelineSemaphoreValues {
|
||||
uint64_t graphics = 0u;
|
||||
uint64_t transfer = 0u;
|
||||
DxvkTimelineSemaphoreValues timelines;
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user