From 5316e7061425524682cafbafe8e0b86494a70470 Mon Sep 17 00:00:00 2001 From: Lukasz Stalmirski Date: Thu, 3 Sep 2026 15:59:00 +0200 Subject: [PATCH] Backends: Vulkan: support multiple Vulkan contexts with custom loader. (#6616) Vulkan function calls now go through a short trampoline function, only apply when IMGUI_IMPL_VULKAN_USE_LOADER is set. --- backends/imgui_impl_vulkan.cpp | 45 +++++++++++++++++++++++++++++++--- docs/CHANGELOG.txt | 1 + 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 57ebdb064..0e172bfb8 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -27,6 +27,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-09-03: Added for support for multiple Vulkan contexts with custom loaders. (#6616) // 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378) // 2026-04-22: *BREAKING CHANGE* redesigned to use separate ImageView + Sampler instead of Combined Image Sampler. This change allows us to facilitate changing samplers, in line with other backends. // - When registering custom textures: changed ImGui_ImplVulkan_AddTexture() signature to remove Sampler. @@ -230,10 +231,28 @@ static bool g_FunctionsLoaded = true; IMGUI_VULKAN_FUNC_MAP_MACRO(vkUpdateDescriptorSets) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkWaitForFences) +struct ImGui_ImplVulkan_Functions +{ // Define function pointers -#define IMGUI_VULKAN_FUNC_DEF(func) static PFN_##func func; +#define IMGUI_VULKAN_FUNC_DEF(func) PFN_##func pfn_##func; IMGUI_VULKAN_FUNC_MAP(IMGUI_VULKAN_FUNC_DEF) #undef IMGUI_VULKAN_FUNC_DEF +}; + +// Globally available function pointers used for initialization of the backend data +static ImGui_ImplVulkan_Functions ImGuiImplVulkanFuncs; + +// Multi Vulkan contexts support: wrap each Vulkan function pointer to properly dispatch it using the current backend data +static ImGui_ImplVulkan_Functions& ImGui_ImplVulkan_GetFunctions(); +#define IMGUI_VULKAN_FUNC_WRAPPER(func) \ + template \ + auto func(Args&&... args) -> decltype(ImGui_ImplVulkan_GetFunctions().pfn_##func(args...)) \ + { \ + return ImGui_ImplVulkan_GetFunctions().pfn_##func(args...); \ + } +IMGUI_VULKAN_FUNC_MAP(IMGUI_VULKAN_FUNC_WRAPPER) +#undef IMGUI_VULKAN_FUNC_WRAPPER + #endif // IMGUI_IMPL_VULKAN_USE_LOADER #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING @@ -300,6 +319,11 @@ struct ImGui_ImplVulkan_Data // Render buffers for main window ImGui_ImplVulkan_WindowRenderBuffers MainWindowRenderBuffers; + // Vulkan function pointers loaded for this context +#ifdef IMGUI_IMPL_VULKAN_USE_LOADER + ImGui_ImplVulkan_Functions Functions; +#endif + ImGui_ImplVulkan_Data() { memset((void*)this, 0, sizeof(*this)); @@ -434,6 +458,16 @@ static ImGui_ImplVulkan_Data* ImGui_ImplVulkan_GetBackendData() return ImGui::GetCurrentContext() ? (ImGui_ImplVulkan_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; } +#ifdef IMGUI_IMPL_VULKAN_USE_LOADER +// Get the Vulkan function pointers used by the current backend. +// If no backend is available, return the currently loaded global function pointers (ImGuiImplVulkanFuncs). +static ImGui_ImplVulkan_Functions& ImGui_ImplVulkan_GetFunctions() +{ + ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); + return bd ? bd->Functions : ImGuiImplVulkanFuncs; +} +#endif + static uint32_t ImGui_ImplVulkan_MemoryType(VkMemoryPropertyFlags properties, uint32_t type_bits) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); @@ -529,7 +563,7 @@ static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, VkPipeline constants[1] = 2.0f / draw_data->DisplaySize.y; constants[2] = -1.0f - draw_data->DisplayPos.x * constants[0]; // Translate constants[3] = -1.0f - draw_data->DisplayPos.y * constants[1]; - vkCmdPushConstants(command_buffer, bd->PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(float) * 4, constants); + vkCmdPushConstants(command_buffer, bd->PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, (uint32_t)sizeof(float) * 4, constants); // Setup sampler vkCmdBindDescriptorSets(bd->RenderState->CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 1, 1, &bd->SamplerLinearDS, 0, nullptr); @@ -1321,8 +1355,8 @@ bool ImGui_ImplVulkan_LoadFunctions(uint32_t api_version, PFN_vkVoidFunction( #ifdef IMGUI_IMPL_VULKAN_USE_LOADER #define IMGUI_VULKAN_FUNC_LOAD(func) \ - func = reinterpret_cast(loader_func(#func, user_data)); \ - if (func == nullptr) \ + ImGuiImplVulkanFuncs.pfn_##func = reinterpret_cast(loader_func(#func, user_data)); \ + if (ImGuiImplVulkanFuncs.pfn_##func == nullptr) \ return false; IMGUI_VULKAN_FUNC_MAP(IMGUI_VULKAN_FUNC_LOAD) #undef IMGUI_VULKAN_FUNC_LOAD @@ -1390,6 +1424,9 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info) IM_ASSERT(info->PipelineInfoMain.RenderPass == VK_NULL_HANDLE); bd->VulkanInitInfo = *info; +#ifdef IMGUI_IMPL_VULKAN_USE_LOADER + bd->Functions = ImGuiImplVulkanFuncs; +#endif VkPhysicalDeviceProperties properties; vkGetPhysicalDeviceProperties(info->PhysicalDevice, &properties); diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 1749549ce..2ce07692c 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -86,6 +86,7 @@ Other Changes: - QNX: added QNX Screen backend. (#9492) [@mgorchak-blackberry] - SDL2: fixed querying framebuffer scale/density when using Metal without going through a SDL_Renderer. (#5592) [@lailoken] + - Vulkan: added for support for multiple Vulkan contexts with custom loaders. (#6616) [@lstalmir] - WebGPU: fixed passing non-integer sizes to `wgpuRenderPassEncoderSetViewport()` when when `FramebufferScale` is >1.0f. (#9515, #8628) [@WayU] - WebGPU: update to build with wgpu-native 29.0+. (#9377, #9532, #9530) [@lucascompython, @ivan-enzhaev]