Performance: Limit recounting during selection mode flushing.

This patch ensures that selection mode flushing updates total selection
counts internally. This reduces recounting when we are sure that the
input total selection counts were up to date.

For example for circle selection the total selection counts were
correct. But during flushing the selection could have been changed and
therefore the selection was always recounted.

This increased the performance on selected system from 6.90 FPS to 8.25
FPS during circle selection operations.

Before: {F10179981}
After: {F10179982}

Reviewed By: mano-wii

Differential Revision: https://developer.blender.org/D11647
This commit is contained in:
Jeroen Bakker 2021-06-18 15:31:14 +02:00 committed by Jeroen Bakker
parent a9d5c8f97f
commit ea4309925f
Notes: blender-bot 2023-02-14 05:52:32 +01:00
Referenced by commit b2510b9e20, Fix T89271: Selecting all vertices doesn't select all edges.
Referenced by issue #95165, Regression: Custom Normals tools dont update immediately (when started with Auto Smooth OFF)
Referenced by issue #89323, Ctrl-R loop cut and LMB click doesn't always slide
Referenced by issue #89303, UVs do not always show up in UV editor
Referenced by issue #89293, Edit Mesh Mode - selection regression
Referenced by issue #89271, Selecting all vertices on a face doesn't select the face and selects only some edges
7 changed files with 87 additions and 51 deletions

@ -1 +1 @@
Subproject commit 4833954c0ac85cc407e1d5a153aa11b1d1823ec0
Subproject commit ab283053ab455f76f5620b59b823e73bd9f601ce

@ -1 +1 @@
Subproject commit f86f25e62217264495d05f116ccb09d575fe9841
Subproject commit ec07ed4c2e0495bea7fbe0b546d25e35211506a9

View File

@ -40,32 +40,51 @@
/* For '_FLAG_OVERLAP'. */
#include "bmesh_private.h"
static int recount_totsel(BMesh *bm, BMIterType iter_type)
{
BMIter iter;
BMElem *ele;
int count = 0;
BM_ITER_MESH (ele, &iter, bm, iter_type) {
if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
count += 1;
}
}
return count;
}
static void recount_totvertsel(BMesh *bm)
{
bm->totvertsel = recount_totsel(bm, BM_VERTS_OF_MESH);
}
static void recount_totedgesel(BMesh *bm)
{
bm->totedgesel = recount_totsel(bm, BM_EDGES_OF_MESH);
}
static void recount_totfacesel(BMesh *bm)
{
bm->totfacesel = recount_totsel(bm, BM_FACES_OF_MESH);
}
static void recount_totsels(BMesh *bm)
{
const char iter_types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
int *tots[3];
int i;
/* Recount total selection variables. */
bm->totvertsel = bm->totedgesel = bm->totfacesel = 0;
tots[0] = &bm->totvertsel;
tots[1] = &bm->totedgesel;
tots[2] = &bm->totfacesel;
for (i = 0; i < 3; i++) {
BMIter iter;
BMElem *ele;
int count = 0;
BM_ITER_MESH (ele, &iter, bm, iter_types[i]) {
if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
count += 1;
}
}
*tots[i] = count;
}
recount_totvertsel(bm);
recount_totedgesel(bm);
recount_totfacesel(bm);
}
#ifndef NDEBUG
static bool recount_totsels_are_ok(BMesh *bm)
{
return bm->totvertsel == recount_totsel(bm, BM_VERTS_OF_MESH) &&
bm->totedgesel == recount_totsel(bm, BM_EDGES_OF_MESH) &&
bm->totfacesel == recount_totsel(bm, BM_FACES_OF_MESH);
}
#endif
/* -------------------------------------------------------------------- */
/** \name BMesh helper functions for selection & hide flushing.
* \{ */
@ -238,7 +257,7 @@ void BM_mesh_select_mode_clean(BMesh *bm)
* (ie: all verts of an edge selects the edge and so on).
* This should only be called by system and not tool authors.
*/
void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode)
void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode, eBMSelectionFlushFLags flags)
{
BMEdge *e;
BMLoop *l_iter;
@ -251,34 +270,22 @@ void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode)
if (selectmode & SCE_SELECT_VERTEX) {
/* both loops only set edge/face flags and read off verts */
BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(e->v1, BM_ELEM_SELECT) && BM_elem_flag_test(e->v2, BM_ELEM_SELECT) &&
!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
const bool is_selected = BM_elem_flag_test(e, BM_ELEM_SELECT);
if (!is_selected &&
(BM_elem_flag_test(e->v1, BM_ELEM_SELECT) && BM_elem_flag_test(e->v2, BM_ELEM_SELECT))) {
BM_elem_flag_enable(e, BM_ELEM_SELECT);
bm->totedgesel += 1;
}
else {
BM_elem_flag_disable(e, BM_ELEM_SELECT);
bm->totedgesel += is_selected ? -1 : 0;
}
}
BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
bool ok = true;
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
if (!BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT)) {
ok = false;
break;
}
} while ((l_iter = l_iter->next) != l_first);
}
else {
ok = false;
}
BM_elem_flag_set(f, BM_ELEM_SELECT, ok);
}
}
else if (selectmode & SCE_SELECT_EDGE) {
if (selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) {
BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
const bool is_selected = BM_elem_flag_test(f, BM_ELEM_SELECT);
bool ok = true;
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
@ -294,18 +301,33 @@ void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode)
}
BM_elem_flag_set(f, BM_ELEM_SELECT, ok);
if (is_selected && !ok) {
bm->totfacesel -= 1;
}
else if (ok && !is_selected) {
bm->totfacesel += 1;
}
}
}
/* Remove any deselected elements from the BMEditSelection */
BM_select_history_validate(bm);
recount_totsels(bm);
if (flags & BM_SELECT_LEN_FLUSH_RECALC_VERT) {
recount_totvertsel(bm);
}
if (flags & BM_SELECT_LEN_FLUSH_RECALC_EDGE) {
recount_totedgesel(bm);
}
if (flags & BM_SELECT_LEN_FLUSH_RECALC_FACE) {
recount_totfacesel(bm);
}
BLI_assert(recount_totsels_are_ok(bm));
}
void BM_mesh_select_mode_flush(BMesh *bm)
{
BM_mesh_select_mode_flush_ex(bm, bm->selectmode);
BM_mesh_select_mode_flush_ex(bm, bm->selectmode, BM_SELECT_LEN_FLUSH_RECALC_ALL);
}
/**

View File

@ -26,6 +26,16 @@ typedef struct BMEditSelection {
char htype;
} BMEditSelection;
typedef enum eBMSelectionFlushFLags {
BM_SELECT_LEN_FLUSH_RECALC_NOTHING = 0,
BM_SELECT_LEN_FLUSH_RECALC_VERT = (1 << 0),
BM_SELECT_LEN_FLUSH_RECALC_EDGE = (1 << 1),
BM_SELECT_LEN_FLUSH_RECALC_FACE = (1 << 2),
BM_SELECT_LEN_FLUSH_RECALC_ALL = (BM_SELECT_LEN_FLUSH_RECALC_VERT |
BM_SELECT_LEN_FLUSH_RECALC_EDGE |
BM_SELECT_LEN_FLUSH_RECALC_FACE),
} eBMSelectionFlushFLags;
/* geometry hiding code */
#define BM_elem_hide_set(bm, ele, hide) _bm_elem_hide_set(bm, &(ele)->head, hide)
void _bm_elem_hide_set(BMesh *bm, BMHeader *head, const bool hide);
@ -72,7 +82,7 @@ void BM_mesh_select_mode_clean_ex(BMesh *bm, const short selectmode);
void BM_mesh_select_mode_clean(BMesh *bm);
void BM_mesh_select_mode_set(BMesh *bm, int selectmode);
void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode);
void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode, eBMSelectionFlushFLags flags);
void BM_mesh_select_mode_flush(BMesh *bm);
void BM_mesh_deselect_flush(BMesh *bm);

