Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vulkan: Re-create main window pipeline (standalone) with docking #8111

Open
wants to merge 1 commit into
base: docking
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 116 additions & 17 deletions backends/imgui_impl_vulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();

Expand All @@ -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;
}

Expand Down Expand Up @@ -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;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be clean to use a PCI factory so you can one shot this pci struct with something like PCISettings.createBaseVulkanPCI()

#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;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same thing with render_info. Surely there is some cross impl pattern in the data structure that make it worth creating a factory.

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)
Expand Down
29 changes: 22 additions & 7 deletions backends/imgui_impl_vulkan.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down