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.
This commit is contained in:
2021-07-02 12:46:08 +10:00
parent afe7387be8
commit 04313f1bb5
14 changed files with 151 additions and 96 deletions

View File

@@ -115,45 +115,6 @@ void EDBM_redo_state_free(BMBackup *backup, BMEditMesh *em, int recalctess)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Edit-Mesh Copy API (Internal)
* \{ */
static void edbm_op_emcopy_incref_and_ensure(BMEditMesh *em, const BMOperator *UNUSED(bmop))
{
if (em->emcopy == NULL) {
em->emcopy = BKE_editmesh_copy(em);
}
em->emcopyusers++;
}
static void edbm_op_emcopy_decref(BMEditMesh *em, const BMOperator *UNUSED(bmop))
{
em->emcopyusers--;
if (em->emcopyusers < 0) {
printf("warning: em->emcopyusers was less than zero.\n");
}
if (em->emcopyusers <= 0) {
BKE_editmesh_free(em->emcopy);
MEM_freeN(em->emcopy);
em->emcopy = NULL;
}
}
static void edbm_op_emcopy_restore_and_clear(BMEditMesh *em, const BMOperator *UNUSED(bmop))
{
BLI_assert(em->emcopy != NULL);
BMEditMesh *emcopy = em->emcopy;
EDBM_mesh_free(em);
*em = *emcopy;
MEM_freeN(emcopy);
em->emcopyusers = 0;
em->emcopy = NULL;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name BMesh Operator (BMO) API Wrapper
* \{ */
@@ -171,8 +132,6 @@ bool EDBM_op_init(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char *
return false;
}
edbm_op_emcopy_incref_and_ensure(em, bmop);
va_end(list);
return true;
@@ -187,29 +146,62 @@ bool EDBM_op_finish(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const bool
{
const char *errmsg;
#ifndef NDEBUG
struct {
int verts_len, edges_len, loops_len, faces_len;
} em_state_prev = {
.verts_len = em->bm->totvert,
.edges_len = em->bm->totedge,
.loops_len = em->bm->totloop,
.faces_len = em->bm->totface,
};
#endif
BMO_op_finish(em->bm, bmop);
if (BMO_error_get(em->bm, &errmsg, NULL)) {
BLI_assert(em->emcopy != NULL);
bool changed = false;
bool changed_was_set = false;
eBMOpErrorLevel level;
while (BMO_error_pop(em->bm, &errmsg, NULL, &level)) {
ReportType type = RPT_INFO;
switch (level) {
case BMO_ERROR_CANCEL: {
changed_was_set = true;
break;
}
case BMO_ERROR_WARN: {
type = RPT_WARNING;
changed_was_set = true;
changed = true;
break;
}
case BMO_ERROR_FATAL: {
type = RPT_ERROR;
changed_was_set = true;
changed = true;
break;
}
}
if (do_report) {
BKE_report(op->reports, RPT_ERROR, errmsg);
BKE_report(op->reports, type, errmsg);
}
edbm_op_emcopy_restore_and_clear(em, bmop);
/* when copying, tessellation isn't to for faster copying,
* but means we need to re-tessellate here */
if (em->looptris == NULL) {
BKE_editmesh_looptri_calc(em);
}
return false;
}
if (changed_was_set == false) {
changed = true;
}
edbm_op_emcopy_decref(em, bmop);
#ifndef NDEBUG
if (changed == false) {
BLI_assert((em_state_prev.verts_len == em->bm->totvert) &&
(em_state_prev.edges_len == em->bm->totedge) &&
(em_state_prev.loops_len == em->bm->totloop) &&
(em_state_prev.faces_len == em->bm->totface));
}
#endif
return true;
return changed;
}
bool EDBM_op_callf(BMEditMesh *em, wmOperator *op, const char *fmt, ...)
@@ -226,8 +218,6 @@ bool EDBM_op_callf(BMEditMesh *em, wmOperator *op, const char *fmt, ...)
return false;
}
edbm_op_emcopy_incref_and_ensure(em, &bmop);
BMO_op_exec(bm, &bmop);
va_end(list);
@@ -255,8 +245,6 @@ bool EDBM_op_call_and_selectf(BMEditMesh *em,
return false;
}
edbm_op_emcopy_incref_and_ensure(em, &bmop);
BMO_op_exec(bm, &bmop);
slot_select_out = BMO_slot_get(bmop.slots_out, select_slot_out);
@@ -287,8 +275,6 @@ bool EDBM_op_call_silentf(BMEditMesh *em, const char *fmt, ...)
return false;
}
edbm_op_emcopy_incref_and_ensure(em, &bmop);
BMO_op_exec(bm, &bmop);
va_end(list);