diff options
author | Jeroen Bakker <jeroen@blender.org> | 2021-06-21 09:13:40 +0300 |
---|---|---|
committer | Jeroen Bakker <jeroen@blender.org> | 2021-06-21 17:35:28 +0300 |
commit | b9ccfb89ce91676269811407c84fdff1dbbee94f (patch) | |
tree | dc8daad21f927411efd982d7db276e4147f88877 /source/blender/bmesh/intern | |
parent | ce64cfd6edc2a0ec0aabfd4daaa5f655763cc74b (diff) |
Performance: Flush selection to edges/faces.
This patch uses threading to flush selection from verts to edges and
from edges to faces. The solution is lockless and should scale well on
modern CPU architectures.
Master:{F10185359}
Patch:{F10185361}
End user performance went from 3.9 to 4.6 FPS (Stanford Dragon) but that
was measured on a Intel Core i7-6700 CPU and AMD RX480 Gpu. The more
cores the better improvements you get.
Reviewed By: mano-wii
Differential Revision: https://developer.blender.org/D11644
Diffstat (limited to 'source/blender/bmesh/intern')
-rw-r--r-- | source/blender/bmesh/intern/bmesh_marking.c | 150 |
1 files changed, 104 insertions, 46 deletions
diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c index 19d94613afe..190698f504c 100644 --- a/source/blender/bmesh/intern/bmesh_marking.c +++ b/source/blender/bmesh/intern/bmesh_marking.c @@ -324,6 +324,106 @@ void BM_mesh_select_mode_clean(BMesh *bm) BM_mesh_select_mode_clean_ex(bm, bm->selectmode); } +/* -------------------------------------------------------------------- */ +/** \name Select mode flush selection + * \{ */ + +typedef struct SelectionFlushChunkData { + int delta_selection_len; +} SelectionFlushChunkData; + +static void bm_mesh_select_mode_flush_vert_to_edge_iter_fn(void *UNUSED(userdata), + MempoolIterData *iter, + const TaskParallelTLS *__restrict tls) +{ + SelectionFlushChunkData *chunk_data = tls->userdata_chunk; + BMEdge *e = (BMEdge *)iter; + const bool is_selected = BM_elem_flag_test(e, BM_ELEM_SELECT); + const bool is_hidden = BM_elem_flag_test(e, BM_ELEM_HIDDEN); + if (!is_hidden && + (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); + chunk_data->delta_selection_len += is_selected ? 0 : 1; + } + else { + BM_elem_flag_disable(e, BM_ELEM_SELECT); + chunk_data->delta_selection_len += is_selected ? -1 : 0; + } +} + +static void bm_mesh_select_mode_flush_edge_to_face_iter_fn(void *UNUSED(userdata), + MempoolIterData *iter, + const TaskParallelTLS *__restrict tls) +{ + SelectionFlushChunkData *chunk_data = tls->userdata_chunk; + BMFace *f = (BMFace *)iter; + BMLoop *l_iter; + BMLoop *l_first; + 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); + do { + if (!BM_elem_flag_test(l_iter->e, 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); + if (is_selected && !ok) { + chunk_data->delta_selection_len -= 1; + } + else if (ok && !is_selected) { + chunk_data->delta_selection_len += 1; + } +} + +static void bm_mesh_select_mode_flush_reduce_fn(const void *__restrict UNUSED(userdata), + void *__restrict chunk_join, + void *__restrict chunk) +{ + SelectionFlushChunkData *dst = chunk_join; + const SelectionFlushChunkData *src = chunk; + dst->delta_selection_len += src->delta_selection_len; +} + +static void bm_mesh_select_mode_flush_vert_to_edge(BMesh *bm) +{ + SelectionFlushChunkData chunk_data = {0}; + + TaskParallelSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = bm->totedge >= BM_OMP_LIMIT; + settings.userdata_chunk = &chunk_data; + settings.userdata_chunk_size = sizeof(chunk_data); + settings.func_reduce = bm_mesh_select_mode_flush_reduce_fn; + + BM_iter_parallel( + bm, BM_EDGES_OF_MESH, bm_mesh_select_mode_flush_vert_to_edge_iter_fn, NULL, &settings); + bm->totedgesel += chunk_data.delta_selection_len; +} + +static void bm_mesh_select_mode_flush_edge_to_face(BMesh *bm) +{ + SelectionFlushChunkData chunk_data = {0}; + + TaskParallelSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = bm->totface >= BM_OMP_LIMIT; + settings.userdata_chunk = &chunk_data; + settings.userdata_chunk_size = sizeof(chunk_data); + settings.func_reduce = bm_mesh_select_mode_flush_reduce_fn; + + BM_iter_parallel( + bm, BM_FACES_OF_MESH, bm_mesh_select_mode_flush_edge_to_face_iter_fn, NULL, &settings); + bm->totfacesel += chunk_data.delta_selection_len; +} + /** * \brief Select Mode Flush * @@ -333,56 +433,12 @@ void BM_mesh_select_mode_clean(BMesh *bm) */ void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode, eBMSelectionFlushFLags flags) { - BMEdge *e; - BMLoop *l_iter; - BMLoop *l_first; - BMFace *f; - - BMIter eiter; - BMIter fiter; - 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) { - const bool is_selected = BM_elem_flag_test(e, BM_ELEM_SELECT); - const bool is_hidden = BM_elem_flag_test(e, BM_ELEM_HIDDEN); - if (!is_hidden && - (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 += is_selected ? 0 : 1; - } - else { - BM_elem_flag_disable(e, BM_ELEM_SELECT); - bm->totedgesel += is_selected ? -1 : 0; - } - } + bm_mesh_select_mode_flush_vert_to_edge(bm); } 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); - do { - if (!BM_elem_flag_test(l_iter->e, 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); - if (is_selected && !ok) { - bm->totfacesel -= 1; - } - else if (ok && !is_selected) { - bm->totfacesel += 1; - } - } + bm_mesh_select_mode_flush_edge_to_face(bm); } /* Remove any deselected elements from the BMEditSelection */ @@ -405,6 +461,8 @@ void BM_mesh_select_mode_flush(BMesh *bm) BM_mesh_select_mode_flush_ex(bm, bm->selectmode, BM_SELECT_LEN_FLUSH_RECALC_ALL); } +/** \} */ + /** * mode independent flushing up/down */ |