Store common stacked settings contiguously in memory to reduce cache misses & unnecessary heap allocations

This commit is contained in:
ocornut 2015-05-27 15:35:49 +01:00
parent 3d36c81241
commit 0a7024c198

View File

@ -1091,7 +1091,7 @@ struct ImGuiDrawContext
ImVec2 CursorPos; ImVec2 CursorPos;
ImVec2 CursorPosPrevLine; ImVec2 CursorPosPrevLine;
ImVec2 CursorStartPos; ImVec2 CursorStartPos;
ImVec2 CursorMaxPos; // Implicitly calculate the size of our contents, always extending. Saved into window->SizeContents at the end of the frame ImVec2 CursorMaxPos; // Implicitly calculate the size of our contents, always extending. Saved into window->SizeContents at the end of the frame
float CurrentLineHeight; float CurrentLineHeight;
float CurrentLineTextBaseOffset; float CurrentLineTextBaseOffset;
float PrevLineHeight; float PrevLineHeight;
@ -1108,17 +1108,21 @@ struct ImGuiDrawContext
ImGuiStorage* StateStorage; ImGuiStorage* StateStorage;
ImGuiLayoutType LayoutType; ImGuiLayoutType LayoutType;
bool ButtonRepeat; // == ButtonRepeatStack.back() [false] // We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings.
bool ButtonRepeat; // == ButtonRepeatStack.back() [empty == false]
bool AllowKeyboardFocus; // == AllowKeyboardFocusStack.back() [empty == true]
float ItemWidth; // == ItemWidthStack.back(). 0.0: default, >0.0: width in pixels, <0.0: align xx pixels to the right of window
float TextWrapPos; // == TextWrapPosStack.back() [empty == -1.0f]
ImVector<bool> ButtonRepeatStack; ImVector<bool> ButtonRepeatStack;
ImVector<bool> AllowKeyboardFocus; ImVector<bool> AllowKeyboardFocusStack;
ImVector<float> ItemWidth; // 0.0: default, >0.0: width in pixels, <0.0: align xx pixels to the right of window ImVector<float> ItemWidthStack;
ImVector<float> TextWrapPos; ImVector<float> TextWrapPosStack;
ImVector<ImGuiGroupData> GroupStack; ImVector<ImGuiGroupData>GroupStack;
ImGuiColorEditMode ColorEditMode; ImGuiColorEditMode ColorEditMode;
int StackSizesBackup[6]; // Store size of various stacks for asserting int StackSizesBackup[6]; // Store size of various stacks for asserting
float ColumnsStartX; // Indentation / start position from left of window (increased by TreePush/TreePop, etc.) float ColumnsStartX; // Indentation / start position from left of window (increased by TreePush/TreePop, etc.)
float ColumnsOffsetX; // Offset to the current column (if ColumnsCurrent > 0). FIXME: This and the above should be a stack to allow use cases like Tree->Column->Tree. Need revamp columns API. float ColumnsOffsetX; // Offset to the current column (if ColumnsCurrent > 0). FIXME: This and the above should be a stack to allow use cases like Tree->Column->Tree. Need revamp columns API.
int ColumnsCurrent; int ColumnsCurrent;
int ColumnsCount; int ColumnsCount;
ImVec2 ColumnsStartPos; ImVec2 ColumnsStartPos;
@ -1126,7 +1130,7 @@ struct ImGuiDrawContext
float ColumnsCellMaxY; float ColumnsCellMaxY;
bool ColumnsShowBorders; bool ColumnsShowBorders;
ImGuiID ColumnsSetID; ImGuiID ColumnsSetID;
ImVector<float> ColumnsOffsetsT; // Columns offset normalized 0.0 (far left) -> 1.0 (far right) ImVector<float> ColumnsOffsetsT; // Columns offset normalized 0.0 (far left) -> 1.0 (far right)
ImGuiDrawContext() ImGuiDrawContext()
{ {
@ -1801,7 +1805,7 @@ bool ImGuiWindow::FocusItemRegister(bool is_active, bool tab_stop)
ImGuiState& g = *GImGui; ImGuiState& g = *GImGui;
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
const bool allow_keyboard_focus = window->DC.AllowKeyboardFocus.back(); const bool allow_keyboard_focus = window->DC.AllowKeyboardFocus;
FocusIdxAllCounter++; FocusIdxAllCounter++;
if (allow_keyboard_focus) if (allow_keyboard_focus)
FocusIdxTabCounter++; FocusIdxTabCounter++;
@ -3256,7 +3260,7 @@ void ImGui::EndChildFrame()
// Save and compare stack sizes on Begin()/End() to detect usage errors // Save and compare stack sizes on Begin()/End() to detect usage errors
static void CheckStacksSize(ImGuiWindow* window, bool write) static void CheckStacksSize(ImGuiWindow* window, bool write)
{ {
// NOT checking: DC.ItemWidth, DC.AllowKeyboardFocus, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin) // NOT checking: DC.ItemWidth, DC.AllowKeyboardFocus, DC.ButtonRepeat, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin)
ImGuiState& g = *GImGui; ImGuiState& g = *GImGui;
int* p_backup = &window->DC.StackSizesBackup[0]; int* p_backup = &window->DC.StackSizesBackup[0];
{ int current = (int)window->IDStack.size(); if (write) *p_backup = current; else IM_ASSERT(*p_backup == current); p_backup++; } // User forgot PopID() { int current = (int)window->IDStack.size(); if (write) *p_backup = current; else IM_ASSERT(*p_backup == current); p_backup++; } // User forgot PopID()
@ -3786,15 +3790,16 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
window->DC.MenuBarOffsetX = ImMax(window->DC.ColumnsStartX, style.ItemSpacing.x); window->DC.MenuBarOffsetX = ImMax(window->DC.ColumnsStartX, style.ItemSpacing.x);
window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f;
window->DC.ChildWindows.resize(0); window->DC.ChildWindows.resize(0);
window->DC.ItemWidth.resize(0);
window->DC.ItemWidth.push_back(window->ItemWidthDefault);
window->DC.LayoutType = ImGuiLayoutType_Vertical; window->DC.LayoutType = ImGuiLayoutType_Vertical;
window->DC.ItemWidthStack.resize(0);
window->DC.ItemWidthStack.push_back(window->ItemWidthDefault);
window->DC.ItemWidth = window->ItemWidthDefault;
window->DC.ButtonRepeat = false; window->DC.ButtonRepeat = false;
window->DC.ButtonRepeatStack.resize(0); window->DC.ButtonRepeatStack.resize(0);
window->DC.AllowKeyboardFocus.resize(0); window->DC.AllowKeyboardFocus = true;
window->DC.AllowKeyboardFocus.push_back(true); window->DC.AllowKeyboardFocusStack.resize(0);
window->DC.TextWrapPos.resize(0); window->DC.TextWrapPos = -1.0f; // disabled
window->DC.TextWrapPos.push_back(-1.0f); // disabled window->DC.TextWrapPosStack.resize(0);
window->DC.ColorEditMode = ImGuiColorEditMode_UserSelect; window->DC.ColorEditMode = ImGuiColorEditMode_UserSelect;
window->DC.ColumnsCurrent = 0; window->DC.ColumnsCurrent = 0;
window->DC.ColumnsCount = 1; window->DC.ColumnsCount = 1;
@ -4004,7 +4009,8 @@ static void FocusWindow(ImGuiWindow* window)
void ImGui::PushItemWidth(float item_width) void ImGui::PushItemWidth(float item_width)
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
window->DC.ItemWidth.push_back(item_width == 0.0f ? window->ItemWidthDefault : item_width); window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width);
window->DC.ItemWidthStack.push_back(window->DC.ItemWidth);
} }
static void PushMultiItemsWidths(int components, float w_full = 0.0f) static void PushMultiItemsWidths(int components, float w_full = 0.0f)
@ -4015,21 +4021,23 @@ static void PushMultiItemsWidths(int components, float w_full = 0.0f)
w_full = ImGui::CalcItemWidth(); w_full = ImGui::CalcItemWidth();
const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.FramePadding.x*2.0f + style.ItemInnerSpacing.x) * (components-1)) / (float)components)); const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.FramePadding.x*2.0f + style.ItemInnerSpacing.x) * (components-1)) / (float)components));
const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one + style.FramePadding.x*2.0f + style.ItemInnerSpacing.x) * (components-1))); const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one + style.FramePadding.x*2.0f + style.ItemInnerSpacing.x) * (components-1)));
window->DC.ItemWidth.push_back(w_item_last); window->DC.ItemWidthStack.push_back(w_item_last);
for (int i = 0; i < components-1; i++) for (int i = 0; i < components-1; i++)
window->DC.ItemWidth.push_back(w_item_one); window->DC.ItemWidthStack.push_back(w_item_one);
window->DC.ItemWidth = window->DC.ItemWidthStack.back();
} }
void ImGui::PopItemWidth() void ImGui::PopItemWidth()
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
window->DC.ItemWidth.pop_back(); window->DC.ItemWidthStack.pop_back();
window->DC.ItemWidth = window->DC.ItemWidthStack.back();
} }
float ImGui::CalcItemWidth() float ImGui::CalcItemWidth()
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
float w = window->DC.ItemWidth.back(); float w = window->DC.ItemWidth;
if (w < 0.0f) if (w < 0.0f)
{ {
// Align to a right-side limit. We include 1 frame padding in the calculation because this is how the width is always used (we add 2 frame padding to it), but we could move that responsibility to the widget as well. // Align to a right-side limit. We include 1 frame padding in the calculation because this is how the width is always used (we add 2 frame padding to it), but we could move that responsibility to the widget as well.
@ -4073,13 +4081,15 @@ void ImGui::PopFont()
void ImGui::PushAllowKeyboardFocus(bool allow_keyboard_focus) void ImGui::PushAllowKeyboardFocus(bool allow_keyboard_focus)
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
window->DC.AllowKeyboardFocus.push_back(allow_keyboard_focus); window->DC.AllowKeyboardFocus = allow_keyboard_focus;
window->DC.AllowKeyboardFocusStack.push_back(allow_keyboard_focus);
} }
void ImGui::PopAllowKeyboardFocus() void ImGui::PopAllowKeyboardFocus()
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
window->DC.AllowKeyboardFocus.pop_back(); window->DC.AllowKeyboardFocusStack.pop_back();
window->DC.AllowKeyboardFocus = window->DC.AllowKeyboardFocusStack.empty() ? true : window->DC.AllowKeyboardFocusStack.back();
} }
void ImGui::PushButtonRepeat(bool repeat) void ImGui::PushButtonRepeat(bool repeat)
@ -4096,16 +4106,18 @@ void ImGui::PopButtonRepeat()
window->DC.ButtonRepeat = window->DC.ButtonRepeatStack.empty() ? false : window->DC.ButtonRepeatStack.back(); window->DC.ButtonRepeat = window->DC.ButtonRepeatStack.empty() ? false : window->DC.ButtonRepeatStack.back();
} }
void ImGui::PushTextWrapPos(float wrap_x) void ImGui::PushTextWrapPos(float wrap_pos_x)
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
window->DC.TextWrapPos.push_back(wrap_x); window->DC.TextWrapPos = wrap_pos_x;
window->DC.TextWrapPosStack.push_back(wrap_pos_x);
} }
void ImGui::PopTextWrapPos() void ImGui::PopTextWrapPos()
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
window->DC.TextWrapPos.pop_back(); window->DC.TextWrapPosStack.pop_back();
window->DC.TextWrapPos = window->DC.TextWrapPosStack.back();
} }
void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col) void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col)
@ -4661,7 +4673,7 @@ void ImGui::TextUnformatted(const char* text, const char* text_end)
if (text_end == NULL) if (text_end == NULL)
text_end = text + strlen(text); // FIXME-OPT text_end = text + strlen(text); // FIXME-OPT
const float wrap_pos_x = window->DC.TextWrapPos.back(); const float wrap_pos_x = window->DC.TextWrapPos;
const bool wrap_enabled = wrap_pos_x >= 0.0f; const bool wrap_enabled = wrap_pos_x >= 0.0f;
if (text_end - text > 2000 && !wrap_enabled) if (text_end - text > 2000 && !wrap_enabled)
{ {