Merge branch 'vulkan_fix_master' into vulkan_fix_docking (WARNING: as is the validation layer will error on same vertex/index buffer being used for all frames)

# Conflicts:
#	examples/imgui_impl_vulkan.cpp
#	examples/imgui_impl_vulkan.h
This commit is contained in:
omar 2019-04-05 18:27:15 +02:00
commit e70f866ed2
5 changed files with 139 additions and 107 deletions

View File

@ -98,16 +98,12 @@ Other changes:
----------------------------------------------------------------------- -----------------------------------------------------------------------
Breaking Changes: Breaking Changes:
- Examples: Vulkan: Added extra parameter to ImGui_ImplVulkan_RenderDrawData(). Engine/app is - Examples: Vulkan: Added MinImageCount/ImageCount fields in ImGui_ImplVulkan_InitInfo, required
in charge of owning/storing 1 ImGui_ImplVulkan_FrameRenderBuffers per in-flight rendering frame. during initialization to specify the number of in-flight image requested by swap chains.
(The demo helper ImGui_ImplVulkanH_Window structure carries them.) (#2461, #2348, #2378, #2097)
- Examples: Vulkan: Added MinImageCount field in ImGui_ImplVulkan_InitInfo, required during
initialization to specify the number of in-flight image requested by swap chains.
(was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). (#2071, #1677) [@nathanvoglsam] (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). (#2071, #1677) [@nathanvoglsam]
- Examples: Vulkan: Tidying up the demo/internals helpers (most engine/app should not rely - Examples: Vulkan: Tidying up the demo/internals helpers (most engine/app should not rely
on them but it is possible you have!). on them but it is possible you have!).
Other Changes: Other Changes:
- InputText: Fixed selection background starts rendering one frame after the cursor movement - InputText: Fixed selection background starts rendering one frame after the cursor movement
when first transitioning from no-selection to has-selection. (Bug in 1.69) (#2436) [@Nazg-Gul] when first transitioning from no-selection to has-selection. (Bug in 1.69) (#2436) [@Nazg-Gul]
@ -120,8 +116,10 @@ Other Changes:
- Examples: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized - Examples: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized
GL function loaders early, and help users understand what they are missing. (#2421) GL function loaders early, and help users understand what they are missing. (#2421)
- Examples: OpenGL3: Minor tweaks + not calling glBindBuffer more than necessary in the render loop. - Examples: OpenGL3: Minor tweaks + not calling glBindBuffer more than necessary in the render loop.
- Examples: Vulkan: Fixed in-flight buffers issues when using multi-viewports. (#2461, #2348, #2378, #2097)
- Examples: Vulkan: Added missing support for 32-bit indices (#define ImDrawIdx unsigned int). - 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: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like.
- Examples: Vulkan: Added ImGui_ImplVulkan_SetMinImageCount() to change min image count at runtime. (#2071) [@nathanvoglsam]
- Examples: DirectX9: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects(). (#2454) - 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: 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] - Examples: GLUT: Renamed imgui_impl_freeglut.cpp/.h to imgui_impl_glut.cpp/.h. (#2465) [@andrewwillmott]

View File

@ -287,7 +287,7 @@ static void FrameRender(ImGui_ImplVulkanH_Window* wd)
} }
// Record Imgui Draw Data and draw funcs into command buffer // Record Imgui Draw Data and draw funcs into command buffer
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), fd->CommandBuffer, &fd->RenderBuffers); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), fd->CommandBuffer);
// Submit command buffer // Submit command buffer
vkCmdEndRenderPass(fd->CommandBuffer); vkCmdEndRenderPass(fd->CommandBuffer);
@ -403,6 +403,7 @@ int main(int, char**)
init_info.DescriptorPool = g_DescriptorPool; init_info.DescriptorPool = g_DescriptorPool;
init_info.Allocator = g_Allocator; init_info.Allocator = g_Allocator;
init_info.MinImageCount = g_MinImageCount; init_info.MinImageCount = g_MinImageCount;
init_info.ImageCount = wd->ImageCount;
init_info.CheckVkResultFn = check_vk_result; init_info.CheckVkResultFn = check_vk_result;
ImGui_ImplVulkan_Init(&init_info, wd->RenderPass); ImGui_ImplVulkan_Init(&init_info, wd->RenderPass);
@ -468,8 +469,8 @@ int main(int, char**)
if (g_SwapChainRebuild) if (g_SwapChainRebuild)
{ {
g_SwapChainRebuild = false; g_SwapChainRebuild = false;
ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
ImGui_ImplVulkanH_CreateWindow(g_Instance, g_PhysicalDevice, g_Device, &g_WindowData, g_QueueFamily, g_Allocator, g_SwapChainResizeWidth, g_SwapChainResizeHeight, g_MinImageCount); ImGui_ImplVulkanH_CreateWindow(g_Instance, g_PhysicalDevice, g_Device, &g_WindowData, g_QueueFamily, g_Allocator, g_SwapChainResizeWidth, g_SwapChainResizeHeight, g_MinImageCount);
ImGui_ImplVulkan_SetSwapChainMinImageCount(g_MinImageCount);
g_WindowData.FrameIndex = 0; g_WindowData.FrameIndex = 0;
} }

View File

@ -279,7 +279,7 @@ static void FrameRender(ImGui_ImplVulkanH_Window* wd)
} }
// Record Imgui Draw Data and draw funcs into command buffer // Record Imgui Draw Data and draw funcs into command buffer
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), fd->CommandBuffer, &fd->RenderBuffers); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), fd->CommandBuffer);
// Submit command buffer // Submit command buffer
vkCmdEndRenderPass(fd->CommandBuffer); vkCmdEndRenderPass(fd->CommandBuffer);
@ -387,6 +387,7 @@ int main(int, char**)
init_info.DescriptorPool = g_DescriptorPool; init_info.DescriptorPool = g_DescriptorPool;
init_info.Allocator = g_Allocator; init_info.Allocator = g_Allocator;
init_info.MinImageCount = g_MinImageCount; init_info.MinImageCount = g_MinImageCount;
init_info.ImageCount = wd->ImageCount;
init_info.CheckVkResultFn = check_vk_result; init_info.CheckVkResultFn = check_vk_result;
ImGui_ImplVulkan_Init(&init_info, wd->RenderPass); ImGui_ImplVulkan_Init(&init_info, wd->RenderPass);
@ -465,8 +466,8 @@ int main(int, char**)
if (g_SwapChainRebuild) if (g_SwapChainRebuild)
{ {
g_SwapChainRebuild = false; g_SwapChainRebuild = false;
ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
ImGui_ImplVulkanH_CreateWindow(g_Instance, g_PhysicalDevice, g_Device, &g_WindowData, g_QueueFamily, g_Allocator, g_SwapChainResizeWidth, g_SwapChainResizeHeight, g_MinImageCount); ImGui_ImplVulkanH_CreateWindow(g_Instance, g_PhysicalDevice, g_Device, &g_WindowData, g_QueueFamily, g_Allocator, g_SwapChainResizeWidth, g_SwapChainResizeHeight, g_MinImageCount);
ImGui_ImplVulkan_SetSwapChainMinImageCount(g_MinImageCount);
g_WindowData.FrameIndex = 0; g_WindowData.FrameIndex = 0;
} }

