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) {
|
||||
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
|
||||
if (m_acquireStatus == VK_NOT_READY) {
|
||||
waitForSwapchainFence(semaphores);
|
||||
|
||||
m_acquireStatus = m_vkd->vkAcquireNextImageKHR(m_vkd->device(),
|
||||
m_swapchain, std::numeric_limits<uint64_t>::max(),
|
||||
sync.acquire, VK_NULL_HANDLE, &m_imageIndex);
|
||||
@ -68,19 +71,23 @@ namespace dxvk {
|
||||
VkResult Presenter::presentImage(
|
||||
VkPresentModeKHR mode,
|
||||
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 };
|
||||
presentId.swapchainCount = 1;
|
||||
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 };
|
||||
modeInfo.swapchainCount = 1;
|
||||
modeInfo.pPresentModes = &mode;
|
||||
|
||||
VkPresentInfoKHR info = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
|
||||
info.waitSemaphoreCount = 1;
|
||||
info.pWaitSemaphores = &sync.present;
|
||||
info.pWaitSemaphores = &currSync.present;
|
||||
info.swapchainCount = 1;
|
||||
info.pSwapchains = &m_swapchain;
|
||||
info.pImageIndices = &m_imageIndex;
|
||||
@ -88,12 +95,17 @@ namespace dxvk {
|
||||
if (m_device->features().khrPresentId.presentId && frameId)
|
||||
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));
|
||||
fenceInfo.pNext = const_cast<void*>(std::exchange(info.pNext, &fenceInfo));
|
||||
}
|
||||
|
||||
VkResult status = m_vkd->vkQueuePresentKHR(
|
||||
m_device->queues().graphics.queueHandle, &info);
|
||||
|
||||
if (m_device->features().extSwapchainMaintenance1.swapchainMaintenance1)
|
||||
currSync.fenceSignaled = status >= 0;
|
||||
|
||||
if (status != VK_SUCCESS && status != VK_SUBOPTIMAL_KHR)
|
||||
return status;
|
||||
|
||||
@ -102,11 +114,12 @@ namespace dxvk {
|
||||
m_frameIndex += 1;
|
||||
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_swapchain, std::numeric_limits<uint64_t>::max(),
|
||||
sync.acquire, VK_NULL_HANDLE, &m_imageIndex);
|
||||
nextSync.acquire, VK_NULL_HANDLE, &m_imageIndex);
|
||||
|
||||
return status;
|
||||
}
|
||||
@ -356,10 +369,19 @@ namespace dxvk {
|
||||
return status;
|
||||
}
|
||||
|
||||
// Create one set of semaphores per swap image
|
||||
m_semaphores.resize(m_info.imageCount);
|
||||
// Create one set of semaphores per swap image, as well as a fence
|
||||
// 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 };
|
||||
|
||||
if ((status = m_vkd->vkCreateSemaphore(m_vkd->device(),
|
||||
@ -369,6 +391,12 @@ namespace dxvk {
|
||||
if ((status = m_vkd->vkCreateSemaphore(m_vkd->device(),
|
||||
&semInfo, nullptr, &m_semaphores[i].present)))
|
||||
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
|
||||
@ -623,12 +651,16 @@ namespace dxvk {
|
||||
if (m_signal != nullptr)
|
||||
m_signal->wait(m_lastFrameId.load(std::memory_order_acquire));
|
||||
|
||||
for (auto& sem : m_semaphores)
|
||||
waitForSwapchainFence(sem);
|
||||
|
||||
for (const auto& img : m_images)
|
||||
m_vkd->vkDestroyImageView(m_vkd->device(), img.view, nullptr);
|
||||
|
||||
for (const auto& sem : m_semaphores) {
|
||||
m_vkd->vkDestroySemaphore(m_vkd->device(), sem.acquire, 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);
|
||||
@ -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() {
|
||||
env::setThreadName("dxvk-frame");
|
||||
|
||||
|
@ -66,17 +66,19 @@ namespace dxvk {
|
||||
* image acquisition.
|
||||
*/
|
||||
struct PresenterSync {
|
||||
VkSemaphore acquire;
|
||||
VkSemaphore present;
|
||||
VkSemaphore acquire = VK_NULL_HANDLE;
|
||||
VkSemaphore present = VK_NULL_HANDLE;
|
||||
VkFence fence = VK_NULL_HANDLE;
|
||||
VkBool32 fenceSignaled = VK_FALSE;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Queued frame
|
||||
*/
|
||||
struct PresenterFrame {
|
||||
uint64_t frameId;
|
||||
VkPresentModeKHR mode;
|
||||
VkResult result;
|
||||
uint64_t frameId = 0u;
|
||||
VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR;
|
||||
VkResult result = VK_NOT_READY;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -294,6 +296,9 @@ namespace dxvk {
|
||||
|
||||
void destroySurface();
|
||||
|
||||
void waitForSwapchainFence(
|
||||
PresenterSync& sync);
|
||||
|
||||
void runFrameThread();
|
||||
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user