Sculpt-dev: bke_pbvh_update_vert_boundary is

now atomic

* bke_pbvh_update_vert_boundary now uses atomics
* This allows dyntopo surface smoothing
  (surface_smooth_v_safe) to update vertex boundary
  flags inside of a thread.  This lessens degenerate
  geometry created by hard edged brushes like
  clay strips.
This commit is contained in:
Joseph Eagar 2022-01-08 12:57:29 -08:00
parent 8b3fc04d4e
commit 118edbef0e
2 changed files with 69 additions and 27 deletions

View File

@ -34,8 +34,9 @@
#include <stdio.h>
//#define DYNTOPO_REPORT
#define DYNTOPO_REPORT
//#define WITH_ADAPTIVE_CURVATURE
//#define DYNTOPO_NO_THREADING
#define SCULPTVERT_VALENCE_TEMP SCULPTVERT_SPLIT_TEMP
@ -595,7 +596,7 @@ BLI_INLINE void surface_smooth_v_safe(PBVH *pbvh, BMVert *v, float fac)
}
if (mv1->flag & SCULPTVERT_NEED_BOUNDARY) {
return; // can't update boundary in thread
pbvh_check_vert_boundary(pbvh, v);
}
// pbvh_check_vert_boundary(pbvh, v);
@ -2843,8 +2844,12 @@ static void long_edge_queue_create(EdgeQueueContext *eq_ctx,
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
#ifdef DYNTOPO_NO_THREADING
settings.use_threading = false;
#endif
BLI_task_parallel_range(0, count, tdata, long_edge_queue_task_cb, &settings);
const int cd_sculpt_vert = pbvh->cd_sculpt_vert;
for (int i = 0; i < count; i++) {
@ -2967,6 +2972,10 @@ static void edge_queue_create_local(EdgeQueueContext *eq_ctx,
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
#ifdef DYNTOPO_NO_THREADING
settings.use_threading = false;
#endif
BLI_task_parallel_range(0, count, tdata, short_edge_queue_task_cb_local, &settings);
const int cd_sculpt_vert = pbvh->cd_sculpt_vert;
@ -3240,6 +3249,10 @@ static void short_edge_queue_create(EdgeQueueContext *eq_ctx,
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
#ifdef DYNTOPO_NO_THREADING
settings.use_threading = false;
#endif
BLI_task_parallel_range(0, count, tdata, short_edge_queue_task_cb, &settings);
const int cd_sculpt_vert = pbvh->cd_sculpt_vert;

View File

@ -1760,6 +1760,19 @@ static int color_boundary_key(float col[4])
}
#endif
/* calls atomic_cas_uint32 on two adjacent (and int aligned) shorts */
BLI_INLINE void atomic_cas_short2(ushort *base, ushort olda, ushort oldb, ushort newa, ushort newb) {
uint oldi, newi;
((ushort *)&oldi)[0] = olda;
((ushort *)&oldi)[1] = oldb;
((ushort *)&newi)[0] = newa;
((ushort *)&newi)[1] = newb;
atomic_cas_uint32((uint32_t *)base, oldi, newi);
}
void bke_pbvh_update_vert_boundary(int cd_sculpt_vert,
int cd_faceset_offset,
int cd_vert_node_offset,
@ -1774,16 +1787,25 @@ void bke_pbvh_update_vert_boundary(int cd_sculpt_vert,
float curv = 0.0f, totcurv = 0.0f;
int newflag = mv->flag;
int oldflag = newflag;
int oldval = mv->valence;
BMEdge *e = v->e;
mv->flag &= ~(SCULPTVERT_BOUNDARY | SCULPTVERT_FSET_BOUNDARY | SCULPTVERT_NEED_BOUNDARY |
newflag &= ~(SCULPTVERT_BOUNDARY | SCULPTVERT_FSET_BOUNDARY | SCULPTVERT_NEED_BOUNDARY |
SCULPTVERT_NEED_TRIANGULATE | SCULPTVERT_FSET_CORNER | SCULPTVERT_CORNER |
SCULPTVERT_NEED_VALENCE | SCULPTVERT_SEAM_BOUNDARY | SCULPTVERT_SHARP_BOUNDARY |
SCULPTVERT_SEAM_CORNER | SCULPTVERT_SHARP_CORNER | SCULPTVERT_PBVH_BOUNDARY |
SCULPTVERT_UV_BOUNDARY | SCULPTVERT_UV_CORNER);
ushort stroke_id = (ushort)mv->stroke_id;
if (!e) {
mv->flag |= SCULPTVERT_BOUNDARY;
mv->valence = 0;
newflag |= SCULPTVERT_BOUNDARY;
atomic_cas_int32(&mv->flag, oldflag, newflag);
atomic_cas_short2(&mv->valence, (ushort)oldval, stroke_id, 0, stroke_id);
return;
}
@ -1838,15 +1860,15 @@ void bke_pbvh_update_vert_boundary(int cd_sculpt_vert,
#endif
if (BM_ELEM_CD_GET_INT(v2, cd_vert_node_offset) != ni) {
mv->flag |= SCULPTVERT_PBVH_BOUNDARY;
newflag |= SCULPTVERT_PBVH_BOUNDARY;
}
if (e->head.hflag & BM_ELEM_SEAM) {
mv->flag |= SCULPTVERT_SEAM_BOUNDARY;
newflag |= SCULPTVERT_SEAM_BOUNDARY;
seamcount++;
if (seamcount > 2) {
mv->flag |= SCULPTVERT_SEAM_CORNER;
newflag |= SCULPTVERT_SEAM_CORNER;
}
}
@ -1863,17 +1885,17 @@ void bke_pbvh_update_vert_boundary(int cd_sculpt_vert,
int colorkey2 = color_boundary_key(color2);
if (colorkey1 != colorkey2) {
mv->flag |= SCULPTVERT_FSET_BOUNDARY;
newflag |= SCULPTVERT_FSET_BOUNDARY;
}
}
#endif
if (!(e->head.hflag & BM_ELEM_SMOOTH)) {
mv->flag |= SCULPTVERT_SHARP_BOUNDARY;
newflag |= SCULPTVERT_SHARP_BOUNDARY;
sharpcount++;
if (sharpcount > 2) {
mv->flag |= SCULPTVERT_SHARP_CORNER;
newflag |= SCULPTVERT_SHARP_CORNER;
}
}
@ -1904,11 +1926,11 @@ void bke_pbvh_update_vert_boundary(int cd_sculpt_vert,
len_squared_v2v2(lastuv2[i], luv->uv) > uv_snap_limit;
if (!same) {
mv->flag |= SCULPTVERT_UV_BOUNDARY;
newflag |= SCULPTVERT_UV_BOUNDARY;
}
if (corner) {
mv->flag |= SCULPTVERT_UV_CORNER;
newflag |= SCULPTVERT_UV_CORNER;
}
if (!same) {
@ -1922,7 +1944,7 @@ void bke_pbvh_update_vert_boundary(int cd_sculpt_vert,
}
if (BM_ELEM_CD_GET_INT(e->l->f, cd_face_node_offset) != ni) {
mv->flag |= SCULPTVERT_PBVH_BOUNDARY;
newflag |= SCULPTVERT_PBVH_BOUNDARY;
}
if (e->l != e->l->radial_next) {
@ -1935,7 +1957,7 @@ void bke_pbvh_update_vert_boundary(int cd_sculpt_vert,
}
if (BM_ELEM_CD_GET_INT(e->l->radial_next->f, cd_face_node_offset) != ni) {
mv->flag |= SCULPTVERT_PBVH_BOUNDARY;
newflag |= SCULPTVERT_PBVH_BOUNDARY;
}
}
@ -1943,7 +1965,7 @@ void bke_pbvh_update_vert_boundary(int cd_sculpt_vert,
BM_ELEM_CD_GET_INT(e->l->f, cd_faceset_offset), bound_symmetry, v2->co);
if (e->l->f->len > 3) {
mv->flag |= SCULPTVERT_NEED_TRIANGULATE;
newflag |= SCULPTVERT_NEED_TRIANGULATE;
}
bool ok = true;
@ -1983,37 +2005,36 @@ void bke_pbvh_update_vert_boundary(int cd_sculpt_vert,
}
if (e->l->radial_next->f->len > 3) {
mv->flag |= SCULPTVERT_NEED_TRIANGULATE;
newflag |= SCULPTVERT_NEED_TRIANGULATE;
}
}
}
if (!e->l || e->l->radial_next == e->l) {
mv->flag |= SCULPTVERT_BOUNDARY;
newflag |= SCULPTVERT_BOUNDARY;
}
val++;
} while ((e = BM_DISK_EDGE_NEXT(e, v)) != v->e);
if (BLI_array_len(fsets) > 1) {
mv->flag |= SCULPTVERT_FSET_BOUNDARY;
newflag |= SCULPTVERT_FSET_BOUNDARY;
}
if (BLI_array_len(fsets) > 2) {
mv->flag |= SCULPTVERT_FSET_CORNER;
newflag |= SCULPTVERT_FSET_CORNER;
}
if (sharpcount == 1) {
mv->flag |= SCULPTVERT_SHARP_CORNER;
newflag |= SCULPTVERT_SHARP_CORNER;
}
if (seamcount == 1) {
mv->flag |= SCULPTVERT_SEAM_CORNER;
newflag |= SCULPTVERT_SEAM_CORNER;
}
mv->valence = val;
if ((mv->flag & SCULPTVERT_BOUNDARY) && quadcount >= 3) {
mv->flag |= SCULPTVERT_CORNER;
if ((newflag & SCULPTVERT_BOUNDARY) && quadcount >= 3) {
newflag |= SCULPTVERT_CORNER;
}
#if 0
@ -2034,8 +2055,16 @@ void bke_pbvh_update_vert_boundary(int cd_sculpt_vert,
}
#endif
// mv->curv = (short)(fabsf(min_ff(curv * 50.0f, 1.0f)) * 32767.0f);
mv->curv = (short)(min_ff(fabsf(curv), 1.0f) * 65535.0f);
atomic_cas_int32(&mv->flag, oldflag, newflag);
atomic_cas_short2(&mv->valence, (ushort)oldval, stroke_id, (ushort)val, stroke_id);
/* no atomic_cas_int16, so do origmask and curv at once */
ushort newcurv = (unsigned short)(min_ff(fabsf(curv), 1.0f) * 65535.0f);
ushort oldcurv = mv->curv;
ushort origmask = mv->origmask;
atomic_cas_short2(&mv->origmask, origmask, oldcurv, origmask, newcurv);
BLI_array_free(fsets);
}