[Bf-blender-cvs] [a0ec3b7fd76] tmp-batch-cache-cleanup: Mesh Batch Cache: Fix some threadsafety issue with indices buffers

Clément Foucault noreply at git.blender.org
Tue Jul 23 00:10:55 CEST 2019


Commit: a0ec3b7fd761155b5f82b3cfb0f305d6a04d6127
Author: Clément Foucault
Date:   Tue Jul 23 00:05:15 2019 +0200
Branches: tmp-batch-cache-cleanup
https://developer.blender.org/rBa0ec3b7fd761155b5f82b3cfb0f305d6a04d6127

Mesh Batch Cache: Fix some threadsafety issue with indices buffers

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

M	source/blender/draw/intern/draw_cache_impl_mesh.c
M	source/blender/gpu/intern/gpu_element.c

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

diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index 094cff77ea5..d9edbdc4511 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -233,6 +233,21 @@ BLI_INLINE void mesh_cd_layers_type_clear(DRW_MeshCDMask *a)
   *((uint32_t *)a) = 0;
 }
 
+BLI_INLINE BMFace *bm_original_face_get(BMesh *bm, int idx)
+{
+  return ((idx != ORIGINDEX_NONE) ? BM_face_at_index(bm, idx) : NULL);
+}
+
+BLI_INLINE BMEdge *bm_original_edge_get(BMesh *bm, int idx)
+{
+  return ((idx != ORIGINDEX_NONE) ? BM_edge_at_index(bm, idx) : NULL);
+}
+
+BLI_INLINE BMVert *bm_original_vert_get(BMesh *bm, int idx)
+{
+  return ((idx != ORIGINDEX_NONE) ? BM_vert_at_index(bm, idx) : NULL);
+}
+
 static void mesh_cd_calc_active_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used)
 {
   const CustomData *cd_ldata = (me->edit_mesh) ? &me->edit_mesh->bm->ldata : &me->ldata;
@@ -1201,7 +1216,7 @@ typedef struct MeshExtractIterData {
   int v1, v2, v3;
 
   bool use_hide;
-  MeshRenderData *mr;
+  const MeshRenderData *mr;
   /** iter function list */
   void *itr_fn;
 } MeshExtractIterData;
@@ -1224,93 +1239,132 @@ typedef struct MeshExtract {
 /** \name Extract Triangles Indices
  * \{ */
 
-typedef struct MeshExtract_Tri_Data {
-  GPUIndexBufBuilder elb;
-  uint32_t mat_tri_idx[0];
-} MeshExtract_Tri_Data;
-
 static void *mesh_tri_init(const MeshRenderData *mr, void *UNUSED(ibo))
 {
-  size_t mat_tri_idx_size = sizeof(uint32_t) * mr->mat_len;
-  MeshExtract_Tri_Data *data = MEM_callocN(sizeof(*data) + mat_tri_idx_size, __func__);
-  GPU_indexbuf_init(&data->elb, GPU_PRIM_TRIS, mr->tri_len, mr->loop_len);
-  /* Set all indices to primitive restart. We do this to bypass hidden elements. */
-  /* NOTE: This is not the best method as it leave holes in the index buffer.
-   * TODO(fclem): Better approach would be to remove the holes by moving all the indices block to
-   * have a continuous buffer. The issue is that we need to randomly set indices in the buffer
-   * for multithreading. */
-  // memset(data->elb.data, 0xFF, sizeof(uint) * mr->tri_len * 3);
-  /* Count how many triangle for each material. */
-  if (mr->mat_len > 1) {
-    if (mr->extract_type == MR_EXTRACT_BMESH) {
-      BMIter iter;
-      BMFace *efa;
-      BM_ITER_MESH (efa, &iter, mr->bm, BM_FACES_OF_MESH) {
-        BLI_assert(efa->len > 2);
-        data->mat_tri_idx[efa->mat_nr] += efa->len - 2;
-      }
-    }
-    else {
-      const MPoly *mpoly = mr->mpoly;
-      for (int p = 0; p < mr->poly_len; p++, mpoly++) {
-        BLI_assert(mpoly->totloop > 2);
-        data->mat_tri_idx[mpoly->mat_nr] += mpoly->totloop - 2;
-      }
-    }
-  }
-  /* Accumulate tri len per mat to have correct offsets. */
-  int ofs = data->mat_tri_idx[0];
-  data->mat_tri_idx[0] = 0;
-  for (int i = 1; i < mr->mat_len; i++) {
-    int tmp = data->mat_tri_idx[i];
-    data->mat_tri_idx[i] = ofs;
-    ofs += tmp;
-  }
-  /* HACK pass per mat triangle start and end outside the extract loop. */
-  MEM_SAFE_FREE(mr->cache->tri_mat_end);
-  MEM_SAFE_FREE(mr->cache->tri_mat_start);
-  mr->cache->tri_mat_end = MEM_mallocN(mat_tri_idx_size, __func__);
-  mr->cache->tri_mat_start = MEM_mallocN(mat_tri_idx_size, __func__);
-  memcpy(mr->cache->tri_mat_start, data->mat_tri_idx, mat_tri_idx_size);
+  GPUIndexBufBuilder *elb = MEM_callocN(sizeof(*elb), __func__);
+  GPU_indexbuf_init(elb, GPU_PRIM_TRIS, mr->tri_len, mr->loop_len);
 
-  return data;
+  return elb;
 }
-static void mesh_tri_iter(const MeshExtractIterData *iter, void *UNUSED(buf), void *user_data)
+static void mesh_tri_iter(const MeshExtractIterData *iter, void *UNUSED(buf), void *elb)
 {
   if (!(iter->use_hide && (iter->mpoly->flag & ME_HIDE))) {
-    MeshExtract_Tri_Data *data = user_data;
-    uint32_t tri_idx = atomic_fetch_and_add_uint32(&data->mat_tri_idx[iter->mpoly->mat_nr], 1u);
-    GPU_indexbuf_set_tri_verts(&data->elb, tri_idx, iter->v1, iter->v2, iter->v3);
+    GPU_indexbuf_set_tri_verts(elb, iter->tri_idx, iter->v1, iter->v2, iter->v3);
+  }
+  else {
+    GPU_indexbuf_set_tri_restart(elb, iter->tri_idx);
   }
 }
-static void mesh_tri_iter_edit(const MeshExtractIterData *iter, void *UNUSED(buf), void *user_data)
+static void mesh_tri_iter_edit(const MeshExtractIterData *iter, void *UNUSED(buf), void *elb)
 {
   if (!iter->efa) {
-    mesh_tri_iter(iter, NULL, user_data);
+    mesh_tri_iter(iter, NULL, elb);
   }
   else if (!BM_elem_flag_test(iter->efa, BM_ELEM_HIDDEN)) {
-    MeshExtract_Tri_Data *data = user_data;
-    uint32_t tri_idx = atomic_fetch_and_add_uint32(&data->mat_tri_idx[iter->efa->mat_nr], 1u);
-    GPU_indexbuf_set_tri_verts(&data->elb, tri_idx, iter->v1, iter->v2, iter->v3);
+    GPU_indexbuf_set_tri_verts(elb, iter->tri_idx, iter->v1, iter->v2, iter->v3);
+  }
+  else {
+    GPU_indexbuf_set_tri_restart(elb, iter->tri_idx);
   }
 }
-static void mesh_tri_finish(const MeshRenderData *mr, void *ibo, void *user_data)
+static void mesh_tri_finish(const MeshRenderData *mr, void *ibo, void *elb)
 {
-  MeshExtract_Tri_Data *data = user_data;
-  GPU_indexbuf_build_in_place(&data->elb, ibo);
+  MEM_SAFE_FREE(mr->cache->tri_mat_end);
+  MEM_SAFE_FREE(mr->cache->tri_mat_start);
   /* HACK pass per mat triangle start and end outside the extract loop. */
-  memcpy(mr->cache->tri_mat_end, data->mat_tri_idx, sizeof(uint32_t) * mr->mat_len);
+  size_t mat_tri_idx_size = sizeof(int) * mr->mat_len;
+  mr->cache->tri_mat_start = MEM_callocN(mat_tri_idx_size, __func__);
+  mr->cache->tri_mat_end = MEM_callocN(mat_tri_idx_size, __func__);
 
-  for (int mat = 0; mat < mr->mat_len; mat++) {
-    if (mr->cache->tri_mat_end[mat] < mr->cache->tri_mat_start[mat]) {
-      /* Fill the rest of the buffer with restart index. */
-      for (int tri = mr->cache->tri_mat_end[mat]; tri < mr->cache->tri_mat_start[mat]; tri++) {
-        GPU_indexbuf_set_tri_restart(&data->elb, tri);
+  if (mr->mat_len > 1) {
+    int *mat_tri_ofs = mr->cache->tri_mat_start;
+    int *mat_tri_len = mr->cache->tri_mat_end;
+    /* Count how many triangle for each material. */
+    if (mr->extract_type == MR_EXTRACT_BMESH) {
+      BMIter iter;
+      BMFace *efa;
+      BM_ITER_MESH (efa, &iter, mr->bm, BM_FACES_OF_MESH) {
+        int poly_tri_len = efa->len - 2;
+        mat_tri_ofs[efa->mat_nr] += poly_tri_len;
+      }
+    }
+    else {
+      const MPoly *mpoly = mr->mpoly;
+      for (int p = 0; p < mr->poly_len; p++, mpoly++) {
+        int poly_tri_len = mpoly->totloop - 2;
+        mat_tri_ofs[mpoly->mat_nr] += poly_tri_len;
       }
     }
+    // memcpy(mat_tri_len, mat_tri_ofs, sizeof(*mat_tri_len) * mr->mat_len);
+    /* Accumulate tri len per mat to have correct offsets. */
+    int ofs = mat_tri_ofs[0];
+    mat_tri_ofs[0] = 0;
+    for (int i = 1; i < mr->mat_len; i++) {
+      int tmp = mat_tri_ofs[i];
+      mat_tri_ofs[i] = ofs;
+      ofs += tmp;
+    }
+    /* Now sort triangles per materials. */
+    uint(*tri_sorted)[3] = MEM_mallocN(sizeof(*tri_sorted) * mr->tri_len, __func__);
+    uint(*tri_source)[3] = (uint(*)[3])((GPUIndexBufBuilder *)elb)->data;
+    if (mr->extract_type == MR_EXTRACT_BMESH) {
+      int tri_idx = 0;
+      BMIter iter;
+      BMFace *efa;
+      BM_ITER_MESH (efa, &iter, mr->bm, BM_FACES_OF_MESH) {
+        int poly_tri_len = efa->len - 2;
+        uint(*src)[3] = tri_source + tri_idx;
+        uint(*dst)[3] = tri_sorted + mat_tri_ofs[efa->mat_nr] + mat_tri_len[efa->mat_nr];
+        memcpy(dst, src, sizeof(*dst) * poly_tri_len);
+        mat_tri_len[efa->mat_nr] += poly_tri_len;
+        tri_idx += poly_tri_len;
+      }
+    }
+    else {
+      const MPoly *mpoly = mr->mpoly;
+      int mat_curr = mpoly->mat_nr;
+      int cpy_sta = 0, cpy_end = 0, cpy_len;
+      int tri_idx = 0;
+      for (int p = 0; p < mr->poly_len; p++, mpoly++) {
+        if ((mat_curr != mpoly->mat_nr) || (p == mr->poly_len - 1)) {
+          cpy_end = (p == mr->poly_len - 1) ? tri_idx + mpoly->totloop - 2 : tri_idx;
+          cpy_len = cpy_end - cpy_sta;
+          int dst_sta = mat_tri_ofs[mat_curr] + mat_tri_len[mat_curr];
+          uint(*src)[3] = tri_source + cpy_sta;
+          uint(*dst)[3] = tri_sorted + dst_sta;
+          printf("copy mat[%d] %d-%d to %d-%d\n",
+                 mat_curr,
+                 cpy_sta,
+                 cpy_sta + cpy_len,
+                 dst_sta,
+                 dst_sta + cpy_len);
+          memcpy(dst, src, sizeof(*dst) * cpy_len);
+
+          mat_tri_len[mat_curr] += cpy_len;
+          cpy_sta = tri_idx;
+          mat_curr = mpoly->mat_nr;
+        }
+        tri_idx += mpoly->totloop - 2;
+      }
+    }
+
+    /* Replace old (unsorted) data and free it. */
+    ((GPUIndexBufBuilder *)elb)->data = (uint *)tri_sorted;
+    MEM_freeN(tri_source);
+    /* Set material indices end. */
+    for (int i = 1; i < mr->mat_len; i++) {
+      mr->cache->tri_mat_end[i] = mat_tri_ofs[i] + mat_tri_len[i];
+    }
   }
+  else {
+    mr->cache->tri_mat_start[0] = 0;
+    mr->cache->tri_mat_end[0] = mr->tri_len;
+  }
+  /* XXX overriding here in case multithread hazard happened. */
+  ((GPUIndexBufBuilder *)elb)->index_len = mr->tri_len * 3;
+  GPU_indexbuf_build_in_place(elb, ibo);
 
-  MEM_freeN(user_data);
+  MEM_freeN(elb);
 }
 
 MeshExtract extract_tris = {
@@ -1380,7 +1434,8 @@ static void mesh_edge_finish(const MeshRenderData *mr, void *ibo, void *elb)
     mr->cache->edge_loose_start = 0;
     mr->cache->edge_loose_end = 0;
   }
-
+  /* XXX overriding here in case multithread hazard happened. */
+  ((GPUIndexBufBuilder *)elb)->index_len = (mr->edge_len + mr->edge_loose_len) * 2;
   GPU_indexbuf_build_in_place(elb, ibo);
   MEM_freeN(elb);
 }
@@ -1428,8 +1483,10 @@ static void mesh_vert_iter_edit(const MeshExtractIterData *iter, void *UNUSED(bu
     GPU_indexbuf_set_point_restart(elb, iter->vert_idx);
   }
 }
-static void mesh_vert_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *elb)
+static void mesh_vert_finish(const MeshRenderData *mr, void *ibo, void *elb)
 {
+  /* XXX overriding here in case multithread hazard happened. */
+  ((GPUIndexBufBuilder *)elb)->index_len = mr->vert_len;
   GPU_indexbu

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list