GUI: Fix `Tree` performance regression by using cache

This commit is contained in:
Danil Alexeev 2023-07-11 11:58:19 +03:00
parent eb4301b941
commit 5fb975e4a5
No known key found for this signature in database
GPG Key ID: 124453E157DA8DC7
2 changed files with 57 additions and 39 deletions

View File

@ -1923,6 +1923,7 @@ void Tree::update_column(int p_col) {
} }
columns.write[p_col].text_buf->add_string(columns[p_col].title, theme_cache.font, theme_cache.font_size, columns[p_col].language); columns.write[p_col].text_buf->add_string(columns[p_col].title, theme_cache.font, theme_cache.font_size, columns[p_col].language);
columns.write[p_col].cached_minimum_width_dirty = true;
} }
void Tree::update_item_cell(TreeItem *p_item, int p_col) { void Tree::update_item_cell(TreeItem *p_item, int p_col) {
@ -2015,7 +2016,7 @@ void Tree::update_item_cache(TreeItem *p_item) {
} }
} }
int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 &p_draw_size, TreeItem *p_item, int *r_self_height) { int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 &p_draw_size, TreeItem *p_item, int &r_self_height) {
if (p_pos.y - theme_cache.offset.y > (p_draw_size.height)) { if (p_pos.y - theme_cache.offset.y > (p_draw_size.height)) {
return -1; //draw no more! return -1; //draw no more!
} }
@ -2097,11 +2098,12 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
p_item->cells.write[i].text_buf->set_width(item_width); p_item->cells.write[i].text_buf->set_width(item_width);
label_h = compute_item_height(p_item); r_self_height = compute_item_height(p_item);
if (r_self_height != nullptr) { label_h = r_self_height + theme_cache.v_separation;
*r_self_height = label_h;
if (p_pos.y + label_h - theme_cache.offset.y < 0) {
continue; // No need to draw.
} }
label_h += theme_cache.v_separation;
Rect2i item_rect = Rect2i(Point2i(ofs, p_pos.y) - theme_cache.offset + p_draw_ofs, Size2i(item_width, label_h)); Rect2i item_rect = Rect2i(Point2i(ofs, p_pos.y) - theme_cache.offset + p_draw_ofs, Size2i(item_width, label_h));
Rect2i cell_rect = item_rect; Rect2i cell_rect = item_rect;
@ -2450,7 +2452,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
int child_h = -1; int child_h = -1;
int child_self_height = 0; int child_self_height = 0;
if (htotal >= 0) { if (htotal >= 0) {
child_h = draw_item(children_pos, p_draw_ofs, p_draw_size, c, &child_self_height); child_h = draw_item(children_pos, p_draw_ofs, p_draw_size, c, child_self_height);
child_self_height += theme_cache.v_separation; child_self_height += theme_cache.v_separation;
} }
@ -4232,7 +4234,8 @@ void Tree::_notification(int p_what) {
cache.rtl = is_layout_rtl(); cache.rtl = is_layout_rtl();
if (root && get_size().x > 0 && get_size().y > 0) { if (root && get_size().x > 0 && get_size().y > 0) {
draw_item(Point2(), draw_ofs, draw_size, root); int self_height = 0; // Just to pass a reference, we don't need the root's `self_height`.
draw_item(Point2(), draw_ofs, draw_size, root, self_height);
} }
if (show_column_titles) { if (show_column_titles) {
@ -4250,6 +4253,7 @@ void Tree::_notification(int p_what) {
//text //text
int clip_w = tbrect.size.width - sb->get_minimum_size().width; int clip_w = tbrect.size.width - sb->get_minimum_size().width;
columns.write[i].text_buf->set_width(clip_w); columns.write[i].text_buf->set_width(clip_w);
columns.write[i].cached_minimum_width_dirty = true;
Vector2 text_pos = Point2i(tbrect.position.x, tbrect.position.y + (tbrect.size.height - columns[i].text_buf->get_size().y) / 2); Vector2 text_pos = Point2i(tbrect.position.x, tbrect.position.y + (tbrect.size.height - columns[i].text_buf->get_size().y) / 2);
switch (columns[i].title_alignment) { switch (columns[i].title_alignment) {
@ -4387,6 +4391,7 @@ void Tree::item_edited(int p_column, TreeItem *p_item, MouseButton p_custom_mous
void Tree::item_changed(int p_column, TreeItem *p_item) { void Tree::item_changed(int p_column, TreeItem *p_item) {
if (p_item != nullptr && p_column >= 0 && p_column < p_item->cells.size()) { if (p_item != nullptr && p_column >= 0 && p_column < p_item->cells.size()) {
p_item->cells.write[p_column].dirty = true; p_item->cells.write[p_column].dirty = true;
columns.write[p_column].cached_minimum_width_dirty = true;
} }
queue_redraw(); queue_redraw();
} }
@ -4518,6 +4523,7 @@ void Tree::set_column_custom_minimum_width(int p_column, int p_min_width) {
return; return;
} }
columns.write[p_column].custom_min_width = p_min_width; columns.write[p_column].custom_min_width = p_min_width;
columns.write[p_column].cached_minimum_width_dirty = true;
queue_redraw(); queue_redraw();
} }
@ -4529,6 +4535,7 @@ void Tree::set_column_expand(int p_column, bool p_expand) {
} }
columns.write[p_column].expand = p_expand; columns.write[p_column].expand = p_expand;
columns.write[p_column].cached_minimum_width_dirty = true;
queue_redraw(); queue_redraw();
} }
@ -4540,6 +4547,7 @@ void Tree::set_column_expand_ratio(int p_column, int p_ratio) {
} }
columns.write[p_column].expand_ratio = p_ratio; columns.write[p_column].expand_ratio = p_ratio;
columns.write[p_column].cached_minimum_width_dirty = true;
queue_redraw(); queue_redraw();
} }
@ -4551,6 +4559,7 @@ void Tree::set_column_clip_content(int p_column, bool p_fit) {
} }
columns.write[p_column].clip_content = p_fit; columns.write[p_column].clip_content = p_fit;
columns.write[p_column].cached_minimum_width_dirty = true;
queue_redraw(); queue_redraw();
} }
@ -4633,6 +4642,7 @@ TreeItem *Tree::get_next_selected(TreeItem *p_item) {
int Tree::get_column_minimum_width(int p_column) const { int Tree::get_column_minimum_width(int p_column) const {
ERR_FAIL_INDEX_V(p_column, columns.size(), -1); ERR_FAIL_INDEX_V(p_column, columns.size(), -1);
if (columns[p_column].cached_minimum_width_dirty) {
// Use the custom minimum width. // Use the custom minimum width.
int min_width = columns[p_column].custom_min_width; int min_width = columns[p_column].custom_min_width;
@ -4672,7 +4682,11 @@ int Tree::get_column_minimum_width(int p_column) const {
} }
} }
return min_width; columns.get(p_column).cached_minimum_width = min_width;
columns.get(p_column).cached_minimum_width_dirty = false;
}
return columns[p_column].cached_minimum_width;
} }
int Tree::get_column_width(int p_column) const { int Tree::get_column_width(int p_column) const {

View File

@ -452,6 +452,10 @@ private:
Ref<TextParagraph> text_buf; Ref<TextParagraph> text_buf;
String language; String language;
Control::TextDirection text_direction = Control::TEXT_DIRECTION_INHERITED; Control::TextDirection text_direction = Control::TEXT_DIRECTION_INHERITED;
mutable int cached_minimum_width = 0;
mutable bool cached_minimum_width_dirty = true;
ColumnInfo() { ColumnInfo() {
text_buf.instantiate(); text_buf.instantiate();
} }
@ -484,7 +488,7 @@ private:
void update_item_cache(TreeItem *p_item); void update_item_cache(TreeItem *p_item);
//void draw_item_text(String p_text,const Ref<Texture2D>& p_icon,int p_icon_max_w,bool p_tool,Rect2i p_rect,const Color& p_color); //void draw_item_text(String p_text,const Ref<Texture2D>& p_icon,int p_icon_max_w,bool p_tool,Rect2i p_rect,const Color& p_color);
void draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Color &p_color, const Color &p_icon_color, int p_ol_size, const Color &p_ol_color); void draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Color &p_color, const Color &p_icon_color, int p_ol_size, const Color &p_ol_color);
int draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 &p_draw_size, TreeItem *p_item, int *r_self_height = nullptr); int draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 &p_draw_size, TreeItem *p_item, int &r_self_height);
void select_single_item(TreeItem *p_selected, TreeItem *p_current, int p_col, TreeItem *p_prev = nullptr, bool *r_in_range = nullptr, bool p_force_deselect = false); void select_single_item(TreeItem *p_selected, TreeItem *p_current, int p_col, TreeItem *p_prev = nullptr, bool *r_in_range = nullptr, bool p_force_deselect = false);
int propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int x_limit, bool p_double_click, TreeItem *p_item, MouseButton p_button, const Ref<InputEventWithModifiers> &p_mod); int propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int x_limit, bool p_double_click, TreeItem *p_item, MouseButton p_button, const Ref<InputEventWithModifiers> &p_mod);
void _line_editor_submit(String p_text); void _line_editor_submit(String p_text);