From bbc89b6391a0f89dc48c8c223b221820a3feceec Mon Sep 17 00:00:00 2001 From: ChrisTom-94 Date: Wed, 7 May 2025 15:19:45 +0200 Subject: [PATCH] Backends: Vulkan: fixed validation errors during window detach in multi-viewport mode. (#8600, #8176) --- backends/imgui_impl_vulkan.cpp | 79 ++++++++++++++++++++++++++++++++++ docs/CHANGELOG.txt | 3 ++ 2 files changed, 82 insertions(+) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 2cebb6c25..78d092217 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -26,6 +26,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-05-07- Vulkan: Fixed validation errors during window detach in multi-viewport mode. (#8600, #8176) // 2025-05-07: Vulkan: Load dynamic rendering functions using vkGetDeviceProcAddr() + try both non-KHR and KHR versions. (#8600, #8326, #8365) // 2025-04-07: Vulkan: Deep-copy ImGui_ImplVulkan_InitInfo::PipelineRenderingCreateInfo's pColorAttachmentFormats buffer when set, in order to reduce common user-error of specifying a pointer to data that gets out of scope. (#8282) // 2025-02-14: *BREAKING CHANGE*: Added uint32_t api_version to ImGui_ImplVulkan_LoadFunctions(). @@ -1086,6 +1087,8 @@ void ImGui_ImplVulkan_DestroyDeviceObjects() #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING static void ImGui_ImplVulkan_LoadDynamicRenderingFunctions(uint32_t api_version, PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data) { + IM_UNUSED(api_version); + // Manually load those two (see #5446, #8326, #8365, #8600) // - Try loading core (non-KHR) versions first (this will work for Vulkan 1.3+ and the device supports dynamic rendering) ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR = reinterpret_cast(loader_func("vkCmdBeginRendering", user_data)); @@ -1667,6 +1670,82 @@ void ImGui_ImplVulkanH_CreateOrResizeWindow(VkInstance instance, VkPhysicalDevic (void)instance; ImGui_ImplVulkanH_CreateWindowSwapChain(physical_device, device, wd, allocator, width, height, min_image_count); ImGui_ImplVulkanH_CreateWindowCommandBuffers(physical_device, device, wd, queue_family, allocator); + + // FIXME: to submit the command buffer, we need a queue. In the examples folder, the ImGui_ImplVulkanH_CreateOrResizeWindow function is called + // before the ImGui_ImplVulkan_Init function, so we don't have access to the queue yet. Here we have the queue_family that we can use to grab + // a queue from the device and submit the command buffer. It would be better to have access to the queue as suggested in the FIXME below. + VkCommandPool command_pool; + VkCommandPoolCreateInfo pool_info = {}; + pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + pool_info.queueFamilyIndex = queue_family; + pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + VkResult err = vkCreateCommandPool(device, &pool_info, allocator, &command_pool); + check_vk_result(err); + + VkFenceCreateInfo fence_info = {}; + fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + VkFence fence; + err = vkCreateFence(device, &fence_info, allocator, &fence); + check_vk_result(err); + + VkCommandBufferAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + alloc_info.commandPool = command_pool; + alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + alloc_info.commandBufferCount = 1; + VkCommandBuffer command_buffer; + err = vkAllocateCommandBuffers(device, &alloc_info, &command_buffer); + check_vk_result(err); + + VkCommandBufferBeginInfo begin_info = {}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + err = vkBeginCommandBuffer(command_buffer, &begin_info); + check_vk_result(err); + + // Transition the images to the correct layout for rendering + for (uint32_t i = 0; i < wd->ImageCount; i++) + { + VkImageMemoryBarrier barrier = {}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.image = wd->Frames[i].Backbuffer; + barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + barrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.layerCount = 1; + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier); + } + + err = vkEndCommandBuffer(command_buffer); + check_vk_result(err); + VkSubmitInfo submit_info = {}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &command_buffer; + + VkQueue queue; + vkGetDeviceQueue(device, queue_family, 0, &queue); + err = vkQueueSubmit(queue, 1, &submit_info, fence); + check_vk_result(err); + err = vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX); + check_vk_result(err); + err = vkResetFences(device, 1, &fence); + check_vk_result(err); + + err = vkResetCommandPool(device, command_pool, 0); + check_vk_result(err); + + // Destroy command buffer and fence and command pool + vkFreeCommandBuffers(device, command_pool, 1, &command_buffer); + vkDestroyCommandPool(device, command_pool, allocator); + vkDestroyFence(device, fence, allocator); + command_pool = VK_NULL_HANDLE; + command_buffer = VK_NULL_HANDLE; + fence = VK_NULL_HANDLE; + queue = VK_NULL_HANDLE; } void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ff5a8b90a..9074f906c 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -121,6 +121,9 @@ Other changes: specifying a pointer to data that gets out of scope. (#8282) - Backends: Vulkan: Load dynamic rendering functions using vkGetDeviceProcAddr() + try both non-KHR and KHR versions. (#8600, #8326, #8365) [@ChrisTom-94] +- Backends: Vulkan: fixed validation errors in window create/resize helpers used by examples + and by multi-viewports implementation, which would typically trigger errors while detaching + secondary viewports. (#8600, #8176) [@ChrisTom-94] - Examples: DirectX12+Win32: also test for IsIconic() for sleeping since we don't seem to get a DXGI_STATUS_OCCLUDED signal when minimized. (#8603) [@dooann]