mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-03-14 04:29:15 +01:00
[dxvk] Perform acquire and present synchronization in the backend
And add method to explicitly destroy relevant Vulkan objects.
This commit is contained in:
parent
b03ff775ce
commit
42adc4ac11
@ -70,14 +70,25 @@ namespace dxvk {
|
||||
|
||||
|
||||
VkResult Presenter::acquireNextImage(PresenterSync& sync, Rc<DxvkImage>& image) {
|
||||
std::lock_guard lock(m_surfaceMutex);
|
||||
std::unique_lock lock(m_surfaceMutex);
|
||||
|
||||
// Don't acquire more than one image at a time
|
||||
VkResult status = VK_SUCCESS;
|
||||
|
||||
m_surfaceCond.wait(lock, [this, &status] {
|
||||
status = m_device->getDeviceStatus();
|
||||
return !m_presentPending || status < 0;
|
||||
});
|
||||
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
// Ensure that the swap chain gets recreated if it is dirty
|
||||
bool hasSwapchain = m_swapchain != VK_NULL_HANDLE;
|
||||
|
||||
updateSwapChain();
|
||||
|
||||
// Don't acquire more than one image at a time
|
||||
// Don't acquire if we already did so after present
|
||||
if (m_acquireStatus == VK_NOT_READY && m_swapchain) {
|
||||
PresenterSync sync = m_semaphores.at(m_frameIndex);
|
||||
|
||||
@ -136,6 +147,7 @@ namespace dxvk {
|
||||
sync = m_semaphores.at(m_frameIndex);
|
||||
image = m_images.at(m_imageIndex);
|
||||
|
||||
m_presentPending = true;
|
||||
return m_acquireStatus;
|
||||
}
|
||||
|
||||
@ -185,25 +197,29 @@ namespace dxvk {
|
||||
m_frameIndex %= m_semaphores.size();
|
||||
}
|
||||
|
||||
// On a successful present, try to acquire next image already, in
|
||||
// order to hide potential delays from the application thread.
|
||||
if (status == VK_SUCCESS) {
|
||||
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(),
|
||||
nextSync.acquire, VK_NULL_HANDLE, &m_imageIndex);
|
||||
}
|
||||
|
||||
// Recreate the swapchain on the next acquire, even if we get suboptimal.
|
||||
// There is no guarantee that suboptimal state is returned by both functions.
|
||||
std::lock_guard lock(m_surfaceMutex);
|
||||
|
||||
if (status != VK_SUCCESS) {
|
||||
Logger::info(str::format("Presenter: Got ", status, ", recreating swapchain"));
|
||||
|
||||
std::lock_guard lock(m_surfaceMutex);
|
||||
m_dirtySwapchain = true;
|
||||
return status;
|
||||
}
|
||||
|
||||
// On a successful present, try to acquire next image already, in
|
||||
// order to hide potential delays from the application thread.
|
||||
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(),
|
||||
nextSync.acquire, VK_NULL_HANDLE, &m_imageIndex);
|
||||
|
||||
m_presentPending = false;
|
||||
m_surfaceCond.notify_one();
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -265,6 +281,19 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
void Presenter::destroyResources() {
|
||||
std::unique_lock lock(m_surfaceMutex);
|
||||
|
||||
m_surfaceCond.wait(lock, [this] {
|
||||
VkResult status = m_device->getDeviceStatus();
|
||||
return !m_presentPending || status < 0;
|
||||
});
|
||||
|
||||
destroySwapchain();
|
||||
destroySurface();
|
||||
}
|
||||
|
||||
|
||||
void Presenter::setSyncInterval(uint32_t syncInterval) {
|
||||
std::lock_guard lock(m_surfaceMutex);
|
||||
|
||||
@ -965,6 +994,8 @@ namespace dxvk {
|
||||
|
||||
m_swapchain = VK_NULL_HANDLE;
|
||||
m_acquireStatus = VK_NOT_READY;
|
||||
|
||||
m_presentPending = false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -200,6 +200,17 @@ namespace dxvk {
|
||||
*/
|
||||
void invalidateSurface();
|
||||
|
||||
/**
|
||||
* \brief Destroys resources immediately
|
||||
*
|
||||
* Blocks calling thread until pending swapchain operations
|
||||
* have completed, and guarantees that the Vulkan swapchain
|
||||
* and surface get destroyed before the function returns.
|
||||
* This is useful to ensure that the application window can
|
||||
* be reused, even if the presenter object is kept alive.
|
||||
*/
|
||||
void destroyResources();
|
||||
|
||||
private:
|
||||
|
||||
Rc<DxvkDevice> m_device;
|
||||
@ -208,9 +219,11 @@ namespace dxvk {
|
||||
Rc<vk::InstanceFn> m_vki;
|
||||
Rc<vk::DeviceFn> m_vkd;
|
||||
|
||||
dxvk::mutex m_surfaceMutex;
|
||||
PresenterSurfaceProc m_surfaceProc;
|
||||
|
||||
dxvk::mutex m_surfaceMutex;
|
||||
dxvk::condition_variable m_surfaceCond;
|
||||
|
||||
VkSurfaceKHR m_surface = VK_NULL_HANDLE;
|
||||
VkSwapchainKHR m_swapchain = VK_NULL_HANDLE;
|
||||
|
||||
@ -234,6 +247,7 @@ namespace dxvk {
|
||||
uint32_t m_frameIndex = 0;
|
||||
|
||||
VkResult m_acquireStatus = VK_NOT_READY;
|
||||
bool m_presentPending = false;
|
||||
|
||||
std::optional<VkHdrMetadataEXT> m_hdrMetadata;
|
||||
bool m_hdrMetadataDirty = false;
|
||||
|
Loading…
x
Reference in New Issue
Block a user