Sculpt-dev: fix thread contention
in weighted smooth * Cached face areas are now updated in a double buffered fashion; all threads read from one side of the buffer while the other is written to by the threads that own a given face; the buffers are swapped on each iteration of a tool that uses face areas. * Fixes smooth flickering.
This commit is contained in:
parent
e21c21bbf9
commit
628925a5c6
|
@ -2449,7 +2449,7 @@ static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform, bool
|
|||
BKE_sculptsession_check_mdyntopo(ob->sculpt, pbvh, me->totvert);
|
||||
|
||||
MEM_SAFE_FREE(ss->face_areas);
|
||||
ss->face_areas = MEM_calloc_arrayN(me->totpoly, sizeof(float), "ss->face_areas");
|
||||
ss->face_areas = MEM_calloc_arrayN(me->totpoly, sizeof(float) * 2, "ss->face_areas");
|
||||
|
||||
BKE_pbvh_build_mesh(pbvh,
|
||||
me,
|
||||
|
@ -2496,7 +2496,7 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect
|
|||
int totgridfaces = base_mesh->totpoly * (key.grid_size - 1) * (key.grid_size - 1);
|
||||
|
||||
MEM_SAFE_FREE(ss->face_areas);
|
||||
ss->face_areas = MEM_calloc_arrayN(totgridfaces, sizeof(float), "ss->face_areas");
|
||||
ss->face_areas = MEM_calloc_arrayN(totgridfaces, sizeof(float) * 2, "ss->face_areas");
|
||||
|
||||
BKE_pbvh_build_grids(pbvh,
|
||||
subdiv_ccg->grids,
|
||||
|
@ -2944,7 +2944,7 @@ void BKE_sculptsession_bmesh_add_layers(Object *ob)
|
|||
|
||||
BMCustomLayerReq flayers[] = {
|
||||
{CD_PROP_INT32, dyntopop_node_idx_layer_id, CD_FLAG_TEMPORARY | CD_FLAG_NOCOPY},
|
||||
{CD_PROP_FLOAT, dyntopop_faces_areas_layer_id, CD_FLAG_TEMPORARY | CD_FLAG_NOCOPY},
|
||||
{CD_PROP_FLOAT2, dyntopop_faces_areas_layer_id, CD_FLAG_TEMPORARY | CD_FLAG_NOCOPY},
|
||||
};
|
||||
BM_data_layers_ensure(ss->bm, &ss->bm->pdata, flayers, 2);
|
||||
|
||||
|
|
|
@ -4248,8 +4248,17 @@ void BKE_pbvh_node_mark_update_tri_area(PBVHNode *node)
|
|||
node->flag |= PBVH_UpdateTriAreas;
|
||||
}
|
||||
|
||||
/* must be called outside of threads */
|
||||
void BKE_pbvh_face_areas_begin(PBVH *pbvh)
|
||||
{
|
||||
pbvh->face_area_i ^= 1;
|
||||
}
|
||||
|
||||
void BKE_pbvh_update_all_tri_areas(PBVH *pbvh)
|
||||
{
|
||||
/* swap read/write face area buffers */
|
||||
pbvh->face_area_i ^= 1;
|
||||
|
||||
for (int i = 0; i < pbvh->totnode; i++) {
|
||||
PBVHNode *node = pbvh->nodes + i;
|
||||
if (node->flag & PBVH_Leaf) {
|
||||
|
@ -4279,6 +4288,8 @@ void BKE_pbvh_check_tri_areas(PBVH *pbvh, PBVHNode *node)
|
|||
BKE_pbvh_bmesh_check_tris(pbvh, node);
|
||||
}
|
||||
|
||||
const int cur_i = pbvh->face_area_i ^ 1;
|
||||
|
||||
switch (BKE_pbvh_type(pbvh)) {
|
||||
case PBVH_FACES: {
|
||||
for (int i = 0; i < node->totprim; i++) {
|
||||
|
@ -4289,7 +4300,7 @@ void BKE_pbvh_check_tri_areas(PBVH *pbvh, PBVHNode *node)
|
|||
continue;
|
||||
}
|
||||
|
||||
pbvh->face_areas[lt->poly] = 0.0f;
|
||||
pbvh->face_areas[lt->poly * 2 + cur_i] = 0.0f;
|
||||
}
|
||||
|
||||
for (int i = 0; i < node->totprim; i++) {
|
||||
|
@ -4304,7 +4315,14 @@ void BKE_pbvh_check_tri_areas(PBVH *pbvh, PBVHNode *node)
|
|||
MVert *mv2 = pbvh->verts + pbvh->mloop[lt->tri[1]].v;
|
||||
MVert *mv3 = pbvh->verts + pbvh->mloop[lt->tri[2]].v;
|
||||
|
||||
pbvh->face_areas[lt->poly] += area_tri_v3(mv1->co, mv2->co, mv3->co);
|
||||
float area = area_tri_v3(mv1->co, mv2->co, mv3->co);
|
||||
|
||||
pbvh->face_areas[lt->poly * 2 + cur_i] += area;
|
||||
|
||||
/* sanity check on read side of read write buffer */
|
||||
if (pbvh->face_areas[lt->poly * 2 + (cur_i ^ 1)] == 0.0f) {
|
||||
pbvh->face_areas[lt->poly * 2 + (cur_i ^ 1)] = pbvh->face_areas[lt->poly * 2 + cur_i];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -4313,7 +4331,8 @@ void BKE_pbvh_check_tri_areas(PBVH *pbvh, PBVHNode *node)
|
|||
const int cd_face_area = pbvh->cd_face_area;
|
||||
|
||||
TGSET_ITER (f, node->bm_faces) {
|
||||
BM_ELEM_CD_SET_FLOAT(f, cd_face_area, 0.0f);
|
||||
float *areabuf = BM_ELEM_CD_GET_VOID_P(f, cd_face_area);
|
||||
areabuf[cur_i] = 0.0f;
|
||||
}
|
||||
TGSET_ITER_END;
|
||||
|
||||
|
@ -4325,10 +4344,12 @@ void BKE_pbvh_check_tri_areas(PBVH *pbvh, PBVHNode *node)
|
|||
BMVert *v3 = (BMVert *)(node->tribuf->verts[tri->v[2]].i);
|
||||
BMFace *f = (BMFace *)tri->f.i;
|
||||
|
||||
float *areabuf = BM_ELEM_CD_GET_VOID_P(f, cd_face_area);
|
||||
|
||||
float area = area_tri_v3(v1->co, v2->co, v3->co);
|
||||
float farea = BM_ELEM_CD_GET_FLOAT(f, cd_face_area);
|
||||
|
||||
BM_ELEM_CD_SET_FLOAT(f, cd_face_area, farea + area);
|
||||
areabuf[cur_i] = farea + area;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -4439,6 +4460,8 @@ void BKE_pbvh_set_vemap(PBVH *pbvh, MeshElemMap *vemap)
|
|||
|
||||
void BKE_pbvh_get_vert_face_areas(PBVH *pbvh, SculptVertRef vertex, float *r_areas, int valence)
|
||||
{
|
||||
const int cur_i = pbvh->face_area_i;
|
||||
|
||||
switch (BKE_pbvh_type(pbvh)) {
|
||||
case PBVH_FACES: {
|
||||
int *edges = BLI_array_alloca(edges, 16);
|
||||
|
@ -4470,10 +4493,10 @@ void BKE_pbvh_get_vert_face_areas(PBVH *pbvh, SculptVertRef vertex, float *r_are
|
|||
}
|
||||
}
|
||||
for (int i = 0; i < len; i++) {
|
||||
r_areas[i] = pbvh->face_areas[polys[i * 2]];
|
||||
r_areas[i] = pbvh->face_areas[polys[i * 2] * 2 + cur_i];
|
||||
|
||||
if (polys[i * 2 + 1] != -1) {
|
||||
r_areas[i] += pbvh->face_areas[polys[i * 2 + 1]];
|
||||
r_areas[i] += pbvh->face_areas[polys[i * 2 + 1] * 2 + cur_i];
|
||||
r_areas[i] *= 0.5f;
|
||||
}
|
||||
}
|
||||
|
@ -4507,8 +4530,11 @@ void BKE_pbvh_get_vert_face_areas(PBVH *pbvh, SculptVertRef vertex, float *r_are
|
|||
w = 0.0f;
|
||||
}
|
||||
else {
|
||||
w += BM_ELEM_CD_GET_FLOAT(e->l->f, cd_face_area) * 0.5f;
|
||||
w += BM_ELEM_CD_GET_FLOAT(e->l->radial_next->f, cd_face_area) * 0.5f;
|
||||
float *a1 = BM_ELEM_CD_GET_VOID_P(e->l->f, cd_face_area);
|
||||
float *a2 = BM_ELEM_CD_GET_VOID_P(e->l->radial_next->f, cd_face_area);
|
||||
|
||||
w += a1[cur_i] * 0.5f;
|
||||
w += a2[cur_i] * 0.5f;
|
||||
}
|
||||
|
||||
if (j >= valence) {
|
||||
|
|
|
@ -45,6 +45,7 @@ Topology rake:
|
|||
#include "BLI_array.h"
|
||||
#include "BLI_buffer.h"
|
||||
#include "BLI_ghash.h"
|
||||
#include "BLI_hash.h"
|
||||
#include "BLI_heap_simple.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_memarena.h"
|
||||
|
@ -2463,6 +2464,31 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh,
|
|||
}
|
||||
|
||||
pbvh_print_mem_size(pbvh);
|
||||
|
||||
/* update face areas */
|
||||
const int cd_face_area = pbvh->cd_face_area;
|
||||
for (int i = 0; i < pbvh->totnode; i++) {
|
||||
PBVHNode *node = pbvh->nodes + i;
|
||||
|
||||
if (!(node->flag & PBVH_Leaf)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BKE_pbvh_bmesh_check_tris(pbvh, node);
|
||||
|
||||
node->flag |= PBVH_UpdateTriAreas;
|
||||
BKE_pbvh_check_tri_areas(pbvh, node);
|
||||
|
||||
int area_src_i = pbvh->face_area_i ^ 1;
|
||||
int area_dst_i = pbvh->face_area_i;
|
||||
|
||||
/* make sure read side of double buffer is set too */
|
||||
TGSET_ITER (f, node->bm_faces) {
|
||||
float *areabuf = BM_ELEM_CD_GET_VOID_P(f, cd_face_area);
|
||||
areabuf[area_dst_i] = areabuf[area_src_i];
|
||||
}
|
||||
TGSET_ITER_END;
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_pbvh_set_bm_log(PBVH *pbvh, struct BMLog *log)
|
||||
|
@ -2808,7 +2834,8 @@ static uintptr_t tri_loopkey(BMLoop *l, int mat_nr, int cd_fset, int cd_uvs[], i
|
|||
key ^= (uintptr_t)l->v;
|
||||
|
||||
if (cd_fset >= 0) {
|
||||
key ^= BM_ELEM_CD_GET_INT(l->f, cd_fset);
|
||||
// key ^= (uintptr_t)BLI_hash_int(BM_ELEM_CD_GET_INT(l->f, cd_fset));
|
||||
key ^= (uintptr_t)BM_ELEM_CD_GET_INT(l->f, cd_fset);
|
||||
}
|
||||
|
||||
for (int i = 0; i < totuv; i++) {
|
||||
|
|
|
@ -172,7 +172,8 @@ struct PBVH {
|
|||
int face_sets_color_seed;
|
||||
int face_sets_color_default;
|
||||
int *face_sets;
|
||||
float *face_areas;
|
||||
float *face_areas; /* float2 vector, double buffered to avoid thread contention */
|
||||
int face_area_i;
|
||||
|
||||
/* Grid Data */
|
||||
CCGKey gridkey;
|
||||
|
|
|
@ -412,6 +412,8 @@ void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
|
|||
ss->cache->automasking->settings.flags &= ~BRUSH_AUTOMASKING_FACE_SETS;
|
||||
}
|
||||
|
||||
bool modified = false;
|
||||
|
||||
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
|
||||
if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
|
||||
MeshElemMap *vert_map = &ss->pmap[vd.index];
|
||||
|
@ -501,6 +503,7 @@ void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
|
|||
|
||||
if (ok) {
|
||||
ss->face_sets[vert_map->indices[j]] = new_fset;
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -590,6 +593,7 @@ void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
|
|||
|
||||
if (ok) {
|
||||
BM_ELEM_CD_SET_INT(f, ss->cd_faceset_offset, new_fset);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -621,12 +625,17 @@ void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
|
|||
|
||||
if (!use_fset_strength || fade > test_limit) {
|
||||
SCULPT_vertex_face_set_set(ss, vd.vertex, new_fset);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BKE_pbvh_vertex_iter_end;
|
||||
|
||||
if (modified) {
|
||||
BKE_pbvh_node_mark_update_triangulation(data->nodes[n]);
|
||||
}
|
||||
|
||||
// restore automasking flag
|
||||
if (set_active_faceset) {
|
||||
ss->cache->automasking->settings.flags |= automasking_fset_flag;
|
||||
|
|
|
@ -781,6 +781,10 @@ static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent *
|
|||
bool needs_pmap = sculpt_mesh_filter_needs_pmap(filter_type);
|
||||
BKE_sculpt_update_object_for_edit(depsgraph, ob, needs_pmap, false, false);
|
||||
|
||||
if (ELEM(filter_type, MESH_FILTER_SMOOTH) && ss->filter_cache->weighted_smooth) {
|
||||
BKE_pbvh_update_all_tri_areas(ss->pbvh);
|
||||
}
|
||||
|
||||
SculptThreadedTaskData data = {
|
||||
.sd = sd,
|
||||
.ob = ob,
|
||||
|
|
|
@ -1655,10 +1655,15 @@ void SCULPT_smooth(Sculpt *sd,
|
|||
return;
|
||||
}
|
||||
|
||||
if (SCULPT_stroke_is_first_brush_step(ss->cache) &&
|
||||
((ss->cache->brush->flag2 & BRUSH_SMOOTH_USE_AREA_WEIGHT) ||
|
||||
ss->cache->brush->boundary_smooth_factor > 0.0f)) {
|
||||
BKE_pbvh_update_all_tri_areas(ss->pbvh);
|
||||
if ((ss->cache->brush->flag2 & BRUSH_SMOOTH_USE_AREA_WEIGHT) ||
|
||||
ss->cache->brush->boundary_smooth_factor > 0.0f) {
|
||||
if (SCULPT_stroke_is_first_brush_step(ss->cache)) {
|
||||
BKE_pbvh_update_all_tri_areas(ss->pbvh);
|
||||
}
|
||||
else {
|
||||
void BKE_pbvh_face_areas_begin(PBVH * pbvh);
|
||||
BKE_pbvh_face_areas_begin(ss->pbvh);
|
||||
}
|
||||
}
|
||||
|
||||
SculptLayerParams params = {.permanent = false, .simple_array = false};
|
||||
|
|
Loading…
Reference in New Issue