View File

@ -21,8 +21,7 @@
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details) // (minor and older changes stripped away, please see git history for details)
// 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_Window structure carries them.) // 2019-XX-XX: *BREAKING CHANGE*: Vulkan: Added ImageCount/MinImageCount fields in ImGui_ImplVulkan_InitInfo, required for initialization (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). Added ImGui_ImplVulkan_SetMinImageCount().
// 2019-XX-XX: *BREAKING CHANGE*: Vulkan: Added MinImageCount field in ImGui_ImplVulkan_InitInfo, required for initialization (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). Added ImGui_ImplVulkan_SetSwapChainMinImageCount().
// 2019-XX-XX: Vulkan: Added VkInstance argument to ImGui_ImplVulkanH_CreateWindow() optional helper. // 2019-XX-XX: Vulkan: Added VkInstance argument to ImGui_ImplVulkanH_CreateWindow() optional helper.
// 2019-04-04: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like. // 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-04-01: Vulkan: Support for 32-bit index buffer (#define ImDrawIdx unsigned int).
@ -45,6 +44,27 @@
#include "imgui_impl_vulkan.h" #include "imgui_impl_vulkan.h"
#include <stdio.h> #include <stdio.h>
// Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplVulkan_RenderDrawData()
// [Please zero-clear before use!]
struct ImGui_ImplVulkanH_FrameRenderBuffers
{
VkDeviceMemory VertexBufferMemory;
VkDeviceMemory IndexBufferMemory;
VkDeviceSize VertexBufferSize;
VkDeviceSize IndexBufferSize;
VkBuffer VertexBuffer;
VkBuffer IndexBuffer;
};
// Each viewport will hold 1 ImGui_ImplVulkanH_WindowRenderBuffers
// [Please zero-clear before use!]
struct ImGui_ImplVulkanH_WindowRenderBuffers
{
uint32_t Index;
uint32_t Count;
ImGui_ImplVulkanH_FrameRenderBuffers* FrameRenderBuffers;
};
// Vulkan data // Vulkan data
static ImGui_ImplVulkan_InitInfo g_VulkanInitInfo = {}; static ImGui_ImplVulkan_InitInfo g_VulkanInitInfo = {};
static VkRenderPass g_RenderPass = VK_NULL_HANDLE; static VkRenderPass g_RenderPass = VK_NULL_HANDLE;
@ -63,11 +83,16 @@ static VkImageView g_FontView = VK_NULL_HANDLE;
static VkDeviceMemory g_UploadBufferMemory = VK_NULL_HANDLE; static VkDeviceMemory g_UploadBufferMemory = VK_NULL_HANDLE;
static VkBuffer g_UploadBuffer = VK_NULL_HANDLE; static VkBuffer g_UploadBuffer = VK_NULL_HANDLE;
// Render buffers
static ImGui_ImplVulkanH_WindowRenderBuffers g_MainWindowRenderBuffers;
// Forward Declarations // Forward Declarations
void ImGui_ImplVulkanH_DestroyFrame(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator); void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator);
void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator); void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator);
void ImGui_ImplVulkanH_CreateWindowSwapChain(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count); void ImGui_ImplVulkanH_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkanH_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator);
void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator); void ImGui_ImplVulkanH_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkanH_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator);
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);
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// SHADERS // SHADERS
@ -239,7 +264,7 @@ static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory
// Render function // 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) // (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, ImGui_ImplVulkan_FrameRenderBuffers* fd) void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer)
{ {
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) // 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); int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
@ -248,23 +273,37 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
return; return;
ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo; ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
// Allocate array to store enough vertex/index buffers
ImGui_ImplVulkanH_WindowRenderBuffers* wrb = &g_MainWindowRenderBuffers;
if (wrb->FrameRenderBuffers == NULL)
{
wrb->Index = 0;
wrb->Count = v->ImageCount;
wrb->FrameRenderBuffers = new ImGui_ImplVulkanH_FrameRenderBuffers[wrb->Count];
memset(wrb->FrameRenderBuffers, 0, sizeof(ImGui_ImplVulkanH_FrameRenderBuffers) * wrb->Count);
}
IM_ASSERT(wrb->Count == v->ImageCount);
wrb->Index = (wrb->Index + 1) % wrb->Count;
ImGui_ImplVulkanH_FrameRenderBuffers* rb = &wrb->FrameRenderBuffers[wrb->Index];
VkResult err; VkResult err;
// Create the Vertex and Index buffers: // Create or resize the vertex/index buffers
size_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert); size_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert);
size_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx); size_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx);
if (fd->VertexBuffer == VK_NULL_HANDLE || fd->VertexBufferSize < vertex_size) if (rb->VertexBuffer == VK_NULL_HANDLE || rb->VertexBufferSize < vertex_size)
CreateOrResizeBuffer(fd->VertexBuffer, fd->VertexBufferMemory, fd->VertexBufferSize, vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); CreateOrResizeBuffer(rb->VertexBuffer, rb->VertexBufferMemory, rb->VertexBufferSize, vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
if (fd->IndexBuffer == VK_NULL_HANDLE || fd->IndexBufferSize < index_size) if (rb->IndexBuffer == VK_NULL_HANDLE || rb->IndexBufferSize < index_size)
CreateOrResizeBuffer(fd->IndexBuffer, fd->IndexBufferMemory, fd->IndexBufferSize, index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT); CreateOrResizeBuffer(rb->IndexBuffer, rb->IndexBufferMemory, rb->IndexBufferSize, index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
// Upload vertex/index data into a single contiguous GPU buffer // Upload vertex/index data into a single contiguous GPU buffer
{ {
ImDrawVert* vtx_dst = NULL; ImDrawVert* vtx_dst = NULL;
ImDrawIdx* idx_dst = NULL; ImDrawIdx* idx_dst = NULL;
err = vkMapMemory(v->Device, fd->VertexBufferMemory, 0, vertex_size, 0, (void**)(&vtx_dst)); err = vkMapMemory(v->Device, rb->VertexBufferMemory, 0, vertex_size, 0, (void**)(&vtx_dst));
check_vk_result(err); check_vk_result(err);
err = vkMapMemory(v->Device, fd->IndexBufferMemory, 0, index_size, 0, (void**)(&idx_dst)); err = vkMapMemory(v->Device, rb->IndexBufferMemory, 0, index_size, 0, (void**)(&idx_dst));
check_vk_result(err); check_vk_result(err);
for (int n = 0; n < draw_data->CmdListsCount; n++) for (int n = 0; n < draw_data->CmdListsCount; n++)
{ {
@ -276,15 +315,15 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
} }
VkMappedMemoryRange range[2] = {}; VkMappedMemoryRange range[2] = {};
range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
range[0].memory = fd->VertexBufferMemory; range[0].memory = rb->VertexBufferMemory;
range[0].size = VK_WHOLE_SIZE; range[0].size = VK_WHOLE_SIZE;
range[1].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; range[1].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
range[1].memory = fd->IndexBufferMemory; range[1].memory = rb->IndexBufferMemory;
range[1].size = VK_WHOLE_SIZE; range[1].size = VK_WHOLE_SIZE;
err = vkFlushMappedMemoryRanges(v->Device, 2, range); err = vkFlushMappedMemoryRanges(v->Device, 2, range);
check_vk_result(err); check_vk_result(err);
vkUnmapMemory(v->Device, fd->VertexBufferMemory); vkUnmapMemory(v->Device, rb->VertexBufferMemory);
vkUnmapMemory(v->Device, fd->IndexBufferMemory); vkUnmapMemory(v->Device, rb->IndexBufferMemory);
} }
// Bind pipeline and descriptor sets: // Bind pipeline and descriptor sets:
@ -296,10 +335,10 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
// Bind Vertex And Index Buffer: // Bind Vertex And Index Buffer:
{ {
VkBuffer vertex_buffers[1] = { fd->VertexBuffer }; VkBuffer vertex_buffers[1] = { rb->VertexBuffer };
VkDeviceSize vertex_offset[1] = { 0 }; VkDeviceSize vertex_offset[1] = { 0 };
vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, vertex_offset); vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, vertex_offset);
vkCmdBindIndexBuffer(command_buffer, fd->IndexBuffer, 0, sizeof(ImDrawIdx) == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32); vkCmdBindIndexBuffer(command_buffer, rb->IndexBuffer, 0, sizeof(ImDrawIdx) == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32);
} }
// Setup viewport: // Setup viewport:
@ -738,8 +777,9 @@ void ImGui_ImplVulkan_DestroyFontUploadObjects()
void ImGui_ImplVulkan_DestroyDeviceObjects() void ImGui_ImplVulkan_DestroyDeviceObjects()
{ {
ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo; ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
ImGui_ImplVulkanH_DestroyWindowRenderBuffers(v->Device, &g_MainWindowRenderBuffers, v->Allocator);
ImGui_ImplVulkan_DestroyFontUploadObjects(); ImGui_ImplVulkan_DestroyFontUploadObjects();
if (g_FontView) { vkDestroyImageView(v->Device, g_FontView, v->Allocator); g_FontView = VK_NULL_HANDLE; } if (g_FontView) { vkDestroyImageView(v->Device, g_FontView, v->Allocator); g_FontView = VK_NULL_HANDLE; }
if (g_FontImage) { vkDestroyImage(v->Device, g_FontImage, v->Allocator); g_FontImage = VK_NULL_HANDLE; } if (g_FontImage) { vkDestroyImage(v->Device, g_FontImage, v->Allocator); g_FontImage = VK_NULL_HANDLE; }
if (g_FontMemory) { vkFreeMemory(v->Device, g_FontMemory, v->Allocator); g_FontMemory = VK_NULL_HANDLE; } if (g_FontMemory) { vkFreeMemory(v->Device, g_FontMemory, v->Allocator); g_FontMemory = VK_NULL_HANDLE; }
@ -762,6 +802,7 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass rend
IM_ASSERT(info->Queue != VK_NULL_HANDLE); IM_ASSERT(info->Queue != VK_NULL_HANDLE);
IM_ASSERT(info->DescriptorPool != VK_NULL_HANDLE); IM_ASSERT(info->DescriptorPool != VK_NULL_HANDLE);
IM_ASSERT(info->MinImageCount >= 2); IM_ASSERT(info->MinImageCount >= 2);
IM_ASSERT(info->ImageCount >= info->MinImageCount);
IM_ASSERT(render_pass != VK_NULL_HANDLE); IM_ASSERT(render_pass != VK_NULL_HANDLE);
g_VulkanInitInfo = *info; g_VulkanInitInfo = *info;
@ -784,28 +825,19 @@ void ImGui_ImplVulkan_NewFrame()
{ {
} }
void ImGui_ImplVulkan_SetSwapChainMinImageCount(int min_image_count) void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count)
{ {
IM_ASSERT(min_image_count >= 2); IM_ASSERT(min_image_count >= 2);
if (g_VulkanInitInfo.MinImageCount == min_image_count) if (g_VulkanInitInfo.MinImageCount == min_image_count)
return; return;
IM_ASSERT(0); // FIXME-VIEWPORT: Need to recreate all swap chains? IM_ASSERT(0); // FIXME-VIEWPORT: Need to recreate all swap chains?
ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;
VkResult err = vkDeviceWaitIdle(v->Device);
check_vk_result(err);
ImGui_ImplVulkanH_DestroyWindowRenderBuffers(v->Device, &g_MainWindowRenderBuffers, v->Allocator);
g_VulkanInitInfo.MinImageCount = min_image_count; g_VulkanInitInfo.MinImageCount = min_image_count;
} }
// This is a public function because we require the user to pass a ImGui_ImplVulkan_FrameRenderBuffers
// structure to ImGui_ImplVulkan_RenderDrawData.
void ImGui_ImplVulkan_DestroyFrameRenderBuffers(VkInstance instance, VkDevice device, ImGui_ImplVulkan_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator)
{
(void)instance;
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; }
if (buffers->IndexBufferMemory) { vkFreeMemory (device, buffers->IndexBufferMemory, allocator); buffers->IndexBufferMemory = VK_NULL_HANDLE; }
buffers->VertexBufferSize = 0;
buffers->IndexBufferSize = 0;
}
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
// Internal / Miscellaneous Vulkan Helpers // Internal / Miscellaneous Vulkan Helpers
@ -891,16 +923,15 @@ VkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_d
return VK_PRESENT_MODE_FIFO_KHR; // Always available return VK_PRESENT_MODE_FIFO_KHR; // Always available
} }
void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator) void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator)
{ {
IM_ASSERT(instance != VK_NULL_HANDLE && physical_device != VK_NULL_HANDLE && device != VK_NULL_HANDLE); IM_ASSERT(physical_device != VK_NULL_HANDLE && device != VK_NULL_HANDLE);
(void)instance;
(void)physical_device; (void)physical_device;
(void)allocator; (void)allocator;
// Create Command Buffers // Create Command Buffers
VkResult err; VkResult err;
for (uint32_t i = 0; i < wd->FramesQueueSize; i++) for (uint32_t i = 0; i < wd->ImageCount; i++)
{ {
ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i]; ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[i]; ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[i];
@ -952,7 +983,7 @@ int ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_m
} }
// Also destroy old swap chain and in-flight frames data, if any. // Also destroy old swap chain and in-flight frames data, if any.
void ImGui_ImplVulkanH_CreateWindowSwapChain(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count) 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)
{ {
VkResult err; VkResult err;
VkSwapchainKHR old_swapchain = wd->Swapchain; VkSwapchainKHR old_swapchain = wd->Swapchain;
@ -961,16 +992,16 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkInstance instance, VkPhysicalDevi
// We don't use ImGui_ImplVulkanH_DestroyWindow() because we want to preserve the old swapchain to create the new one. // We don't use ImGui_ImplVulkanH_DestroyWindow() because we want to preserve the old swapchain to create the new one.
// Destroy old Framebuffer // Destroy old Framebuffer
for (uint32_t i = 0; i < wd->FramesQueueSize; i++) for (uint32_t i = 0; i < wd->ImageCount; i++)
{ {
ImGui_ImplVulkanH_DestroyFrame(instance, device, &wd->Frames[i], allocator); ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator);
ImGui_ImplVulkanH_DestroyFrameSemaphores(instance, device, &wd->FrameSemaphores[i], allocator); ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator);
} }
delete[] wd->Frames; delete[] wd->Frames;
delete[] wd->FrameSemaphores; delete[] wd->FrameSemaphores;
wd->Frames = NULL; wd->Frames = NULL;
wd->FrameSemaphores = NULL; wd->FrameSemaphores = NULL;
wd->FramesQueueSize = 0; wd->ImageCount = 0;
if (wd->RenderPass) if (wd->RenderPass)
vkDestroyRenderPass(device, wd->RenderPass, allocator); vkDestroyRenderPass(device, wd->RenderPass, allocator);
@ -1014,20 +1045,20 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkInstance instance, VkPhysicalDevi
} }
err = vkCreateSwapchainKHR(device, &info, allocator, &wd->Swapchain); err = vkCreateSwapchainKHR(device, &info, allocator, &wd->Swapchain);
check_vk_result(err); check_vk_result(err);
err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->FramesQueueSize, NULL); err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, NULL);
check_vk_result(err); check_vk_result(err);
VkImage backbuffers[16] = {}; VkImage backbuffers[16] = {};
IM_ASSERT(wd->FramesQueueSize >= min_image_count); IM_ASSERT(wd->ImageCount >= min_image_count);
IM_ASSERT(wd->FramesQueueSize < IM_ARRAYSIZE(backbuffers)); IM_ASSERT(wd->ImageCount < IM_ARRAYSIZE(backbuffers));
err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->FramesQueueSize, backbuffers); err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, backbuffers);
check_vk_result(err); check_vk_result(err);
IM_ASSERT(wd->Frames == NULL); IM_ASSERT(wd->Frames == NULL);
wd->Frames = new ImGui_ImplVulkanH_Frame[wd->FramesQueueSize]; wd->Frames = new ImGui_ImplVulkanH_Frame[wd->ImageCount];
wd->FrameSemaphores = new ImGui_ImplVulkanH_FrameSemaphores[wd->FramesQueueSize]; wd->FrameSemaphores = new ImGui_ImplVulkanH_FrameSemaphores[wd->ImageCount];
memset(wd->Frames, 0, sizeof(wd->Frames[0]) * wd->FramesQueueSize); memset(wd->Frames, 0, sizeof(wd->Frames[0]) * wd->ImageCount);
memset(wd->FrameSemaphores, 0, sizeof(wd->FrameSemaphores[0]) * wd->FramesQueueSize); memset(wd->FrameSemaphores, 0, sizeof(wd->FrameSemaphores[0]) * wd->ImageCount);
for (uint32_t i = 0; i < wd->FramesQueueSize; i++) for (uint32_t i = 0; i < wd->ImageCount; i++)
wd->Frames[i].Backbuffer = backbuffers[i]; wd->Frames[i].Backbuffer = backbuffers[i];
} }
if (old_swapchain) if (old_swapchain)
@ -1082,7 +1113,7 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkInstance instance, VkPhysicalDevi
info.components.a = VK_COMPONENT_SWIZZLE_A; info.components.a = VK_COMPONENT_SWIZZLE_A;
VkImageSubresourceRange image_range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; VkImageSubresourceRange image_range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
info.subresourceRange = image_range; info.subresourceRange = image_range;
for (uint32_t i = 0; i < wd->FramesQueueSize; i++) for (uint32_t i = 0; i < wd->ImageCount; i++)
{ {
ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i]; ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
info.image = fd->Backbuffer; info.image = fd->Backbuffer;
@ -1102,7 +1133,7 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkInstance instance, VkPhysicalDevi
info.width = wd->Width; info.width = wd->Width;
info.height = wd->Height; info.height = wd->Height;
info.layers = 1; info.layers = 1;
for (uint32_t i = 0; i < wd->FramesQueueSize; i++) for (uint32_t i = 0; i < wd->ImageCount; i++)
{ {
ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i]; ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];
attachment[0] = fd->BackbufferView; attachment[0] = fd->BackbufferView;
@ -1114,8 +1145,9 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkInstance instance, VkPhysicalDevi
void ImGui_ImplVulkanH_CreateWindow(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) void ImGui_ImplVulkanH_CreateWindow(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)
{ {
ImGui_ImplVulkanH_CreateWindowSwapChain(instance, physical_device, device, wd, allocator, width, height, min_image_count); (void)instance;
ImGui_ImplVulkanH_CreateWindowCommandBuffers(instance, physical_device, device, wd, queue_family, allocator); ImGui_ImplVulkanH_CreateWindowSwapChain(physical_device, device, wd, allocator, width, height, min_image_count);
ImGui_ImplVulkanH_CreateWindowCommandBuffers(physical_device, device, wd, queue_family, allocator);
} }
void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator) void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator)
@ -1123,10 +1155,10 @@ void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui
vkDeviceWaitIdle(device); // FIXME: We could wait on the Queue if we had the queue in wd-> (otherwise VulkanH functions can't use globals) 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); //vkQueueWaitIdle(g_Queue);
for (uint32_t i = 0; i < wd->FramesQueueSize; i++) for (uint32_t i = 0; i < wd->ImageCount; i++)
{ {
ImGui_ImplVulkanH_DestroyFrame(instance, device, &wd->Frames[i], allocator); ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator);
ImGui_ImplVulkanH_DestroyFrameSemaphores(instance, device, &wd->FrameSemaphores[i], allocator); ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator);
} }
delete[] wd->Frames; delete[] wd->Frames;
delete[] wd->FrameSemaphores; delete[] wd->FrameSemaphores;
@ -1139,17 +1171,8 @@ void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui
*wd = ImGui_ImplVulkanH_Window(); *wd = ImGui_ImplVulkanH_Window();
} }
void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator) void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator)
{ {
(void)instance;
vkDestroySemaphore(device, fsd->ImageAcquiredSemaphore, allocator);
vkDestroySemaphore(device, fsd->RenderCompleteSemaphore, allocator);
fsd->ImageAcquiredSemaphore = fsd->RenderCompleteSemaphore = VK_NULL_HANDLE;
}
void ImGui_ImplVulkanH_DestroyFrame(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator)
{
(void)instance;
vkDestroyFence(device, fd->Fence, allocator); vkDestroyFence(device, fd->Fence, allocator);
vkFreeCommandBuffers(device, fd->CommandPool, 1, &fd->CommandBuffer); vkFreeCommandBuffers(device, fd->CommandPool, 1, &fd->CommandBuffer);
vkDestroyCommandPool(device, fd->CommandPool, allocator); vkDestroyCommandPool(device, fd->CommandPool, allocator);
@ -1159,8 +1182,33 @@ void ImGui_ImplVulkanH_DestroyFrame(VkInstance instance, VkDevice device, ImGui_
vkDestroyImageView(device, fd->BackbufferView, allocator); vkDestroyImageView(device, fd->BackbufferView, allocator);
vkDestroyFramebuffer(device, fd->Framebuffer, allocator); vkDestroyFramebuffer(device, fd->Framebuffer, allocator);
}
ImGui_ImplVulkan_DestroyFrameRenderBuffers(instance, device, &fd->RenderBuffers, allocator); void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator)
{
vkDestroySemaphore(device, fsd->ImageAcquiredSemaphore, allocator);
vkDestroySemaphore(device, fsd->RenderCompleteSemaphore, allocator);
fsd->ImageAcquiredSemaphore = fsd->RenderCompleteSemaphore = VK_NULL_HANDLE;
}
void ImGui_ImplVulkanH_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkanH_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator)
{
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; }
if (buffers->IndexBufferMemory) { vkFreeMemory(device, buffers->IndexBufferMemory, allocator); buffers->IndexBufferMemory = VK_NULL_HANDLE; }
buffers->VertexBufferSize = 0;
buffers->IndexBufferSize = 0;
}
void ImGui_ImplVulkanH_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkanH_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator)
{
for (uint32_t n = 0; n < buffers->Count; n++)
ImGui_ImplVulkanH_DestroyFrameRenderBuffers(device, &buffers->FrameRenderBuffers[n], allocator);
delete[] buffers->FrameRenderBuffers;
buffers->FrameRenderBuffers = NULL;
buffers->Index = 0;
buffers->Count = 0;
} }
@ -1286,7 +1334,7 @@ static void ImGui_ImplVulkan_RenderWindow(ImGuiViewport* viewport, void*)
} }
} }
ImGui_ImplVulkan_RenderDrawData(viewport->DrawData, fd->CommandBuffer, &fd->RenderBuffers); ImGui_ImplVulkan_RenderDrawData(viewport->DrawData, fd->CommandBuffer);
{ {
vkCmdEndRenderPass(fd->CommandBuffer); vkCmdEndRenderPass(fd->CommandBuffer);
@ -1332,8 +1380,8 @@ static void ImGui_ImplVulkan_SwapBuffers(ImGuiViewport* viewport, void*)
err = vkQueuePresentKHR(v->Queue, &info); err = vkQueuePresentKHR(v->Queue, &info);
check_vk_result(err); check_vk_result(err);
wd->FrameIndex = (wd->FrameIndex + 1) % wd->FramesQueueSize; // This is for the next vkWaitForFences() wd->FrameIndex = (wd->FrameIndex + 1) % wd->ImageCount; // This is for the next vkWaitForFences()
wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->FramesQueueSize; // Now we can use the next set of semaphores wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->ImageCount; // Now we can use the next set of semaphores
} }
void ImGui_ImplVulkan_InitPlatformInterface() void ImGui_ImplVulkan_InitPlatformInterface()

