From 66f4be2e13105d7ae636eff161ff1644275227bd Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 4 Apr 2019 22:27:29 +0200 Subject: [PATCH] Vulkan: Added extra parameter to ImGui_ImplVulkan_RenderDrawData(). User is in charge of owning/storing 1 ImGui_ImplVulkan_FrameRenderBuffers per in-flight rendering frame. Removed ImGui_ImplVulkan_SetFramesQueueSize. (#2461, #2348, #2378, #2097, #2071, #1677) --- docs/CHANGELOG.txt | 10 +- examples/example_glfw_vulkan/main.cpp | 7 +- examples/example_sdl_vulkan/main.cpp | 7 +- examples/imgui_impl_vulkan.cpp | 178 ++++++++++---------------- examples/imgui_impl_vulkan.h | 35 +++-- 5 files changed, 109 insertions(+), 128 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 6046f19b..0b3ed421 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -34,6 +34,13 @@ HOW TO UPDATE? ----------------------------------------------------------------------- Breaking Changes: +- Examples: Vulkan: Added extra parameter to ImGui_ImplVulkan_RenderDrawData(). Engine/app is + in charge of owning/storing 1 ImGui_ImplVulkan_FrameRenderBuffers per in-flight rendering frame. + (The demo helper ImGui_ImplVulkanH_WindowData structure carries them.) (#2461, #2348, #2378, #2097) +- Examples: Vulkan: Added FramesQueueSize field in ImGui_ImplVulkan_InitInfo, required during + initialization to specify the number of in-flight image required by the swap chain. + (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). (#2071, #1677) [@nathanvoglsam] + Other Changes: - InputText: Fixed selection background starts rendering one frame after the cursor movement @@ -49,9 +56,6 @@ Other Changes: - Examples: OpenGL3: Minor tweaks + not calling glBindBuffer more than necessary in the render loop. - Examples: Vulkan: Added missing support for 32-bit indices (#define ImDrawIdx unsigned int). - Examples: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like. -- Examples: Vulkan: Added FramesQueueSize field in ImGui_ImplVulkan_InitInfo, required during - initialization (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). (#2071) [@nathanvoglsam] - Added ImGui_ImplVulkan_SetFramesQueueSize() to override FramesQueueSize while running. - Examples: DirectX9: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects(). (#2454) - Examples: GLUT: Fixed existing FreeGLUT example to work with regular GLUT. (#2465) [@andrewwillmott] - Examples: GLUT: Renamed imgui_impl_freeglut.cpp/.h to imgui_impl_glut.cpp/.h. (#2465) [@andrewwillmott] diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp index f9f260d7..037d4791 100644 --- a/examples/example_glfw_vulkan/main.cpp +++ b/examples/example_glfw_vulkan/main.cpp @@ -115,6 +115,7 @@ static void SetupVulkan(const char** extensions, uint32_t extensions_count) uint32_t gpu_count; err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, NULL); check_vk_result(err); + IM_ASSERT(gpu_count > 0); VkPhysicalDevice* gpus = (VkPhysicalDevice*)malloc(sizeof(VkPhysicalDevice) * gpu_count); err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, gpus); @@ -219,7 +220,7 @@ static void SetupVulkanWindowData(ImGui_ImplVulkanH_WindowData* wd, VkSurfaceKHR //printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode); // Create SwapChain, RenderPass, Framebuffer, etc. - ImGui_ImplVulkanH_CreateWindowData(g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount); + ImGui_ImplVulkanH_CreateWindowData(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount); IM_ASSERT(wd->FramesQueueSize >= 2); } @@ -277,7 +278,7 @@ static void FrameRender(ImGui_ImplVulkanH_WindowData* wd) } // Record Imgui Draw Data and draw funcs into command buffer - ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), fd->CommandBuffer); + ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), fd->CommandBuffer, &fd->RenderBuffers); // Submit command buffer vkCmdEndRenderPass(fd->CommandBuffer); @@ -444,7 +445,7 @@ int main(int, char**) glfwPollEvents(); if (g_WantSwapChainRebuild) { - ImGui_ImplVulkanH_CreateWindowData(g_PhysicalDevice, g_Device, &g_WindowData, g_QueueFamily, g_Allocator, g_ResizeWidth, g_ResizeHeight, g_MinImageCount); + ImGui_ImplVulkanH_CreateWindowData(g_Instance, g_PhysicalDevice, g_Device, &g_WindowData, g_QueueFamily, g_Allocator, g_ResizeWidth, g_ResizeHeight, g_MinImageCount); ImGui_ImplVulkan_SetFramesQueueSize(g_WindowData.FramesQueueSize); g_WindowData.FrameIndex = 0; g_WantSwapChainRebuild = false; diff --git a/examples/example_sdl_vulkan/main.cpp b/examples/example_sdl_vulkan/main.cpp index 6c5684e8..e4721943 100644 --- a/examples/example_sdl_vulkan/main.cpp +++ b/examples/example_sdl_vulkan/main.cpp @@ -106,6 +106,7 @@ static void SetupVulkan(const char** extensions, uint32_t extensions_count) uint32_t gpu_count; err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, NULL); check_vk_result(err); + IM_ASSERT(gpu_count > 0); VkPhysicalDevice* gpus = (VkPhysicalDevice*)malloc(sizeof(VkPhysicalDevice) * gpu_count); err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, gpus); @@ -210,7 +211,7 @@ static void SetupVulkanWindowData(ImGui_ImplVulkanH_WindowData* wd, VkSurfaceKHR //printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode); // Create SwapChain, RenderPass, Framebuffer, etc. - ImGui_ImplVulkanH_CreateWindowData(g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount); + ImGui_ImplVulkanH_CreateWindowData(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount); IM_ASSERT(wd->FramesQueueSize >= 2); } @@ -268,7 +269,7 @@ static void FrameRender(ImGui_ImplVulkanH_WindowData* wd) } // Record Imgui Draw Data and draw funcs into command buffer - ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), fd->CommandBuffer); + ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), fd->CommandBuffer, &fd->RenderBuffers); // Submit command buffer vkCmdEndRenderPass(fd->CommandBuffer); @@ -441,7 +442,7 @@ int main(int, char**) if (g_WantSwapChainRebuild) { - ImGui_ImplVulkanH_CreateWindowData(g_PhysicalDevice, g_Device, &g_WindowData, g_QueueFamily, g_Allocator, g_WindowData.Width, g_WindowData.Height, g_MinImageCount); + ImGui_ImplVulkanH_CreateWindowData(g_Instance, g_PhysicalDevice, g_Device, &g_WindowData, g_QueueFamily, g_Allocator, g_WindowData.Width, g_WindowData.Height, g_MinImageCount); ImGui_ImplVulkan_SetFramesQueueSize(g_WindowData.FramesQueueSize); g_WindowData.FrameIndex = 0; g_WantSwapChainRebuild = false; diff --git a/examples/imgui_impl_vulkan.cpp b/examples/imgui_impl_vulkan.cpp index bdf1e661..61351679 100644 --- a/examples/imgui_impl_vulkan.cpp +++ b/examples/imgui_impl_vulkan.cpp @@ -20,7 +20,9 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2019-XX-XX: Vulkan: Added FramesQueueSize field in ImGui_ImplVulkan_InitInfo, required for initialization (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). Added ImGui_ImplVulkan_SetFramesQueueSize() to override FramesQueueSize while running. +// 2019-XX-XX: *BREAKING CHANGE*: Vulkan: Added extra parameter to ImGui_ImplVulkan_RenderDrawData(). Engine/app is in charge of owning/storing 1 ImGui_ImplVulkan_FrameRenderBuffers per in-flight rendering frame. (The demo helper ImGui_ImplVulkanH_WindowData structure carries them.) +// 2019-XX-XX: *BREAKING CHANGE*: Vulkan: Added FramesQueueSize field in ImGui_ImplVulkan_InitInfo, required for initialization (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). Added ImGui_ImplVulkan_SetFramesQueueSize() to override FramesQueueSize while running. +// 2019-XX-XX: Vulkan: Added VkInstance argument to ImGui_ImplVulkanH_CreateWindowData() optional helper. // 2019-04-04: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like. // 2019-04-01: Vulkan: Support for 32-bit index buffer (#define ImDrawIdx unsigned int). // 2019-02-16: Vulkan: Viewport and clipping rectangles correctly using draw_data->FramebufferScale to allow retina display. @@ -44,51 +46,37 @@ // Vulkan data static const VkAllocationCallbacks* g_Allocator = NULL; -static VkPhysicalDevice g_PhysicalDevice = VK_NULL_HANDLE; -static VkInstance g_Instance = VK_NULL_HANDLE; -static VkDevice g_Device = VK_NULL_HANDLE; -static uint32_t g_QueueFamily = (uint32_t)-1; -static VkQueue g_Queue = VK_NULL_HANDLE; -static VkPipelineCache g_PipelineCache = VK_NULL_HANDLE; -static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE; -static VkRenderPass g_RenderPass = VK_NULL_HANDLE; -static void (*g_CheckVkResultFn)(VkResult err) = NULL; +static VkPhysicalDevice g_PhysicalDevice = VK_NULL_HANDLE; +static VkInstance g_Instance = VK_NULL_HANDLE; +static VkDevice g_Device = VK_NULL_HANDLE; +static uint32_t g_QueueFamily = (uint32_t)-1; +static VkQueue g_Queue = VK_NULL_HANDLE; +static VkPipelineCache g_PipelineCache = VK_NULL_HANDLE; +static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE; +static int g_FramesQueueSize = 0; +static VkRenderPass g_RenderPass = VK_NULL_HANDLE; +static void (*g_CheckVkResultFn)(VkResult err) = NULL; -static VkDeviceSize g_BufferMemoryAlignment = 256; -static VkPipelineCreateFlags g_PipelineCreateFlags = 0; - -static VkDescriptorSetLayout g_DescriptorSetLayout = VK_NULL_HANDLE; -static VkPipelineLayout g_PipelineLayout = VK_NULL_HANDLE; -static VkDescriptorSet g_DescriptorSet = VK_NULL_HANDLE; -static VkPipeline g_Pipeline = VK_NULL_HANDLE; - -// Frame data -struct FrameDataForRender -{ - VkDeviceMemory VertexBufferMemory; - VkDeviceMemory IndexBufferMemory; - VkDeviceSize VertexBufferSize; - VkDeviceSize IndexBufferSize; - VkBuffer VertexBuffer; - VkBuffer IndexBuffer; - - FrameDataForRender() { VertexBufferMemory = IndexBufferMemory = VK_NULL_HANDLE; VertexBufferSize = IndexBufferSize = VK_NULL_HANDLE; VertexBuffer = IndexBuffer = VK_NULL_HANDLE; } -}; -static int g_FrameIndex = 0; -static ImVector g_FramesDataBuffers; +static VkDeviceSize g_BufferMemoryAlignment = 256; +static VkPipelineCreateFlags g_PipelineCreateFlags = 0x00; +static VkDescriptorSetLayout g_DescriptorSetLayout = VK_NULL_HANDLE; +static VkPipelineLayout g_PipelineLayout = VK_NULL_HANDLE; +static VkDescriptorSet g_DescriptorSet = VK_NULL_HANDLE; +static VkPipeline g_Pipeline = VK_NULL_HANDLE; // Font data -static VkSampler g_FontSampler = VK_NULL_HANDLE; -static VkDeviceMemory g_FontMemory = VK_NULL_HANDLE; -static VkImage g_FontImage = VK_NULL_HANDLE; -static VkImageView g_FontView = VK_NULL_HANDLE; -static VkDeviceMemory g_UploadBufferMemory = VK_NULL_HANDLE; -static VkBuffer g_UploadBuffer = VK_NULL_HANDLE; +static VkSampler g_FontSampler = VK_NULL_HANDLE; +static VkDeviceMemory g_FontMemory = VK_NULL_HANDLE; +static VkImage g_FontImage = VK_NULL_HANDLE; +static VkImageView g_FontView = VK_NULL_HANDLE; +static VkDeviceMemory g_UploadBufferMemory = VK_NULL_HANDLE; +static VkBuffer g_UploadBuffer = VK_NULL_HANDLE; // Forward Declarations void ImGui_ImplVulkanH_DestroyFrameData(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_FrameData* fd, const VkAllocationCallbacks* allocator); -void ImGui_ImplVulkanH_CreateWindowDataSwapChain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count); -void ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator); +void ImGui_ImplVulkanH_DestroyFrameRenderBuffers(VkInstance instance, VkDevice device, ImGui_ImplVulkan_FrameRenderBuffers* frb, const VkAllocationCallbacks* allocator); +void ImGui_ImplVulkanH_CreateWindowDataSwapChain(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count); +void ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator); //----------------------------------------------------------------------------- // SHADERS @@ -253,7 +241,7 @@ static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory // Render function // (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop) -void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer) +void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, ImGui_ImplVulkan_FrameRenderBuffers* fd) { // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); @@ -262,8 +250,6 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm return; VkResult err; - FrameDataForRender* fd = &g_FramesDataBuffers[g_FrameIndex]; - g_FrameIndex = (g_FrameIndex + 1) % g_FramesDataBuffers.Size; // Create the Vertex and Index buffers: size_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert); @@ -747,22 +733,8 @@ void ImGui_ImplVulkan_DestroyFontUploadObjects() } } -static void ImGui_ImplVulkan_InvalidateFrameDeviceObjects() -{ - for (int i = 0; i < g_FramesDataBuffers.Size; i++) - { - FrameDataForRender* fd = &g_FramesDataBuffers[i]; - if (fd->VertexBuffer) { vkDestroyBuffer(g_Device, fd->VertexBuffer, g_Allocator); fd->VertexBuffer = VK_NULL_HANDLE; } - if (fd->VertexBufferMemory) { vkFreeMemory (g_Device, fd->VertexBufferMemory, g_Allocator); fd->VertexBufferMemory = VK_NULL_HANDLE; } - if (fd->IndexBuffer) { vkDestroyBuffer(g_Device, fd->IndexBuffer, g_Allocator); fd->IndexBuffer = VK_NULL_HANDLE; } - if (fd->IndexBufferMemory) { vkFreeMemory (g_Device, fd->IndexBufferMemory, g_Allocator); fd->IndexBufferMemory = VK_NULL_HANDLE; } - } - g_FramesDataBuffers.clear(); -} - void ImGui_ImplVulkan_DestroyDeviceObjects() { - ImGui_ImplVulkan_InvalidateFrameDeviceObjects(); ImGui_ImplVulkan_DestroyFontUploadObjects(); if (g_FontView) { vkDestroyImageView(g_Device, g_FontView, g_Allocator); g_FontView = VK_NULL_HANDLE; } @@ -795,13 +767,10 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass rend g_RenderPass = render_pass; g_PipelineCache = info->PipelineCache; g_DescriptorPool = info->DescriptorPool; + g_FramesQueueSize = info->FramesQueueSize; g_Allocator = info->Allocator; g_CheckVkResultFn = info->CheckVkResultFn; - g_FramesDataBuffers.reserve(info->FramesQueueSize); - for (int i = 0; i < info->FramesQueueSize; i++) - g_FramesDataBuffers.push_back(FrameDataForRender()); - ImGui_ImplVulkan_CreateDeviceObjects(); return true; @@ -818,14 +787,7 @@ void ImGui_ImplVulkan_NewFrame() void ImGui_ImplVulkan_SetFramesQueueSize(int frames_queue_size) { - if (frames_queue_size == g_FramesDataBuffers.Size) - return; - ImGui_ImplVulkan_InvalidateFrameDeviceObjects(); - - g_FrameIndex = 0; - g_FramesDataBuffers.reserve(frames_queue_size); - for (int i = 0; i < frames_queue_size; i++) - g_FramesDataBuffers.push_back(FrameDataForRender()); + (void)frames_queue_size; } @@ -840,39 +802,13 @@ void ImGui_ImplVulkan_SetFramesQueueSize(int frames_queue_size) // Generally we avoid exposing any kind of superfluous high-level helpers in the bindings, // but it is too much code to duplicate everywhere so we exceptionally expose them. // -// Your application/engine will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.). +// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.). // You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work. // (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions) //------------------------------------------------------------------------- #include // malloc -ImGui_ImplVulkanH_FrameData::ImGui_ImplVulkanH_FrameData() -{ - CommandPool = VK_NULL_HANDLE; - CommandBuffer = VK_NULL_HANDLE; - Fence = VK_NULL_HANDLE; - ImageAcquiredSemaphore = VK_NULL_HANDLE; - RenderCompleteSemaphore = VK_NULL_HANDLE; - Backbuffer = VK_NULL_HANDLE; - BackbufferView = VK_NULL_HANDLE; - Framebuffer = VK_NULL_HANDLE; -} - -ImGui_ImplVulkanH_WindowData::ImGui_ImplVulkanH_WindowData() -{ - Width = Height = 0; - Swapchain = VK_NULL_HANDLE; - Surface = VK_NULL_HANDLE; - memset(&SurfaceFormat, 0, sizeof(SurfaceFormat)); - PresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR; - RenderPass = VK_NULL_HANDLE; - ClearEnable = true; - memset(&ClearValue, 0, sizeof(ClearValue)); - FramesQueueSize = 0; - FrameIndex = 0; -} - VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space) { IM_ASSERT(request_formats != NULL); @@ -939,15 +875,16 @@ VkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_d return VK_PRESENT_MODE_FIFO_KHR; // Always available } -void ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator) +void ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator) { - IM_ASSERT(physical_device != VK_NULL_HANDLE && device != VK_NULL_HANDLE); + IM_ASSERT(instance != VK_NULL_HANDLE && physical_device != VK_NULL_HANDLE && device != VK_NULL_HANDLE); + (void)instance; (void)physical_device; (void)allocator; // Create Command Buffers VkResult err; - for (int i = 0; i < wd->Frames.Size; i++) + for (uint32_t i = 0; i < wd->FramesQueueSize; i++) { ImGui_ImplVulkanH_FrameData* fd = &wd->Frames[i]; { @@ -985,6 +922,7 @@ void ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(VkPhysicalDevice physical_ } } +// MinImageCount will usually turn into FramesQueueSize int ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode) { if (present_mode == VK_PRESENT_MODE_MAILBOX_KHR) @@ -997,17 +935,20 @@ int ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_m return 1; } -void ImGui_ImplVulkanH_CreateWindowDataSwapChain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count) +// Also destroy old swap chain and in-flight frames data, if any. +void ImGui_ImplVulkanH_CreateWindowDataSwapChain(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count) { VkResult err; VkSwapchainKHR old_swapchain = wd->Swapchain; err = vkDeviceWaitIdle(device); check_vk_result(err); + // We don't use ImGui_ImplVulkanH_DestroyWindowData() because we want to preserve the old swapchain to create the new one. // Destroy old Framebuffer for (uint32_t i = 0; i < wd->FramesQueueSize; i++) - ImGui_ImplVulkanH_DestroyFrameData(g_Instance, device, &wd->Frames[i], allocator); - wd->Frames.clear(); + ImGui_ImplVulkanH_DestroyFrameData(instance, device, &wd->Frames[i], allocator); + delete[] wd->Frames; + wd->Frames = NULL; wd->FramesQueueSize = 0; if (wd->RenderPass) vkDestroyRenderPass(device, wd->RenderPass, allocator); @@ -1059,12 +1000,11 @@ void ImGui_ImplVulkanH_CreateWindowDataSwapChain(VkPhysicalDevice physical_devic err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->FramesQueueSize, backbuffers); check_vk_result(err); - wd->Frames.reserve((int)wd->FramesQueueSize); - for (int i = 0; i < (int)wd->FramesQueueSize; i++) - { - wd->Frames.push_back(ImGui_ImplVulkanH_FrameData()); + IM_ASSERT(wd->Frames == NULL); + wd->Frames = new ImGui_ImplVulkanH_FrameData[wd->FramesQueueSize]; + memset(wd->Frames, 0, sizeof(wd->Frames[0]) * wd->FramesQueueSize); + for (uint32_t i = 0; i < wd->FramesQueueSize; i++) wd->Frames[i].Backbuffer = backbuffers[i]; - } } if (old_swapchain) vkDestroySwapchainKHR(device, old_swapchain, allocator); @@ -1148,10 +1088,10 @@ void ImGui_ImplVulkanH_CreateWindowDataSwapChain(VkPhysicalDevice physical_devic } } -void ImGui_ImplVulkanH_CreateWindowData(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int width, int height, uint32_t min_image_count) +void ImGui_ImplVulkanH_CreateWindowData(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int width, int height, uint32_t min_image_count) { - ImGui_ImplVulkanH_CreateWindowDataSwapChain(physical_device, device, wd, allocator, width, height, min_image_count); - ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(physical_device, device, wd, queue_family, allocator); + ImGui_ImplVulkanH_CreateWindowDataSwapChain(instance, physical_device, device, wd, allocator, width, height, min_image_count); + ImGui_ImplVulkanH_CreateWindowDataCommandBuffers(instance, physical_device, device, wd, queue_family, allocator); } void ImGui_ImplVulkanH_DestroyWindowData(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator) @@ -1159,11 +1099,14 @@ void ImGui_ImplVulkanH_DestroyWindowData(VkInstance instance, VkDevice device, I vkDeviceWaitIdle(device); // FIXME: We could wait on the Queue if we had the queue in wd-> (otherwise VulkanH functions can't use globals) //vkQueueWaitIdle(g_Queue); - for (int i = 0; i < wd->Frames.Size; i++) + for (uint32_t i = 0; i < wd->FramesQueueSize; i++) ImGui_ImplVulkanH_DestroyFrameData(instance, device, &wd->Frames[i], allocator); + delete[] wd->Frames; + wd->Frames = NULL; vkDestroyRenderPass(device, wd->RenderPass, allocator); vkDestroySwapchainKHR(device, wd->Swapchain, allocator); vkDestroySurfaceKHR(instance, wd->Surface, allocator); + *wd = ImGui_ImplVulkanH_WindowData(); } @@ -1182,4 +1125,17 @@ void ImGui_ImplVulkanH_DestroyFrameData(VkInstance instance, VkDevice device, Im vkDestroyImageView(device, fd->BackbufferView, allocator); vkDestroyFramebuffer(device, fd->Framebuffer, allocator); + + ImGui_ImplVulkanH_DestroyFrameRenderBuffers(instance, device, &fd->RenderBuffers, allocator); +} + +void ImGui_ImplVulkanH_DestroyFrameRenderBuffers(VkInstance instance, VkDevice device, ImGui_ImplVulkan_FrameRenderBuffers* frb, const VkAllocationCallbacks* allocator) +{ + (void)instance; + if (frb->VertexBuffer) { vkDestroyBuffer(device, frb->VertexBuffer, allocator); frb->VertexBuffer = VK_NULL_HANDLE; } + if (frb->VertexBufferMemory) { vkFreeMemory (device, frb->VertexBufferMemory, allocator); frb->VertexBufferMemory = VK_NULL_HANDLE; } + if (frb->IndexBuffer) { vkDestroyBuffer(device, frb->IndexBuffer, allocator); frb->IndexBuffer = VK_NULL_HANDLE; } + if (frb->IndexBufferMemory) { vkFreeMemory (device, frb->IndexBufferMemory, allocator); frb->IndexBufferMemory = VK_NULL_HANDLE; } + frb->VertexBufferSize = 0; + frb->IndexBufferSize = 0; } diff --git a/examples/imgui_impl_vulkan.h b/examples/imgui_impl_vulkan.h index 6306f30e..334910f6 100644 --- a/examples/imgui_impl_vulkan.h +++ b/examples/imgui_impl_vulkan.h @@ -38,12 +38,26 @@ struct ImGui_ImplVulkan_InitInfo void (*CheckVkResultFn)(VkResult err); }; +// Reusable buffers used for rendering by current in-flight frame, for ImGui_ImplVulkan_RenderDrawData() +// [Please zero-clear before use!] +// In the examples we store those in the helper ImGui_ImplVulkanH_FrameData structure, however as your own engine/app likely won't use the ImGui_Impl_VulkanH_XXXX helpers, +// you are expected to hold on as many ImGui_ImplVulkan_FrameRenderBuffers structures on your side as you have in-flight frames (== init_info.FramesQueueSize) +struct ImGui_ImplVulkan_FrameRenderBuffers +{ + VkDeviceMemory VertexBufferMemory; + VkDeviceMemory IndexBufferMemory; + VkDeviceSize VertexBufferSize; + VkDeviceSize IndexBufferSize; + VkBuffer VertexBuffer; + VkBuffer IndexBuffer; +}; + // Called by user code IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass); IMGUI_IMPL_API void ImGui_ImplVulkan_Shutdown(); IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame(); IMGUI_IMPL_API void ImGui_ImplVulkan_SetFramesQueueSize(int frames_queue_size); // To override FramesQueueSize after initialization -IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer); +IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, ImGui_ImplVulkan_FrameRenderBuffers* buffers); IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer); IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontUploadObjects(); @@ -71,7 +85,7 @@ IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyDeviceObjects(); struct ImGui_ImplVulkanH_FrameData; struct ImGui_ImplVulkanH_WindowData; -IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateWindowData(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count); +IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateWindowData(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count); IMGUI_IMPL_API void ImGui_ImplVulkanH_DestroyWindowData(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_WindowData* wd, const VkAllocationCallbacks* allocator); IMGUI_IMPL_API VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space); IMGUI_IMPL_API VkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkPresentModeKHR* request_modes, int request_modes_count); @@ -79,6 +93,7 @@ IMGUI_IMPL_API int ImGui_ImplVulkanH_GetMinImageCountFromPresen // Helper structure to hold the data needed by one rendering frame // (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own app.) +// [Please zero-clear before use!] struct ImGui_ImplVulkanH_FrameData { VkCommandPool CommandPool; @@ -89,8 +104,7 @@ struct ImGui_ImplVulkanH_FrameData VkImage Backbuffer; VkImageView BackbufferView; VkFramebuffer Framebuffer; - - IMGUI_IMPL_API ImGui_ImplVulkanH_FrameData(); + ImGui_ImplVulkan_FrameRenderBuffers RenderBuffers; }; // Helper structure to hold the data needed by one rendering context into one OS window @@ -106,10 +120,15 @@ struct ImGui_ImplVulkanH_WindowData VkRenderPass RenderPass; bool ClearEnable; VkClearValue ClearValue; - uint32_t FramesQueueSize; // Number of simultaneous in-flight frames (returned by vkGetSwapchainImagesKHR) - uint32_t FrameIndex; // Current frame being rendered to (0 <= FrameIndex < FrameInFlightCount) - ImVector Frames; + uint32_t FrameIndex; // Current frame being rendered to (0 <= FrameIndex < FrameInFlightCount) + uint32_t FramesQueueSize; // Number of simultaneous in-flight frames (returned by vkGetSwapchainImagesKHR, usually derived from min_image_count) + ImGui_ImplVulkanH_FrameData* Frames; - IMGUI_IMPL_API ImGui_ImplVulkanH_WindowData(); + ImGui_ImplVulkanH_WindowData() + { + memset(this, 0, sizeof(*this)); + PresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR; + ClearEnable = true; + } };