From b077de086e14291fe5f7cdf6d3564a8f1cfb9cb3 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Thu, 20 Aug 2020 20:17:00 +0200 Subject: Outliner: Avoid rebuilding tree on selection/active changes We can avoid the rather expensive outliner tree rebuilds and only redraw if nothing but the selection or active item changes. This should give a bit of speedup for heavy scenes. For this to work I had to correct a few notifiers, some were only sending selection/active change notifiers that actually did things like adding objects. I also added a more precise notifier type for when the active collection changes. At the notifier subtype/action level we're not even close to running out of bits, so this should be fine. Also had to correct a wrong notifier check (was using `&` rather than `==`). --- source/blender/editors/space_outliner/outliner_edit.c | 16 ++-------------- .../blender/editors/space_outliner/outliner_intern.h | 4 +++- .../blender/editors/space_outliner/outliner_select.c | 12 ++++++++---- source/blender/editors/space_outliner/outliner_tools.c | 1 + source/blender/editors/space_outliner/outliner_tree.c | 10 ++++------ source/blender/editors/space_outliner/outliner_utils.c | 18 ++++++++++++++++++ source/blender/editors/space_outliner/space_outliner.c | 18 ++++++++++++++---- 7 files changed, 50 insertions(+), 29 deletions(-) (limited to 'source/blender/editors/space_outliner') diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index cd2fcd8e2cf..8567dd4da13 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -193,13 +193,7 @@ static int outliner_item_openclose_modal(bContext *C, wmOperator *op, const wmEv if (te->xs == data->x_location) { outliner_item_openclose(te, data->open, false); - /* Avoid rebuild if possible. */ - if (outliner_element_needs_rebuild_on_open_change(TREESTORE(te))) { - ED_region_tag_redraw(region); - } - else { - ED_region_tag_redraw_no_rebuild(region); - } + outliner_tag_redraw_avoid_rebuild_on_open_change(space_outliner, region); } } @@ -239,13 +233,7 @@ static int outliner_item_openclose_invoke(bContext *C, wmOperator *op, const wmE (toggle_all && (outliner_flag_is_any_test(&te->subtree, TSE_CLOSED, 1))); outliner_item_openclose(te, open, toggle_all); - /* Avoid rebuild if possible. */ - if (outliner_element_needs_rebuild_on_open_change(TREESTORE(te))) { - ED_region_tag_redraw(region); - } - else { - ED_region_tag_redraw_no_rebuild(region); - } + outliner_tag_redraw_avoid_rebuild_on_open_change(space_outliner, region); /* Only toggle once for single click toggling */ if (event->type == LEFTMOUSE) { diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index 33dbbb274c0..9795bb73efe 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -237,7 +237,7 @@ void outliner_build_tree(struct Main *mainvar, struct SpaceOutliner *space_outliner, struct ARegion *region); -bool outliner_element_needs_rebuild_on_open_change(const TreeStoreElem *tselem); +bool outliner_mode_requires_always_rebuild(const struct SpaceOutliner *space_outliner); typedef struct IDsSelectedData { struct ListBase selected_array; @@ -515,6 +515,8 @@ float outliner_restrict_columns_width(const struct SpaceOutliner *space_outliner TreeElement *outliner_find_element_with_flag(const ListBase *lb, short flag); bool outliner_is_element_visible(const TreeElement *te); void outliner_scroll_view(struct ARegion *region, int delta_y); +void outliner_tag_redraw_avoid_rebuild_on_open_change(const struct SpaceOutliner *space_outliner, + struct ARegion *region); /* outliner_sync.c ---------------------------------------------- */ diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index 1ac1b46f0d1..d720747e953 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -1000,7 +1000,9 @@ static eOLDrawState tree_element_active_master_collection(bContext *C, ViewLayer *view_layer = CTX_data_view_layer(C); LayerCollection *layer_collection = view_layer->layer_collections.first; BKE_layer_collection_activate(view_layer, layer_collection); - WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + /* A very precise notifier - ND_LAYER alone is quite vague, we want to avoid unnecessary work + * when only the active collection changes. */ + WM_main_add_notifier(NC_SCENE | ND_LAYER | NS_LAYER_COLLECTION | NA_ACTIVATED, NULL); } return OL_DRAWSEL_NONE; @@ -1022,7 +1024,9 @@ static eOLDrawState tree_element_active_layer_collection(bContext *C, LayerCollection *layer_collection = te->directdata; ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, layer_collection); BKE_layer_collection_activate(view_layer, layer_collection); - WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + /* A very precise notifier - ND_LAYER alone is quite vague, we want to avoid unnecessary work + * when only the active collection changes. */ + WM_main_add_notifier(NC_SCENE | ND_LAYER | NS_LAYER_COLLECTION | NA_ACTIVATED, NULL); } return OL_DRAWSEL_NONE; @@ -1507,7 +1511,7 @@ static int outliner_box_select_exec(bContext *C, wmOperator *op) DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - ED_region_tag_redraw(region); + ED_region_tag_redraw_no_rebuild(region); ED_outliner_select_sync_from_outliner(C, space_outliner); @@ -1729,7 +1733,7 @@ static int outliner_walk_select_invoke(bContext *C, wmOperator *op, const wmEven outliner_walk_scroll(region, active_te); ED_outliner_select_sync_from_outliner(C, space_outliner); - ED_region_tag_redraw(region); + outliner_tag_redraw_avoid_rebuild_on_open_change(space_outliner, region); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 4b037327038..2a13f9d6a66 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -1630,6 +1630,7 @@ static int outliner_delete_exec(bContext *C, wmOperator *op) DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene); ED_outliner_select_sync_from_object_tag(C); return OPERATOR_FINISHED; diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 60058c82283..9e3cbabf283 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -244,14 +244,12 @@ static TreeElement *outliner_add_element(SpaceOutliner *space_outliner, /* -------------------------------------------------------- */ /** - * Check if an element type needs a full rebuild if the open/collapsed state changes. - * These element types don't add children if collapsed. - * - * This current check isn't great really. A per element-type flag would be preferable. + * Check if a display mode needs a full rebuild if the open/collapsed state changes. + * Element types in these modes don't actually add children if collapsed, so the rebuild is needed. */ -bool outliner_element_needs_rebuild_on_open_change(const TreeStoreElem *tselem) +bool outliner_mode_requires_always_rebuild(const SpaceOutliner *space_outliner) { - return ELEM(tselem->type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_KEYMAP); + return ELEM(space_outliner->outlinevis, SO_DATA_API); } /* special handling of hierarchical non-lib data */ diff --git a/source/blender/editors/space_outliner/outliner_utils.c b/source/blender/editors/space_outliner/outliner_utils.c index 1da44b5e51e..25dc7bc271e 100644 --- a/source/blender/editors/space_outliner/outliner_utils.c +++ b/source/blender/editors/space_outliner/outliner_utils.c @@ -37,6 +37,7 @@ #include "ED_armature.h" #include "ED_outliner.h" +#include "ED_screen.h" #include "UI_interface.h" #include "UI_view2d.h" @@ -455,6 +456,23 @@ void outliner_scroll_view(ARegion *region, int delta_y) } } +/** + * The outliner should generally use #ED_region_tag_redraw_no_rebuild() to avoid unnecessary tree + * rebuilds. If elements are open or closed, we may still have to rebuild. + * Upon changing the open/closed state, call this to avoid rebuilds if possible. + */ +void outliner_tag_redraw_avoid_rebuild_on_open_change(const SpaceOutliner *space_outliner, + ARegion *region) +{ + /* Avoid rebuild if possible. */ + if (outliner_mode_requires_always_rebuild(space_outliner)) { + ED_region_tag_redraw(region); + } + else { + ED_region_tag_redraw_no_rebuild(region); + } +} + /* Get base of object under cursor. Used for eyedropper tool */ Base *ED_outliner_give_base_under_cursor(bContext *C, const int mval[2]) { diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index b14afed81dd..6854367d975 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -114,6 +114,8 @@ static void outliner_main_region_listener(wmWindow *UNUSED(win), switch (wmn->data) { case ND_OB_ACTIVE: case ND_OB_SELECT: + ED_region_tag_redraw_no_rebuild(region); + break; case ND_OB_VISIBLE: case ND_OB_RENDER: case ND_MODE: @@ -121,15 +123,23 @@ static void outliner_main_region_listener(wmWindow *UNUSED(win), case ND_FRAME: case ND_RENDER_OPTIONS: case ND_SEQUENCER: - case ND_LAYER: case ND_LAYER_CONTENT: case ND_WORLD: case ND_SCENEBROWSE: + ED_region_tag_redraw(region); + break; + case ND_LAYER: + /* Avoid rebuild if only the active collection changes */ + if ((wmn->subtype == NS_LAYER_COLLECTION) && (wmn->action == NA_ACTIVATED)) { + ED_region_tag_redraw_no_rebuild(region); + break; + } + ED_region_tag_redraw(region); break; } - if (wmn->action & NA_EDITED) { - ED_region_tag_redraw(region); + if (wmn->action == NA_EDITED) { + ED_region_tag_redraw_no_rebuild(region); } break; case NC_OBJECT: @@ -181,7 +191,7 @@ static void outliner_main_region_listener(wmWindow *UNUSED(win), case NC_MATERIAL: switch (wmn->data) { case ND_SHADING_LINKS: - ED_region_tag_redraw(region); + ED_region_tag_redraw_no_rebuild(region); break; } break; -- cgit v1.2.3