View File

@ -34,34 +34,20 @@ struct ImGui_ImplVulkan_InitInfo
VkQueue Queue; VkQueue Queue;
VkPipelineCache PipelineCache; VkPipelineCache PipelineCache;
VkDescriptorPool DescriptorPool; VkDescriptorPool DescriptorPool;
int MinImageCount; // >= 2 uint32_t MinImageCount; // >= 2
uint32_t ImageCount; // >= MinImageCount
const VkAllocationCallbacks* Allocator; const VkAllocationCallbacks* Allocator;
void (*CheckVkResultFn)(VkResult err); 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 // Called by user code
IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass); 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_Shutdown();
IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame(); IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame();
IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, ImGui_ImplVulkan_FrameRenderBuffers* buffers); IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer);
IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer); IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer);
IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontUploadObjects(); IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontUploadObjects();
IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFrameRenderBuffers(VkInstance instance, VkDevice device, ImGui_ImplVulkan_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator); IMGUI_IMPL_API void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated)
IMGUI_IMPL_API void ImGui_ImplVulkan_SetSwapChainMinImageCount(int min_image_count); // To override MinImageCount after initialization
// Called by ImGui_ImplVulkan_Init(), might be useful elsewhere. // Called by ImGui_ImplVulkan_Init(), might be useful elsewhere.
IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateDeviceObjects(); IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateDeviceObjects();
@ -105,7 +91,6 @@ struct ImGui_ImplVulkanH_Frame
VkImage Backbuffer; VkImage Backbuffer;
VkImageView BackbufferView; VkImageView BackbufferView;
VkFramebuffer Framebuffer; VkFramebuffer Framebuffer;
ImGui_ImplVulkan_FrameRenderBuffers RenderBuffers;
}; };
struct ImGui_ImplVulkanH_FrameSemaphores struct ImGui_ImplVulkanH_FrameSemaphores
@ -128,12 +113,11 @@ struct ImGui_ImplVulkanH_Window
bool ClearEnable; bool ClearEnable;
VkClearValue ClearValue; VkClearValue ClearValue;
uint32_t FrameIndex; // Current frame being rendered to (0 <= FrameIndex < FrameInFlightCount) 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) uint32_t ImageCount; // Number of simultaneous in-flight frames (returned by vkGetSwapchainImagesKHR, usually derived from min_image_count)
uint32_t SemaphoreIndex; // Current set of swapchain wait semaphores we're using (needs to be distinct from per frame data) uint32_t SemaphoreIndex; // Current set of swapchain wait semaphores we're using (needs to be distinct from per frame data)
ImGui_ImplVulkanH_Frame* Frames; ImGui_ImplVulkanH_Frame* Frames;
ImGui_ImplVulkanH_FrameSemaphores* FrameSemaphores; ImGui_ImplVulkanH_FrameSemaphores* FrameSemaphores;
ImGui_ImplVulkanH_Window() ImGui_ImplVulkanH_Window()
{ {
memset(this, 0, sizeof(*this)); memset(this, 0, sizeof(*this));