diff options
author | Campbell Barton <ideasman42@gmail.com> | 2021-07-02 05:46:08 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2021-07-05 11:36:33 +0300 |
commit | 04313f1bb5ff89168099cdc03d1855ae5118d29c (patch) | |
tree | 8f3238a4edbbdb0e12de8b111d31454f1bb5509b /source/blender/bmesh | |
parent | afe7387be81ef04dc566a182ccadb2b1e739f809 (diff) |
BMesh: remove redundant mesh-backups from EDBM_op_* API
Using BMesh operators through the edit-mesh API created a full copy
of the mesh so it was possible to restore the mesh in case
one of the operators raised an error.
Remove support for automatic backup/restore from the EDBM_op_* API's
as it adds significant overhead and was rarely used.
Operators that need this can use the BMBackup API to backup & restore
the mesh in case of failure.
Add warning levels to BMO_error_raise so operators can report problems
without it being interpreted as a request to cancel the operation.
For high-poly meshes creating and freeing a full copy is an expensive
operation, removing this gives a speedup of ~1.77x for most operators
except for "connect_verts" / "connect_vert_pair"
which still uses this functionality.
Diffstat (limited to 'source/blender/bmesh')
-rw-r--r-- | source/blender/bmesh/intern/bmesh_error.h | 37 | ||||
-rw-r--r-- | source/blender/bmesh/intern/bmesh_operators.c | 44 | ||||
-rw-r--r-- | source/blender/bmesh/operators/bmo_bisect_plane.c | 2 | ||||
-rw-r--r-- | source/blender/bmesh/operators/bmo_bridge.c | 6 | ||||
-rw-r--r-- | source/blender/bmesh/operators/bmo_connect.c | 2 | ||||
-rw-r--r-- | source/blender/bmesh/operators/bmo_dissolve.c | 2 | ||||
-rw-r--r-- | source/blender/bmesh/operators/bmo_fill_grid.c | 7 | ||||
-rw-r--r-- | source/blender/bmesh/operators/bmo_hull.c | 2 | ||||
-rw-r--r-- | source/blender/bmesh/operators/bmo_subdivide_edgering.c | 6 |
9 files changed, 84 insertions, 24 deletions
diff --git a/source/blender/bmesh/intern/bmesh_error.h b/source/blender/bmesh/intern/bmesh_error.h index e9cdc120657..7694d4dbfb6 100644 --- a/source/blender/bmesh/intern/bmesh_error.h +++ b/source/blender/bmesh/intern/bmesh_error.h @@ -24,17 +24,46 @@ /*----------- bmop error system ----------*/ +/** + * \note More can be added as needed. + */ +typedef enum eBMOpErrorLevel { + /** + * Use when the operation could not succeed, + * typically from input that isn't sufficient for completing the operation. + */ + BMO_ERROR_CANCEL = 0, + /** + * Use this when one or more operations could not succeed, + * when the resulting mesh can be used (since some operations succeeded or no change was made). + * This is used by default. + */ + BMO_ERROR_WARN = 1, + /** + * The mesh resulting from this operation should not be used (where possible). + * It should not be left in a corrupt state either. + * + * See #BMBackup type & function calls. + */ + BMO_ERROR_FATAL = 2, +} eBMOpErrorLevel; + /* Pushes an error onto the bmesh error stack. * if msg is null, then the default message for the `errcode` is used. */ -void BMO_error_raise(BMesh *bm, BMOperator *owner, const char *msg) ATTR_NONNULL(1, 2, 3); +void BMO_error_raise(BMesh *bm, BMOperator *owner, eBMOpErrorLevel level, const char *msg) + ATTR_NONNULL(1, 2, 4); /* Gets the topmost error from the stack. * returns error code or 0 if no error. */ -bool BMO_error_get(BMesh *bm, const char **r_msg, BMOperator **r_op); -bool BMO_error_occurred(BMesh *bm); +bool BMO_error_get(BMesh *bm, const char **r_msg, BMOperator **r_op, eBMOpErrorLevel *r_level); +bool BMO_error_get_at_level(BMesh *bm, + eBMOpErrorLevel level, + const char **r_msg, + BMOperator **r_op); +bool BMO_error_occurred_at_level(BMesh *bm, eBMOpErrorLevel level); /* Same as #BMO_error_get, only pops the error off the stack as well. */ -bool BMO_error_pop(BMesh *bm, const char **r_msg, BMOperator **r_op); +bool BMO_error_pop(BMesh *bm, const char **r_msg, BMOperator **r_op, eBMOpErrorLevel *r_level); void BMO_error_clear(BMesh *bm); /* This is meant for handling errors, like self-intersection test failures. diff --git a/source/blender/bmesh/intern/bmesh_operators.c b/source/blender/bmesh/intern/bmesh_operators.c index 37b1c9386e5..4a611d78d58 100644 --- a/source/blender/bmesh/intern/bmesh_operators.c +++ b/source/blender/bmesh/intern/bmesh_operators.c @@ -1553,32 +1553,39 @@ typedef struct BMOpError { struct BMOpError *next, *prev; BMOperator *op; const char *msg; + eBMOpErrorLevel level; } BMOpError; void BMO_error_clear(BMesh *bm) { - while (BMO_error_pop(bm, NULL, NULL)) { + while (BMO_error_pop(bm, NULL, NULL, NULL)) { /* pass */ } } -void BMO_error_raise(BMesh *bm, BMOperator *owner, const char *msg) +void BMO_error_raise(BMesh *bm, BMOperator *owner, eBMOpErrorLevel level, const char *msg) { BMOpError *err = MEM_callocN(sizeof(BMOpError), "bmop_error"); err->msg = msg; err->op = owner; + err->level = level; BLI_addhead(&bm->errorstack, err); } -bool BMO_error_occurred(BMesh *bm) +bool BMO_error_occurred_at_level(BMesh *bm, eBMOpErrorLevel level) { - return (BLI_listbase_is_empty(&bm->errorstack) == false); + for (const BMOpError *err = bm->errorstack.first; err; err = err->next) { + if (err->level == level) { + return true; + } + } + return false; } /* returns error code or 0 if no error */ -bool BMO_error_get(BMesh *bm, const char **r_msg, BMOperator **r_op) +bool BMO_error_get(BMesh *bm, const char **r_msg, BMOperator **r_op, eBMOpErrorLevel *r_level) { BMOpError *err = bm->errorstack.first; if (err == NULL) { @@ -1591,13 +1598,36 @@ bool BMO_error_get(BMesh *bm, const char **r_msg, BMOperator **r_op) if (r_op) { *r_op = err->op; } + if (r_level) { + *r_level = err->level; + } return true; } -bool BMO_error_pop(BMesh *bm, const char **msg, BMOperator **op) +bool BMO_error_get_at_level(BMesh *bm, + eBMOpErrorLevel level, + const char **r_msg, + BMOperator **r_op) +{ + for (BMOpError *err = bm->errorstack.first; err; err = err->next) { + if (err->level >= level) { + if (r_msg) { + *r_msg = err->msg; + } + if (r_op) { + *r_op = err->op; + } + return true; + } + } + + return false; +} + +bool BMO_error_pop(BMesh *bm, const char **r_msg, BMOperator **r_op, eBMOpErrorLevel *r_level) { - bool result = BMO_error_get(bm, msg, op); + bool result = BMO_error_get(bm, r_msg, r_op, r_level); if (result) { BMOpError *err = bm->errorstack.first; diff --git a/source/blender/bmesh/operators/bmo_bisect_plane.c b/source/blender/bmesh/operators/bmo_bisect_plane.c index 2663f271b6e..55b6337bea4 100644 --- a/source/blender/bmesh/operators/bmo_bisect_plane.c +++ b/source/blender/bmesh/operators/bmo_bisect_plane.c @@ -50,7 +50,7 @@ void bmo_bisect_plane_exec(BMesh *bm, BMOperator *op) BMO_slot_vec_get(op->slots_in, "plane_no", plane_no); if (is_zero_v3(plane_no)) { - BMO_error_raise(bm, op, "Zero normal given"); + BMO_error_raise(bm, op, BMO_ERROR_CANCEL, "Zero normal given"); return; } diff --git a/source/blender/bmesh/operators/bmo_bridge.c b/source/blender/bmesh/operators/bmo_bridge.c index 005b8a2f5e8..fb913d4f19f 100644 --- a/source/blender/bmesh/operators/bmo_bridge.c +++ b/source/blender/bmesh/operators/bmo_bridge.c @@ -576,12 +576,12 @@ void bmo_bridge_loops_exec(BMesh *bm, BMOperator *op) BM_mesh_edgeloops_calc_center(bm, &eloops); if (count < 2) { - BMO_error_raise(bm, op, "Select at least two edge loops"); + BMO_error_raise(bm, op, BMO_ERROR_CANCEL, "Select at least two edge loops"); goto cleanup; } if (use_pairs && (count % 2)) { - BMO_error_raise(bm, op, "Select an even number of loops to bridge pairs"); + BMO_error_raise(bm, op, BMO_ERROR_CANCEL, "Select an even number of loops to bridge pairs"); goto cleanup; } @@ -595,7 +595,7 @@ void bmo_bridge_loops_exec(BMesh *bm, BMOperator *op) } } if (!match) { - BMO_error_raise(bm, op, "Selected loops must have equal edge counts"); + BMO_error_raise(bm, op, BMO_ERROR_CANCEL, "Selected loops must have equal edge counts"); goto cleanup; } } diff --git a/source/blender/bmesh/operators/bmo_connect.c b/source/blender/bmesh/operators/bmo_connect.c index b701c1291a6..abc040f7564 100644 --- a/source/blender/bmesh/operators/bmo_connect.c +++ b/source/blender/bmesh/operators/bmo_connect.c @@ -211,7 +211,7 @@ void bmo_connect_verts_exec(BMesh *bm, BMOperator *op) /* connect faces */ while ((f = BLI_LINKSTACK_POP(faces))) { if (bm_face_connect_verts(bm, f, check_degenerate) == -1) { - BMO_error_raise(bm, op, "Could not connect vertices"); + BMO_error_raise(bm, op, BMO_ERROR_FATAL, "Could not connect vertices"); } } diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c index c0ce63fb0eb..efba0ec99ec 100644 --- a/source/blender/bmesh/operators/bmo_dissolve.c +++ b/source/blender/bmesh/operators/bmo_dissolve.c @@ -257,7 +257,7 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op) } } - BLI_assert(!BMO_error_occurred(bm)); + BLI_assert(!BMO_error_occurred_at_level(bm, BMO_ERROR_FATAL)); BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "region.out", BM_FACE, FACE_NEW); diff --git a/source/blender/bmesh/operators/bmo_fill_grid.c b/source/blender/bmesh/operators/bmo_fill_grid.c index 4ba7dbad736..2e09b21c9cc 100644 --- a/source/blender/bmesh/operators/bmo_fill_grid.c +++ b/source/blender/bmesh/operators/bmo_fill_grid.c @@ -619,6 +619,7 @@ void bmo_grid_fill_exec(BMesh *bm, BMOperator *op) * extract two 'rail' loops from a single edge loop, see T72075. */ BMO_error_raise(bm, op, + BMO_ERROR_CANCEL, "Select two edge loops " "or a single closed edge loop from which two edge loops can be calculated"); goto cleanup; @@ -633,7 +634,7 @@ void bmo_grid_fill_exec(BMesh *bm, BMOperator *op) v_b_last = ((LinkData *)BM_edgeloop_verts_get(estore_b)->last)->data; if (BM_edgeloop_is_closed(estore_a) || BM_edgeloop_is_closed(estore_b)) { - BMO_error_raise(bm, op, "Closed loops unsupported"); + BMO_error_raise(bm, op, BMO_ERROR_CANCEL, "Closed loops unsupported"); goto cleanup; } @@ -671,7 +672,7 @@ void bmo_grid_fill_exec(BMesh *bm, BMOperator *op) bm_edgeloop_flag_set(estore_b, BM_ELEM_HIDDEN, false); if (BLI_listbase_is_empty(&eloops_rail)) { - BMO_error_raise(bm, op, "Loops are not connected by wire/boundary edges"); + BMO_error_raise(bm, op, BMO_ERROR_CANCEL, "Loops are not connected by wire/boundary edges"); goto cleanup; } @@ -679,7 +680,7 @@ void bmo_grid_fill_exec(BMesh *bm, BMOperator *op) BLI_assert(v_a_last != v_b_last); if (BM_edgeloop_overlap_check(estore_rail_a, estore_rail_b)) { - BMO_error_raise(bm, op, "Connecting edge loops overlap"); + BMO_error_raise(bm, op, BMO_ERROR_CANCEL, "Connecting edge loops overlap"); goto cleanup; } diff --git a/source/blender/bmesh/operators/bmo_hull.c b/source/blender/bmesh/operators/bmo_hull.c index dd2fe52293f..0801300b6c2 100644 --- a/source/blender/bmesh/operators/bmo_hull.c +++ b/source/blender/bmesh/operators/bmo_hull.c @@ -554,7 +554,7 @@ void bmo_convex_hull_exec(BMesh *bm, BMOperator *op) /* Verify that at least three verts in the input */ if (!hull_num_input_verts_is_ok(op)) { - BMO_error_raise(bm, op, "Requires at least three vertices"); + BMO_error_raise(bm, op, BMO_ERROR_CANCEL, "Requires at least three vertices"); return; } diff --git a/source/blender/bmesh/operators/bmo_subdivide_edgering.c b/source/blender/bmesh/operators/bmo_subdivide_edgering.c index caca24f4409..d015b715a69 100644 --- a/source/blender/bmesh/operators/bmo_subdivide_edgering.c +++ b/source/blender/bmesh/operators/bmo_subdivide_edgering.c @@ -1143,7 +1143,7 @@ void bmo_subdivide_edgering_exec(BMesh *bm, BMOperator *op) count = BM_mesh_edgeloops_find(bm, &eloops_rim, bm_edge_rim_test_cb, (void *)bm); if (count < 2) { - BMO_error_raise(bm, op, "No edge rings found"); + BMO_error_raise(bm, op, BMO_ERROR_CANCEL, "No edge rings found"); goto cleanup; } else if (count == 2) { @@ -1167,7 +1167,7 @@ void bmo_subdivide_edgering_exec(BMesh *bm, BMOperator *op) changed = true; } else { - BMO_error_raise(bm, op, "Edge-ring pair isn't connected"); + BMO_error_raise(bm, op, BMO_ERROR_CANCEL, "Edge-ring pair isn't connected"); goto cleanup; } } @@ -1179,7 +1179,7 @@ void bmo_subdivide_edgering_exec(BMesh *bm, BMOperator *op) LoopPairStore **lpair_arr; if (eloop_pairs_gs == NULL) { - BMO_error_raise(bm, op, "Edge-rings are not connected"); + BMO_error_raise(bm, op, BMO_ERROR_CANCEL, "Edge-rings are not connected"); goto cleanup; } |