change to imgui docker version

rename to work-calendar
This commit is contained in:
2025-08-11 19:34:03 +02:00
parent 515fdbc83c
commit 86f2520c3e
78 changed files with 12220 additions and 506 deletions
+346 -9
View File
@@ -6,6 +6,7 @@
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
// [x] Renderer: Multi-viewport / platform windows. With issues (flickering when creating a new viewport).
// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
@@ -27,6 +28,7 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2025-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2025-07-27: Vulkan: Fixed texture update corruption introduced on 2025-06-11. (#8801, #8755, #8840)
// 2025-07-07: Vulkan: Fixed texture synchronization issue introduced on 2025-06-11. (#8772)
// 2025-06-27: Vulkan: Fixed validation errors during texture upload/update by aligning upload size to 'nonCoherentAtomSize'. (#8743, #8744)
@@ -115,6 +117,7 @@ void ImGui_ImplVulkan_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulka
void ImGui_ImplVulkan_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkan_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator);
void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator);
void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator);
void ImGui_ImplVulkanH_DestroyAllViewportsRenderBuffers(VkDevice device, 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);
@@ -131,15 +134,18 @@ static bool g_FunctionsLoaded = true;
IMGUI_VULKAN_FUNC_MAP_MACRO(vkAllocateCommandBuffers) \
IMGUI_VULKAN_FUNC_MAP_MACRO(vkAllocateDescriptorSets) \
IMGUI_VULKAN_FUNC_MAP_MACRO(vkAllocateMemory) \
IMGUI_VULKAN_FUNC_MAP_MACRO(vkAcquireNextImageKHR) \
IMGUI_VULKAN_FUNC_MAP_MACRO(vkBeginCommandBuffer) \
IMGUI_VULKAN_FUNC_MAP_MACRO(vkBindBufferMemory) \
IMGUI_VULKAN_FUNC_MAP_MACRO(vkBindImageMemory) \
IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBeginRenderPass) \
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(vkCmdEndRenderPass) \
IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdPipelineBarrier) \
IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdPushConstants) \
IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdSetScissor) \
@@ -191,8 +197,10 @@ static bool g_FunctionsLoaded = true;
IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfaceCapabilitiesKHR) \
IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfaceFormatsKHR) \
IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfacePresentModesKHR) \
IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfaceSupportKHR) \
IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetSwapchainImagesKHR) \
IMGUI_VULKAN_FUNC_MAP_MACRO(vkMapMemory) \
IMGUI_VULKAN_FUNC_MAP_MACRO(vkQueuePresentKHR) \
IMGUI_VULKAN_FUNC_MAP_MACRO(vkQueueSubmit) \
IMGUI_VULKAN_FUNC_MAP_MACRO(vkQueueWaitIdle) \
IMGUI_VULKAN_FUNC_MAP_MACRO(vkResetCommandPool) \
@@ -243,6 +251,20 @@ struct ImGui_ImplVulkan_Texture
ImGui_ImplVulkan_Texture() { memset((void*)this, 0, sizeof(*this)); }
};
// For multi-viewport support:
// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data.
struct ImGui_ImplVulkan_ViewportData
{
ImGui_ImplVulkanH_Window Window; // Used by secondary viewports only
ImGui_ImplVulkan_WindowRenderBuffers RenderBuffers; // Used by all viewports
bool WindowOwned;
bool SwapChainNeedRebuild; // Flag when viewport swapchain resized in the middle of processing a frame
bool SwapChainSuboptimal; // Flag when VK_SUBOPTIMAL_KHR was returned.
ImGui_ImplVulkan_ViewportData() { WindowOwned = SwapChainNeedRebuild = SwapChainSuboptimal = false; memset((void*)&RenderBuffers, 0, sizeof(RenderBuffers)); }
~ImGui_ImplVulkan_ViewportData() { }
};
// Vulkan data
struct ImGui_ImplVulkan_Data
{
@@ -252,7 +274,8 @@ struct ImGui_ImplVulkan_Data
VkPipelineCreateFlags PipelineCreateFlags;
VkDescriptorSetLayout DescriptorSetLayout;
VkPipelineLayout PipelineLayout;
VkPipeline Pipeline;
VkPipeline Pipeline; // pipeline for main render pass (created by app)
VkPipeline PipelineForViewports; // pipeline for secondary viewports (created by backend)
VkShaderModule ShaderModuleVert;
VkShaderModule ShaderModuleFrag;
VkDescriptorPool DescriptorPool;
@@ -277,6 +300,10 @@ struct ImGui_ImplVulkan_Data
// SHADERS
//-----------------------------------------------------------------------------
// Forward Declarations
static void ImGui_ImplVulkan_InitMultiViewportSupport();
static void ImGui_ImplVulkan_ShutdownMultiViewportSupport();
// backends/vulkan/glsl_shader.vert, compiled with:
// # glslangValidator -V -x -o glsl_shader.vert.u32 glsl_shader.vert
/*
@@ -521,8 +548,10 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
if (pipeline == VK_NULL_HANDLE)
pipeline = bd->Pipeline;
// Allocate array to store enough vertex/index buffers
ImGui_ImplVulkan_WindowRenderBuffers* wrb = &bd->MainWindowRenderBuffers;
// Allocate array to store enough vertex/index buffers. Each unique viewport gets its own storage.
ImGui_ImplVulkan_ViewportData* viewport_renderer_data = (ImGui_ImplVulkan_ViewportData*)draw_data->OwnerViewport->RendererUserData;
IM_ASSERT(viewport_renderer_data != nullptr);
ImGui_ImplVulkan_WindowRenderBuffers* wrb = &viewport_renderer_data->RenderBuffers;
if (wrb->FrameRenderBuffers.Size == 0)
{
wrb->Index = 0;
@@ -1121,7 +1150,7 @@ void ImGui_ImplVulkan_DestroyDeviceObjects()
{
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
ImGui_ImplVulkan_DestroyWindowRenderBuffers(v->Device, &bd->MainWindowRenderBuffers, v->Allocator);
ImGui_ImplVulkanH_DestroyAllViewportsRenderBuffers(v->Device, v->Allocator);
// Destroy all textures
for (ImTextureData* tex : ImGui::GetPlatformIO().Textures)
@@ -1136,6 +1165,7 @@ void ImGui_ImplVulkan_DestroyDeviceObjects()
if (bd->DescriptorSetLayout) { vkDestroyDescriptorSetLayout(v->Device, bd->DescriptorSetLayout, v->Allocator); bd->DescriptorSetLayout = VK_NULL_HANDLE; }
if (bd->PipelineLayout) { vkDestroyPipelineLayout(v->Device, bd->PipelineLayout, v->Allocator); bd->PipelineLayout = VK_NULL_HANDLE; }
if (bd->Pipeline) { vkDestroyPipeline(v->Device, bd->Pipeline, v->Allocator); bd->Pipeline = VK_NULL_HANDLE; }
if (bd->PipelineForViewports) { vkDestroyPipeline(v->Device, bd->PipelineForViewports, v->Allocator); bd->PipelineForViewports = VK_NULL_HANDLE; }
if (bd->DescriptorPool) { vkDestroyDescriptorPool(v->Device, bd->DescriptorPool, v->Allocator); bd->DescriptorPool = VK_NULL_HANDLE; }
}
@@ -1228,6 +1258,7 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info)
io.BackendRendererName = "imgui_impl_vulkan";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
IM_ASSERT(info->Instance != VK_NULL_HANDLE);
IM_ASSERT(info->PhysicalDevice != VK_NULL_HANDLE);
@@ -1262,6 +1293,12 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info)
if (!ImGui_ImplVulkan_CreateDeviceObjects())
IM_ASSERT(0 && "ImGui_ImplVulkan_CreateDeviceObjects() failed!"); // <- Can't be hit yet.
// Our render function expect RendererUserData to be storing the window render buffer we need (for the main viewport we won't use ->Window)
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
main_viewport->RendererUserData = IM_NEW(ImGui_ImplVulkan_ViewportData)();
ImGui_ImplVulkan_InitMultiViewportSupport();
return true;
}
@@ -1271,14 +1308,24 @@ void ImGui_ImplVulkan_Shutdown()
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
// First destroy objects in all viewports
ImGui_ImplVulkan_DestroyDeviceObjects();
#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
IM_FREE((void*)const_cast<VkFormat*>(bd->VulkanInitInfo.PipelineRenderingCreateInfo.pColorAttachmentFormats));
#endif
// Manually delete main viewport render data in-case we haven't initialized for viewports
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
if (ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)main_viewport->RendererUserData)
IM_DELETE(vd);
main_viewport->RendererUserData = nullptr;
// Clean up windows
ImGui_ImplVulkan_ShutdownMultiViewportSupport();
io.BackendRendererName = nullptr;
io.BackendRendererUserData = nullptr;
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_RendererHasViewports);
IM_DELETE(bd);
}
@@ -1296,10 +1343,12 @@ void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count)
if (bd->VulkanInitInfo.MinImageCount == min_image_count)
return;
IM_ASSERT(0); // FIXME-VIEWPORT: Unsupported. Need to recreate all swap chains!
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
VkResult err = vkDeviceWaitIdle(v->Device);
check_vk_result(err);
ImGui_ImplVulkan_DestroyWindowRenderBuffers(v->Device, &bd->MainWindowRenderBuffers, v->Allocator);
ImGui_ImplVulkanH_DestroyAllViewportsRenderBuffers(v->Device, v->Allocator);
bd->VulkanInitInfo.MinImageCount = min_image_count;
}
@@ -1576,8 +1625,6 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, V
wd->ImageCount = 0;
if (wd->RenderPass)
vkDestroyRenderPass(device, wd->RenderPass, allocator);
if (wd->Pipeline)
vkDestroyPipeline(device, wd->Pipeline, allocator);
// If min image count was not specified, request different count of images dependent on selected present mode
if (min_image_count == 0)
@@ -1729,6 +1776,7 @@ void ImGui_ImplVulkanH_CreateOrResizeWindow(VkInstance instance, VkPhysicalDevic
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_ImplVulkan_CreatePipeline(device, allocator, VK_NULL_HANDLE, wd->RenderPass, VK_SAMPLE_COUNT_1_BIT, &wd->Pipeline, g_VulkanInitInfo.Subpass);
ImGui_ImplVulkanH_CreateWindowCommandBuffers(physical_device, device, wd, queue_family, allocator);
// FIXME: to submit the command buffer, we need a queue. In the examples folder, the ImGui_ImplVulkanH_CreateOrResizeWindow function is called
@@ -1819,7 +1867,6 @@ void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui
ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator);
wd->Frames.clear();
wd->FrameSemaphores.clear();
vkDestroyPipeline(device, wd->Pipeline, allocator);
vkDestroyRenderPass(device, wd->RenderPass, allocator);
vkDestroySwapchainKHR(device, wd->Swapchain, allocator);
vkDestroySurfaceKHR(instance, wd->Surface, allocator);
@@ -1847,6 +1894,296 @@ void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH
fsd->ImageAcquiredSemaphore = fsd->RenderCompleteSemaphore = VK_NULL_HANDLE;
}
void ImGui_ImplVulkanH_DestroyAllViewportsRenderBuffers(VkDevice device, const VkAllocationCallbacks* allocator)
{
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
for (int n = 0; n < platform_io.Viewports.Size; n++)
if (ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)platform_io.Viewports[n]->RendererUserData)
ImGui_ImplVulkan_DestroyWindowRenderBuffers(device, &vd->RenderBuffers, allocator);
}
//--------------------------------------------------------------------------------------------------------
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
//--------------------------------------------------------------------------------------------------------
static void ImGui_ImplVulkan_CreateWindow(ImGuiViewport* viewport)
{
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
ImGui_ImplVulkan_ViewportData* vd = IM_NEW(ImGui_ImplVulkan_ViewportData)();
viewport->RendererUserData = vd;
ImGui_ImplVulkanH_Window* wd = &vd->Window;
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
// Create surface
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
VkResult err = (VkResult)platform_io.Platform_CreateVkSurface(viewport, (ImU64)v->Instance, (const void*)v->Allocator, (ImU64*)&wd->Surface);
check_vk_result(err);
// Check for WSI support
VkBool32 res;
vkGetPhysicalDeviceSurfaceSupportKHR(v->PhysicalDevice, v->QueueFamily, wd->Surface, &res);
if (res != VK_TRUE)
{
IM_ASSERT(0); // Error: no WSI support on physical device
return;
}
// Select Surface Format
ImVector<VkFormat> requestSurfaceImageFormats;
#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
for (uint32_t n = 0; n < v->PipelineRenderingCreateInfo.colorAttachmentCount; n++)
requestSurfaceImageFormats.push_back(v->PipelineRenderingCreateInfo.pColorAttachmentFormats[n]);
#endif
const VkFormat defaultFormats[] = { VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM };
for (VkFormat format : defaultFormats)
requestSurfaceImageFormats.push_back(format);
const VkColorSpaceKHR requestSurfaceColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
wd->SurfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(v->PhysicalDevice, wd->Surface, requestSurfaceImageFormats.Data, (size_t)requestSurfaceImageFormats.Size, requestSurfaceColorSpace);
// Select Present Mode
// FIXME-VULKAN: Even thought mailbox seems to get us maximum framerate with a single window, it halves framerate with a second window etc. (w/ Nvidia and SDK 1.82.1)
VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_FIFO_KHR };
wd->PresentMode = ImGui_ImplVulkanH_SelectPresentMode(v->PhysicalDevice, wd->Surface, &present_modes[0], IM_ARRAYSIZE(present_modes));
//printf("[vulkan] Secondary window selected PresentMode = %d\n", wd->PresentMode);
// Create SwapChain, RenderPass, Framebuffer, etc.
wd->ClearEnable = (viewport->Flags & ImGuiViewportFlags_NoRendererClear) ? false : true;
wd->UseDynamicRendering = v->UseDynamicRendering;
ImGui_ImplVulkanH_CreateOrResizeWindow(v->Instance, v->PhysicalDevice, v->Device, wd, v->QueueFamily, v->Allocator, (int)viewport->Size.x, (int)viewport->Size.y, v->MinImageCount);
vd->WindowOwned = true;
// Create pipeline (shared by all secondary viewports)
if (bd->PipelineForViewports == VK_NULL_HANDLE)
ImGui_ImplVulkan_CreatePipeline(v->Device, v->Allocator, VK_NULL_HANDLE, wd->RenderPass, VK_SAMPLE_COUNT_1_BIT, &bd->PipelineForViewports, 0);
}
static void ImGui_ImplVulkan_DestroyWindow(ImGuiViewport* viewport)
{
// The main viewport (owned by the application) will always have RendererUserData == 0 since we didn't create the data for it.
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
if (ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)viewport->RendererUserData)
{
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
if (vd->WindowOwned)
ImGui_ImplVulkanH_DestroyWindow(v->Instance, v->Device, &vd->Window, v->Allocator);
ImGui_ImplVulkan_DestroyWindowRenderBuffers(v->Device, &vd->RenderBuffers, v->Allocator);
IM_DELETE(vd);
}
viewport->RendererUserData = nullptr;
}
static void ImGui_ImplVulkan_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
{
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)viewport->RendererUserData;
if (vd == nullptr) // This is nullptr for the main viewport (which is left to the user/app to handle)
return;
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
vd->Window.ClearEnable = (viewport->Flags & ImGuiViewportFlags_NoRendererClear) ? false : true;
ImGui_ImplVulkanH_CreateOrResizeWindow(v->Instance, v->PhysicalDevice, v->Device, &vd->Window, v->QueueFamily, v->Allocator, (int)size.x, (int)size.y, v->MinImageCount);
}
static void ImGui_ImplVulkan_RenderWindow(ImGuiViewport* viewport, void*)
{
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)viewport->RendererUserData;
ImGui_ImplVulkanH_Window* wd = &vd->Window;
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
VkResult err;
if (vd->SwapChainNeedRebuild || vd->SwapChainSuboptimal)
{
ImGui_ImplVulkanH_CreateOrResizeWindow(v->Instance, v->PhysicalDevice, v->Device, wd, v->QueueFamily, v->Allocator, (int)viewport->Size.x, (int)viewport->Size.y, v->MinImageCount);
vd->SwapChainNeedRebuild = vd->SwapChainSuboptimal = false;
}
ImGui_ImplVulkanH_Frame* fd = nullptr;
ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[wd->SemaphoreIndex];
{
{
err = vkAcquireNextImageKHR(v->Device, wd->Swapchain, UINT64_MAX, fsd->ImageAcquiredSemaphore, VK_NULL_HANDLE, &wd->FrameIndex);
if (err == VK_ERROR_OUT_OF_DATE_KHR)
{
vd->SwapChainNeedRebuild = true; // Since we are not going to swap this frame anyway, it's ok that recreation happens on next frame.
return;
}
if (err == VK_SUBOPTIMAL_KHR)
vd->SwapChainSuboptimal = true;
else
check_vk_result(err);
fd = &wd->Frames[wd->FrameIndex];
}
for (;;)
{
err = vkWaitForFences(v->Device, 1, &fd->Fence, VK_TRUE, 100);
if (err == VK_SUCCESS) break;
if (err == VK_TIMEOUT) continue;
check_vk_result(err);
}
{
err = vkResetCommandPool(v->Device, fd->CommandPool, 0);
check_vk_result(err);
VkCommandBufferBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
err = vkBeginCommandBuffer(fd->CommandBuffer, &info);
check_vk_result(err);
}
{
ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
memcpy(&wd->ClearValue.color.float32[0], &clear_color, 4 * sizeof(float));
}
#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
if (v->UseDynamicRendering)
{
// Transition swapchain image to a layout suitable for drawing.
VkImageMemoryBarrier barrier = {};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
barrier.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
barrier.image = fd->Backbuffer;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.layerCount = 1;
vkCmdPipelineBarrier(fd->CommandBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_NONE, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
VkRenderingAttachmentInfo attachmentInfo = {};
attachmentInfo.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR;
attachmentInfo.imageView = fd->BackbufferView;
attachmentInfo.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachmentInfo.resolveMode = VK_RESOLVE_MODE_NONE;
attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachmentInfo.clearValue = wd->ClearValue;
VkRenderingInfo renderingInfo = {};
renderingInfo.sType = VK_STRUCTURE_TYPE_RENDERING_INFO_KHR;
renderingInfo.renderArea.extent.width = wd->Width;
renderingInfo.renderArea.extent.height = wd->Height;
renderingInfo.layerCount = 1;
renderingInfo.viewMask = 0;
renderingInfo.colorAttachmentCount = 1;
renderingInfo.pColorAttachments = &attachmentInfo;
ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR(fd->CommandBuffer, &renderingInfo);
}
else
#endif
{
VkRenderPassBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = wd->RenderPass;
info.framebuffer = fd->Framebuffer;
info.renderArea.extent.width = wd->Width;
info.renderArea.extent.height = wd->Height;
info.clearValueCount = (viewport->Flags & ImGuiViewportFlags_NoRendererClear) ? 0 : 1;
info.pClearValues = (viewport->Flags & ImGuiViewportFlags_NoRendererClear) ? nullptr : &wd->ClearValue;
vkCmdBeginRenderPass(fd->CommandBuffer, &info, VK_SUBPASS_CONTENTS_INLINE);
}
}
ImGui_ImplVulkan_RenderDrawData(viewport->DrawData, fd->CommandBuffer, bd->PipelineForViewports);
{
#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
if (v->UseDynamicRendering)
{
ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR(fd->CommandBuffer);
// Transition image to a layout suitable for presentation
VkImageMemoryBarrier barrier = {};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
barrier.image = fd->Backbuffer;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.layerCount = 1;
vkCmdPipelineBarrier(fd->CommandBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
}
else
#endif
{
vkCmdEndRenderPass(fd->CommandBuffer);
}
{
VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkSubmitInfo info = {};
info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
info.waitSemaphoreCount = 1;
info.pWaitSemaphores = &fsd->ImageAcquiredSemaphore;
info.pWaitDstStageMask = &wait_stage;
info.commandBufferCount = 1;
info.pCommandBuffers = &fd->CommandBuffer;
info.signalSemaphoreCount = 1;
info.pSignalSemaphores = &fsd->RenderCompleteSemaphore;
err = vkEndCommandBuffer(fd->CommandBuffer);
check_vk_result(err);
err = vkResetFences(v->Device, 1, &fd->Fence);
check_vk_result(err);
err = vkQueueSubmit(v->Queue, 1, &info, fd->Fence);
check_vk_result(err);
}
}
}
static void ImGui_ImplVulkan_SwapBuffers(ImGuiViewport* viewport, void*)
{
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)viewport->RendererUserData;
ImGui_ImplVulkanH_Window* wd = &vd->Window;
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
if (vd->SwapChainNeedRebuild) // Frame data became invalid in the middle of rendering
return;
VkResult err;
uint32_t present_index = wd->FrameIndex;
ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[wd->SemaphoreIndex];
VkPresentInfoKHR info = {};
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
info.waitSemaphoreCount = 1;
info.pWaitSemaphores = &fsd->RenderCompleteSemaphore;
info.swapchainCount = 1;
info.pSwapchains = &wd->Swapchain;
info.pImageIndices = &present_index;
err = vkQueuePresentKHR(v->Queue, &info);
if (err == VK_ERROR_OUT_OF_DATE_KHR)
{
vd->SwapChainNeedRebuild = true;
return;
}
if (err == VK_SUBOPTIMAL_KHR)
vd->SwapChainSuboptimal = true;
else
check_vk_result(err);
wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->SemaphoreCount; // Now we can use the next set of semaphores
}
void ImGui_ImplVulkan_InitMultiViewportSupport()
{
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
if (ImGui::GetIO().BackendFlags & ImGuiBackendFlags_PlatformHasViewports)
IM_ASSERT(platform_io.Platform_CreateVkSurface != nullptr && "Platform needs to setup the CreateVkSurface handler.");
platform_io.Renderer_CreateWindow = ImGui_ImplVulkan_CreateWindow;
platform_io.Renderer_DestroyWindow = ImGui_ImplVulkan_DestroyWindow;
platform_io.Renderer_SetWindowSize = ImGui_ImplVulkan_SetWindowSize;
platform_io.Renderer_RenderWindow = ImGui_ImplVulkan_RenderWindow;
platform_io.Renderer_SwapBuffers = ImGui_ImplVulkan_SwapBuffers;
}
void ImGui_ImplVulkan_ShutdownMultiViewportSupport()
{
ImGui::DestroyPlatformWindows();
}
//-----------------------------------------------------------------------------
#endif // #ifndef IMGUI_DISABLE