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

[dxvk] Use swap chain fences to synchronize WSI semaphores

Requires EXT_swapchain_maintenance1 to work, otherwise we won't use this.
This commit is contained in:
Philip Rebohle 2024-10-18 23:06:50 +02:00
parent 70e4017fdc
commit d41231fc13
2 changed files with 69 additions and 14 deletions

View File

@ -48,10 +48,13 @@ namespace dxvk {
VkResult Presenter::acquireNextImage(PresenterSync& sync, uint32_t& index) { VkResult Presenter::acquireNextImage(PresenterSync& sync, uint32_t& index) {
sync = m_semaphores.at(m_frameIndex); PresenterSync& semaphores = m_semaphores.at(m_frameIndex);
sync = semaphores;
// Don't acquire more than one image at a time // Don't acquire more than one image at a time
if (m_acquireStatus == VK_NOT_READY) { if (m_acquireStatus == VK_NOT_READY) {
waitForSwapchainFence(semaphores);
m_acquireStatus = m_vkd->vkAcquireNextImageKHR(m_vkd->device(), m_acquireStatus = m_vkd->vkAcquireNextImageKHR(m_vkd->device(),
m_swapchain, std::numeric_limits<uint64_t>::max(), m_swapchain, std::numeric_limits<uint64_t>::max(),
sync.acquire, VK_NULL_HANDLE, &m_imageIndex); sync.acquire, VK_NULL_HANDLE, &m_imageIndex);
@ -68,19 +71,23 @@ namespace dxvk {
VkResult Presenter::presentImage( VkResult Presenter::presentImage(
VkPresentModeKHR mode, VkPresentModeKHR mode,
uint64_t frameId) { uint64_t frameId) {
PresenterSync sync = m_semaphores.at(m_frameIndex); PresenterSync& currSync = m_semaphores.at(m_frameIndex);
VkPresentIdKHR presentId = { VK_STRUCTURE_TYPE_PRESENT_ID_KHR }; VkPresentIdKHR presentId = { VK_STRUCTURE_TYPE_PRESENT_ID_KHR };
presentId.swapchainCount = 1; presentId.swapchainCount = 1;
presentId.pPresentIds = &frameId; presentId.pPresentIds = &frameId;
VkSwapchainPresentFenceInfoEXT fenceInfo = { VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_EXT };
fenceInfo.swapchainCount = 1;
fenceInfo.pFences = &currSync.fence;
VkSwapchainPresentModeInfoEXT modeInfo = { VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_EXT }; VkSwapchainPresentModeInfoEXT modeInfo = { VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_EXT };
modeInfo.swapchainCount = 1; modeInfo.swapchainCount = 1;
modeInfo.pPresentModes = &mode; modeInfo.pPresentModes = &mode;
VkPresentInfoKHR info = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR }; VkPresentInfoKHR info = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
info.waitSemaphoreCount = 1; info.waitSemaphoreCount = 1;
info.pWaitSemaphores = &sync.present; info.pWaitSemaphores = &currSync.present;
info.swapchainCount = 1; info.swapchainCount = 1;
info.pSwapchains = &m_swapchain; info.pSwapchains = &m_swapchain;
info.pImageIndices = &m_imageIndex; info.pImageIndices = &m_imageIndex;
@ -88,12 +95,17 @@ namespace dxvk {
if (m_device->features().khrPresentId.presentId && frameId) if (m_device->features().khrPresentId.presentId && frameId)
presentId.pNext = const_cast<void*>(std::exchange(info.pNext, &presentId)); presentId.pNext = const_cast<void*>(std::exchange(info.pNext, &presentId));
if (m_device->features().extSwapchainMaintenance1.swapchainMaintenance1) if (m_device->features().extSwapchainMaintenance1.swapchainMaintenance1) {
modeInfo.pNext = const_cast<void*>(std::exchange(info.pNext, &modeInfo)); modeInfo.pNext = const_cast<void*>(std::exchange(info.pNext, &modeInfo));
fenceInfo.pNext = const_cast<void*>(std::exchange(info.pNext, &fenceInfo));
}
VkResult status = m_vkd->vkQueuePresentKHR( VkResult status = m_vkd->vkQueuePresentKHR(
m_device->queues().graphics.queueHandle, &info); m_device->queues().graphics.queueHandle, &info);
if (m_device->features().extSwapchainMaintenance1.swapchainMaintenance1)
currSync.fenceSignaled = status >= 0;
if (status != VK_SUCCESS && status != VK_SUBOPTIMAL_KHR) if (status != VK_SUCCESS && status != VK_SUBOPTIMAL_KHR)
return status; return status;
@ -102,11 +114,12 @@ namespace dxvk {
m_frameIndex += 1; m_frameIndex += 1;
m_frameIndex %= m_semaphores.size(); m_frameIndex %= m_semaphores.size();
sync = m_semaphores.at(m_frameIndex); PresenterSync& nextSync = m_semaphores.at(m_frameIndex);
waitForSwapchainFence(nextSync);
m_acquireStatus = m_vkd->vkAcquireNextImageKHR(m_vkd->device(), m_acquireStatus = m_vkd->vkAcquireNextImageKHR(m_vkd->device(),
m_swapchain, std::numeric_limits<uint64_t>::max(), m_swapchain, std::numeric_limits<uint64_t>::max(),
sync.acquire, VK_NULL_HANDLE, &m_imageIndex); nextSync.acquire, VK_NULL_HANDLE, &m_imageIndex);
return status; return status;
} }
@ -356,10 +369,19 @@ namespace dxvk {
return status; return status;
} }
// Create one set of semaphores per swap image // Create one set of semaphores per swap image, as well as a fence
m_semaphores.resize(m_info.imageCount); // that we use to ensure that semaphores are safe to access.
uint32_t semaphoreCount = m_info.imageCount;
for (uint32_t i = 0; i < m_semaphores.size(); i++) { if (!m_device->features().extSwapchainMaintenance1.swapchainMaintenance1) {
// Without support for present fences, just give up and allocate extra
// semaphores. We have no real guarantees when they are safe to access.
semaphoreCount *= 2u;
}
m_semaphores.resize(semaphoreCount);
for (uint32_t i = 0; i < semaphoreCount; i++) {
VkSemaphoreCreateInfo semInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO }; VkSemaphoreCreateInfo semInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
if ((status = m_vkd->vkCreateSemaphore(m_vkd->device(), if ((status = m_vkd->vkCreateSemaphore(m_vkd->device(),
@ -369,6 +391,12 @@ namespace dxvk {
if ((status = m_vkd->vkCreateSemaphore(m_vkd->device(), if ((status = m_vkd->vkCreateSemaphore(m_vkd->device(),
&semInfo, nullptr, &m_semaphores[i].present))) &semInfo, nullptr, &m_semaphores[i].present)))
return status; return status;
VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
if ((status = m_vkd->vkCreateFence(m_vkd->device(),
&fenceInfo, nullptr, &m_semaphores[i].fence)))
return status;
} }
// Invalidate indices // Invalidate indices
@ -623,12 +651,16 @@ namespace dxvk {
if (m_signal != nullptr) if (m_signal != nullptr)
m_signal->wait(m_lastFrameId.load(std::memory_order_acquire)); m_signal->wait(m_lastFrameId.load(std::memory_order_acquire));
for (auto& sem : m_semaphores)
waitForSwapchainFence(sem);
for (const auto& img : m_images) for (const auto& img : m_images)
m_vkd->vkDestroyImageView(m_vkd->device(), img.view, nullptr); m_vkd->vkDestroyImageView(m_vkd->device(), img.view, nullptr);
for (const auto& sem : m_semaphores) { for (const auto& sem : m_semaphores) {
m_vkd->vkDestroySemaphore(m_vkd->device(), sem.acquire, nullptr); m_vkd->vkDestroySemaphore(m_vkd->device(), sem.acquire, nullptr);
m_vkd->vkDestroySemaphore(m_vkd->device(), sem.present, nullptr); m_vkd->vkDestroySemaphore(m_vkd->device(), sem.present, nullptr);
m_vkd->vkDestroyFence(m_vkd->device(), sem.fence, nullptr);
} }
m_vkd->vkDestroySwapchainKHR(m_vkd->device(), m_swapchain, nullptr); m_vkd->vkDestroySwapchainKHR(m_vkd->device(), m_swapchain, nullptr);
@ -648,6 +680,24 @@ namespace dxvk {
} }
void Presenter::waitForSwapchainFence(
PresenterSync& sync) {
if (!sync.fenceSignaled)
return;
VkResult vr = m_vkd->vkWaitForFences(m_vkd->device(),
1, &sync.fence, VK_TRUE, ~0ull);
if (vr)
Logger::err(str::format("Failed to wait for WSI fence: ", vr));
if ((vr = m_vkd->vkResetFences(m_vkd->device(), 1, &sync.fence)))
Logger::err(str::format("Failed to reset WSI fence: ", vr));
sync.fenceSignaled = VK_FALSE;
}
void Presenter::runFrameThread() { void Presenter::runFrameThread() {
env::setThreadName("dxvk-frame"); env::setThreadName("dxvk-frame");

View File

@ -66,17 +66,19 @@ namespace dxvk {
* image acquisition. * image acquisition.
*/ */
struct PresenterSync { struct PresenterSync {
VkSemaphore acquire; VkSemaphore acquire = VK_NULL_HANDLE;
VkSemaphore present; VkSemaphore present = VK_NULL_HANDLE;
VkFence fence = VK_NULL_HANDLE;
VkBool32 fenceSignaled = VK_FALSE;
}; };
/** /**
* \brief Queued frame * \brief Queued frame
*/ */
struct PresenterFrame { struct PresenterFrame {
uint64_t frameId; uint64_t frameId = 0u;
VkPresentModeKHR mode; VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR;
VkResult result; VkResult result = VK_NOT_READY;
}; };
/** /**
@ -294,6 +296,9 @@ namespace dxvk {
void destroySurface(); void destroySurface();
void waitForSwapchainFence(
PresenterSync& sync);
void runFrameThread(); void runFrameThread();
}; };