diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 9f4f8993..b9e3dcb3 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -593,6 +593,13 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; + // Destroy existing texture (if any) + if (bd->FontView || bd->FontImage || bd->FontMemory || bd->FontDescriptorSet) + { + vkQueueWaitIdle(v->Queue); + ImGui_ImplVulkan_DestroyFontsTexture(); + } + unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); @@ -728,6 +735,25 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) return true; } +void ImGui_ImplVulkan_DestroyFontsTexture() +{ + ImGuiIO& io = ImGui::GetIO(); + ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); + ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; + + if (bd->FontDescriptorSet) + { + ImGui_ImplVulkan_RemoveTexture(bd->FontDescriptorSet); + bd->FontDescriptorSet = VK_NULL_HANDLE; + io.Fonts->SetTexID(0); + } + + if (bd->FontView) { vkDestroyImageView(v->Device, bd->FontView, v->Allocator); bd->FontView = VK_NULL_HANDLE; } + if (bd->FontImage) { vkDestroyImage(v->Device, bd->FontImage, v->Allocator); bd->FontImage = VK_NULL_HANDLE; } + if (bd->FontMemory) { vkFreeMemory(v->Device, bd->FontMemory, v->Allocator); bd->FontMemory = VK_NULL_HANDLE; } + ImGui_ImplVulkan_DestroyFontUploadObjects(); +} + static void ImGui_ImplVulkan_CreateShaderModules(VkDevice device, const VkAllocationCallbacks* allocator) { // Create the shader modules @@ -952,12 +978,10 @@ void ImGui_ImplVulkan_DestroyDeviceObjects() ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; ImGui_ImplVulkanH_DestroyWindowRenderBuffers(v->Device, &bd->MainWindowRenderBuffers, v->Allocator); ImGui_ImplVulkan_DestroyFontUploadObjects(); + ImGui_ImplVulkan_DestroyFontsTexture(); if (bd->ShaderModuleVert) { vkDestroyShaderModule(v->Device, bd->ShaderModuleVert, v->Allocator); bd->ShaderModuleVert = VK_NULL_HANDLE; } if (bd->ShaderModuleFrag) { vkDestroyShaderModule(v->Device, bd->ShaderModuleFrag, v->Allocator); bd->ShaderModuleFrag = VK_NULL_HANDLE; } - if (bd->FontView) { vkDestroyImageView(v->Device, bd->FontView, v->Allocator); bd->FontView = VK_NULL_HANDLE; } - if (bd->FontImage) { vkDestroyImage(v->Device, bd->FontImage, v->Allocator); bd->FontImage = VK_NULL_HANDLE; } - if (bd->FontMemory) { vkFreeMemory(v->Device, bd->FontMemory, v->Allocator); bd->FontMemory = VK_NULL_HANDLE; } if (bd->FontSampler) { vkDestroySampler(v->Device, bd->FontSampler, v->Allocator); bd->FontSampler = VK_NULL_HANDLE; } if (bd->DescriptorSetLayout) { vkDestroyDescriptorSetLayout(v->Device, bd->DescriptorSetLayout, v->Allocator); bd->DescriptorSetLayout = VK_NULL_HANDLE; } if (bd->PipelineLayout) { vkDestroyPipelineLayout(v->Device, bd->PipelineLayout, v->Allocator); bd->PipelineLayout = VK_NULL_HANDLE; } diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index 46fd9536..1251aca8 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -79,6 +79,7 @@ IMGUI_IMPL_API void ImGui_ImplVulkan_Shutdown(); IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame(); IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline = VK_NULL_HANDLE); IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer); +IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontsTexture(); IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontUploadObjects(); IMGUI_IMPL_API void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 56cef3c6..09e1d726 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -210,6 +210,9 @@ Other changes: - Demo: Added "Drag and Drop -> Tooltip at target location" demo. - Demo: Added "Layout -> Child Windows -> Manual-resize" demo. (#1710) - Demo: Added "Layout -> Child Windows -> Auto-resize with constraints" demo. (#1666, #1395, #1496, #1710) +- Backends: Vulkan: Added ImGui_ImplVulkan_DestroyFontsTexture(), made ImGui_ImplVulkan_CreateFontsTexture() + destroy previous one, allowing recreation of fonts without leaks. (#6943, #6715, #6327, #3743, #4618) + [@helynranta, @thomasherzog, @guybrush77, @albin-johansson, @MiroKaku, @benbatya-fb] - Backends: GLFW: Clear emscripten's MouseWheel callback before shutdown. (#6790, #6096, #4019) [@halx99] - Backends: GLFW: Added support for F13 to F24 function keys. (#6891) - Backends: SDL2, SDL3: Added support for F13 to F24 function keys, AppBack, AppForward. (#6891) @@ -223,6 +226,7 @@ Other changes: - Backends: OpenGL3: Update GL3W based imgui_impl_opengl3_loader.h to load "libGL.so" instead of "libGL.so.1", accomodating for NetBSD systems having only "libGL.so.3" available. (#6983) - Backends: OSX: Added support for F13 to F20 function keys. Support mapping F13 to PrintScreen. (#6891) +- Examples: GLFW+Vulkan, SDL+Vulkan: Extracted font upload code into a UploadFonts() function. - Internals: Renamed ImFloor() to ImTrunc(). Renamed ImFloorSigned() to ImFloor(). (#6861) diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp index 412fc19c..49a87c58 100644 --- a/examples/example_glfw_vulkan/main.cpp +++ b/examples/example_glfw_vulkan/main.cpp @@ -47,6 +47,9 @@ static VkDebugReportCallbackEXT g_DebugReport = VK_NULL_HANDLE; static VkPipelineCache g_PipelineCache = VK_NULL_HANDLE; static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE; +static VkCommandPool g_FontCommandPool = VK_NULL_HANDLE; +static VkCommandBuffer g_FontCommandBuffer = VK_NULL_HANDLE; + static ImGui_ImplVulkanH_Window g_MainWindowData; static int g_MinImageCount = 2; static bool g_SwapChainRebuild = false; @@ -273,6 +276,7 @@ static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface static void CleanupVulkan() { + vkDestroyCommandPool(g_Device, g_FontCommandPool, g_Allocator); vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator); #ifdef IMGUI_VULKAN_DEBUG_REPORT @@ -379,6 +383,51 @@ static void FramePresent(ImGui_ImplVulkanH_Window* wd) wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->ImageCount; // Now we can use the next set of semaphores } +static void UploadFonts() +{ + if (g_FontCommandPool == VK_NULL_HANDLE) + { + VkCommandPoolCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + info.queueFamilyIndex = g_QueueFamily; + vkCreateCommandPool(g_Device, &info, nullptr, &g_FontCommandPool); + } + + if (g_FontCommandBuffer == VK_NULL_HANDLE) + { + VkCommandBufferAllocateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + info.commandPool = g_FontCommandPool; + info.commandBufferCount = 1; + VkResult err = vkAllocateCommandBuffers(g_Device, &info, &g_FontCommandBuffer); + check_vk_result(err); + } + + VkResult err = vkResetCommandPool(g_Device, g_FontCommandPool, 0); + 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(g_FontCommandBuffer, &begin_info); + check_vk_result(err); + + ImGui_ImplVulkan_CreateFontsTexture(g_FontCommandBuffer); + + VkSubmitInfo end_info = {}; + end_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + end_info.commandBufferCount = 1; + end_info.pCommandBuffers = &g_FontCommandBuffer; + err = vkEndCommandBuffer(g_FontCommandBuffer); + check_vk_result(err); + err = vkQueueSubmit(g_Queue, 1, &end_info, VK_NULL_HANDLE); + check_vk_result(err); + + err = vkDeviceWaitIdle(g_Device); + check_vk_result(err); + ImGui_ImplVulkan_DestroyFontUploadObjects(); +} + // Main code int main(int, char**) { @@ -459,34 +508,7 @@ int main(int, char**) //IM_ASSERT(font != nullptr); // Upload Fonts - { - // Use any command queue - VkCommandPool command_pool = wd->Frames[wd->FrameIndex].CommandPool; - VkCommandBuffer command_buffer = wd->Frames[wd->FrameIndex].CommandBuffer; - - err = vkResetCommandPool(g_Device, command_pool, 0); - 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); - - ImGui_ImplVulkan_CreateFontsTexture(command_buffer); - - VkSubmitInfo end_info = {}; - end_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - end_info.commandBufferCount = 1; - end_info.pCommandBuffers = &command_buffer; - err = vkEndCommandBuffer(command_buffer); - check_vk_result(err); - err = vkQueueSubmit(g_Queue, 1, &end_info, VK_NULL_HANDLE); - check_vk_result(err); - - err = vkDeviceWaitIdle(g_Device); - check_vk_result(err); - ImGui_ImplVulkan_DestroyFontUploadObjects(); - } + UploadFonts(); // Our state bool show_demo_window = true; diff --git a/examples/example_sdl2_vulkan/main.cpp b/examples/example_sdl2_vulkan/main.cpp index a0f4a6a2..a2d08f1e 100644 --- a/examples/example_sdl2_vulkan/main.cpp +++ b/examples/example_sdl2_vulkan/main.cpp @@ -39,6 +39,9 @@ static VkDebugReportCallbackEXT g_DebugReport = VK_NULL_HANDLE; static VkPipelineCache g_PipelineCache = VK_NULL_HANDLE; static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE; +static VkCommandPool g_FontCommandPool = VK_NULL_HANDLE; +static VkCommandBuffer g_FontCommandBuffer = VK_NULL_HANDLE; + static ImGui_ImplVulkanH_Window g_MainWindowData; static uint32_t g_MinImageCount = 2; static bool g_SwapChainRebuild = false; @@ -261,6 +264,7 @@ static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface static void CleanupVulkan() { + vkDestroyCommandPool(g_Device, g_FontCommandPool, g_Allocator); vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator); #ifdef IMGUI_VULKAN_DEBUG_REPORT @@ -367,6 +371,51 @@ static void FramePresent(ImGui_ImplVulkanH_Window* wd) wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->ImageCount; // Now we can use the next set of semaphores } +static void UploadFonts() +{ + if (g_FontCommandPool == VK_NULL_HANDLE) + { + VkCommandPoolCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + info.queueFamilyIndex = g_QueueFamily; + vkCreateCommandPool(g_Device, &info, nullptr, &g_FontCommandPool); + } + + if (g_FontCommandBuffer == VK_NULL_HANDLE) + { + VkCommandBufferAllocateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + info.commandPool = g_FontCommandPool; + info.commandBufferCount = 1; + VkResult err = vkAllocateCommandBuffers(g_Device, &info, &g_FontCommandBuffer); + check_vk_result(err); + } + + VkResult err = vkResetCommandPool(g_Device, g_FontCommandPool, 0); + 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(g_FontCommandBuffer, &begin_info); + check_vk_result(err); + + ImGui_ImplVulkan_CreateFontsTexture(g_FontCommandBuffer); + + VkSubmitInfo end_info = {}; + end_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + end_info.commandBufferCount = 1; + end_info.pCommandBuffers = &g_FontCommandBuffer; + err = vkEndCommandBuffer(g_FontCommandBuffer); + check_vk_result(err); + err = vkQueueSubmit(g_Queue, 1, &end_info, VK_NULL_HANDLE); + check_vk_result(err); + + err = vkDeviceWaitIdle(g_Device); + check_vk_result(err); + ImGui_ImplVulkan_DestroyFontUploadObjects(); +} + // Main code int main(int, char**) { @@ -454,34 +503,7 @@ int main(int, char**) //IM_ASSERT(font != nullptr); // Upload Fonts - { - // Use any command queue - VkCommandPool command_pool = wd->Frames[wd->FrameIndex].CommandPool; - VkCommandBuffer command_buffer = wd->Frames[wd->FrameIndex].CommandBuffer; - - err = vkResetCommandPool(g_Device, command_pool, 0); - 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); - - ImGui_ImplVulkan_CreateFontsTexture(command_buffer); - - VkSubmitInfo end_info = {}; - end_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - end_info.commandBufferCount = 1; - end_info.pCommandBuffers = &command_buffer; - err = vkEndCommandBuffer(command_buffer); - check_vk_result(err); - err = vkQueueSubmit(g_Queue, 1, &end_info, VK_NULL_HANDLE); - check_vk_result(err); - - err = vkDeviceWaitIdle(g_Device); - check_vk_result(err); - ImGui_ImplVulkan_DestroyFontUploadObjects(); - } + UploadFonts(); // Our state bool show_demo_window = true;