From 7a50853131f6ea7d8815c7e171f03bd026fdf08e Mon Sep 17 00:00:00 2001 From: Ronan Cailleau Date: Tue, 29 Oct 2024 14:03:44 +0100 Subject: [PATCH] Merge branch 'feature/vk_re_create_pipeline_2' into feature/docking_vk_re_create_pipeline_2 --- backends/imgui_impl_vulkan.cpp | 133 ++++++++++++++++++++++++++++----- backends/imgui_impl_vulkan.h | 29 +++++-- 2 files changed, 138 insertions(+), 24 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 09f4edfad..d3192f22e 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -887,10 +887,21 @@ static void ImGui_ImplVulkan_CreateShaderModules(VkDevice device, const VkAlloca } } -static void ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAllocationCallbacks* allocator, VkPipelineCache pipelineCache, VkRenderPass renderPass, VkSampleCountFlagBits MSAASamples, VkPipeline* pipeline, uint32_t subpass) +struct ImGui_ImplVulkan_PipelineCreateInfo +{ + VkDevice Device = VK_NULL_HANDLE; + const VkAllocationCallbacks* Allocator = nullptr; + VkPipelineCache PipelineCache = VK_NULL_HANDLE; + VkRenderPass RenderPass = VK_NULL_HANDLE; + uint32_t Subpass = 0; + VkSampleCountFlagBits MSAASamples = {}; + const ImGui_ImplVulkan_PipelineRenderingInfo* pRenderingInfo = nullptr; +}; + +static VkPipeline ImGui_ImplVulkan_CreatePipeline(ImGui_ImplVulkan_PipelineCreateInfo const& pci) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - ImGui_ImplVulkan_CreateShaderModules(device, allocator); + ImGui_ImplVulkan_CreateShaderModules(pci.Device, pci.Allocator); VkPipelineShaderStageCreateInfo stage[2] = {}; stage[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; @@ -945,7 +956,7 @@ static void ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAllocationC VkPipelineMultisampleStateCreateInfo ms_info = {}; ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - ms_info.rasterizationSamples = (MSAASamples != 0) ? MSAASamples : VK_SAMPLE_COUNT_1_BIT; + ms_info.rasterizationSamples = (pci.MSAASamples != 0) ? pci.MSAASamples : VK_SAMPLE_COUNT_1_BIT; VkPipelineColorBlendAttachmentState color_attachment[1] = {}; color_attachment[0].blendEnable = VK_TRUE; @@ -985,21 +996,22 @@ static void ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAllocationC info.pColorBlendState = &blend_info; info.pDynamicState = &dynamic_state; info.layout = bd->PipelineLayout; - info.renderPass = renderPass; - info.subpass = subpass; + info.renderPass = pci.RenderPass; + info.subpass = pci.Subpass; #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING if (bd->VulkanInitInfo.UseDynamicRendering) { - IM_ASSERT(bd->VulkanInitInfo.PipelineRenderingCreateInfo.sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR && "PipelineRenderingCreateInfo sType must be VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR"); - IM_ASSERT(bd->VulkanInitInfo.PipelineRenderingCreateInfo.pNext == nullptr && "PipelineRenderingCreateInfo pNext must be NULL"); - info.pNext = &bd->VulkanInitInfo.PipelineRenderingCreateInfo; info.renderPass = VK_NULL_HANDLE; // Just make sure it's actually nullptr. + IM_ASSERT(pci.pRenderingInfo->sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR && "PipelineRenderingCreateInfo::sType must be VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR"); + IM_ASSERT(pci.pRenderingInfo->pNext == nullptr && "PipelineRenderingCreateInfo::pNext must be NULL"); + info.pNext = pci.pRenderingInfo; } #endif - - VkResult err = vkCreateGraphicsPipelines(device, pipelineCache, 1, &info, allocator, pipeline); + VkPipeline res; + VkResult err = vkCreateGraphicsPipelines(pci.Device, pci.PipelineCache, 1, &info, pci.Allocator, &res); check_vk_result(err); + return res; } bool ImGui_ImplVulkan_CreateDeviceObjects() @@ -1058,11 +1070,43 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() check_vk_result(err); } - ImGui_ImplVulkan_CreatePipeline(v->Device, v->Allocator, v->PipelineCache, v->RenderPass, v->MSAASamples, &bd->Pipeline, v->Subpass); - return true; } +void ImGui_ImplVulkan_ReCreateMainPipeline(ImGui_ImplVulkan_MainPipelineCreateInfo const& info) +{ + ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); + ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; + if (bd->Pipeline) + { + vkDestroyPipeline(v->Device, bd->Pipeline, v->Allocator); + bd->Pipeline = VK_NULL_HANDLE; + } + v->RenderPass = info.RenderPass; + v->MSAASamples = info.MSAASamples; + v->Subpass = info.Subpass; + +#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING + if (info.pDynamicRendering) + { + v->PipelineRenderingCreateInfo = *info.pDynamicRendering; + } +#else + IM_ASSERT(p_dynamic_rendering == nullptr); +#endif + + ImGui_ImplVulkan_PipelineCreateInfo pci; + pci.Device = v->Device; + pci.Allocator = v->Allocator; + pci.PipelineCache = v->PipelineCache; + pci.RenderPass = v->RenderPass; + pci.Subpass = v->Subpass; + pci.MSAASamples = v->MSAASamples; + pci.pRenderingInfo = info.pDynamicRendering; + + bd->Pipeline = ImGui_ImplVulkan_CreatePipeline(pci); +} + void ImGui_ImplVulkan_DestroyDeviceObjects() { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); @@ -1145,10 +1189,11 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info) IM_ASSERT(info->DescriptorPool != VK_NULL_HANDLE); IM_ASSERT(info->MinImageCount >= 2); IM_ASSERT(info->ImageCount >= info->MinImageCount); - if (info->UseDynamicRendering == false) - IM_ASSERT(info->RenderPass != VK_NULL_HANDLE); + //if (info->UseDynamicRendering == false) + // IM_ASSERT(info->RenderPass != VK_NULL_HANDLE); - bd->VulkanInitInfo = *info; + ImGui_ImplVulkan_InitInfo * v = &bd->VulkanInitInfo; + *v = *info; ImGui_ImplVulkan_CreateDeviceObjects(); @@ -1158,6 +1203,35 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info) ImGui_ImplVulkan_InitMultiViewportSupport(); + { + bool create_pipeline = false; + const ImGui_ImplVulkan_PipelineRenderingInfo * p_dynamic_rendering = nullptr; + if (v->RenderPass) + { + create_pipeline = true; + } + else + { + #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING + if (v->UseDynamicRendering && v->PipelineRenderingCreateInfo.sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR) + { + p_dynamic_rendering = &v->PipelineRenderingCreateInfo; + create_pipeline = true; + } + #endif + } + if (create_pipeline) + { + ImGui_ImplVulkan_MainPipelineCreateInfo mp_info = {}; + mp_info.RenderPass = v->RenderPass; + mp_info.Subpass = v->Subpass; + mp_info.MSAASamples = info->MSAASamples; + mp_info.pDynamicRendering = p_dynamic_rendering; + + ImGui_ImplVulkan_ReCreateMainPipeline(mp_info); + } + } + return true; } @@ -1699,8 +1773,33 @@ static void ImGui_ImplVulkan_CreateWindow(ImGuiViewport* viewport) vd->WindowOwned = true; // Create pipeline (shared by all secondary viewports) - if (bd->PipelineForViewports == VK_NULL_HANDLE) - ImGui_ImplVulkan_CreatePipeline(v->Device, v->Allocator, VK_NULL_HANDLE, wd->RenderPass, VK_SAMPLE_COUNT_1_BIT, &bd->PipelineForViewports, 0); + if (bd->PipelineForViewports == VK_NULL_HANDLE) + { + ImGui_ImplVulkan_PipelineCreateInfo pci; + pci.Device = v->Device; + pci.Allocator = v->Allocator; + pci.PipelineCache = VK_NULL_HANDLE; + pci.RenderPass = wd->RenderPass; + pci.Subpass = 0; + pci.MSAASamples = VK_SAMPLE_COUNT_1_BIT; +#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING + VkPipelineRenderingCreateInfoKHR rendering_info = {}; + if (wd->UseDynamicRendering) + { + rendering_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO; + rendering_info.pNext = nullptr; + rendering_info.viewMask = 0; + rendering_info.colorAttachmentCount = 1; + rendering_info.pColorAttachmentFormats = &wd->SurfaceFormat.format; + rendering_info.depthAttachmentFormat = VK_FORMAT_UNDEFINED; + rendering_info.stencilAttachmentFormat = VK_FORMAT_UNDEFINED; + pci.RenderPass = VK_NULL_HANDLE; + pci.pRenderingInfo = &rendering_info; + } +#endif + bd->PipelineForViewports = ImGui_ImplVulkan_CreatePipeline(pci); + + } } static void ImGui_ImplVulkan_DestroyWindow(ImGuiViewport* viewport) diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index fe1d78f10..a69c7960e 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -62,6 +62,12 @@ #define IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING #endif +#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING +typedef VkPipelineRenderingCreateInfoKHR ImGui_ImplVulkan_PipelineRenderingInfo; +#else +typedef void ImGui_ImplVulkan_PipelineRenderingInfo; +#endif + // Initialization data, for ImGui_ImplVulkan_Init() // - VkDescriptorPool should be created with VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, // and must contain a pool size large enough to hold an ImGui VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER descriptor. @@ -98,13 +104,22 @@ struct ImGui_ImplVulkan_InitInfo }; // Follow "Getting Started" link and check examples/ folder to learn about using backends! -IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info); -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(); -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) +IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info); // The main pipeline will be created if possible (RenderPass xor (UseDynamicRendering && PipelineRenderingCreateInfo->sType is correct)) +#define IMGUI_IMPL_VULKAN_HAS_MAIN_PIPELINE_RE_CREATION 1 +struct ImGui_ImplVulkan_MainPipelineCreateInfo +{ + VkRenderPass RenderPass = VK_NULL_HANDLE; + uint32_t Subpass = 0; + VkSampleCountFlagBits MSAASamples = {}; + const ImGui_ImplVulkan_PipelineRenderingInfo* pDynamicRendering = nullptr; +}; +IMGUI_IMPL_API void ImGui_ImplVulkan_ReCreateMainPipeline(ImGui_ImplVulkan_MainPipelineCreateInfo const& info); // (render_pass xor (p_dynamic_rendering && p_dynamic_rendering is correct (sType and pNext)) +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(); +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) // FIXME: This is experimental in the sense that we are unsure how to best design/tackle this problem