Backends: Vulkan: Rework support for custom function/symbol loader (#3759, #3227), add ImGui_ImplVulkan_LoadFunctions (amend 6001c54)
Making it a separate function allows to use/test this with our examples or any code using the VulkanH helper called before ImGui_ImplVulkan_Init()
diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp
index c0c65bc..bae3b2b 100644
--- a/backends/imgui_impl_vulkan.cpp
+++ b/backends/imgui_impl_vulkan.cpp
@@ -22,6 +22,7 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
+// 2021-01-27: Vulkan: Added support for custom function load and IMGUI_IMPL_VULKAN_NO_PROTOTYPES by using ImGui_ImplVulkan_LoadFunctions().
// 2020-11-11: Vulkan: Added support for specifying which subpass to reference during VkPipeline creation.
// 2020-09-07: Vulkan: Added VkPipeline parameter to ImGui_ImplVulkan_RenderDrawData (default to one passed to ImGui_ImplVulkan_Init).
// 2020-05-04: Vulkan: Fixed crash if initial frame has no vertices.
@@ -51,72 +52,6 @@
#include "imgui_impl_vulkan.h"
#include <stdio.h>
-#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
@@ -150,6 +85,11 @@
static uint32_t g_Subpass = 0;
static VkShaderModule g_ShaderModuleVert;
static VkShaderModule g_ShaderModuleFrag;
+#ifdef VK_NO_PROTOTYPES
+static bool g_FunctionsLoaded = false;
+#else
+static bool g_FunctionsLoaded = true;
+#endif
// Font data
static VkSampler g_FontSampler = VK_NULL_HANDLE;
@@ -172,6 +112,75 @@
void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator);
+// Vulkan prototypes for use with custom loaders
+// (see description of IMGUI_IMPL_VULKAN_NO_PROTOTYPES in imgui_impl_vulkan.h
+#ifdef VK_NO_PROTOTYPES
+#define IMGUI_VULKAN_FUNC_MAP(IMGUI_VULKAN_FUNC_MAP_MACRO) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkAllocateCommandBuffers) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkAllocateDescriptorSets) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkAllocateMemory) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkBindBufferMemory) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkBindImageMemory) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBindDescriptorSets) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBindIndexBuffer) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBindPipeline) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBindVertexBuffers) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdCopyBufferToImage) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdDrawIndexed) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdPipelineBarrier) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdPushConstants) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdSetScissor) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdSetViewport) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateBuffer) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateCommandPool) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateDescriptorSetLayout) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateFence) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateFramebuffer) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateGraphicsPipelines) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateImage) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateImageView) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreatePipelineLayout) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateRenderPass) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateSampler) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateSemaphore) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateShaderModule) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateSwapchainKHR) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyBuffer) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyCommandPool) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyDescriptorSetLayout) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyFence) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyFramebuffer) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyImage) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyImageView) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyPipeline) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyPipelineLayout) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyRenderPass) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroySampler) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroySemaphore) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyShaderModule) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroySurfaceKHR) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroySwapchainKHR) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDeviceWaitIdle) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkFlushMappedMemoryRanges) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkFreeCommandBuffers) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkFreeMemory) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetBufferMemoryRequirements) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetImageMemoryRequirements) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceMemoryProperties) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfaceCapabilitiesKHR) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfaceFormatsKHR) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfacePresentModesKHR) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetSwapchainImagesKHR) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkMapMemory) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkUnmapMemory) \
+ IMGUI_VULKAN_FUNC_MAP_MACRO(vkUpdateDescriptorSets)
+
+// Define function pointers
+#define IMGUI_VULKAN_FUNC_DEF(func) static PFN_##func func;
+IMGUI_VULKAN_FUNC_MAP(IMGUI_VULKAN_FUNC_DEF)
+#undef IMGUI_VULKAN_FUNC_DEF
+#endif // VK_NO_PROTOTYPES
+
//-----------------------------------------------------------------------------
// SHADERS
//-----------------------------------------------------------------------------
@@ -951,19 +960,30 @@
if (g_Pipeline) { vkDestroyPipeline(v->Device, g_Pipeline, v->Allocator); g_Pipeline = VK_NULL_HANDLE; }
}
+bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data)
+{
+ // Load function pointers
+ // You can use the default Vulkan loader using:
+ // ImGui_ImplVulkan_LoadFunctions([](const char* function_name, void*) { return vkGetInstanceProcAddr(your_vk_isntance, function_name); });
+ // But this would be equivalent to not setting VK_NO_PROTOTYPES.
+#ifdef VK_NO_PROTOTYPES
+#define IMGUI_VULKAN_FUNC_LOAD(func) \
+ func = reinterpret_cast<decltype(func)>(loader_func(#func, user_data)); \
+ if (func == NULL) \
+ return false;
+ IMGUI_VULKAN_FUNC_MAP(IMGUI_VULKAN_FUNC_LOAD)
+#undef IMGUI_VULKAN_FUNC_LOAD
+#else
+ IM_UNUSED(loader_func);
+ IM_UNUSED(user_data);
+#endif
+ g_FunctionsLoaded = true;
+ return true;
+}
+
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<decltype(func)>(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
+ IM_ASSERT(g_FunctionsLoaded && "Need to call ImGui_ImplVulkan_LoadFunctions() if IMGUI_IMPL_VULKAN_NO_PROTOTYPES or VK_NO_PROTOTYPES are set!");
// Setup backend capabilities flags
ImGuiIO& io = ImGui::GetIO();
@@ -1029,6 +1049,7 @@
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!");
IM_ASSERT(request_formats != NULL);
IM_ASSERT(request_formats_count > 0);
@@ -1073,6 +1094,7 @@
VkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkPresentModeKHR* request_modes, int request_modes_count)
{
+ IM_ASSERT(g_FunctionsLoaded && "Need to call ImGui_ImplVulkan_LoadFunctions() if IMGUI_IMPL_VULKAN_NO_PROTOTYPES or VK_NO_PROTOTYPES are set!");
IM_ASSERT(request_modes != NULL);
IM_ASSERT(request_modes_count > 0);
@@ -1323,6 +1345,7 @@
// Create or resize window
void ImGui_ImplVulkanH_CreateOrResizeWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int width, int height, uint32_t min_image_count)
{
+ IM_ASSERT(g_FunctionsLoaded && "Need to call ImGui_ImplVulkan_LoadFunctions() if IMGUI_IMPL_VULKAN_NO_PROTOTYPES or VK_NO_PROTOTYPES are set!");
(void)instance;
ImGui_ImplVulkanH_CreateWindowSwapChain(physical_device, device, wd, allocator, width, height, min_image_count);
ImGui_ImplVulkanH_CreateWindowCommandBuffers(physical_device, device, wd, queue_family, allocator);
diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h
index 9915872..9f9010e 100644
--- a/backends/imgui_impl_vulkan.h
+++ b/backends/imgui_impl_vulkan.h
@@ -23,15 +23,21 @@
#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!
+// [Configuration] in order to use a custom Vulkan function loader:
+// (1) You'll need to disable default Vulkan function prototypes.
+// We provide a '#define IMGUI_IMPL_VULKAN_NO_PROTOTYPES' convenience configuration flag.
+// In order to make sure this is visible from the imgui_impl_vulkan.cpp compilation unit:
+// - Add '#define IMGUI_IMPL_VULKAN_NO_PROTOTYPES' in your imconfig.h file
+// - Or as a compilation flag in your build system
+// - Or uncomment here (not recommended because you'd be modifying imgui sources!)
+// - Do not simply add it in a .cpp file!
+// (2) Call ImGui_ImplVulkan_LoadFunctions() before ImGui_ImplVulkan_Init() with your custom function.
+// If you have no idea what this is, leave it alone!
//#define IMGUI_IMPL_VULKAN_NO_PROTOTYPES
-#ifdef IMGUI_IMPL_VULKAN_NO_PROTOTYPES
-#define VK_NO_PROTOTYPES 1
+// Vulkan includes
+#if defined(IMGUI_IMPL_VULKAN_NO_PROTOTYPES) && !defined(VK_NO_PROTOTYPES)
+#define VK_NO_PROTOTYPES
#endif
#include <vulkan/vulkan.h>
@@ -39,27 +45,19 @@
// [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);
-#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
+ 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);
};
// Called by user code
@@ -71,6 +69,9 @@
IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontUploadObjects();
IMGUI_IMPL_API void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated)
+// Optional: load Vulkan functions with a custom function loader
+// This is only useful with IMGUI_IMPL_VULKAN_NO_PROTOTYPES / VK_NO_PROTOTYPES
+IMGUI_IMPL_API bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data = NULL);
//-------------------------------------------------------------------------
// Internal / Miscellaneous Vulkan Helpers
diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index b472c93..209f3be 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -55,6 +55,8 @@
Would lead to a buffer read overflow.
- Backends: Win32: Dynamically loading XInput DLL instead of linking with it, facilite compiling with
old WindowSDK versions or running on Windows 7. (#3646, #3645, #3248, #2716) [@Demonese]
+- Backends: Vulkan: Add support for custom Vulkan function loader and VK_NO_PROTOTYPES. (#3759, #3227) [@Hossein-Noroozpour]
+ User needs to call ImGui_ImplVulkan_LoadFunctions() with their custom loader prior to other functions.
- Backends: Metal: Fixed texture storage mode when building on Mac Catalyst. (#3748) [@Belinsky-L-V]
- Backends: OSX: Fixed mouse position not being reported when mouse buttons other than left one are down. (#3762) [@rokups]