[Bf-blender-cvs] [628925a5c67] sculpt-dev: 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.

Joseph Eagar noreply at git.blender.org
Sun Nov 28 11:25:03 CET 2021


Commit: 628925a5c679fd371b42a1b3aeba907c0fb01a99
Author: Joseph Eagar
Date:   Sun Nov 28 02:23:06 2021 -0800
Branches: sculpt-dev
https://developer.blender.org/rB628925a5c679fd371b42a1b3aeba907c0fb01a99

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.

===================================================================

M	source/blender/blenkernel/intern/paint.c
M	source/blender/blenkernel/intern/pbvh.c
M	source/blender/blenkernel/intern/pbvh_bmesh.c
M	source/blender/blenkernel/intern/pbvh_intern.h
M	source/blender/editors/sculpt_paint/sculpt_face_set.c
M	source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
M	source/blender/editors/sculpt_paint/sculpt_smooth.c

===================================================================

diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 9b28a12c57a..03ff3a6d833 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -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);
 
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 83557ba41de..518f065e8b6 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -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) {
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index a6a0d8acf45..d6127f8b430 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -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++) {
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index a361257a9b0..cf566efa75e 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -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;
diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c
index 3a636a9f1c8..b5b6e2e7180 100644
--- a/source/blender/editors/sculpt_paint/sculpt_face_set.c
+++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c
@@ -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;
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
index c8c3965a85e..47c4e2a2dbe 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
@@ -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, 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list