Commit: 108e6d4ef2bc62752f8071179092c0cc80b3f867
Author: Howard Trickey
Date:   Tue Aug 18 21:51:35 2020 -0400
Branches: newboolean
https://developer.blender.org/rB108e6d4ef2bc62752f8071179092c0cc80b3f867

Better performance when there are clusters of coplanar triangles.

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

M       source/blender/blenlib/intern/mesh_intersect.cc
M       source/blender/blenlib/tests/BLI_mesh_intersect_test.cc

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

diff --git a/source/blender/blenlib/intern/mesh_intersect.cc 
b/source/blender/blenlib/intern/mesh_intersect.cc
index db70f74ecb1..ddd305b31f2 100644
--- a/source/blender/blenlib/intern/mesh_intersect.cc
+++ b/source/blender/blenlib/intern/mesh_intersect.cc
@@ -53,7 +53,7 @@ static void dump_perfdata(void);
 #  endif
 
 /* For debugging, can disable threading in intersect code with this static 
constant. */
-static constexpr bool intersect_use_threading = false; /*DEBUG!!*/
+static constexpr bool intersect_use_threading = true;
 
 Vert::Vert(const mpq3 &mco, const double3 &dco, int id, int orig)
     : co_exact(mco), co(dco), id(id), orig(orig)
@@ -2459,6 +2459,79 @@ class TriOverlaps {
   }
 };
 
