[Bf-blender-cvs] [6e999e08ab8] master: T88352: Use threaded ibo.tris extraction for single material meshes.

Jeroen Bakker noreply at git.blender.org
Wed Jun 9 16:20:55 CEST 2021


Commit: 6e999e08ab87712a9baca33ab691af2b83762b7e
Author: Jeroen Bakker
Date:   Wed Jun 9 16:20:38 2021 +0200
Branches: master
https://developer.blender.org/rB6e999e08ab87712a9baca33ab691af2b83762b7e

T88352: Use threaded ibo.tris extraction for single material meshes.

This patch adds a specific extraction method when the mesh has only
one material. This method is multi-threaded.

There is a trade-off in this patch as the ibo isn't compressed (it adds
restart indexes for hidden faces). So it depends if threading is faster
than the additional GPU buffer upload.

# Subdivided cube
I used a cube subdivided 7 times, modifiers applied. that gives around 400000 faces.

The test is selecting some vertices and move them. During this test the next buffers are updated on each frame:
* vbo.pos_nor
* vbo.lnor
* vbo.edit_data
* ibo.tris
* ibo.points

System info:
|platform| Linux-5.11.0-7614-generic-x86_64-with-glibc2.33|
| renderer|      AMD SIENNA_CICHLID (DRM 3.40.0, 5.11.0-7614-generic, LLVM 11.0.1)|
|vendor|         AMD|
|version|        4.6 (Core Profile) Mesa 21.0.1|
|cpu|              Intel(R) Core(TM) i7-6700 CPU @ 3.40GHz|
|compiler|     gcc version 10.3.0|

Timing have been measured using DEBUG_TIME in `draw_cache_extract_mesh`.

master: `rdata 8ms iter 45ms (frame 153ms)`
this patch `rdata 6ms iter 36ms (frame 132ms)`

Reviewed By: mano-wii

Maniphest Tasks: T88352

Differential Revision: https://developer.blender.org/D11290

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

M	source/blender/draw/intern/draw_cache_extract.h
M	source/blender/draw/intern/draw_cache_extract_mesh.cc
M	source/blender/draw/intern/draw_cache_extract_mesh_extractors.c
M	source/blender/draw/intern/draw_cache_extract_mesh_private.h
M	source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc

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

diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h
index 0b6dffa9073..304cae1d2dc 100644
--- a/source/blender/draw/intern/draw_cache_extract.h
+++ b/source/blender/draw/intern/draw_cache_extract.h
@@ -90,7 +90,7 @@ ENUM_OPERATORS(eMRDataType, MR_DATA_TAN_LOOP_NOR)
 extern "C" {
 #endif
 
-BLI_INLINE int mesh_render_mat_len_get(Mesh *me)
+BLI_INLINE int mesh_render_mat_len_get(const Mesh *me)
 {
   /* In edit mode, the displayed mesh is stored in the edit-mesh. */
   if (me->edit_mesh && me->edit_mesh->mesh_eval_final) {
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc
index 7b2c0da4dd9..6b5877e6759 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.cc
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc
@@ -866,6 +866,7 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
    */
   const bool do_hq_normals = (scene->r.perf_flag & SCE_PERF_HQ_NORMALS) != 0 ||
                              GPU_use_hq_normals_workaround();
+  const bool override_single_mat = mesh_render_mat_len_get(me) <= 1;
 
   /* Create an array containing all the extractors that needs to be executed. */
   ExtractorRunDatas extractors;
@@ -873,7 +874,8 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
 #define EXTRACT_ADD_REQUESTED(type, type_lowercase, name) \
   do { \
     if (DRW_##type_lowercase##_requested(mbc->type_lowercase.name)) { \
-      const MeshExtract *extractor = mesh_extract_override_get(&extract_##name, do_hq_normals); \
+      const MeshExtract *extractor = mesh_extract_override_get( \
+          &extract_##name, do_hq_normals, override_single_mat); \
       extractors.append(extractor); \
     } \
   } while (0)
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_extractors.c b/source/blender/draw/intern/draw_cache_extract_mesh_extractors.c
index b79f80866ec..3cac391c42d 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh_extractors.c
+++ b/source/blender/draw/intern/draw_cache_extract_mesh_extractors.c
@@ -94,12 +94,26 @@ static const MeshExtract *mesh_extract_override_hq_normals(const MeshExtract *ex
   return extractor;
 }
 
+static const MeshExtract *mesh_extract_override_single_material(const MeshExtract *extractor)
+{
+  if (extractor == &extract_tris) {
+    return &extract_tris_single_mat;
+  }
+  return extractor;
+}
+
 const MeshExtract *mesh_extract_override_get(const MeshExtract *extractor,
-                                             const bool do_hq_normals)
+                                             const bool do_hq_normals,
+                                             const bool do_single_mat)
 {
   if (do_hq_normals) {
     extractor = mesh_extract_override_hq_normals(extractor);
   }
+
+  if (do_single_mat) {
+    extractor = mesh_extract_override_single_material(extractor);
+  }
+
   return extractor;
 }
 
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_private.h b/source/blender/draw/intern/draw_cache_extract_mesh_private.h
index e4ea3e44843..e2d97b73db2 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh_private.h
+++ b/source/blender/draw/intern/draw_cache_extract_mesh_private.h
@@ -468,13 +468,15 @@ void mesh_render_data_update_looptris(MeshRenderData *mr,
 void *mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferCache *mbc);
 eMRIterType mesh_extract_iter_type(const MeshExtract *ext);
 const MeshExtract *mesh_extract_override_get(const MeshExtract *extractor,
-                                             const bool do_hq_normals);
+                                             const bool do_hq_normals,
+                                             const bool do_single_mat);
 /*
  * Total number of extractions types.
  */
 #define M_EXTRACT_LEN 38
 
 extern const MeshExtract extract_tris;
+extern const MeshExtract extract_tris_single_mat;
 extern const MeshExtract extract_lines;
 extern const MeshExtract extract_lines_with_lines_loose;
 extern const MeshExtract extract_lines_loose_only;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc
index aab9ae8c228..acfffdacb88 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc
@@ -28,7 +28,7 @@
 namespace blender::draw {
 
 /* ---------------------------------------------------------------------- */
-/** \name Extract Triangles Indices
+/** \name Extract Triangles Indices (multi material)
  * \{ */
 
 struct MeshExtract_Tri_Data {
@@ -168,8 +168,115 @@ constexpr MeshExtract create_extractor_tris()
 
 /** \} */
 
+/** \name Extract Triangles Indices (single material)
+ * \{ */
+
+static void *extract_tris_single_mat_init(const MeshRenderData *mr,
+                                          struct MeshBatchCache *UNUSED(cache),
+                                          void *UNUSED(ibo))
+{
+  GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(MEM_mallocN(sizeof(*elb), __func__));
+  GPU_indexbuf_init(elb, GPU_PRIM_TRIS, mr->tri_len, mr->loop_len);
+  return elb;
+}
+
+static void *extract_tris_single_mat_task_init(void *_userdata)
+{
+  GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_userdata);
+  GPUIndexBufBuilder *sub_builder = static_cast<GPUIndexBufBuilder *>(
+      MEM_mallocN(sizeof(*sub_builder), __func__));
+  GPU_indexbuf_subbuilder_init(elb, sub_builder);
+  return sub_builder;
+}
+
+static void extract_tris_single_mat_iter_looptri_bm(const MeshRenderData *UNUSED(mr),
+                                                    BMLoop **elt,
+                                                    const int elt_index,
+                                                    void *_data)
+{
+  GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_data);
+  if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) {
+    GPU_indexbuf_set_tri_verts(elb,
+                               elt_index,
+                               BM_elem_index_get(elt[0]),
+                               BM_elem_index_get(elt[1]),
+                               BM_elem_index_get(elt[2]));
+  }
+  else {
+    GPU_indexbuf_set_tri_restart(elb, elt_index);
+  }
+}
+
+static void extract_tris_single_mat_iter_looptri_mesh(const MeshRenderData *mr,
+                                                      const MLoopTri *mlt,
+                                                      const int mlt_index,
+                                                      void *_data)
+{
+  GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_data);
+  const MPoly *mp = &mr->mpoly[mlt->poly];
+  if (!(mr->use_hide && (mp->flag & ME_HIDE))) {
+    GPU_indexbuf_set_tri_verts(elb, mlt_index, mlt->tri[0], mlt->tri[1], mlt->tri[2]);
+  }
+  else {
+    GPU_indexbuf_set_tri_restart(elb, mlt_index);
+  }
+}
+
+static void extract_tris_single_mat_task_finish(void *_userdata, void *_task_userdata)
+{
+  GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_userdata);
+  GPUIndexBufBuilder *sub_builder = static_cast<GPUIndexBufBuilder *>(_task_userdata);
+  GPU_indexbuf_subbuilder_finish(elb, sub_builder);
+  MEM_freeN(sub_builder);
+}
+
+static void extract_tris_single_mat_finish(const MeshRenderData *mr,
+                                           struct MeshBatchCache *cache,
+                                           void *buf,
+                                           void *_data)
+{
+  GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
+  GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_data);
+  GPU_indexbuf_build_in_place(elb, ibo);
+
+  /* Create ibo sub-ranges. Always do this to avoid error when the standard surface batch
+   * is created before the surfaces-per-material. */
+  if (mr->use_final_mesh && cache->final.tris_per_mat) {
+    MeshBufferCache *mbc = &cache->final;
+    for (int i = 0; i < mr->mat_len; i++) {
+      /* These IBOs have not been queried yet but we create them just in case they are needed
+       * later since they are not tracked by mesh_buffer_cache_create_requested(). */
+      if (mbc->tris_per_mat[i] == NULL) {
+        mbc->tris_per_mat[i] = GPU_indexbuf_calloc();
+      }
+      /* Multiply by 3 because these are triangle indices. */
+      const int len = mr->tri_len * 3;
+      GPU_indexbuf_create_subrange_in_place(mbc->tris_per_mat[i], ibo, 0, len);
+    }
+  }
+  MEM_freeN(elb);
+}
+
+constexpr MeshExtract create_extractor_tris_single_mat()
+{
+  MeshExtract extractor = {0};
+  extractor.init = extract_tris_single_mat_init;
+  extractor.task_init = extract_tris_single_mat_task_init;
+  extractor.iter_looptri_bm = extract_tris_single_mat_iter_looptri_bm;
+  extractor.iter_looptri_mesh = extract_tris_single_mat_iter_looptri_mesh;
+  extractor.task_finish = extract_tris_single_mat_task_finish;
+  extractor.finish = extract_tris_single_mat_finish;
+  extractor.data_type = MR_DATA_NONE;
+  extractor.use_threading = true;
+  extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.tris);
+  return extractor;
+}
+
+/** \} */
+
 }  // namespace blender::draw
 
 extern "C" {
 const MeshExtract extract_tris = blender::draw::create_extractor_tris();
+const MeshExtract extract_tris_single_mat = blender::draw::create_extractor_tris_single_mat();
 }



More information about the Bf-blender-cvs mailing list