[Bf-blender-cvs] [03aba8046e0] master: LineArt: Object loading optimization

YimingWu noreply at git.blender.org
Wed May 4 16:14:58 CEST 2022


Commit: 03aba8046e07d956e43073502383579b7dfbb284
Author: YimingWu
Date:   Mon Mar 28 13:34:17 2022 +0800
Branches: master
https://developer.blender.org/rB03aba8046e07d956e43073502383579b7dfbb284

LineArt: Object loading optimization

This patch replaces BMesh conversion into index-based triangle adjacent
lookup method, and use multithread in many steps to speed up object
loading for line art.

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

Reviewed By: Sebastian Parborg (zeddb)

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

M	source/blender/gpencil_modifiers/CMakeLists.txt
M	source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
M	source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
A	source/blender/gpencil_modifiers/intern/lineart/lineart_cpp_bridge.cpp
M	source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
M	source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h
M	source/blender/makesdna/DNA_lineart_types.h
M	source/blender/makesrna/intern/rna_gpencil_modifier.c

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

diff --git a/source/blender/gpencil_modifiers/CMakeLists.txt b/source/blender/gpencil_modifiers/CMakeLists.txt
index 6108629183c..3b6f00b56d8 100644
--- a/source/blender/gpencil_modifiers/CMakeLists.txt
+++ b/source/blender/gpencil_modifiers/CMakeLists.txt
@@ -68,12 +68,29 @@ set(SRC
   intern/lineart/lineart_cpu.c
   intern/lineart/lineart_ops.c
   intern/lineart/lineart_util.c
+  intern/lineart/lineart_cpp_bridge.cpp
 
   intern/lineart/MOD_lineart.h
   intern/lineart/lineart_intern.h
 
 )
 
+if(WITH_TBB)
+add_definitions(-DWITH_TBB)
+if(WIN32)
+  # TBB includes Windows.h which will define min/max macros
+  # that will collide with the stl versions.
+  add_definitions(-DNOMINMAX)
+endif()
+list(APPEND INC_SYS
+  ${TBB_INCLUDE_DIRS}
+)
+
+list(APPEND LIB
+  ${TBB_LIBRARIES}
+)
+endif()
+
 set(LIB
 )
 
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
index 1058f861be3..0e7df2a136d 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
@@ -387,7 +387,6 @@ static void options_panel_draw(const bContext *UNUSED(C), Panel *panel)
 
   uiLayout *col = uiLayoutColumn(layout, true);
 
-  uiItemR(col, ptr, "use_remove_doubles", 0, NULL, ICON_NONE);
   uiItemR(col, ptr, "use_edge_overlap", 0, IFACE_("Overlapping Edges As Contour"), ICON_NONE);
   uiItemR(col, ptr, "use_object_instances", 0, NULL, ICON_NONE);
   uiItemR(col, ptr, "use_clip_plane_boundaries", 0, NULL, ICON_NONE);
diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
index 5d952991cf7..99107a96cfe 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
+++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
@@ -132,7 +132,7 @@ typedef struct LineartEdge {
   char min_occ;
 
   /** Also for line type determination on chaining. */
-  unsigned char flags;
+  uint16_t flags;
   unsigned char intersection_mask;
 
   /**
@@ -171,7 +171,7 @@ typedef struct LineartEdgeChainItem {
   /** For restoring position to 3d space. */
   float gpos[3];
   float normal[3];
-  unsigned char line_type;
+  uint16_t line_type;
   char occlusion;
   unsigned char material_mask_bits;
   unsigned char intersection_mask;
@@ -189,6 +189,12 @@ typedef struct LineartChainRegisterEntry {
   char is_left;
 } LineartChainRegisterEntry;
 
+typedef struct LineartAdjacentEdge {
+  unsigned int v1;
+  unsigned int v2;
+  unsigned int e;
+} LineartAdjacentEdge;
+
 enum eLineArtTileRecursiveLimit {
   /* If tile gets this small, it's already much smaller than a pixel. No need to continue
    * splitting. */
@@ -396,7 +402,7 @@ typedef struct LineartObjectInfo {
 
 typedef struct LineartObjectLoadTaskInfo {
   struct LineartRenderBuffer *rb;
-  struct Depsgraph *dg;
+  int thread_id;
   /* LinkNode styled list */
   LineartObjectInfo *pending;
   /* Used to spread the load across several threads. This can not overflow. */
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpp_bridge.cpp b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpp_bridge.cpp
new file mode 100644
index 00000000000..06961bfdb40
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpp_bridge.cpp
@@ -0,0 +1,19 @@
+#include "BLI_sort.hh"
+#include "BLI_vector.hh"
+#include "MOD_lineart.h"
+#include "lineart_intern.h"
+
+static bool cmp_adjacent_items(const LineartAdjacentEdge &p1, const LineartAdjacentEdge &p2)
+{
+  int a = p1.v1 - p2.v1;
+  int b = p1.v2 - p2.v2;
+  /* parallel_sort() requires cmp() to return true when the first element needs to appear before
+   * the second element in the sorted array, false otherwise (strict weak ordering), see
+   * https://en.cppreference.com/w/cpp/named_req/Compare. */
+  return a < 0 ? true : (a == 0 ? b < 0 : false);
+}
+
+void lineart_sort_adjacent_items(LineartAdjacentEdge *ai, int length)
+{
+  blender::parallel_sort(ai, ai + length - 1, cmp_adjacent_items);
+}
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
index 24e11f6be3b..f67499c833c 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
@@ -8,6 +8,7 @@
 #include "MOD_gpencil_lineart.h"
 #include "MOD_lineart.h"
 
+#include "BLI_edgehash.h"
 #include "BLI_linklist.h"
 #include "BLI_listbase.h"
 #include "BLI_math.h"
@@ -28,6 +29,8 @@
 #include "BKE_lib_id.h"
 #include "BKE_material.h"
 #include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
 #include "BKE_object.h"
 #include "BKE_pointcache.h"
 #include "BKE_scene.h"
@@ -1426,17 +1429,45 @@ static void lineart_main_discard_out_of_frame_edges(LineartRenderBuffer *rb)
   }
 }
 
-/**
- * Transform a single vert to it's viewing position.
- */
-static void lineart_vert_transform(
-    BMVert *v, int index, LineartVert *RvBuf, double (*mv_mat)[4], double (*mvp_mat)[4])
+typedef struct LineartEdgeNeighbor {
+  int e;
+  uint16_t flags;
+  int v1, v2;
+} LineartEdgeNeighbor;
+
+typedef struct VertData {
+  MVert *mvert;
+  LineartVert *v_arr;
+  double (*model_view)[4];
+  double (*model_view_proj)[4];
+} VertData;
+
+static void lineart_mvert_transform_task(void *__restrict userdata,
+                                         const int i,
+                                         const TaskParallelTLS *__restrict UNUSED(tls))
 {
+  VertData *vert_task_data = (VertData *)userdata;
+  MVert *m_v = &vert_task_data->mvert[i];
   double co[4];
-  LineartVert *vt = &RvBuf[index];
-  copy_v3db_v3fl(co, v->co);
-  mul_v3_m4v3_db(vt->gloc, mv_mat, co);
-  mul_v4_m4v3_db(vt->fbcoord, mvp_mat, co);
+  LineartVert *v = &vert_task_data->v_arr[i];
+  copy_v3db_v3fl(co, m_v->co);
+  mul_v3_m4v3_db(v->gloc, vert_task_data->model_view, co);
+  mul_v4_m4v3_db(v->fbcoord, vert_task_data->model_view_proj, co);
+  v->index = i;
+}
+
+#define LRT_EDGE_FLAG_TYPE_MAX_BITS 6
+
+static int lineart_edge_type_duplication_count(char eflag)
+{
+  int count = 0;
+  /* See eLineartEdgeFlag for details. */
+  for (int i = 0; i < LRT_EDGE_FLAG_TYPE_MAX_BITS; i++) {
+    if (eflag & (1 << i)) {
+      count++;
+    }
+  }
+  return count;
 }
 
 /**
@@ -1452,88 +1483,123 @@ static LineartTriangle *lineart_triangle_from_index(LineartRenderBuffer *rb,
   return (LineartTriangle *)b;
 }
 
-static uint16_t lineart_identify_feature_line(LineartRenderBuffer *rb,
-                                              BMEdge *e,
-                                              LineartTriangle *rt_array,
-                                              LineartVert *rv_array,
-                                              float crease_threshold,
-                                              bool use_auto_smooth,
-                                              bool use_freestyle_edge,
-                                              bool use_freestyle_face,
-                                              BMesh *bm_if_freestyle)
+typedef struct EdgeFeatData {
+  LineartRenderBuffer *rb;
+  Mesh *me;
+  const MLoopTri *mlooptri;
+  LineartTriangle *tri_array;
+  LineartVert *v_array;
+  float crease_threshold;
+  bool use_auto_smooth;
+  bool use_freestyle_face;
+  int freestyle_face_index;
+  bool use_freestyle_edge;
+  int freestyle_edge_index;
+  LineartEdgeNeighbor *edge_nabr;
+} EdgeFeatData;
+
+typedef struct EdgeFeatReduceData {
+  int feat_edges;
+} EdgeFeatReduceData;
+
+static void feat_data_sum_reduce(const void *__restrict UNUSED(userdata),
+                                 void *__restrict chunk_join,
+                                 void *__restrict chunk)
 {
-  BMLoop *ll, *lr = NULL;
+  EdgeFeatReduceData *feat_chunk_join = (EdgeFeatReduceData *)chunk_join;
+  EdgeFeatReduceData *feat_chunk = (EdgeFeatReduceData *)chunk;
+  feat_chunk_join->feat_edges += feat_chunk->feat_edges;
+}
 
-  ll = e->l;
-  if (ll) {
-    lr = e->l->radial_next;
-  }
+static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
+                                                    const int i,
+                                                    const TaskParallelTLS *__restrict tls)
+{
+  EdgeFeatData *e_feat_data = (EdgeFeatData *)userdata;
+  EdgeFeatReduceData *reduce_data = (EdgeFeatReduceData *)tls->userdata_chunk;
+  Mesh *me = e_feat_data->me;
+  LineartEdgeNeighbor *edge_nabr = e_feat_data->edge_nabr;
+  const MLoopTri *mlooptri = e_feat_data->mlooptri;
 
-  if (!ll && !lr) {
-    return LRT_EDGE_FLAG_LOOSE;
+  uint16_t edge_flag_result = 0;
+
+  /* Because the Edge Neighbour array contains loop edge pairs, we only need to process the first
+   * edge in the pair. Otherwise we would add the same edge that the loops represent twice. */
+  if (i < edge_nabr[i].e) {
+    return;
   }
 
-  FreestyleEdge *fel, *fer;
   bool face_mark_filtered = false;
-  uint16_t edge_flag_result = 0;
+  bool enable_face_mark = (e_feat_data->use_freestyle_face && e_feat_data->rb->filter_face_mark);
   bool only_contour = false;
-
-  if (use_freestyle_face && rb->filter_face_mark) {
-    fel = CustomData_bmesh_get(&bm_if_freestyle->pdata, ll->f->head.data, CD_FREESTYLE_FACE);
-    if (ll != lr && lr) {
-      fer = CustomData_bmesh_get(&bm_if_freestyle->pdata, lr->f->head.data, CD_FREESTYLE_FACE);
+  if (enable_face_mark) {
+    FreestyleFace *ff1, *ff2;
+    int index = e_feat_data->freestyle_face_index;
+    if (index > -1) {
+      ff1 = &((FreestyleFace *)me->pdata.layers[index].data)[mlooptri[i / 3].poly];
+    }
+    if (edge_nabr[i].e > -1) {
+      ff2 = &((FreestyleFace *)me->pdata.layers[index].data)[mlooptri[edge_nabr[i].e / 3].poly];
     }
     else {
-      /* Handles mesh boundary case */
-      fer = fel;
+      /* Handle mesh boundary cases: We want mesh boundaries to respect
+       * `filter_face_mark_boundaries` option the same way as face mark boundaries, and the code
+       * path is simper when it's assuming both ff1 and ff2 not NULL.   */
+      ff2 = ff1;
     }
-    if (rb->filter_face_mark_boundaries ^ rb->filter_face_ma

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list