+/* Data needed for parallelization of calc_overlap_itts. */
+struct OverlapIttsData {
+  Vector<std::pair<int, int>> intersect_pairs;
+  Map<std::pair<int, int>, ITT_value> &itt_map;
+  const Mesh &tm;
+  MArena *arena;
+
+  OverlapIttsData(Map<std::pair<int, int>, ITT_value> &itt_map, const Mesh 
&tm, MArena *arena)
+      : itt_map(itt_map), tm(tm), arena(arena)
+  {
+  }
+};
+
+static void calc_overlap_itts_range_func(void *__restrict userdata,
+                                         const int iter,
+                                         const TaskParallelTLS *__restrict 
UNUSED(tls))
+{
+  constexpr int dbg_level = 0;
+  OverlapIttsData *data = static_cast<OverlapIttsData *>(userdata);
+  std::pair<int, int> tri_pair = data->intersect_pairs[iter];
+  int a = tri_pair.first;
+  int b = tri_pair.second;
+  if (dbg_level > 0) {
+    std::cout << "calc_overlap_itts_range_func a=" << a << ", b=" << b << "\n";
+  }
+  ITT_value itt = intersect_tri_tri(data->tm, a, b);
+  if (dbg_level > 0) {
+    std::cout << "result of intersecting " << a << " and " << b << " = " << 
itt << "\n";
+  }
+  BLI_assert(data->itt_map.contains(tri_pair));
+  data->itt_map.add_overwrite(tri_pair, itt);
+}
+
+/* Fill in itt_map with the vector of ITT_values that result from intersecting 
the triangles in ov.
+ * Use a canonical order for triangles: (a,b) where  a < b.
+ * Don't bother doing this if both a and b are part of the same coplanar 
cluster, as the
+ * intersection for those will be handled by CDT, later.
+ */
+static void calc_overlap_itts(Map<std::pair<int, int>, ITT_value> &itt_map,
+                              const Mesh &tm,
+                              const CoplanarClusterInfo &clinfo,
+                              const TriOverlaps &ov,
+                              MArena *arena)
+{
+  OverlapIttsData data(itt_map, tm, arena);
+  /* Put dummy values in itt_map intially, so map entries will exist when 
doing the range function.
+   * This means we won't have to protect the itt_map.add_overwrite function 
with a lock.
+   */
+  for (const BVHTreeOverlap &olap : ov.overlap()) {
+    int a = olap.indexA;
+    int b = olap.indexB;
+    if (a >= b) {
+      std::swap(a, b);
+    }
+    std::pair<int, int> key(a, b);
+    if (!itt_map.contains(key)) {
+      int ca = clinfo.tri_cluster(a);
+      int cb = clinfo.tri_cluster(b);
+      if (ca == NO_INDEX || ca != cb) {
+        itt_map.add_new(key, ITT_value());
+        data.intersect_pairs.append(key);
+      }
+    }
+  }
+  int tot_intersect_pairs = data.intersect_pairs.size();
+  TaskParallelSettings settings;
+  BLI_parallel_range_settings_defaults(&settings);
+  constexpr int intersect_threading_threshold = 100;
+  settings.use_threading = (intersect_use_threading &&
+                            tot_intersect_pairs > 
intersect_threading_threshold);
+  BLI_task_parallel_range(0, tot_intersect_pairs, &data, 
calc_overlap_itts_range_func, &settings);
+}
+
 /* Data needed for parallelization of calc_subdivided_tris. */
 
 struct OverlapTriRange {
@@ -2469,6 +2542,7 @@ struct OverlapTriRange {
 struct SubdivideTrisData {
   Array<Mesh> &r_tri_subdivided;
   const Mesh &tm;
+  const Map<std::pair<int, int>, ITT_value> &itt_map;
   Span<BVHTreeOverlap> overlap;
   MArena *arena;
 
@@ -2481,10 +2555,12 @@ struct SubdivideTrisData {
 
   SubdivideTrisData(Array<Mesh> &r_tri_subdivided,
                     const Mesh &tm,
+                    const Map<std::pair<int, int>, ITT_value> &itt_map,
                     Span<BVHTreeOverlap> overlap,
                     MArena *arena)
       : r_tri_subdivided(r_tri_subdivided),
         tm(tm),
+        itt_map(itt_map),
         overlap(overlap),
         arena(arena),
         overlap_tri_range{}
@@ -2508,7 +2584,16 @@ static void calc_subdivided_tri_range_func(void 
*__restrict userdata,
   Vector<ITT_value, inline_capacity> itts(otr.len);
   for (int j = otr.overlap_start; j < otr.overlap_start + otr.len; ++j) {
     int t_other = data->overlap[j].indexB;
-    ITT_value itt = intersect_tri_tri(data->tm, t, t_other);
+    int a = t;
+    int b = t_other;
+    if (a >= b) {
+      std::swap(a, b);
+    }
+    std::pair<int, int> key(a, b);
+    ITT_value itt;
+    if (data->itt_map.contains(key)) {
+      itt = data->itt_map.lookup(key);
+    }
     if (itt.kind != INONE) {
       itts.append(itt);
     }
@@ -2531,10 +2616,10 @@ static void calc_subdivided_tri_range_func(void 
*__restrict userdata,
  * all the other triangles in the mesh, if it intersects any others.
  * But don't do this for triangles that are part of a cluster.
  * Also, do nothing here if the answer is just the triangle itself.
- * TODO: parallelize this loop.
  */
 static void calc_subdivided_tris(Array<Mesh> &r_tri_subdivided,
                                  const Mesh &tm,
+                                 const Map<std::pair<int, int>, ITT_value> 
&itt_map,
                                  const CoplanarClusterInfo &clinfo,
                                  const TriOverlaps &ov,
                                  MArena *arena)
@@ -2544,10 +2629,7 @@ static void calc_subdivided_tris(Array<Mesh> 
&r_tri_subdivided,
     std::cout << "\nCALC_SUBDIVIDED_TRIS\n\n";
   }
   Span<BVHTreeOverlap> overlap = ov.overlap();
-  SubdivideTrisData data(r_tri_subdivided, tm, overlap, arena);
-  data.r_tri_subdivided = r_tri_subdivided;
-  data.overlap = overlap;
-  data.arena = arena;
+  SubdivideTrisData data(r_tri_subdivided, tm, itt_map, overlap, arena);
   int overlap_tot = overlap.size();
   data.overlap_tri_range = Vector<OverlapTriRange>();
   data.overlap_tri_range.reserve(overlap_tot);
@@ -2577,14 +2659,39 @@ static void calc_subdivided_tris(Array<Mesh> 
&r_tri_subdivided,
   int overlap_tri_range_tot = data.overlap_tri_range.size();
   TaskParallelSettings settings;
   BLI_parallel_range_settings_defaults(&settings);
-  settings.use_threading = (intersect_use_threading && overlap_tri_range_tot > 
1000);
+  constexpr int trisubdiv_threading_threshold = 100;
+  settings.use_threading = (intersect_use_threading &&
+                            overlap_tri_range_tot > 
trisubdiv_threading_threshold);
   BLI_task_parallel_range(
       0, overlap_tri_range_tot, &data, calc_subdivided_tri_range_func, 
&settings);
 }
 
+/* Get first index in ov where indexA == t. Assuming sorted on indexA. */
+static int find_first_overlap_index(const TriOverlaps &ov, int t)
+{
+  Span<BVHTreeOverlap> span = ov.overlap();
+  int min = 0;
+  int max = static_cast<int>(span.size()) - 1;
+  while (min < max) {
+    int mid = (min + max) / 2;
+    if (t <= span[mid].indexA) {
+      max = mid;
+    }
+    else {
+      min = mid + 1;
+    }
+  }
+  if (span[min].indexA == t) {
+    return min;
+  }
+  return -1;
+}
+
 static CDT_data calc_cluster_subdivided(const CoplanarClusterInfo &clinfo,
                                         int c,
                                         const Mesh &tm,
+                                        const TriOverlaps &ov,
+                                        const Map<std::pair<int, int>, 
ITT_value> &itt_map,
                                         MArena *UNUSED(arena))
 {
   constexpr int dbg_level = 0;
@@ -2592,28 +2699,42 @@ static CDT_data calc_cluster_subdivided(const 
CoplanarClusterInfo &clinfo,
   const CoplanarCluster &cl = clinfo.cluster(c);
   /* Make a CDT input with triangles from C and intersects from other 
triangles in tm. */
   if (dbg_level > 0) {
-    std::cout << "calc_cluster_subdivided for cluster " << c << " = " << cl << 
"\n";
+    std::cout << "CALC_CLUSTER_SUBDIVIDED for cluster " << c << " = " << cl << 
"\n";
   }
   /* Get vector itts of all intersections of a triangle of cl with any 
triangle of tm not
    * in cl and not coplanar with it (for that latter, if there were an 
intersection,
    * it should already be in cluster cl).
    */
   Vector<ITT_value> itts;
-  for (int t_other : tm.face_index_range()) {
-    if (clinfo.tri_cluster(t_other) != c) {
-      if (dbg_level > 0) {
-        std::cout << "intersect cluster " << c << " with tri " << t_other << 
"\n";
-      }
-      for (const int t : cl) {
-        ITT_value itt = intersect_tri_tri(tm, t, t_other);
-#  ifdef PERFDEBUG
-        incperfcount(5); /* intersect_tri_tri calls from 
calc_cluster_subdivided. */
-#  endif
+  Span<BVHTreeOverlap> ovspan = ov.overlap();
+  for (int t : cl) {
+    if (dbg_level > 0) {
+      std::cout << "find intersects with triangle " << t << " of cluster\n";
+    }
+    int first_i = find_first_overlap_index(ov, t);
+    if (first_i == -1) {
+      continue;
+    }
+    for (int i = first_i; i < ovspan.size() && ovspan[i].indexA == t; ++i) {
+      int t_other = ovspan[i].indexB;
+      if (clinfo.tri_cluster(t_other) != c) {
         if (dbg_level > 0) {
-          std::cout << "intersect tri " << t << " with tri " << t_other << " = 
" << itt << "\n";
+          std::cout << "use intersect(" << t << "," << t_other << "\n";
         }
-        if (itt.kind != INONE && itt.kind != ICOPLANAR) {
-          itts.append(itt);
+        int a = t;
+        int b = t_other;
+        if (a >= b) {
+          std::swap(a, b);
+        }
+        std::pair<int, int> key(a, b);
+        if (itt_map.contains(key)) {
+          ITT_value itt = itt_map.lookup(key);
+          if (itt.kind != INONE && itt.kind != ICOPLANAR) {
+            itts.append(itt);
+            if (dbg_level > 0) {
+              std::cout << "  itt = " << itt << "\n";
+            }
+          }
         }
       }
     }
@@

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
https://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to