Fix random crashes in the outliner, especially with bigger scenes.

The outliner can redraw quicker without rebuilding the tree, for example when
just moving the mouse and highlighting different items. The way this worked is
that the outliner would be tagged to avoid rebuilding, however if another
operation that does require rebuilding happens in the meantime we could go out
of sync and crash.
This commit is contained in:
Brecht Van Lommel 2018-05-15 12:49:38 +02:00
parent 8021ac986a
commit 3f20105622
12 changed files with 46 additions and 42 deletions

View File

@ -74,6 +74,7 @@ void ED_region_init(struct bContext *C, struct ARegion *ar);
void ED_region_tag_redraw(struct ARegion *ar);
void ED_region_tag_redraw_partial(struct ARegion *ar, const struct rcti *rct);
void ED_region_tag_redraw_overlay(struct ARegion *ar);
void ED_region_tag_redraw_no_rebuild(struct ARegion *ar);
void ED_region_tag_refresh_ui(struct ARegion *ar);
void ED_region_panels_init(struct wmWindowManager *wm, struct ARegion *ar);
void ED_region_panels(

View File

@ -169,18 +169,19 @@ static void view_pan_apply_ex(bContext *C, v2dViewPanData *vpd, float dx, float
/* validate that view is in valid configuration after this operation */
UI_view2d_curRect_validate(v2d);
/* request updates to be done... */
ED_region_tag_redraw(vpd->ar);
WM_event_add_mousemove(C);
UI_view2d_sync(vpd->sc, vpd->sa, v2d, V2D_LOCK_COPY);
/* exceptions */
if (vpd->sa->spacetype == SPACE_OUTLINER) {
/* don't rebuild full tree, since we're just changing our view */
SpaceOops *soops = vpd->sa->spacedata.first;
soops->storeflag |= SO_TREESTORE_REDRAW;
ED_region_tag_redraw_no_rebuild(vpd->ar);
}
else {
ED_region_tag_redraw(vpd->ar);
}
/* request updates to be done... */
WM_event_add_mousemove(C);
UI_view2d_sync(vpd->sc, vpd->sa, v2d, V2D_LOCK_COPY);
}
static void view_pan_apply(bContext *C, wmOperator *op)

View File

@ -550,7 +550,7 @@ void ED_region_tag_redraw(ARegion *ar)
* but python scripts can cause this to happen indirectly */
if (ar && !(ar->do_draw & RGN_DRAWING)) {
/* zero region means full region redraw */
ar->do_draw &= ~RGN_DRAW_PARTIAL;
ar->do_draw &= ~(RGN_DRAW_PARTIAL | RGN_DRAW_NO_REBUILD);
ar->do_draw |= RGN_DRAW;
memset(&ar->drawrct, 0, sizeof(ar->drawrct));
}
@ -562,6 +562,15 @@ void ED_region_tag_redraw_overlay(ARegion *ar)
ar->do_draw_overlay = RGN_DRAW;
}
void ED_region_tag_redraw_no_rebuild(ARegion *ar)
{
if (ar && !(ar->do_draw & (RGN_DRAWING | RGN_DRAW))) {
ar->do_draw &= ~RGN_DRAW_PARTIAL;
ar->do_draw |= RGN_DRAW_NO_REBUILD;
memset(&ar->drawrct, 0, sizeof(ar->drawrct));
}
}
void ED_region_tag_refresh_ui(ARegion *ar)
{
if (ar) {
@ -572,7 +581,7 @@ void ED_region_tag_refresh_ui(ARegion *ar)
void ED_region_tag_redraw_partial(ARegion *ar, const rcti *rct)
{
if (ar && !(ar->do_draw & RGN_DRAWING)) {
if (!(ar->do_draw & (RGN_DRAW | RGN_DRAW_PARTIAL))) {
if (!(ar->do_draw & (RGN_DRAW | RGN_DRAW_NO_REBUILD | RGN_DRAW_PARTIAL))) {
/* no redraw set yet, set partial region */
ar->do_draw |= RGN_DRAW_PARTIAL;
ar->drawrct = *rct;
@ -583,7 +592,7 @@ void ED_region_tag_redraw_partial(ARegion *ar, const rcti *rct)
BLI_rcti_union(&ar->drawrct, rct);
}
else {
BLI_assert((ar->do_draw & RGN_DRAW) != 0);
BLI_assert((ar->do_draw & (RGN_DRAW | RGN_DRAW_NO_REBUILD)) != 0);
/* Else, full redraw is already requested, nothing to do here. */
}
}

View File

@ -782,7 +782,6 @@ static int collection_delete_exec(bContext *C, wmOperator *UNUSED(op))
/* TODO(sergey): Use proper flag for tagging here. */
DEG_id_tag_update(&scene->id, 0);
soops->storeflag |= SO_TREESTORE_REDRAW;
WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
return OPERATOR_FINISHED;

View File

@ -1987,7 +1987,4 @@ void draw_outliner(const bContext *C)
UI_block_end(C, block);
UI_block_draw(C, block);
/* clear flag that allows quick redraws */
soops->storeflag &= ~SO_TREESTORE_REDRAW;
}

View File

@ -172,8 +172,7 @@ static int outliner_highlight_update(bContext *C, wmOperator *UNUSED(op), const
}
if (changed) {
soops->storeflag |= SO_TREESTORE_REDRAW; /* only needs to redraw, no rebuild */
ED_region_tag_redraw(ar);
ED_region_tag_redraw_no_rebuild(ar);
}
return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH);
@ -903,10 +902,8 @@ static int outliner_toggle_selected_exec(bContext *C, wmOperator *UNUSED(op))
else
outliner_set_flag(&soops->tree, TSE_SELECTED, 1);
soops->storeflag |= SO_TREESTORE_REDRAW;
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
ED_region_tag_redraw(ar);
ED_region_tag_redraw_no_rebuild(ar);
return OPERATOR_FINISHED;
}
@ -1027,11 +1024,9 @@ static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op))
xdelta = (int)(te->xs - v2d->cur.xmin);
v2d->cur.xmin += xdelta;
v2d->cur.xmax += xdelta;
so->storeflag |= SO_TREESTORE_REDRAW;
}
ED_region_tag_redraw(ar);
ED_region_tag_redraw_no_rebuild(ar);
return OPERATOR_FINISHED;
}
@ -1187,7 +1182,7 @@ static void outliner_find_panel(Scene *UNUSED(scene), ARegion *ar, SpaceOops *so
soops->search_flags = flags;
/* redraw */
soops->storeflag |= SO_TREESTORE_REDRAW;
ED_region_tag_redraw_no_rebuild(ar);
}
}
else {

View File

@ -271,11 +271,13 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv
break;
}
if (skip_rebuild) {
soops->storeflag |= SO_TREESTORE_REDRAW; /* only needs to redraw, no rebuild */
}
if (redraw) {
ED_region_tag_redraw(ar);
if (skip_rebuild) {
ED_region_tag_redraw_no_rebuild(ar);
}
else {
ED_region_tag_redraw(ar);
}
}
return retval;
@ -389,8 +391,7 @@ static int outliner_item_drag_drop_invoke(bContext *C, wmOperator *op, const wmE
/* unset highlighted tree element, dragged one will be highlighted instead */
outliner_set_flag(&soops->tree, TSE_HIGHLIGHTED, false);
soops->storeflag |= SO_TREESTORE_REDRAW; /* only needs to redraw, no rebuild */
ED_region_tag_redraw(ar);
ED_region_tag_redraw_no_rebuild(ar);
WM_event_add_modal_handler(C, op);

View File

@ -995,12 +995,13 @@ int outliner_item_do_activate_from_cursor(
}
if (changed) {
if (!rebuild_tree) {
/* only needs to redraw, no rebuild */
soops->storeflag |= SO_TREESTORE_REDRAW;
if (rebuild_tree) {
ED_region_tag_redraw(ar);
}
else {
ED_region_tag_redraw_no_rebuild(ar);
}
ED_undo_push(C, "Outliner selection change");
ED_region_tag_redraw(ar);
}
return OPERATOR_FINISHED;

View File

@ -2034,9 +2034,10 @@ static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soop
outliner_set_flag(&soops->tree, TSE_SELECTED, 0);
tselem->flag |= TSE_SELECTED;
/* redraw, same as outliner_select function */
soops->storeflag |= SO_TREESTORE_REDRAW;
ED_region_tag_redraw(ar);
/* Only redraw, don't rebuild here because TreeElement pointers will
* become invalid and operations will crash. */
ED_region_tag_redraw_no_rebuild(ar);
}
set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);

