Skip to content
Closed
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
160 changes: 143 additions & 17 deletions backends/imgui_impl_vulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -935,10 +935,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;
Expand Down Expand Up @@ -993,7 +1004,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 @@ -1033,21 +1044,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()
Expand Down Expand Up @@ -1121,7 +1134,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)
Expand All @@ -1146,6 +1186,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();
Expand Down Expand Up @@ -1270,17 +1344,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)
Expand All @@ -1299,6 +1371,35 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info)

ImGui_ImplVulkan_InitMultiViewportSupport();

{
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 = info->MSAASamples;
mp_info.pDynamicRendering = p_dynamic_rendering;

ImGui_ImplVulkan_ReCreateMainPipeline(mp_info);
}
}

return true;
}

Expand Down Expand Up @@ -1956,8 +2057,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
21 changes: 20 additions & 1 deletion backends/imgui_impl_vulkan.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,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:
Expand Down Expand Up @@ -99,6 +105,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

Expand All @@ -109,12 +116,24 @@ 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 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)


// (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);

Expand Down