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

This commit is contained in:
ocornut 2020-11-03 11:25:36 +01:00
parent f80097ca96
commit e5a5256971
3 changed files with 80 additions and 4 deletions

View File

@ -2952,6 +2952,7 @@ void ImGui::GcCompactTransientMiscBuffers()
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
g.ItemFlagsStack.clear(); g.ItemFlagsStack.clear();
g.GroupStack.clear(); g.GroupStack.clear();
TableGcCompactSettings();
} }
// Free up/compact internal window buffers, we can use this when a window becomes unused. // 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) if (!window->WasActive && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time)
GcCompactTransientWindowBuffers(window); 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) if (g.GcCompactAll)
GcCompactTransientMiscBuffers(); GcCompactTransientMiscBuffers();
g.GcCompactAll = false; g.GcCompactAll = false;

View File

@ -597,6 +597,8 @@ struct IMGUI_API ImChunkStream
T* end() { return (T*)(void*)(Buf.Data + Buf.Size); } 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; } 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); } 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; ImGuiTable* CurrentTable;
ImPool<ImGuiTable> Tables; ImPool<ImGuiTable> Tables;
ImVector<ImGuiPtrOrIndex> CurrentTableStack; ImVector<ImGuiPtrOrIndex> CurrentTableStack;
ImVector<float> TablesLastTimeActive; // Last used timestamp of each tables (SOA, for efficient GC)
ImVector<ImDrawChannel> DrawChannelsTempMergeBuffer; ImVector<ImDrawChannel> DrawChannelsTempMergeBuffer;
// Tab bars // Tab bars
@ -2040,6 +2043,7 @@ struct ImGuiTable
bool IsDefaultDisplayOrder; // Set when display order is unchanged from default (DisplayOrder contains 0...Count-1) bool IsDefaultDisplayOrder; // Set when display order is unchanged from default (DisplayOrder contains 0...Count-1)
bool IsResetDisplayOrderRequest; bool IsResetDisplayOrderRequest;
bool IsUnfrozen; // Set when we got past the frozen row. 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 bool HostSkipItems; // Backup of InnerWindow->SkipItem at the end of BeginTable(), because we will overwrite InnerWindow->SkipItem on a per-column basis
ImGuiTable() ImGuiTable()
@ -2266,7 +2270,7 @@ namespace ImGui
IMGUI_API float GetColumnNormFromOffset(const ImGuiOldColumns* columns, float offset); IMGUI_API float GetColumnNormFromOffset(const ImGuiOldColumns* columns, float offset);
// Tables // 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 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 TableBeginUpdateColumns(ImGuiTable* table);
IMGUI_API void TableUpdateDrawChannels(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 TableSetColumnAutofit(ImGuiTable* table, int column_n);
IMGUI_API void PushTableBackground(); IMGUI_API void PushTableBackground();
IMGUI_API void PopTableBackground(); IMGUI_API void PopTableBackground();
IMGUI_API void TableRemove(ImGuiTable* table);
IMGUI_API void TableGcCompactTransientBuffers(ImGuiTable* table);
IMGUI_API void TableGcCompactSettings();
// Tables: Settings // Tables: Settings
IMGUI_API void TableLoadSettings(ImGuiTable* table); IMGUI_API void TableLoadSettings(ImGuiTable* table);

View File

@ -134,7 +134,7 @@ inline ImGuiTableFlags TableFixFlags(ImGuiTableFlags flags, ImGuiWindow* outer_w
return flags; return flags;
} }
ImGuiTable* ImGui::FindTableByID(ImGuiID id) ImGuiTable* ImGui::TableFindByID(ImGuiID id)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
return g.Tables.GetByKey(id); 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; outer_window->DC.CurrentTableIdx = table_idx;
if (inner_window != outer_window) // So EndChild() within the inner window can restore the table properly. if (inner_window != outer_window) // So EndChild() within the inner window can restore the table properly.
inner_window->DC.CurrentTableIdx = table_idx; inner_window->DC.CurrentTableIdx = table_idx;
if ((table_last_flags & ImGuiTableFlags_Reorderable) && (flags & ImGuiTableFlags_Reorderable) == 0) if ((table_last_flags & ImGuiTableFlags_Reorderable) && (flags & ImGuiTableFlags_Reorderable) == 0)
table->IsResetDisplayOrderRequest = true; 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) // Setup memory buffer (clear data if columns count changed)
const int stored_size = table->Columns.size(); const int stored_size = table->Columns.size();
if (stored_size != 0 && stored_size != columns_count) if (stored_size != 0 && stored_size != columns_count)
@ -2573,10 +2580,15 @@ static void InitTableSettings(ImGuiTableSettings* settings, ImGuiID id, int colu
settings->WantApply = true; 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) ImGuiTableSettings* ImGui::TableSettingsCreate(ImGuiID id, int columns_count)
{ {
ImGuiContext& g = *GImGui; 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); InitTableSettings(settings, id, columns_count, columns_count);
return settings; return settings;
} }
@ -2759,7 +2771,7 @@ static void* TableSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*,
InitTableSettings(settings, id, columns_count, settings->ColumnsCountMax); // Recycle InitTableSettings(settings, id, columns_count, settings->ColumnsCountMax); // Recycle
return settings; 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); return ImGui::TableSettingsCreate(id, columns_count);
} }
@ -2842,6 +2854,57 @@ void ImGui::TableSettingsInstallHandler(ImGuiContext* context)
g.SettingsHandlers.push_back(ini_handler); 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 // TABLE - Debugging
//------------------------------------------------------------------------- //-------------------------------------------------------------------------