From a456d17dfc7fa5ebbe9d7897552d6e505a593406 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 1 Sep 2020 15:24:24 +0200 Subject: [PATCH 1/4] Internals: Begin: update ->Hidden flags only on first begin of the frame. (ignore whitespace to see simple diff) --- imgui.cpp | 57 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index f0d2a47a..ff6e5fcc 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5248,6 +5248,7 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar ImGuiWindowFlags flags = window->Flags; // Ensure that ScrollBar doesn't read last frame's SkipItems + IM_ASSERT(window->BeginCount == 0); window->SkipItems = false; // Draw window + handle manual resize @@ -6029,37 +6030,41 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->BeginCount++; g.NextWindowData.ClearFlags(); - if (flags & ImGuiWindowFlags_ChildWindow) + // Update visibility + if (first_begin_of_the_frame) { - // Child window can be out of sight and have "negative" clip windows. - // Mark them as collapsed so commands are skipped earlier (we can't manually collapse them because they have no title bar). - IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0); - if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) - if (window->OuterRectClipped.Min.x >= window->OuterRectClipped.Max.x || window->OuterRectClipped.Min.y >= window->OuterRectClipped.Max.y) - window->HiddenFramesCanSkipItems = 1; + if (flags & ImGuiWindowFlags_ChildWindow) + { + // Child window can be out of sight and have "negative" clip windows. + // Mark them as collapsed so commands are skipped earlier (we can't manually collapse them because they have no title bar). + IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0); + if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) + if (window->OuterRectClipped.Min.x >= window->OuterRectClipped.Max.x || window->OuterRectClipped.Min.y >= window->OuterRectClipped.Max.y) + window->HiddenFramesCanSkipItems = 1; - // Hide along with parent or if parent is collapsed - if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCanSkipItems > 0)) + // Hide along with parent or if parent is collapsed + if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCanSkipItems > 0)) + window->HiddenFramesCanSkipItems = 1; + if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCannotSkipItems > 0)) + window->HiddenFramesCannotSkipItems = 1; + } + + // Don't render if style alpha is 0.0 at the time of Begin(). This is arbitrary and inconsistent but has been there for a long while (may remove at some point) + if (style.Alpha <= 0.0f) window->HiddenFramesCanSkipItems = 1; - if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCannotSkipItems > 0)) - window->HiddenFramesCannotSkipItems = 1; + + // Update the Hidden flag + window->Hidden = (window->HiddenFramesCanSkipItems > 0) || (window->HiddenFramesCannotSkipItems > 0); + + // Update the SkipItems flag, used to early out of all items functions (no layout required) + bool skip_items = false; + if (window->Collapsed || !window->Active || window->Hidden) + if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && window->HiddenFramesCannotSkipItems <= 0) + skip_items = true; + window->SkipItems = skip_items; } - // Don't render if style alpha is 0.0 at the time of Begin(). This is arbitrary and inconsistent but has been there for a long while (may remove at some point) - if (style.Alpha <= 0.0f) - window->HiddenFramesCanSkipItems = 1; - - // Update the Hidden flag - window->Hidden = (window->HiddenFramesCanSkipItems > 0) || (window->HiddenFramesCannotSkipItems > 0); - - // Update the SkipItems flag, used to early out of all items functions (no layout required) - bool skip_items = false; - if (window->Collapsed || !window->Active || window->Hidden) - if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && window->HiddenFramesCannotSkipItems <= 0) - skip_items = true; - window->SkipItems = skip_items; - - return !skip_items; + return !window->SkipItems; } void ImGui::End() From f4d062fa110560ef1336acc73b254f265d3dc9fd Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 1 Sep 2020 18:33:51 +0200 Subject: [PATCH 2/4] Nav: Added debug logging, extract bits of code into NavUpdateInitResult(). --- imgui.cpp | 38 +++++++++++++++++++++++++------------- imgui_internal.h | 2 ++ 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ff6e5fcc..7beb69b1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -841,6 +841,7 @@ static void NavUpdate(); static void NavUpdateWindowing(); static void NavUpdateWindowingOverlay(); static void NavUpdateMoveResult(); +static void NavUpdateInitResult(); static float NavUpdatePageUpPageDown(); static inline void NavUpdateAnyRequestFlag(); static void NavEndFrame(); @@ -8444,7 +8445,7 @@ void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit) if (!(window->Flags & ImGuiWindowFlags_NoNavInputs)) if (!(window->Flags & ImGuiWindowFlags_ChildWindow) || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit) init_for_nav = true; - //IMGUI_DEBUG_LOG("[Nav] NavInitWindow() init_for_nav=%d, window=\"%s\", layer=%d\n", init_for_nav, window->Name, g.NavLayer); + IMGUI_DEBUG_LOG("[nav] NavInitRequest: from NavInitWindow(), init_for_nav=%d, window=\"%s\", layer=%d\n", init_for_nav, window->Name, g.NavLayer); if (init_for_nav) { SetNavID(0, g.NavLayer, 0); @@ -8566,17 +8567,8 @@ static void ImGui::NavUpdate() io.NavInputsDownDuration[i] = (io.NavInputs[i] > 0.0f) ? (io.NavInputsDownDuration[i] < 0.0f ? 0.0f : io.NavInputsDownDuration[i] + io.DeltaTime) : -1.0f; // Process navigation init request (select first/default focus) - // In very rare cases g.NavWindow may be null (e.g. clearing focus after requesting an init request, which does happen when releasing Alt while clicking on void) - if (g.NavInitResultId != 0 && (!g.NavDisableHighlight || g.NavInitRequestFromMove) && g.NavWindow) - { - // Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called) - //IMGUI_DEBUG_LOG("[Nav] Apply NavInitRequest result: 0x%08X Layer %d in \"%s\"\n", g.NavInitResultId, g.NavLayer, g.NavWindow->Name); - if (g.NavInitRequestFromMove) - SetNavIDWithRectRel(g.NavInitResultId, g.NavLayer, 0, g.NavInitResultRectRel); - else - SetNavID(g.NavInitResultId, g.NavLayer, 0); - g.NavWindow->NavRectRel[g.NavLayer] = g.NavInitResultRectRel; - } + if (g.NavInitResultId != 0 && (!g.NavDisableHighlight || g.NavInitRequestFromMove)) + NavUpdateInitResult(); g.NavInitRequest = false; g.NavInitRequestFromMove = false; g.NavInitResultId = 0; @@ -8629,6 +8621,7 @@ static void ImGui::NavUpdate() // Process NavCancel input (to close a popup, get back to parent, clear focus) if (IsNavInputTest(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed)) { + IMGUI_DEBUG_LOG_NAV("[nav] ImGuiNavInput_Cancel\n"); if (g.ActiveId != 0) { if (!IsActiveIdUsingNavInput(ImGuiNavInput_Cancel)) @@ -8714,6 +8707,7 @@ static void ImGui::NavUpdate() // (Preserve g.NavMoveRequestFlags, g.NavMoveClipDir which were set by the NavMoveRequestForward() function) IM_ASSERT(g.NavMoveDir != ImGuiDir_None && g.NavMoveClipDir != ImGuiDir_None); IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_ForwardQueued); + IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequestForward %d\n", g.NavMoveDir); g.NavMoveRequestForward = ImGuiNavForward_ForwardActive; } @@ -8732,7 +8726,7 @@ static void ImGui::NavUpdate() } if (g.NavMoveRequest && g.NavId == 0) { - //IMGUI_DEBUG_LOG("[Nav] NavInitRequest from move, window \"%s\", layer=%d\n", g.NavWindow->Name, g.NavLayer); + IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", layer=%d\n", g.NavWindow->Name, g.NavLayer); g.NavInitRequest = g.NavInitRequestFromMove = true; // Reassigning with same value, we're being explicit here. g.NavInitResultId = 0; // -V1048 @@ -8777,6 +8771,7 @@ static void ImGui::NavUpdate() ImRect window_rect_rel(window->InnerRect.Min - window->Pos - ImVec2(1, 1), window->InnerRect.Max - window->Pos + ImVec2(1, 1)); if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer])) { + IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: clamp NavRectRel\n"); float pad = window->CalcFontSize() * 0.5f; window_rect_rel.Expand(ImVec2(-ImMin(window_rect_rel.GetWidth(), pad), -ImMin(window_rect_rel.GetHeight(), pad))); // Terrible approximation for the intent of starting navigation from first fully visible item window->NavRectRel[g.NavLayer].ClipWithFull(window_rect_rel); @@ -8803,6 +8798,22 @@ static void ImGui::NavUpdate() #endif } +static void ImGui::NavUpdateInitResult() +{ + // In very rare cases g.NavWindow may be null (e.g. clearing focus after requesting an init request, which does happen when releasing Alt while clicking on void) + ImGuiContext& g = *GImGui; + if (!g.NavWindow) + return; + + // Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called) + IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", g.NavInitResultId, g.NavLayer, g.NavWindow->Name); + if (g.NavInitRequestFromMove) + SetNavIDWithRectRel(g.NavInitResultId, g.NavLayer, 0, g.NavInitResultRectRel); + else + SetNavID(g.NavInitResultId, g.NavLayer, 0); + g.NavWindow->NavRectRel[g.NavLayer] = g.NavInitResultRectRel; +} + // Apply result from previous frame navigation directional move request static void ImGui::NavUpdateMoveResult() { @@ -8862,6 +8873,7 @@ static void ImGui::NavUpdateMoveResult() g.NavJustMovedToFocusScopeId = result->FocusScopeId; g.NavJustMovedToKeyMods = g.NavMoveRequestKeyMods; } + IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", result->ID, g.NavLayer, g.NavWindow->Name); SetNavIDWithRectRel(result->ID, g.NavLayer, result->FocusScopeId, result->RectRel); } diff --git a/imgui_internal.h b/imgui_internal.h index 7c5cb0fd..1eed0d5b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -163,7 +163,9 @@ namespace ImStb // Debug Logging for selected systems. Remove the '((void)0) //' to enable. //#define IMGUI_DEBUG_LOG_POPUP IMGUI_DEBUG_LOG // Enable log +//#define IMGUI_DEBUG_LOG_NAV IMGUI_DEBUG_LOG // Enable log #define IMGUI_DEBUG_LOG_POPUP(...) ((void)0) // Disable log +#define IMGUI_DEBUG_LOG_NAV(...) ((void)0) // Disable log // Static Asserts #if (__cplusplus >= 201100) From 9a9ee7f813b9f1beb8b0709824b576acd335cbf6 Mon Sep 17 00:00:00 2001 From: Valentin Vanelslande Date: Tue, 1 Sep 2020 16:19:33 -0500 Subject: [PATCH 3/4] NavInitWindow: Change IMGUI_DEBUG_LOG to IMGUI_DEBUG_LOG_NAV (#3450) --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 7beb69b1..e0a15289 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8445,7 +8445,7 @@ void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit) if (!(window->Flags & ImGuiWindowFlags_NoNavInputs)) if (!(window->Flags & ImGuiWindowFlags_ChildWindow) || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit) init_for_nav = true; - IMGUI_DEBUG_LOG("[nav] NavInitRequest: from NavInitWindow(), init_for_nav=%d, window=\"%s\", layer=%d\n", init_for_nav, window->Name, g.NavLayer); + IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from NavInitWindow(), init_for_nav=%d, window=\"%s\", layer=%d\n", init_for_nav, window->Name, g.NavLayer); if (init_for_nav) { SetNavID(0, g.NavLayer, 0); From b73305be117158b21a94eee8fe3668c0275b1e26 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 2 Sep 2020 12:43:05 +0200 Subject: [PATCH 4/4] Examples: Vulkan: Reworked buffer resize handling, amend df89a16d (#3390, #2626) --- examples/example_glfw_vulkan/main.cpp | 29 ++++++++++++++++++--------- examples/example_sdl_vulkan/main.cpp | 29 ++++++++++++++++++--------- 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp index 8e75abbf..6dc2e6cf 100644 --- a/examples/example_glfw_vulkan/main.cpp +++ b/examples/example_glfw_vulkan/main.cpp @@ -43,8 +43,6 @@ static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE; static ImGui_ImplVulkanH_Window g_MainWindowData; static int g_MinImageCount = 2; static bool g_SwapChainRebuild = false; -static int g_SwapChainResizeWidth = 0; -static int g_SwapChainResizeHeight = 0; static void check_vk_result(VkResult err) { @@ -255,6 +253,11 @@ static void FrameRender(ImGui_ImplVulkanH_Window* wd, ImDrawData* draw_data) VkSemaphore image_acquired_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].ImageAcquiredSemaphore; VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore; err = vkAcquireNextImageKHR(g_Device, wd->Swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE, &wd->FrameIndex); + if (err == VK_ERROR_OUT_OF_DATE_KHR) + { + g_SwapChainRebuild = true; + return; + } check_vk_result(err); ImGui_ImplVulkanH_Frame* fd = &wd->Frames[wd->FrameIndex]; @@ -310,8 +313,10 @@ static void FrameRender(ImGui_ImplVulkanH_Window* wd, ImDrawData* draw_data) } } -static void FramePresent(ImGui_ImplVulkanH_Window* wd, GLFWwindow* window) +static void FramePresent(ImGui_ImplVulkanH_Window* wd) { + if (g_SwapChainRebuild) + return; VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore; VkPresentInfoKHR info = {}; info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; @@ -323,7 +328,6 @@ static void FramePresent(ImGui_ImplVulkanH_Window* wd, GLFWwindow* window) VkResult err = vkQueuePresentKHR(g_Queue, &info); if (err == VK_ERROR_OUT_OF_DATE_KHR) { - glfwGetFramebufferSize(window, &g_SwapChainResizeWidth, &g_SwapChainResizeHeight); g_SwapChainRebuild = true; return; } @@ -455,12 +459,17 @@ int main(int, char**) glfwPollEvents(); // Resize swap chain? - if (g_SwapChainRebuild && g_SwapChainResizeWidth > 0 && g_SwapChainResizeHeight > 0) + if (g_SwapChainRebuild) { - g_SwapChainRebuild = false; - ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount); - ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, &g_MainWindowData, g_QueueFamily, g_Allocator, g_SwapChainResizeWidth, g_SwapChainResizeHeight, g_MinImageCount); - g_MainWindowData.FrameIndex = 0; + int width, height; + glfwGetFramebufferSize(window, &width, &height); + if (width > 0 && height > 0) + { + ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount); + ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, &g_MainWindowData, g_QueueFamily, g_Allocator, width, height, g_MinImageCount); + g_MainWindowData.FrameIndex = 0; + g_SwapChainRebuild = false; + } } // Start the Dear ImGui frame @@ -513,7 +522,7 @@ int main(int, char**) { memcpy(&wd->ClearValue.color.float32[0], &clear_color, 4 * sizeof(float)); FrameRender(wd, draw_data); - FramePresent(wd, window); + FramePresent(wd); } } diff --git a/examples/example_sdl_vulkan/main.cpp b/examples/example_sdl_vulkan/main.cpp index c0a98088..b22e4247 100644 --- a/examples/example_sdl_vulkan/main.cpp +++ b/examples/example_sdl_vulkan/main.cpp @@ -35,8 +35,6 @@ static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE; static ImGui_ImplVulkanH_Window g_MainWindowData; static uint32_t g_MinImageCount = 2; static bool g_SwapChainRebuild = false; -static int g_SwapChainResizeWidth = 0; -static int g_SwapChainResizeHeight = 0; static void check_vk_result(VkResult err) { @@ -247,6 +245,11 @@ static void FrameRender(ImGui_ImplVulkanH_Window* wd, ImDrawData* draw_data) VkSemaphore image_acquired_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].ImageAcquiredSemaphore; VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore; err = vkAcquireNextImageKHR(g_Device, wd->Swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE, &wd->FrameIndex); + if (err == VK_ERROR_OUT_OF_DATE_KHR) + { + g_SwapChainRebuild = true; + return; + } check_vk_result(err); ImGui_ImplVulkanH_Frame* fd = &wd->Frames[wd->FrameIndex]; @@ -302,8 +305,10 @@ static void FrameRender(ImGui_ImplVulkanH_Window* wd, ImDrawData* draw_data) } } -static void FramePresent(ImGui_ImplVulkanH_Window* wd, SDL_Window* window) +static void FramePresent(ImGui_ImplVulkanH_Window* wd) { + if (g_SwapChainRebuild) + return; VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore; VkPresentInfoKHR info = {}; info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; @@ -315,7 +320,6 @@ static void FramePresent(ImGui_ImplVulkanH_Window* wd, SDL_Window* window) VkResult err = vkQueuePresentKHR(g_Queue, &info); if (err == VK_ERROR_OUT_OF_DATE_KHR) { - SDL_GetWindowSize(window, &g_SwapChainResizeWidth, &g_SwapChainResizeHeight); g_SwapChainRebuild = true; return; } @@ -454,12 +458,17 @@ int main(int, char**) } // Resize swap chain? - if (g_SwapChainRebuild && g_SwapChainResizeWidth > 0 && g_SwapChainResizeHeight > 0) + if (g_SwapChainRebuild) { - g_SwapChainRebuild = false; - ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount); - ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, &g_MainWindowData, g_QueueFamily, g_Allocator, g_SwapChainResizeWidth, g_SwapChainResizeHeight, g_MinImageCount); - g_MainWindowData.FrameIndex = 0; + int width, height; + SDL_GetWindowSize(window, &width, &height); + if (width > 0 && height > 0) + { + ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount); + ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, &g_MainWindowData, g_QueueFamily, g_Allocator, width, height, g_MinImageCount); + g_MainWindowData.FrameIndex = 0; + g_SwapChainRebuild = false; + } } // Start the Dear ImGui frame @@ -512,7 +521,7 @@ int main(int, char**) { memcpy(&wd->ClearValue.color.float32[0], &clear_color, 4 * sizeof(float)); FrameRender(wd, draw_data); - FramePresent(wd, window); + FramePresent(wd); } }