diff --git a/intern/ghost/intern/GHOST_ContextVK.cc b/intern/ghost/intern/GHOST_ContextVK.cc index 14a1059b1a8..adfaeb48262 100644 --- a/intern/ghost/intern/GHOST_ContextVK.cc +++ b/intern/ghost/intern/GHOST_ContextVK.cc @@ -29,6 +29,7 @@ #include "CLG_log.h" +#include #include #include #include @@ -715,7 +716,10 @@ GHOST_ContextVK::~GHOST_ContextVK() GHOST_InstanceVK &instance_vk = vulkan_instance.value(); GHOST_DeviceVK &device_vk = instance_vk.device.value(); device_vk.wait_idle(); - + for (VkFence fence : fence_pile_) { + vkDestroyFence(device_vk.vk_device, fence, nullptr); + } + fence_pile_.clear(); destroySwapchain(); if (surface_ != VK_NULL_HANDLE) { @@ -760,6 +764,9 @@ GHOST_TSuccess GHOST_ContextVK::swapBufferAcquire() if (submission_frame_data.submission_fence) { vkWaitForFences(vk_device, 1, &submission_frame_data.submission_fence, true, UINT64_MAX); } + for (VkSwapchainKHR swapchain : submission_frame_data.discard_pile.swapchains) { + this->destroySwapchainPresentFences(swapchain); + } submission_frame_data.discard_pile.destroy(vk_device); const bool use_hdr_swapchain = hdr_info_ && @@ -842,6 +849,42 @@ GHOST_TSuccess GHOST_ContextVK::swapBufferAcquire() return GHOST_kSuccess; } +VkFence GHOST_ContextVK::getFence() +{ + if (!fence_pile_.empty()) { + VkFence fence = fence_pile_.back(); + fence_pile_.pop_back(); + return fence; + } + GHOST_DeviceVK &device_vk = vulkan_instance->device.value(); + VkFence fence = VK_NULL_HANDLE; + const VkFenceCreateInfo fence_create_info = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO}; + vkCreateFence(device_vk.vk_device, &fence_create_info, nullptr, &fence); + return fence; +} + +void GHOST_ContextVK::setPresentFence(VkSwapchainKHR swapchain, VkFence present_fence) +{ + if (present_fence == VK_NULL_HANDLE) { + return; + } + present_fences_[swapchain].push_back(present_fence); + GHOST_DeviceVK &device_vk = vulkan_instance->device.value(); + /** Recycle signaled fences. */ + for (std::pair> &item : present_fences_) { + std::vector::iterator end = item.second.end(); + std::vector::iterator it = std::remove_if( + item.second.begin(), item.second.end(), [&](const VkFence fence) { + if (vkGetFenceStatus(device_vk.vk_device, fence) == VK_NOT_READY) { + return false; + } + vkResetFences(device_vk.vk_device, 1, &fence); + fence_pile_.push_back(fence); + return true; + }); + item.second.erase(it, end); + } +} GHOST_TSuccess GHOST_ContextVK::swapBufferRelease() { @@ -894,7 +937,18 @@ GHOST_TSuccess GHOST_ContextVK::swapBufferRelease() VkResult present_result = VK_SUCCESS; { std::scoped_lock lock(device_vk.queue_mutex); + VkSwapchainPresentFenceInfoEXT fence_info{VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_EXT}; + VkFence present_fence = VK_NULL_HANDLE; + if (device_vk.use_vk_ext_swapchain_maintenance_1) { + present_fence = this->getFence(); + + fence_info.swapchainCount = 1; + fence_info.pFences = &present_fence; + + present_info.pNext = &fence_info; + } present_result = vkQueuePresentKHR(device_vk.generic_queue, &present_info); + this->setPresentFence(swapchain_, present_fence); } acquired_swapchain_image_index_.reset(); @@ -1312,11 +1366,25 @@ GHOST_TSuccess GHOST_ContextVK::recreateSwapchain(bool use_hdr_swapchain) return GHOST_kSuccess; } +void GHOST_ContextVK::destroySwapchainPresentFences(VkSwapchainKHR swapchain) +{ + GHOST_DeviceVK &device_vk = vulkan_instance.value().device.value(); + const std::vector &fences = present_fences_[swapchain]; + if (!fences.empty()) { + vkWaitForFences(device_vk.vk_device, fences.size(), fences.data(), VK_TRUE, UINT64_MAX); + for (VkFence fence : fences) { + vkDestroyFence(device_vk.vk_device, fence, nullptr); + } + } + present_fences_.erase(swapchain); +} + GHOST_TSuccess GHOST_ContextVK::destroySwapchain() { GHOST_DeviceVK &device_vk = vulkan_instance.value().device.value(); if (swapchain_ != VK_NULL_HANDLE) { + this->destroySwapchainPresentFences(swapchain_); vkDestroySwapchainKHR(device_vk.vk_device, swapchain_, nullptr); } device_vk.wait_idle(); @@ -1325,6 +1393,9 @@ GHOST_TSuccess GHOST_ContextVK::destroySwapchain() } swapchain_images_.clear(); for (GHOST_Frame &frame_data : frame_data_) { + for (VkSwapchainKHR swapchain : frame_data.discard_pile.swapchains) { + this->destroySwapchainPresentFences(swapchain); + } frame_data.destroy(device_vk.vk_device); } frame_data_.clear(); diff --git a/intern/ghost/intern/GHOST_ContextVK.hh b/intern/ghost/intern/GHOST_ContextVK.hh index 9ebf9bf0996..9dc8ece987f 100644 --- a/intern/ghost/intern/GHOST_ContextVK.hh +++ b/intern/ghost/intern/GHOST_ContextVK.hh @@ -33,6 +33,7 @@ # endif #endif +#include #include #include @@ -247,8 +248,15 @@ class GHOST_ContextVK : public GHOST_Context { std::function openxr_acquire_framebuffer_image_callback_; std::function openxr_release_framebuffer_image_callback_; + std::vector fence_pile_; + std::map> present_fences_; + const char *getPlatformSpecificSurfaceExtension() const; GHOST_TSuccess recreateSwapchain(bool use_hdr_swapchain); GHOST_TSuccess initializeFrameData(); GHOST_TSuccess destroySwapchain(); + + VkFence getFence(); + void setPresentFence(VkSwapchainKHR swapchain, VkFence fence); + void destroySwapchainPresentFences(VkSwapchainKHR swapchain); };