|
@@ -1244,6 +1244,7 @@ ImGuiIO::ImGuiIO()
|
|
|
ConfigInputTextCursorBlink = true;
|
|
|
ConfigWindowsResizeFromEdges = true;
|
|
|
ConfigWindowsMoveFromTitleBarOnly = false;
|
|
|
+ ConfigWindowsMemoryCompactTimer = 60.0f;
|
|
|
|
|
|
// Platform Functions
|
|
|
BackendPlatformName = BackendRendererName = NULL;
|
|
@@ -2699,6 +2700,7 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name)
|
|
|
SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX);
|
|
|
|
|
|
LastFrameActive = -1;
|
|
|
+ LastTimeActive = -1.0f;
|
|
|
ItemWidthDefault = 0.0f;
|
|
|
FontWindowScale = 1.0f;
|
|
|
SettingsIdx = -1;
|
|
@@ -2713,6 +2715,9 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name)
|
|
|
NavLastIds[0] = NavLastIds[1] = 0;
|
|
|
NavRectRel[0] = NavRectRel[1] = ImRect();
|
|
|
NavLastChildNavWindow = NULL;
|
|
|
+
|
|
|
+ MemoryCompacted = false;
|
|
|
+ MemoryDrawListIdxCapacity = MemoryDrawListVtxCapacity = 0;
|
|
|
}
|
|
|
|
|
|
ImGuiWindow::~ImGuiWindow()
|
|
@@ -2783,6 +2788,36 @@ static void SetCurrentWindow(ImGuiWindow* window)
|
|
|
g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
|
|
|
}
|
|
|
|
|
|
+// Free up/compact internal window buffers, we can use this when a window becomes unused.
|
|
|
+// This is currently unused by the library, but you may call this yourself for easy GC.
|
|
|
+// Not freed:
|
|
|
+// - ImGuiWindow, ImGuiWindowSettings, Name
|
|
|
+// - StateStorage, ColumnsStorage (may hold useful data)
|
|
|
+// This should have no noticeable visual effect. When the window reappear however, expect new allocation/buffer growth/copy cost.
|
|
|
+void ImGui::GcCompactTransientWindowBuffers(ImGuiWindow* window)
|
|
|
+{
|
|
|
+ window->MemoryCompacted = true;
|
|
|
+ window->MemoryDrawListIdxCapacity = window->DrawList->IdxBuffer.Capacity;
|
|
|
+ window->MemoryDrawListVtxCapacity = window->DrawList->VtxBuffer.Capacity;
|
|
|
+ window->IDStack.clear();
|
|
|
+ window->DrawList->ClearFreeMemory();
|
|
|
+ window->DC.ChildWindows.clear();
|
|
|
+ window->DC.ItemFlagsStack.clear();
|
|
|
+ window->DC.ItemWidthStack.clear();
|
|
|
+ window->DC.TextWrapPosStack.clear();
|
|
|
+ window->DC.GroupStack.clear();
|
|
|
+}
|
|
|
+
|
|
|
+void ImGui::GcAwakeTransientWindowBuffers(ImGuiWindow* window)
|
|
|
+{
|
|
|
+ // We stored capacity of the ImDrawList buffer to reduce growth-caused allocation/copy when awakening.
|
|
|
+ // The other buffers tends to amortize much faster.
|
|
|
+ window->MemoryCompacted = false;
|
|
|
+ window->DrawList->IdxBuffer.reserve(window->MemoryDrawListIdxCapacity);
|
|
|
+ window->DrawList->VtxBuffer.reserve(window->MemoryDrawListVtxCapacity);
|
|
|
+ window->MemoryDrawListIdxCapacity = window->MemoryDrawListVtxCapacity = 0;
|
|
|
+}
|
|
|
+
|
|
|
void ImGui::SetNavID(ImGuiID id, int nav_layer)
|
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
@@ -3814,8 +3849,9 @@ void ImGui::NewFrame()
|
|
|
|
|
|
g.NavIdTabCounter = INT_MAX;
|
|
|
|
|
|
- // Mark all windows as not visible
|
|
|
+ // Mark all windows as not visible and compact unused memory.
|
|
|
IM_ASSERT(g.WindowsFocusOrder.Size == g.Windows.Size);
|
|
|
+ const float memory_compact_start_time = (g.IO.ConfigWindowsMemoryCompactTimer > 0.0f) ? (float)g.Time - g.IO.ConfigWindowsMemoryCompactTimer : FLT_MAX;
|
|
|
for (int i = 0; i != g.Windows.Size; i++)
|
|
|
{
|
|
|
ImGuiWindow* window = g.Windows[i];
|
|
@@ -3823,6 +3859,10 @@ void ImGui::NewFrame()
|
|
|
window->BeginCount = 0;
|
|
|
window->Active = false;
|
|
|
window->WriteAccessed = false;
|
|
|
+
|
|
|
+ // Garbage collect (this is totally functional but we may need decide if the side-effects are desirable)
|
|
|
+ if (!window->WasActive && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time)
|
|
|
+ GcCompactTransientWindowBuffers(window);
|
|
|
}
|
|
|
|
|
|
// Closing the focused window restore focus to the first active root window in descending z-order
|
|
@@ -5391,6 +5431,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
|
{
|
|
|
window->Flags = (ImGuiWindowFlags)flags;
|
|
|
window->LastFrameActive = current_frame;
|
|
|
+ window->LastTimeActive = (float)g.Time;
|
|
|
window->BeginOrderWithinParent = 0;
|
|
|
window->BeginOrderWithinContext = (short)(g.WindowsActiveCount++);
|
|
|
}
|
|
@@ -5404,6 +5445,10 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
|
ImGuiWindow* parent_window = first_begin_of_the_frame ? ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)) ? parent_window_in_stack : NULL) : window->ParentWindow;
|
|
|
IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow));
|
|
|
|
|
|
+ // We allow window memory to be compacted so recreate the base stack when needed.
|
|
|
+ if (window->IDStack.Size == 0)
|
|
|
+ window->IDStack.push_back(window->ID);
|
|
|
+
|
|
|
// Add to stack
|
|
|
// We intentionally set g.CurrentWindow to NULL to prevent usage until when the viewport is set, then will call SetCurrentWindow()
|
|
|
g.CurrentWindowStack.push_back(window);
|
|
@@ -5468,6 +5513,10 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
|
window->ClipRect = ImVec4(-FLT_MAX,-FLT_MAX,+FLT_MAX,+FLT_MAX);
|
|
|
window->IDStack.resize(1);
|
|
|
|
|
|
+ // Restore buffer capacity when woken from a compacted state, to avoid
|
|
|
+ if (window->MemoryCompacted)
|
|
|
+ GcAwakeTransientWindowBuffers(window);
|
|
|
+
|
|
|
// Update stored window name when it changes (which can _only_ happen with the "###" operator, so the ID would stay unchanged).
|
|
|
// The title bar always display the 'name' parameter, so we only update the string storage if it needs to be visible to the end-user elsewhere.
|
|
|
bool window_title_visible_elsewhere = false;
|