diff --git a/core/deps/imgui/backends/imgui_impl_vulkan.cpp b/core/deps/imgui/backends/imgui_impl_vulkan.cpp index 3e3e744149..c0bf24738e 100644 --- a/core/deps/imgui/backends/imgui_impl_vulkan.cpp +++ b/core/deps/imgui/backends/imgui_impl_vulkan.cpp @@ -33,6 +33,11 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2023-11-10: *BREAKING CHANGE*: Removed parameter from ImGui_ImplVulkan_CreateFontsTexture(): backend now creates its own command-buffer to upload fonts. +// *BREAKING CHANGE*: Removed ImGui_ImplVulkan_DestroyFontUploadObjects() which is now unecessary as we create and destroy those objects in the backend. +// ImGui_ImplVulkan_CreateFontsTexture() is automatically called by NewFrame() the first time. +// You can call ImGui_ImplVulkan_CreateFontsTexture() again to recreate the font atlas texture. +// Added ImGui_ImplVulkan_DestroyFontsTexture() but you probably never need to call this. // 2023-07-04: Vulkan: Added optional support for VK_KHR_dynamic_rendering. User needs to set init_info->UseDynamicRendering = true and init_info->ColorAttachmentFormat. // 2023-01-02: Vulkan: Fixed sampler passed to ImGui_ImplVulkan_AddTexture() not being honored + removed a bunch of duplicate code. // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. @@ -120,8 +125,8 @@ struct ImGui_ImplVulkan_Data VkImage FontImage; VkImageView FontView; VkDescriptorSet FontDescriptorSet; - VkDeviceMemory UploadBufferMemory; - VkBuffer UploadBuffer; + VkCommandPool FontCommandPool; + VkCommandBuffer FontCommandBuffer; // Render buffers for main window ImGui_ImplVulkanH_WindowRenderBuffers MainWindowRenderBuffers; @@ -155,6 +160,7 @@ static bool g_FunctionsLoaded = true; IMGUI_VULKAN_FUNC_MAP_MACRO(vkAllocateCommandBuffers) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkAllocateDescriptorSets) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkAllocateMemory) \ + IMGUI_VULKAN_FUNC_MAP_MACRO(vkBeginCommandBuffer) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkBindBufferMemory) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkBindImageMemory) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBindDescriptorSets) \ @@ -197,6 +203,7 @@ static bool g_FunctionsLoaded = true; IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroySurfaceKHR) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroySwapchainKHR) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDeviceWaitIdle) \ + IMGUI_VULKAN_FUNC_MAP_MACRO(vkEndCommandBuffer) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkFlushMappedMemoryRanges) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkFreeCommandBuffers) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkFreeDescriptorSets) \ @@ -209,6 +216,9 @@ static bool g_FunctionsLoaded = true; IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfacePresentModesKHR) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetSwapchainImagesKHR) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkMapMemory) \ + IMGUI_VULKAN_FUNC_MAP_MACRO(vkQueueSubmit) \ + IMGUI_VULKAN_FUNC_MAP_MACRO(vkQueueWaitIdle) \ + IMGUI_VULKAN_FUNC_MAP_MACRO(vkResetCommandPool) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkUnmapMemory) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkUpdateDescriptorSets) @@ -592,19 +602,55 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm vkCmdSetScissor(command_buffer, 0, 1, &scissor); } -bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) +bool ImGui_ImplVulkan_CreateFontsTexture() { ImGuiIO& io = ImGui::GetIO(); ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; + VkResult err; + + // Destroy existing texture (if any) + if (bd->FontView || bd->FontImage || bd->FontMemory || bd->FontDescriptorSet) + { + vkQueueWaitIdle(v->Queue); + ImGui_ImplVulkan_DestroyFontsTexture(); + } + + // Create command pool/buffer + if (bd->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 = v->QueueFamily; + vkCreateCommandPool(v->Device, &info, nullptr, &bd->FontCommandPool); + } + if (bd->FontCommandBuffer == VK_NULL_HANDLE) + { + VkCommandBufferAllocateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + info.commandPool = bd->FontCommandPool; + info.commandBufferCount = 1; + err = vkAllocateCommandBuffers(v->Device, &info, &bd->FontCommandBuffer); + check_vk_result(err); + } + + // Start command buffer + { + err = vkResetCommandPool(v->Device, bd->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(bd->FontCommandBuffer, &begin_info); + check_vk_result(err); + } unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); size_t upload_size = width * height * 4 * sizeof(char); - VkResult err; - // Create the Image: { VkImageCreateInfo info = {}; @@ -653,40 +699,42 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) bd->FontDescriptorSet = (VkDescriptorSet)ImGui_ImplVulkan_AddTexture(bd->FontSampler, bd->FontView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); // Create the Upload Buffer: + VkDeviceMemory upload_buffer_memory; + VkBuffer upload_buffer; { VkBufferCreateInfo buffer_info = {}; buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; buffer_info.size = upload_size; buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &bd->UploadBuffer); + err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &upload_buffer); check_vk_result(err); VkMemoryRequirements req; - vkGetBufferMemoryRequirements(v->Device, bd->UploadBuffer, &req); + vkGetBufferMemoryRequirements(v->Device, upload_buffer, &req); bd->BufferMemoryAlignment = (bd->BufferMemoryAlignment > req.alignment) ? bd->BufferMemoryAlignment : req.alignment; VkMemoryAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; alloc_info.allocationSize = req.size; alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits); - err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &bd->UploadBufferMemory); + err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &upload_buffer_memory); check_vk_result(err); - err = vkBindBufferMemory(v->Device, bd->UploadBuffer, bd->UploadBufferMemory, 0); + err = vkBindBufferMemory(v->Device, upload_buffer, upload_buffer_memory, 0); check_vk_result(err); } // Upload to Buffer: { char* map = nullptr; - err = vkMapMemory(v->Device, bd->UploadBufferMemory, 0, upload_size, 0, (void**)(&map)); + err = vkMapMemory(v->Device, upload_buffer_memory, 0, upload_size, 0, (void**)(&map)); check_vk_result(err); memcpy(map, pixels, upload_size); VkMappedMemoryRange range[1] = {}; range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; - range[0].memory = bd->UploadBufferMemory; + range[0].memory = upload_buffer_memory; range[0].size = upload_size; err = vkFlushMappedMemoryRanges(v->Device, 1, range); check_vk_result(err); - vkUnmapMemory(v->Device, bd->UploadBufferMemory); + vkUnmapMemory(v->Device, upload_buffer_memory); } // Copy to Image: @@ -702,7 +750,7 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) copy_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copy_barrier[0].subresourceRange.levelCount = 1; copy_barrier[0].subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, copy_barrier); + vkCmdPipelineBarrier(bd->FontCommandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, copy_barrier); VkBufferImageCopy region = {}; region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; @@ -710,7 +758,7 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) region.imageExtent.width = width; region.imageExtent.height = height; region.imageExtent.depth = 1; - vkCmdCopyBufferToImage(command_buffer, bd->UploadBuffer, bd->FontImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + vkCmdCopyBufferToImage(bd->FontCommandBuffer, upload_buffer, bd->FontImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); VkImageMemoryBarrier use_barrier[1] = {}; use_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; @@ -724,15 +772,50 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) use_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; use_barrier[0].subresourceRange.levelCount = 1; use_barrier[0].subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, use_barrier); + vkCmdPipelineBarrier(bd->FontCommandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, use_barrier); } // Store our identifier io.Fonts->SetTexID((ImTextureID)bd->FontDescriptorSet); + // End command buffer + VkSubmitInfo end_info = {}; + end_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + end_info.commandBufferCount = 1; + end_info.pCommandBuffers = &bd->FontCommandBuffer; + err = vkEndCommandBuffer(bd->FontCommandBuffer); + check_vk_result(err); + err = vkQueueSubmit(v->Queue, 1, &end_info, VK_NULL_HANDLE); + check_vk_result(err); + + err = vkDeviceWaitIdle(v->Device); + check_vk_result(err); + + vkDestroyBuffer(v->Device, upload_buffer, v->Allocator); + vkFreeMemory(v->Device, upload_buffer_memory, v->Allocator); + return true; } +// You probably never need to call this, as it is called by ImGui_ImplVulkan_CreateFontsTexture() and ImGui_ImplVulkan_Shutdown(). +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; } +} + static void ImGui_ImplVulkan_CreateShaderModules(VkDevice device, const VkAllocationCallbacks* allocator) { // Create the shader modules @@ -935,34 +1018,16 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() return true; } -void ImGui_ImplVulkan_DestroyFontUploadObjects() -{ - ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; - if (bd->UploadBuffer) - { - vkDestroyBuffer(v->Device, bd->UploadBuffer, v->Allocator); - bd->UploadBuffer = VK_NULL_HANDLE; - } - if (bd->UploadBufferMemory) - { - vkFreeMemory(v->Device, bd->UploadBufferMemory, v->Allocator); - bd->UploadBufferMemory = VK_NULL_HANDLE; - } -} - void ImGui_ImplVulkan_DestroyDeviceObjects() { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; ImGui_ImplVulkanH_DestroyWindowRenderBuffers(v->Device, &bd->MainWindowRenderBuffers, v->Allocator); - ImGui_ImplVulkan_DestroyFontUploadObjects(); + ImGui_ImplVulkan_DestroyFontsTexture(); + if (bd->FontCommandPool) { vkDestroyCommandPool(v->Device, bd->FontCommandPool, v->Allocator); bd->FontCommandPool = VK_NULL_HANDLE; } 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; ImGui::GetIO().Fonts->SetTexID(ImTextureID()); } - 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; } @@ -1060,7 +1125,9 @@ void ImGui_ImplVulkan_NewFrame() { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplVulkan_Init()?"); - IM_UNUSED(bd); + + if (!bd->FontDescriptorSet) + ImGui_ImplVulkan_CreateFontsTexture(); } void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count) diff --git a/core/deps/imgui/backends/imgui_impl_vulkan.h b/core/deps/imgui/backends/imgui_impl_vulkan.h index 46fd953633..c53ba68810 100644 --- a/core/deps/imgui/backends/imgui_impl_vulkan.h +++ b/core/deps/imgui/backends/imgui_impl_vulkan.h @@ -78,8 +78,8 @@ IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* inf 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_DestroyFontUploadObjects(); +IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture(); +IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontsTexture(); IMGUI_IMPL_API void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated) // Register a texture (VkDescriptorSet == ImTextureID) diff --git a/core/rend/vulkan/vulkan_context.cpp b/core/rend/vulkan/vulkan_context.cpp index a89b2127b3..b7f1ec895b 100644 --- a/core/rend/vulkan/vulkan_context.cpp +++ b/core/rend/vulkan/vulkan_context.cpp @@ -311,21 +311,6 @@ void VulkanContext::InitImgui() { die("ImGui initialization failed"); } - if (ImGui::GetIO().Fonts->TexID == 0) - { - // Upload Fonts - device->resetFences(*drawFences.front()); - device->resetCommandPool(*commandPools.front(), vk::CommandPoolResetFlagBits::eReleaseResources); - vk::CommandBuffer& commandBuffer = *commandBuffers.front(); - commandBuffer.begin(vk::CommandBufferBeginInfo(vk::CommandBufferUsageFlagBits::eOneTimeSubmit)); - ImGui_ImplVulkan_CreateFontsTexture((VkCommandBuffer)commandBuffer); - commandBuffer.end(); - vk::SubmitInfo submitInfo(nullptr, nullptr, commandBuffer); - graphicsQueue.submit(submitInfo, *drawFences.front()); - - device->waitIdle(); - ImGui_ImplVulkan_DestroyFontUploadObjects(); - } } bool VulkanContext::InitDevice() diff --git a/core/rend/vulkan/vulkan_driver.h b/core/rend/vulkan/vulkan_driver.h index e659863ae2..ea4dd5b712 100644 --- a/core/rend/vulkan/vulkan_driver.h +++ b/core/rend/vulkan/vulkan_driver.h @@ -33,6 +33,7 @@ class VulkanDriver final : public ImGuiDriver } void newFrame() override { + ImGui_ImplVulkan_NewFrame(); } void renderDrawData(ImDrawData *drawData, bool gui_open) override