[Bf-blender-cvs] [04313f1bb5f] master: BMesh: remove redundant mesh-backups from EDBM_op_* API

Campbell Barton noreply at git.blender.org
Mon Jul 5 10:40:11 CEST 2021


Commit: 04313f1bb5ff89168099cdc03d1855ae5118d29c
Author: Campbell Barton
Date:   Fri Jul 2 12:46:08 2021 +1000
Branches: master
https://developer.blender.org/rB04313f1bb5ff89168099cdc03d1855ae5118d29c

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.

===================================================================

M	source/blender/blenkernel/BKE_editmesh.h
M	source/blender/bmesh/intern/bmesh_error.h
M	source/blender/bmesh/intern/bmesh_operators.c
M	source/blender/bmesh/operators/bmo_bisect_plane.c
M	source/blender/bmesh/operators/bmo_bridge.c
M	source/blender/bmesh/operators/bmo_connect.c
M	source/blender/bmesh/operators/bmo_dissolve.c
M	source/blender/bmesh/operators/bmo_fill_grid.c
M	source/blender/bmesh/operators/bmo_hull.c
M	source/blender/bmesh/operators/bmo_subdivide_edgering.c
M	source/blender/editors/mesh/editmesh_tools.c
M	source/blender/editors/mesh/editmesh_utils.c
M	source/blender/modifiers/intern/MOD_skin.c
M	source/blender/python/bmesh/bmesh_py_ops_call.c

===================================================================

diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h
index e31a0a16408..9112877b5a3 100644
--- a/source/blender/blenkernel/BKE_editmesh.h
+++ b/source/blender/blenkernel/BKE_editmesh.h
@@ -53,10 +53,6 @@ struct Scene;
 typedef struct BMEditMesh {
   struct BMesh *bm;
 
-  /* This is for undoing failed operations. */
-  struct BMEditMesh *emcopy;
-  int emcopyusers;
-
   /* we store tessellations as triplets of three loops,
    * which each define a triangle. */
   struct BMLoop *(*looptris)[3];
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

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list