View File

@ -1705,8 +1705,6 @@ static void outliner_restore_scrolling_position(SpaceOops *soops, ARegion *ar, O
else {
return;
}
soops->storeflag |= SO_TREESTORE_REDRAW;
}
}
@ -2070,8 +2068,9 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa
BKE_outliner_treehash_rebuild_from_treestore(soops->treehash, soops->treestore);
}
if (soops->tree.first && (soops->storeflag & SO_TREESTORE_REDRAW))
if (ar->flag & RGN_DRAW_NO_REBUILD) {
return;
}
OutlinerTreeElementFocus focus;
outliner_store_scrolling_position(soops, ar, &focus);

View File

@ -468,5 +468,6 @@ enum {
#define RGN_DRAW_PARTIAL 2
#define RGN_DRAWING 4
#define RGN_DRAW_REFRESH_UI 8 /* re-create uiBlock's where possible */
#define RGN_DRAW_NO_REBUILD 16
#endif

View File

@ -349,8 +349,7 @@ typedef enum eSpaceOutliner_Mode {
typedef enum eSpaceOutliner_StoreFlag {
/* cleanup tree */
SO_TREESTORE_CLEANUP = (1 << 0),
/* if set, it allows redraws. gets set for some allqueue events */
SO_TREESTORE_REDRAW = (1 << 1),
/* SO_TREESTORE_REDRAW = (1 << 1), */ /* Deprecated */
/* rebuild the tree, similar to cleanup,
* but defer a call to BKE_outliner_treehash_rebuild_from_treestore instead */
SO_TREESTORE_REBUILD = (1 << 2),