Prechádzať zdrojové kódy

Backends: Vulkan: added ImGui_ImplVulkan_CreateMainPipeline(). (#8110, #8111, #8053)

- Added ImGui_ImplVulkan_CreateMainPipeline(...) to explicitly re-create the main window pipeline (when some of its properties are changed).
- Does not implicitly use ImGui_ImplVulkan_InitInfo::PipelineRenderingCreateInfo, but a function parameter.
- The main window pipeline is created only if possible during ImGui_ImplVulkan_Init(...) (if a render pass or rendering info are given), else it should be created with ImGui_ImplVulkan_ReCreateMainPipeline(...)
- ImGui_ImplVulkan_CreatePipeline now takes a struct rather than (too) many parameters (and returns the created pipeline).
Ronan Cailleau 10 mesiacov pred
rodič
commit
e51d93e2f5
2 zmenil súbory, kde vykonal 105 pridanie a 16 odobranie
  1. 87 15
      backends/imgui_impl_vulkan.cpp
  2. 18 1
      backends/imgui_impl_vulkan.h

+ 87 - 15
backends/imgui_impl_vulkan.cpp

@@ -906,10 +906,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_PipelineRenderingCreateInfo* 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;
@@ -964,7 +975,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;
@@ -1004,21 +1015,23 @@ 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 nullptr");
-        info.pNext = &bd->VulkanInitInfo.PipelineRenderingCreateInfo;
+        IM_ASSERT(pci.pRenderingInfo && "PipelineRenderingCreateInfo must not be nullptr when using dynamic rendering");
+        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 nullptr");
+        info.pNext = pci.pRenderingInfo;
         info.renderPass = VK_NULL_HANDLE; // Just make sure it's actually nullptr.
     }
 #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()
@@ -1092,7 +1105,34 @@ 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);
+    {
+        bool create_pipeline = false;
+        const ImGui_ImplVulkan_PipelineRenderingCreateInfo* 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 = v->MSAASamples;
+            mp_info.pDynamicRendering = p_dynamic_rendering;
+
+            ImGui_ImplVulkan_ReCreateMainPipeline(mp_info);
+        }
+    }
 
     // Create command pool/buffer for texture upload
     if (!bd->TexCommandPool)
@@ -1117,6 +1157,40 @@ bool ImGui_ImplVulkan_CreateDeviceObjects()
     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(info.pDynamicRendering == 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();
@@ -1239,17 +1313,15 @@ bool    ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info)
         IM_ASSERT(info->DescriptorPoolSize > 0);
     IM_ASSERT(info->MinImageCount >= 2);
     IM_ASSERT(info->ImageCount >= info->MinImageCount);
-    if (info->UseDynamicRendering == false)
-        IM_ASSERT(info->RenderPass != VK_NULL_HANDLE);
 
-    bd->VulkanInitInfo = *info;
+    ImGui_ImplVulkan_InitInfo * v = &bd->VulkanInitInfo;
+    *v = *info;
 
     VkPhysicalDeviceProperties properties;
     vkGetPhysicalDeviceProperties(info->PhysicalDevice, &properties);
     bd->NonCoherentAtomSize = properties.limits.nonCoherentAtomSize;
 
 #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
-    ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
     if (v->PipelineRenderingCreateInfo.pColorAttachmentFormats != NULL)
     {
         // Deep copy buffer to reduce error-rate for end user (#8282)

+ 18 - 1
backends/imgui_impl_vulkan.h

@@ -65,6 +65,12 @@
 // Backend uses a small number of descriptors per font atlas + as many as additional calls done to ImGui_ImplVulkan_AddTexture().
 #define IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE   (8)     // Minimum per atlas
 
+#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
+typedef VkPipelineRenderingCreateInfoKHR ImGui_ImplVulkan_PipelineRenderingCreateInfo;
+#else
+typedef void ImGui_ImplVulkan_PipelineRenderingCreateInfo;
+#endif
+
 // Initialization data, for ImGui_ImplVulkan_Init()
 // [Please zero-clear before use!]
 // - About descriptor pool:
@@ -98,6 +104,7 @@ struct ImGui_ImplVulkan_InitInfo
     // Need to explicitly enable VK_KHR_dynamic_rendering extension to use this, even for Vulkan 1.3.
     bool                            UseDynamicRendering;
 #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
+    // (Optional, valid iif .sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR)
     VkPipelineRenderingCreateInfoKHR PipelineRenderingCreateInfo;
 #endif
 
@@ -108,12 +115,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 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_PipelineRenderingCreateInfo* 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 void             ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated)
 
+
 // (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually.
 IMGUI_IMPL_API void             ImGui_ImplVulkan_UpdateTexture(ImTextureData* tex);