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:
parent
70e4017fdc
commit
d41231fc13
@ -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");
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user