diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 73213c986..9e849c524 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -176,18 +176,23 @@ static bool g_FunctionsLoaded = true; IMGUI_VULKAN_FUNC_MAP_MACRO(vkResetCommandPool) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkUnmapMemory) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkUpdateDescriptorSets) +#endif // VK_NO_PROTOTYPES +struct ImGui_ImplVulkan_Functions +{ +#ifdef VK_NO_PROTOTYPES // Define function pointers -#define IMGUI_VULKAN_FUNC_DEF(func) static PFN_##func func; -IMGUI_VULKAN_FUNC_MAP(IMGUI_VULKAN_FUNC_DEF) +#define IMGUI_VULKAN_FUNC_DEF(func) PFN_##func pfn_##func; + IMGUI_VULKAN_FUNC_MAP(IMGUI_VULKAN_FUNC_DEF) #undef IMGUI_VULKAN_FUNC_DEF #endif // VK_NO_PROTOTYPES #if defined(VK_VERSION_1_3) || defined(VK_KHR_dynamic_rendering) #define IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING -static PFN_vkCmdBeginRenderingKHR ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR; -static PFN_vkCmdEndRenderingKHR ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR; + PFN_vkCmdBeginRenderingKHR pfn_vkCmdBeginRenderingKHR; + PFN_vkCmdEndRenderingKHR pfn_vkCmdEndRenderingKHR; #endif +}; // Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplVulkan_RenderDrawData() // [Please zero-clear before use!] @@ -236,6 +241,8 @@ struct ImGui_ImplVulkan_Data // Render buffers for main window ImGui_ImplVulkan_WindowRenderBuffers MainWindowRenderBuffers; + ImGui_ImplVulkan_Functions Functions; + ImGui_ImplVulkan_Data() { memset((void*)this, 0, sizeof(*this)); @@ -243,6 +250,82 @@ struct ImGui_ImplVulkan_Data } }; +// Globally available function pointers used for initialization of the backend data +static ImGui_ImplVulkan_Functions g_Functions; + +// Shortcuts to the dynamically loaded function pointers +// imvkFunctions must be a ImGui_ImplVulkan_Functions or an expression that resolves to an instance of this structure +#ifdef VK_NO_PROTOTYPES +#define vkAllocateCommandBuffers imvkFunctions.pfn_vkAllocateCommandBuffers +#define vkAllocateDescriptorSets imvkFunctions.pfn_vkAllocateDescriptorSets +#define vkAllocateMemory imvkFunctions.pfn_vkAllocateMemory +#define vkBeginCommandBuffer imvkFunctions.pfn_vkBeginCommandBuffer +#define vkBindBufferMemory imvkFunctions.pfn_vkBindBufferMemory +#define vkBindImageMemory imvkFunctions.pfn_vkBindImageMemory +#define vkCmdBindDescriptorSets imvkFunctions.pfn_vkCmdBindDescriptorSets +#define vkCmdBindIndexBuffer imvkFunctions.pfn_vkCmdBindIndexBuffer +#define vkCmdBindPipeline imvkFunctions.pfn_vkCmdBindPipeline +#define vkCmdBindVertexBuffers imvkFunctions.pfn_vkCmdBindVertexBuffers +#define vkCmdCopyBufferToImage imvkFunctions.pfn_vkCmdCopyBufferToImage +#define vkCmdDrawIndexed imvkFunctions.pfn_vkCmdDrawIndexed +#define vkCmdPipelineBarrier imvkFunctions.pfn_vkCmdPipelineBarrier +#define vkCmdPushConstants imvkFunctions.pfn_vkCmdPushConstants +#define vkCmdSetScissor imvkFunctions.pfn_vkCmdSetScissor +#define vkCmdSetViewport imvkFunctions.pfn_vkCmdSetViewport +#define vkCreateBuffer imvkFunctions.pfn_vkCreateBuffer +#define vkCreateCommandPool imvkFunctions.pfn_vkCreateCommandPool +#define vkCreateDescriptorSetLayout imvkFunctions.pfn_vkCreateDescriptorSetLayout +#define vkCreateFence imvkFunctions.pfn_vkCreateFence +#define vkCreateFramebuffer imvkFunctions.pfn_vkCreateFramebuffer +#define vkCreateGraphicsPipelines imvkFunctions.pfn_vkCreateGraphicsPipelines +#define vkCreateImage imvkFunctions.pfn_vkCreateImage +#define vkCreateImageView imvkFunctions.pfn_vkCreateImageView +#define vkCreatePipelineLayout imvkFunctions.pfn_vkCreatePipelineLayout +#define vkCreateRenderPass imvkFunctions.pfn_vkCreateRenderPass +#define vkCreateSampler imvkFunctions.pfn_vkCreateSampler +#define vkCreateSemaphore imvkFunctions.pfn_vkCreateSemaphore +#define vkCreateShaderModule imvkFunctions.pfn_vkCreateShaderModule +#define vkCreateSwapchainKHR imvkFunctions.pfn_vkCreateSwapchainKHR +#define vkDestroyBuffer imvkFunctions.pfn_vkDestroyBuffer +#define vkDestroyCommandPool imvkFunctions.pfn_vkDestroyCommandPool +#define vkDestroyDescriptorSetLayout imvkFunctions.pfn_vkDestroyDescriptorSetLayout +#define vkDestroyFence imvkFunctions.pfn_vkDestroyFence +#define vkDestroyFramebuffer imvkFunctions.pfn_vkDestroyFramebuffer +#define vkDestroyImage imvkFunctions.pfn_vkDestroyImage +#define vkDestroyImageView imvkFunctions.pfn_vkDestroyImageView +#define vkDestroyPipeline imvkFunctions.pfn_vkDestroyPipeline +#define vkDestroyPipelineLayout imvkFunctions.pfn_vkDestroyPipelineLayout +#define vkDestroyRenderPass imvkFunctions.pfn_vkDestroyRenderPass +#define vkDestroySampler imvkFunctions.pfn_vkDestroySampler +#define vkDestroySemaphore imvkFunctions.pfn_vkDestroySemaphore +#define vkDestroyShaderModule imvkFunctions.pfn_vkDestroyShaderModule +#define vkDestroySurfaceKHR imvkFunctions.pfn_vkDestroySurfaceKHR +#define vkDestroySwapchainKHR imvkFunctions.pfn_vkDestroySwapchainKHR +#define vkDeviceWaitIdle imvkFunctions.pfn_vkDeviceWaitIdle +#define vkEndCommandBuffer imvkFunctions.pfn_vkEndCommandBuffer +#define vkFlushMappedMemoryRanges imvkFunctions.pfn_vkFlushMappedMemoryRanges +#define vkFreeCommandBuffers imvkFunctions.pfn_vkFreeCommandBuffers +#define vkFreeDescriptorSets imvkFunctions.pfn_vkFreeDescriptorSets +#define vkFreeMemory imvkFunctions.pfn_vkFreeMemory +#define vkGetBufferMemoryRequirements imvkFunctions.pfn_vkGetBufferMemoryRequirements +#define vkGetImageMemoryRequirements imvkFunctions.pfn_vkGetImageMemoryRequirements +#define vkGetPhysicalDeviceMemoryProperties imvkFunctions.pfn_vkGetPhysicalDeviceMemoryProperties +#define vkGetPhysicalDeviceSurfaceCapabilitiesKHR imvkFunctions.pfn_vkGetPhysicalDeviceSurfaceCapabilitiesKHR +#define vkGetPhysicalDeviceSurfaceFormatsKHR imvkFunctions.pfn_vkGetPhysicalDeviceSurfaceFormatsKHR +#define vkGetPhysicalDeviceSurfacePresentModesKHR imvkFunctions.pfn_vkGetPhysicalDeviceSurfacePresentModesKHR +#define vkGetSwapchainImagesKHR imvkFunctions.pfn_vkGetSwapchainImagesKHR +#define vkMapMemory imvkFunctions.pfn_vkMapMemory +#define vkQueueSubmit imvkFunctions.pfn_vkQueueSubmit +#define vkQueueWaitIdle imvkFunctions.pfn_vkQueueWaitIdle +#define vkResetCommandPool imvkFunctions.pfn_vkResetCommandPool +#define vkUnmapMemory imvkFunctions.pfn_vkUnmapMemory +#define vkUpdateDescriptorSets imvkFunctions.pfn_vkUpdateDescriptorSets +#endif // VK_NO_PROTOTYPES +#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING +#define vkCmdBeginRenderingKHR imvkFunctions.pfn_vkCmdBeginRenderingKHR +#define vkCmdEndRenderingKHR imvkFunctions.pfn_vkCmdEndRenderingKHR +#endif + //----------------------------------------------------------------------------- // SHADERS //----------------------------------------------------------------------------- @@ -356,6 +439,9 @@ static uint32_t __glsl_shader_frag_spv[] = // FUNCTIONS //----------------------------------------------------------------------------- +// Always use the current backend's functions in public interface +#define imvkFunctions bd->Functions + // Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts // It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts. // FIXME: multi-context support is not tested and probably dysfunctional in this backend. @@ -1053,16 +1139,16 @@ bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const ch // But this would be equivalent to not setting VK_NO_PROTOTYPES. #ifdef VK_NO_PROTOTYPES #define IMGUI_VULKAN_FUNC_LOAD(func) \ - func = reinterpret_cast(loader_func(#func, user_data)); \ - if (func == nullptr) \ + g_Functions.pfn_##func = reinterpret_cast(loader_func(#func, user_data)); \ + if (g_Functions.pfn_##func == nullptr) \ return false; IMGUI_VULKAN_FUNC_MAP(IMGUI_VULKAN_FUNC_LOAD) #undef IMGUI_VULKAN_FUNC_LOAD #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING // Manually load those two (see #5446) - ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR = reinterpret_cast(loader_func("vkCmdBeginRenderingKHR", user_data)); - ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR = reinterpret_cast(loader_func("vkCmdEndRenderingKHR", user_data)); + g_Functions.pfn_vkCmdBeginRenderingKHR = reinterpret_cast(loader_func("vkCmdBeginRenderingKHR", user_data)); + g_Functions.pfn_vkCmdEndRenderingKHR = reinterpret_cast(loader_func("vkCmdEndRenderingKHR", user_data)); #endif #else IM_UNUSED(loader_func); @@ -1081,11 +1167,11 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass rend { #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING #ifndef VK_NO_PROTOTYPES - ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR = reinterpret_cast(vkGetInstanceProcAddr(info->Instance, "vkCmdBeginRenderingKHR")); - ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR = reinterpret_cast(vkGetInstanceProcAddr(info->Instance, "vkCmdEndRenderingKHR")); + g_Functions.pfn_vkCmdBeginRenderingKHR = reinterpret_cast(vkGetInstanceProcAddr(info->Instance, "vkCmdBeginRenderingKHR")); + g_Functions.pfn_vkCmdEndRenderingKHR = reinterpret_cast(vkGetInstanceProcAddr(info->Instance, "vkCmdEndRenderingKHR")); #endif - IM_ASSERT(ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR != nullptr); - IM_ASSERT(ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR != nullptr); + IM_ASSERT(g_Functions.pfn_vkCmdBeginRenderingKHR != nullptr); + IM_ASSERT(g_Functions.pfn_vkCmdEndRenderingKHR != nullptr); #else IM_ASSERT(0 && "Can't use dynamic rendering when neither VK_VERSION_1_3 or VK_KHR_dynamic_rendering is defined."); #endif @@ -1113,6 +1199,7 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass rend bd->VulkanInitInfo = *info; bd->RenderPass = render_pass; bd->Subpass = info->Subpass; + bd->Functions = g_Functions; ImGui_ImplVulkan_CreateDeviceObjects(); @@ -1200,6 +1287,8 @@ void ImGui_ImplVulkan_RemoveTexture(VkDescriptorSet descriptor_set) void ImGui_ImplVulkan_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkan_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator) { + ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); + IM_UNUSED(bd); // May be unused if (buffers->VertexBuffer) { vkDestroyBuffer(device, buffers->VertexBuffer, allocator); buffers->VertexBuffer = VK_NULL_HANDLE; } if (buffers->VertexBufferMemory) { vkFreeMemory(device, buffers->VertexBufferMemory, allocator); buffers->VertexBufferMemory = VK_NULL_HANDLE; } if (buffers->IndexBuffer) { vkDestroyBuffer(device, buffers->IndexBuffer, allocator); buffers->IndexBuffer = VK_NULL_HANDLE; } @@ -1234,6 +1323,10 @@ void ImGui_ImplVulkan_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulk // (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions) //------------------------------------------------------------------------- +// Use global function pointers +#undef imvkFunctions +#define imvkFunctions g_Functions + VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space) { IM_ASSERT(g_FunctionsLoaded && "Need to call ImGui_ImplVulkan_LoadFunctions() if IMGUI_IMPL_VULKAN_NO_PROTOTYPES or VK_NO_PROTOTYPES are set!");