From 9acb158990ea32cb138801430423a9d0e715354b Mon Sep 17 00:00:00 2001 From: MindSpunk Date: Fri, 5 Apr 2019 15:50:21 +1100 Subject: [PATCH] Vulkan, Viewports: Fix for resizing viewport windows crashing. (#2472) --- examples/example_glfw_vulkan/main.cpp | 9 +++--- examples/example_sdl_vulkan/main.cpp | 9 +++--- examples/imgui_impl_vulkan.cpp | 41 ++++++++++++++++++++------- examples/imgui_impl_vulkan.h | 11 +++++-- 4 files changed, 50 insertions(+), 20 deletions(-) diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp index 0b3bd955..bf5414aa 100644 --- a/examples/example_glfw_vulkan/main.cpp +++ b/examples/example_glfw_vulkan/main.cpp @@ -252,7 +252,8 @@ static void FrameRender(ImGui_ImplVulkanH_Window* wd) { VkResult err; - VkSemaphore& image_acquired_semaphore = wd->Frames[wd->FrameIndex].ImageAcquiredSemaphore; + VkSemaphore image_acquired_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].ImageAcquiredSemaphore; + VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore; err = vkAcquireNextImageKHR(g_Device, wd->Swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE, &wd->FrameIndex); check_vk_result(err); @@ -300,7 +301,7 @@ static void FrameRender(ImGui_ImplVulkanH_Window* wd) info.commandBufferCount = 1; info.pCommandBuffers = &fd->CommandBuffer; info.signalSemaphoreCount = 1; - info.pSignalSemaphores = &fd->RenderCompleteSemaphore; + info.pSignalSemaphores = &render_complete_semaphore; err = vkEndCommandBuffer(fd->CommandBuffer); check_vk_result(err); @@ -311,11 +312,11 @@ static void FrameRender(ImGui_ImplVulkanH_Window* wd) static void FramePresent(ImGui_ImplVulkanH_Window* wd) { - ImGui_ImplVulkanH_Frame* fd = &wd->Frames[wd->FrameIndex]; + VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore; VkPresentInfoKHR info = {}; info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; info.waitSemaphoreCount = 1; - info.pWaitSemaphores = &fd->RenderCompleteSemaphore; + info.pWaitSemaphores = &render_complete_semaphore; info.swapchainCount = 1; info.pSwapchains = &wd->Swapchain; info.pImageIndices = &wd->FrameIndex; diff --git a/examples/example_sdl_vulkan/main.cpp b/examples/example_sdl_vulkan/main.cpp index 37d5ace2..837fc880 100644 --- a/examples/example_sdl_vulkan/main.cpp +++ b/examples/example_sdl_vulkan/main.cpp @@ -244,7 +244,8 @@ static void FrameRender(ImGui_ImplVulkanH_Window* wd) { VkResult err; - VkSemaphore& image_acquired_semaphore = wd->Frames[wd->FrameIndex].ImageAcquiredSemaphore; + VkSemaphore image_acquired_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].ImageAcquiredSemaphore; + VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore; err = vkAcquireNextImageKHR(g_Device, wd->Swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE, &wd->FrameIndex); check_vk_result(err); @@ -292,7 +293,7 @@ static void FrameRender(ImGui_ImplVulkanH_Window* wd) info.commandBufferCount = 1; info.pCommandBuffers = &fd->CommandBuffer; info.signalSemaphoreCount = 1; - info.pSignalSemaphores = &fd->RenderCompleteSemaphore; + info.pSignalSemaphores = &render_complete_semaphore; err = vkEndCommandBuffer(fd->CommandBuffer); check_vk_result(err); @@ -303,11 +304,11 @@ static void FrameRender(ImGui_ImplVulkanH_Window* wd) static void FramePresent(ImGui_ImplVulkanH_Window* wd) { - ImGui_ImplVulkanH_Frame* fd = &wd->Frames[wd->FrameIndex]; + VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore; VkPresentInfoKHR info = {}; info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; info.waitSemaphoreCount = 1; - info.pWaitSemaphores = &fd->RenderCompleteSemaphore; + info.pWaitSemaphores = &render_complete_semaphore; info.swapchainCount = 1; info.pSwapchains = &wd->Swapchain; info.pImageIndices = &wd->FrameIndex; diff --git a/examples/imgui_impl_vulkan.cpp b/examples/imgui_impl_vulkan.cpp index 8767cb2f..88e7e0dc 100644 --- a/examples/imgui_impl_vulkan.cpp +++ b/examples/imgui_impl_vulkan.cpp @@ -65,6 +65,7 @@ static VkBuffer g_UploadBuffer = VK_NULL_HANDLE; // Forward Declarations void ImGui_ImplVulkanH_DestroyFrame(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator); +void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator); void ImGui_ImplVulkanH_CreateWindowSwapChain(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count); void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator); @@ -902,6 +903,7 @@ void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkInstance instance, VkPhysica for (uint32_t i = 0; i < wd->FramesQueueSize; i++) { ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i]; + ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[i]; { VkCommandPoolCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; @@ -929,9 +931,9 @@ void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkInstance instance, VkPhysica { VkSemaphoreCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - err = vkCreateSemaphore(device, &info, allocator, &fd->ImageAcquiredSemaphore); + err = vkCreateSemaphore(device, &info, allocator, &fsd->ImageAcquiredSemaphore); check_vk_result(err); - err = vkCreateSemaphore(device, &info, allocator, &fd->RenderCompleteSemaphore); + err = vkCreateSemaphore(device, &info, allocator, &fsd->RenderCompleteSemaphore); check_vk_result(err); } } @@ -960,9 +962,14 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkInstance instance, VkPhysicalDevi // We don't use ImGui_ImplVulkanH_DestroyWindow() because we want to preserve the old swapchain to create the new one. // Destroy old Framebuffer for (uint32_t i = 0; i < wd->FramesQueueSize; i++) + { ImGui_ImplVulkanH_DestroyFrame(instance, device, &wd->Frames[i], allocator); + ImGui_ImplVulkanH_DestroyFrameSemaphores(instance, device, &wd->FrameSemaphores[i], allocator); + } delete[] wd->Frames; + delete[] wd->FrameSemaphores; wd->Frames = NULL; + wd->FrameSemaphores = NULL; wd->FramesQueueSize = 0; if (wd->RenderPass) vkDestroyRenderPass(device, wd->RenderPass, allocator); @@ -1017,7 +1024,9 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkInstance instance, VkPhysicalDevi IM_ASSERT(wd->Frames == NULL); wd->Frames = new ImGui_ImplVulkanH_Frame[wd->FramesQueueSize]; + wd->FrameSemaphores = new ImGui_ImplVulkanH_FrameSemaphores[wd->FramesQueueSize]; memset(wd->Frames, 0, sizeof(wd->Frames[0]) * wd->FramesQueueSize); + memset(wd->FrameSemaphores, 0, sizeof(wd->FrameSemaphores[0]) * wd->FramesQueueSize); for (uint32_t i = 0; i < wd->FramesQueueSize; i++) wd->Frames[i].Backbuffer = backbuffers[i]; } @@ -1115,9 +1124,14 @@ void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui //vkQueueWaitIdle(g_Queue); for (uint32_t i = 0; i < wd->FramesQueueSize; i++) + { ImGui_ImplVulkanH_DestroyFrame(instance, device, &wd->Frames[i], allocator); + ImGui_ImplVulkanH_DestroyFrameSemaphores(instance, device, &wd->FrameSemaphores[i], allocator); + } delete[] wd->Frames; + delete[] wd->FrameSemaphores; wd->Frames = NULL; + wd->FrameSemaphores = NULL; vkDestroyRenderPass(device, wd->RenderPass, allocator); vkDestroySwapchainKHR(device, wd->Swapchain, allocator); vkDestroySurfaceKHR(instance, wd->Surface, allocator); @@ -1125,18 +1139,23 @@ void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui *wd = ImGui_ImplVulkanH_Window(); } +void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator) +{ + (void)instance; + vkDestroySemaphore(device, fsd->ImageAcquiredSemaphore, allocator); + vkDestroySemaphore(device, fsd->RenderCompleteSemaphore, allocator); + fsd->ImageAcquiredSemaphore = fsd->RenderCompleteSemaphore = VK_NULL_HANDLE; +} + void ImGui_ImplVulkanH_DestroyFrame(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator) { (void)instance; vkDestroyFence(device, fd->Fence, allocator); vkFreeCommandBuffers(device, fd->CommandPool, 1, &fd->CommandBuffer); vkDestroyCommandPool(device, fd->CommandPool, allocator); - vkDestroySemaphore(device, fd->ImageAcquiredSemaphore, allocator); - vkDestroySemaphore(device, fd->RenderCompleteSemaphore, allocator); fd->Fence = VK_NULL_HANDLE; fd->CommandBuffer = VK_NULL_HANDLE; fd->CommandPool = VK_NULL_HANDLE; - fd->ImageAcquiredSemaphore = fd->RenderCompleteSemaphore = VK_NULL_HANDLE; vkDestroyImageView(device, fd->BackbufferView, allocator); vkDestroyFramebuffer(device, fd->Framebuffer, allocator); @@ -1228,6 +1247,7 @@ static void ImGui_ImplVulkan_RenderWindow(ImGuiViewport* viewport, void*) VkResult err; ImGui_ImplVulkanH_Frame* fd = &wd->Frames[wd->FrameIndex]; + ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[wd->SemaphoreIndex]; { for (;;) { @@ -1237,7 +1257,7 @@ static void ImGui_ImplVulkan_RenderWindow(ImGuiViewport* viewport, void*) check_vk_result(err); } { - err = vkAcquireNextImageKHR(v->Device, wd->Swapchain, UINT64_MAX, fd->ImageAcquiredSemaphore, VK_NULL_HANDLE, &wd->FrameIndex); + err = vkAcquireNextImageKHR(v->Device, wd->Swapchain, UINT64_MAX, fsd->ImageAcquiredSemaphore, VK_NULL_HANDLE, &wd->FrameIndex); check_vk_result(err); fd = &wd->Frames[wd->FrameIndex]; } @@ -1275,12 +1295,12 @@ static void ImGui_ImplVulkan_RenderWindow(ImGuiViewport* viewport, void*) VkSubmitInfo info = {}; info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; info.waitSemaphoreCount = 1; - info.pWaitSemaphores = &fd->ImageAcquiredSemaphore; + info.pWaitSemaphores = &fsd->ImageAcquiredSemaphore; info.pWaitDstStageMask = &wait_stage; info.commandBufferCount = 1; info.pCommandBuffers = &fd->CommandBuffer; info.signalSemaphoreCount = 1; - info.pSignalSemaphores = &fd->RenderCompleteSemaphore; + info.pSignalSemaphores = &fsd->RenderCompleteSemaphore; err = vkEndCommandBuffer(fd->CommandBuffer); check_vk_result(err); @@ -1301,11 +1321,11 @@ static void ImGui_ImplVulkan_SwapBuffers(ImGuiViewport* viewport, void*) VkResult err; uint32_t present_index = wd->FrameIndex; - ImGui_ImplVulkanH_Frame* fd = &wd->Frames[present_index]; + ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[wd->SemaphoreIndex]; VkPresentInfoKHR info = {}; info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; info.waitSemaphoreCount = 1; - info.pWaitSemaphores = &fd->RenderCompleteSemaphore; + info.pWaitSemaphores = &fsd->RenderCompleteSemaphore; info.swapchainCount = 1; info.pSwapchains = &wd->Swapchain; info.pImageIndices = &present_index; @@ -1313,6 +1333,7 @@ static void ImGui_ImplVulkan_SwapBuffers(ImGuiViewport* viewport, void*) check_vk_result(err); wd->FrameIndex = (wd->FrameIndex + 1) % wd->FramesQueueSize; // This is for the next vkWaitForFences() + wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->FramesQueueSize; // Now we can use the next set of semaphores } void ImGui_ImplVulkan_InitPlatformInterface() diff --git a/examples/imgui_impl_vulkan.h b/examples/imgui_impl_vulkan.h index 1b156fec..c632d62c 100644 --- a/examples/imgui_impl_vulkan.h +++ b/examples/imgui_impl_vulkan.h @@ -102,14 +102,18 @@ struct ImGui_ImplVulkanH_Frame VkCommandPool CommandPool; VkCommandBuffer CommandBuffer; VkFence Fence; - VkSemaphore ImageAcquiredSemaphore; - VkSemaphore RenderCompleteSemaphore; VkImage Backbuffer; VkImageView BackbufferView; VkFramebuffer Framebuffer; ImGui_ImplVulkan_FrameRenderBuffers RenderBuffers; }; +struct ImGui_ImplVulkanH_FrameSemaphores +{ + VkSemaphore ImageAcquiredSemaphore; + VkSemaphore RenderCompleteSemaphore; +}; + // Helper structure to hold the data needed by one rendering context into one OS window // (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.) struct ImGui_ImplVulkanH_Window @@ -125,7 +129,10 @@ struct ImGui_ImplVulkanH_Window VkClearValue ClearValue; uint32_t FrameIndex; // Current frame being rendered to (0 <= FrameIndex < FrameInFlightCount) uint32_t FramesQueueSize; // Number of simultaneous in-flight frames (returned by vkGetSwapchainImagesKHR, usually derived from min_image_count) + uint32_t SemaphoreIndex; // Current set of swapchain wait semaphores we're using (needs to be distinct from per frame data) ImGui_ImplVulkanH_Frame* Frames; + ImGui_ImplVulkanH_FrameSemaphores* FrameSemaphores; + ImGui_ImplVulkanH_Window() {