2
0
Эх сурвалжийг харах

Tables: Garbage collection to relieve draw splitter buffers + for test engine: compact settings, remove table.

ocornut 4 жил өмнө
parent
commit
e5a5256971
3 өөрчлөгдсөн 80 нэмэгдсэн , 4 устгасан
  1. 6 0
      imgui.cpp
  2. 8 1
      imgui_internal.h
  3. 66 3
      imgui_tables.cpp

+ 6 - 0
imgui.cpp

@@ -2952,6 +2952,7 @@ void ImGui::GcCompactTransientMiscBuffers()
     ImGuiContext& g = *GImGui;
     g.ItemFlagsStack.clear();
     g.GroupStack.clear();
+    TableGcCompactSettings();
 }
 
 // Free up/compact internal window buffers, we can use this when a window becomes unused.
@@ -3906,6 +3907,11 @@ void ImGui::NewFrame()
         if (!window->WasActive && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time)
             GcCompactTransientWindowBuffers(window);
     }
+
+    // Garbage collect transient buffers of recently unused tables
+    for (int i = 0; i < g.TablesLastTimeActive.Size; i++)
+        if (g.TablesLastTimeActive[i] >= 0.0f && g.TablesLastTimeActive[i] < memory_compact_start_time)
+            TableGcCompactTransientBuffers(g.Tables.GetByIndex(i));
     if (g.GcCompactAll)
         GcCompactTransientMiscBuffers();
     g.GcCompactAll = false;

+ 8 - 1
imgui_internal.h

@@ -597,6 +597,8 @@ struct IMGUI_API ImChunkStream
     T*      end()                       { return (T*)(void*)(Buf.Data + Buf.Size); }
     int     offset_from_ptr(const T* p) { IM_ASSERT(p >= begin() && p < end()); const ptrdiff_t off = (const char*)p - Buf.Data; return (int)off; }
     T*      ptr_from_offset(int off)    { IM_ASSERT(off >= 4 && off < Buf.Size); return (T*)(void*)(Buf.Data + off); }
+    void    swap(ImChunkStream<T>& rhs) { rhs.Buf.swap(Buf); }
+
 };
 
 //-----------------------------------------------------------------------------
@@ -1401,6 +1403,7 @@ struct ImGuiContext
     ImGuiTable*                     CurrentTable;
     ImPool<ImGuiTable>              Tables;
     ImVector<ImGuiPtrOrIndex>       CurrentTableStack;
+    ImVector<float>                 TablesLastTimeActive;       // Last used timestamp of each tables (SOA, for efficient GC)
     ImVector<ImDrawChannel>         DrawChannelsTempMergeBuffer;
 
     // Tab bars
@@ -2040,6 +2043,7 @@ struct ImGuiTable
     bool                        IsDefaultDisplayOrder;      // Set when display order is unchanged from default (DisplayOrder contains 0...Count-1)
     bool                        IsResetDisplayOrderRequest;
     bool                        IsUnfrozen;                 // Set when we got past the frozen row.
+    bool                        MemoryCompacted;
     bool                        HostSkipItems;              // Backup of InnerWindow->SkipItem at the end of BeginTable(), because we will overwrite InnerWindow->SkipItem on a per-column basis
 
     ImGuiTable()
@@ -2266,7 +2270,7 @@ namespace ImGui
     IMGUI_API float         GetColumnNormFromOffset(const ImGuiOldColumns* columns, float offset);
 
     // Tables
-    IMGUI_API ImGuiTable*   FindTableByID(ImGuiID id);
+    IMGUI_API ImGuiTable*   TableFindByID(ImGuiID id);
     IMGUI_API bool          BeginTableEx(const char* name, ImGuiID id, int columns_count, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0, 0), float inner_width = 0.0f);
     IMGUI_API void          TableBeginUpdateColumns(ImGuiTable* table);
     IMGUI_API void          TableUpdateDrawChannels(ImGuiTable* table);
@@ -2291,6 +2295,9 @@ namespace ImGui
     IMGUI_API void          TableSetColumnAutofit(ImGuiTable* table, int column_n);
     IMGUI_API void          PushTableBackground();
     IMGUI_API void          PopTableBackground();
+    IMGUI_API void          TableRemove(ImGuiTable* table);
+    IMGUI_API void          TableGcCompactTransientBuffers(ImGuiTable* table);
+    IMGUI_API void          TableGcCompactSettings();
 
     // Tables: Settings
     IMGUI_API void                  TableLoadSettings(ImGuiTable* table);

+ 66 - 3
imgui_tables.cpp

@@ -134,7 +134,7 @@ inline ImGuiTableFlags TableFixFlags(ImGuiTableFlags flags, ImGuiWindow* outer_w
     return flags;
 }
 
