change to imgui docker version
rename to work-calendar
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user