View File

@ -438,7 +438,7 @@ void EDBM_selectmode_to_scene(bContext *C)
void EDBM_selectmode_flush_ex(BMEditMesh *em, const short selectmode)
{
BM_mesh_select_mode_flush_ex(em->bm, selectmode);
BM_mesh_select_mode_flush_ex(em->bm, selectmode, BM_SELECT_LEN_FLUSH_RECALC_ALL);
}
void EDBM_selectmode_flush(BMEditMesh *em)

View File

@ -3725,6 +3725,9 @@ static bool mesh_circle_select(ViewContext *vc,
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
if (vc->em->bm->totvertsel) {
EDBM_flag_disable_all(vc->em, BM_ELEM_SELECT);
vc->em->bm->totvertsel = 0;
vc->em->bm->totedgesel = 0;
vc->em->bm->totfacesel = 0;
changed = true;
}
}
@ -3790,7 +3793,8 @@ static bool mesh_circle_select(ViewContext *vc,
changed |= data.is_changed;
if (changed) {
EDBM_selectmode_flush(vc->em);
BM_mesh_select_mode_flush_ex(
vc->em->bm, vc->em->selectmode, BM_SELECT_LEN_FLUSH_RECALC_NOTHING);
}
return changed;
}

View File

@ -552,7 +552,7 @@ static bool uv_shortest_path_pick_ex(const SpaceImage *sima,
if (uv_selectmode & UV_SELECT_EDGE) {
/* Special case as we don't use true edge selection,
* flush the selection from the vertices. */
BM_mesh_select_mode_flush_ex(em->bm, SCE_SELECT_VERTEX);
BM_mesh_select_mode_flush_ex(em->bm, SCE_SELECT_VERTEX, BM_SELECT_LEN_FLUSH_RECALC_ALL);
}
}
ED_uvedit_select_sync_flush(scene->toolsettings, em, select);