-ImGuiTable* ImGui::FindTableByID(ImGuiID id)
+ImGuiTable* ImGui::TableFindByID(ImGuiID id)
 {
     ImGuiContext& g = *GImGui;
     return g.Tables.GetByKey(id);
@@ -342,9 +342,16 @@ bool    ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
     outer_window->DC.CurrentTableIdx = table_idx;
     if (inner_window != outer_window) // So EndChild() within the inner window can restore the table properly.
         inner_window->DC.CurrentTableIdx = table_idx;
+
     if ((table_last_flags & ImGuiTableFlags_Reorderable) && (flags & ImGuiTableFlags_Reorderable) == 0)
         table->IsResetDisplayOrderRequest = true;
 
+    // Mark as used
+    if (table_idx >= g.TablesLastTimeActive.Size)
+        g.TablesLastTimeActive.resize(table_idx + 1, -1.0f);
+    g.TablesLastTimeActive[table_idx] = (float)g.Time;
+    table->MemoryCompacted = false;
+
     // Setup memory buffer (clear data if columns count changed)
     const int stored_size = table->Columns.size();
     if (stored_size != 0 && stored_size != columns_count)
@@ -2573,10 +2580,15 @@ static void InitTableSettings(ImGuiTableSettings* settings, ImGuiID id, int colu
     settings->WantApply = true;
 }
 
+static size_t TableSettingsCalcChunkSize(int columns_count)
+{
+    return sizeof(ImGuiTableSettings) + (size_t)columns_count * sizeof(ImGuiTableColumnSettings);
+}
+
 ImGuiTableSettings* ImGui::TableSettingsCreate(ImGuiID id, int columns_count)
 {
     ImGuiContext& g = *GImGui;
-    ImGuiTableSettings* settings = g.SettingsTables.alloc_chunk(sizeof(ImGuiTableSettings) + (size_t)columns_count * sizeof(ImGuiTableColumnSettings));
+    ImGuiTableSettings* settings = g.SettingsTables.alloc_chunk(TableSettingsCalcChunkSize(columns_count));
     InitTableSettings(settings, id, columns_count, columns_count);
     return settings;
 }
@@ -2759,7 +2771,7 @@ static void* TableSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*,
             InitTableSettings(settings, id, columns_count, settings->ColumnsCountMax); // Recycle
             return settings;
         }
-        settings->ID = 0; // Invalidate storage if we won't fit because of a count change
+        settings->ID = 0; // Invalidate storage, we won't fit because of a count change
     }
     return ImGui::TableSettingsCreate(id, columns_count);
 }
@@ -2842,6 +2854,57 @@ void    ImGui::TableSettingsInstallHandler(ImGuiContext* context)
     g.SettingsHandlers.push_back(ini_handler);
 }
 
+//-------------------------------------------------------------------------
+// TABLE - Garbage Collection
+//-------------------------------------------------------------------------
+
+// Remove Table (currently only used by TestEngine)
+void    ImGui::TableRemove(ImGuiTable* table)
+{
+    //IMGUI_DEBUG_LOG("TableRemove() id=0x%08X\n", table->ID);
+    ImGuiContext& g = *GImGui;
+    int table_idx = g.Tables.GetIndex(table);
+    //memset(table->RawData.Data, 0, table->RawData.size_in_bytes());
+    //memset(table, 0, sizeof(ImGuiTable));
+    g.Tables.Remove(table->ID, table);
+    g.TablesLastTimeActive[table_idx] = -1.0f;
+}
+
+// Free up/compact internal Table buffers for when it gets unused
+void    ImGui::TableGcCompactTransientBuffers(ImGuiTable* table)
+{
+    //IMGUI_DEBUG_LOG("TableGcCompactTransientBuffers() id=0x%08X\n", table->ID);
+    ImGuiContext& g = *GImGui;
+    IM_ASSERT(table->MemoryCompacted == false);
+    table->DrawSplitter.ClearFreeMemory();
+    table->SortSpecsData.clear();
+    table->SortSpecs.Specs = NULL;
+    table->IsSortSpecsDirty = true;
+    table->ColumnsNames.clear();
+    table->MemoryCompacted = true;
+    for (int n = 0; n < table->ColumnsCount; n++)
+        table->Columns[n].NameOffset = -1;
+    g.TablesLastTimeActive[g.Tables.GetIndex(table)] = -1.0f;
+}
+
+// Compact and remove unused settings data (currently only used by TestEngine)
+void ImGui::TableGcCompactSettings()
+{
+    ImGuiContext& g = *GImGui;
+    int required_memory = 0;
+    for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings))
+        if (settings->ID != 0)
+            required_memory += (int)TableSettingsCalcChunkSize(settings->ColumnsCount);
+    if (required_memory == g.SettingsTables.Buf.Size)
+        return;
+    ImChunkStream<ImGuiTableSettings> new_chunk_stream;
+    new_chunk_stream.Buf.reserve(required_memory);
+    for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings))
+        if (settings->ID != 0)
+            memcpy(new_chunk_stream.alloc_chunk(TableSettingsCalcChunkSize(settings->ColumnsCount)), settings, TableSettingsCalcChunkSize(settings->ColumnsCount));
+    g.SettingsTables.swap(new_chunk_stream);
+}
+
 //-------------------------------------------------------------------------
 // TABLE - Debugging
 //-------------------------------------------------------------------------