From 6001c54598c98dd056e2e19891cb7dbbcd6d3e4b Mon Sep 17 00:00:00 2001 From: Hossein Noroozpour Date: Tue, 26 Jan 2021 21:04:12 +0330 Subject: [PATCH] Backends: Vulkan: Support for custom function/symbol loader (#3759, #3227) - It adds an optional feature to support dynamic linkage of Vulkan instead of using default linkage. - It is now possible to have several potentially working implementation and whenever the Vulkan library was available it can work. --- backends/imgui_impl_vulkan.cpp | 79 +++++++++++++++++++++++++++++++++- backends/imgui_impl_vulkan.h | 45 +++++++++++++------ 2 files changed, 110 insertions(+), 14 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 460623905..c0c65bc34 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -48,10 +48,75 @@ // 2016-10-18: Vulkan: Add location decorators & change to use structs as in/out in glsl, update embedded spv (produced with glslangValidator -x). Null the released resources. // 2016-08-27: Vulkan: Fix Vulkan example for use when a depth buffer is active. -#include "imgui.h" #include "imgui_impl_vulkan.h" #include +#ifdef IMGUI_IMPL_VULKAN_NO_PROTOTYPES +#define IMGUI_VULKAN_FUNCTIONS_DEF(func) static PFN_##func func; +#define IMGUI_VULKAN_FUNCTIONS_MAP(IMGUI_VULKAN_FUNCTIONS_MAP_MACRO) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkAllocateCommandBuffers) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkAllocateDescriptorSets) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkAllocateMemory) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkBindBufferMemory) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkBindImageMemory) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkCmdBindDescriptorSets) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkCmdBindIndexBuffer) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkCmdBindPipeline) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkCmdBindVertexBuffers) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkCmdCopyBufferToImage) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkCmdDrawIndexed) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkCmdPipelineBarrier) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkCmdPushConstants) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkCmdSetScissor) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkCmdSetViewport) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkCreateBuffer) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkCreateCommandPool) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkCreateDescriptorSetLayout) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkCreateFence) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkCreateFramebuffer) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkCreateGraphicsPipelines) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkCreateImage) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkCreateImageView) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkCreatePipelineLayout) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkCreateRenderPass) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkCreateSampler) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkCreateSemaphore) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkCreateShaderModule) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkCreateSwapchainKHR) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkDestroyBuffer) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkDestroyCommandPool) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkDestroyDescriptorSetLayout) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkDestroyFence) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkDestroyFramebuffer) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkDestroyImage) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkDestroyImageView) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkDestroyPipeline) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkDestroyPipelineLayout) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkDestroyRenderPass) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkDestroySampler) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkDestroySemaphore) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkDestroyShaderModule) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkDestroySurfaceKHR) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkDestroySwapchainKHR) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkDeviceWaitIdle) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkFlushMappedMemoryRanges) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkFreeCommandBuffers) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkFreeMemory) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkGetBufferMemoryRequirements) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkGetImageMemoryRequirements) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkGetPhysicalDeviceMemoryProperties) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkGetPhysicalDeviceSurfaceCapabilitiesKHR) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkGetPhysicalDeviceSurfaceFormatsKHR) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkGetPhysicalDeviceSurfacePresentModesKHR) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkGetSwapchainImagesKHR) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkMapMemory) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkUnmapMemory) \ + IMGUI_VULKAN_FUNCTIONS_MAP_MACRO(vkUpdateDescriptorSets) + +IMGUI_VULKAN_FUNCTIONS_MAP(IMGUI_VULKAN_FUNCTIONS_DEF) +#undef IMGUI_VULKAN_FUNCTIONS_DEF +#endif + // Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplVulkan_RenderDrawData() // [Please zero-clear before use!] struct ImGui_ImplVulkanH_FrameRenderBuffers @@ -888,6 +953,18 @@ void ImGui_ImplVulkan_DestroyDeviceObjects() bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass) { + +#ifdef IMGUI_IMPL_VULKAN_NO_PROTOTYPES + IM_ASSERT(info->GetVulkanProcAddressFn != NULL); +#define IMGUI_VULKAN_FUNCTIONS_LOAD(func) \ + func = reinterpret_cast(info->GetVulkanProcAddressFn(info->user_data, #func)); \ + if(NULL == func) { \ + return false; \ + } + IMGUI_VULKAN_FUNCTIONS_MAP(IMGUI_VULKAN_FUNCTIONS_LOAD) +#undef IMGUI_VULKAN_FUNCTIONS_LOAD +#endif + // Setup backend capabilities flags ImGuiIO& io = ImGui::GetIO(); io.BackendRendererName = "imgui_impl_vulkan"; diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index 1e984b39c..99158722b 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -22,25 +22,44 @@ #pragma once #include "imgui.h" // IMGUI_IMPL_API + +// In order to be able to use a customized Vulkan loader instead of the default one, you can uncomment the +// underlying definition in here (not in your code) or define it as a compilation flag in your build system. +// After enabling this, the user has to provide 'GetVulkanProcAddressFn' (and 'user_data' if it was needed) in +// the 'ImGui_ImplVulkan_InitInfo' so the implementation can resolve function addresses with that. +// If you have no idea what it is, leave it alone! +//#define IMGUI_IMPL_VULKAN_NO_PROTOTYPES + +#ifdef IMGUI_IMPL_VULKAN_NO_PROTOTYPES +#define VK_NO_PROTOTYPES 1 +#endif #include // Initialization data, for ImGui_ImplVulkan_Init() // [Please zero-clear before use!] struct ImGui_ImplVulkan_InitInfo { - VkInstance Instance; - VkPhysicalDevice PhysicalDevice; - VkDevice Device; - uint32_t QueueFamily; - VkQueue Queue; - VkPipelineCache PipelineCache; - VkDescriptorPool DescriptorPool; - uint32_t Subpass; - uint32_t MinImageCount; // >= 2 - uint32_t ImageCount; // >= MinImageCount - VkSampleCountFlagBits MSAASamples; // >= VK_SAMPLE_COUNT_1_BIT - const VkAllocationCallbacks* Allocator; - void (*CheckVkResultFn)(VkResult err); + VkInstance Instance; + VkPhysicalDevice PhysicalDevice; + VkDevice Device; + uint32_t QueueFamily; + VkQueue Queue; + VkPipelineCache PipelineCache; + VkDescriptorPool DescriptorPool; + uint32_t Subpass; + uint32_t MinImageCount; // >= 2 + uint32_t ImageCount; // >= MinImageCount + VkSampleCountFlagBits MSAASamples; // >= VK_SAMPLE_COUNT_1_BIT + const VkAllocationCallbacks* Allocator; + void (*CheckVkResultFn)(VkResult err); +#ifdef IMGUI_IMPL_VULKAN_NO_PROTOTYPES + // This function pointer is needed when the default Vulkan loader is disabled(not applicable). + // For more information look at comments before '#define IMGUI_IMPL_VULKAN_NO_PROTOTYPES' + PFN_vkVoidFunction (*GetVulkanProcAddressFn)(void *user_data, const char* pName); + // This pointer is going to be fed to the 'GetVulkanProcAddressFn', you can use it for + // accessing contex/object that is maybe needed for the function call. + void *user_data; +#endif }; // Called by user code