[Bf-blender-cvs] [0cd34967c0a] master: Curves: Multithread Curve to CurveEval conversion

Hans Goudey noreply at git.blender.org
Mon Jun 21 01:42:18 CEST 2021


Commit: 0cd34967c0a844c7cebe6f835a3c2303a5e53ef6
Author: Hans Goudey
Date:   Sun Jun 20 18:42:02 2021 -0500
Branches: master
https://developer.blender.org/rB0cd34967c0a844c7cebe6f835a3c2303a5e53ef6

Curves: Multithread Curve to CurveEval conversion

A different data structure / implementation is used for curves in the
node tree currently. Converting from the DNA `Curve` structure to this
wasn't slow, but it's nice to decrease overhead. In a test of 14000
splines with 128000 points, this halves the runtime from about 5ms
to about 2.5ms.

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

M	source/blender/blenkernel/intern/curve_eval.cc

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

diff --git a/source/blender/blenkernel/intern/curve_eval.cc b/source/blender/blenkernel/intern/curve_eval.cc
index c9408cf4fcd..0a6e4458a35 100644
--- a/source/blender/blenkernel/intern/curve_eval.cc
+++ b/source/blender/blenkernel/intern/curve_eval.cc
@@ -15,10 +15,13 @@
  */
 
 #include "BLI_array.hh"
+#include "BLI_index_range.hh"
 #include "BLI_listbase.h"
 #include "BLI_map.hh"
 #include "BLI_span.hh"
 #include "BLI_string_ref.hh"
+#include "BLI_task.hh"
+#include "BLI_vector.hh"
 
 #include "DNA_curve_types.h"
 
@@ -28,9 +31,12 @@
 using blender::Array;
 using blender::float3;
 using blender::float4x4;
+using blender::IndexRange;
 using blender::Map;
+using blender::MutableSpan;
 using blender::Span;
 using blender::StringRefNull;
+using blender::Vector;
 
 blender::Span<SplinePtr> CurveEval::splines() const
 {
@@ -168,70 +174,118 @@ static NURBSpline::KnotsMode knots_mode_from_dna_nurb(const short flag)
   return NURBSpline::KnotsMode::Normal;
 }
 
+static SplinePtr spline_from_dna_bezier(const Nurb &nurb)
+{
+  std::unique_ptr<BezierSpline> spline = std::make_unique<BezierSpline>();
+  spline->set_resolution(nurb.resolu);
+  spline->set_cyclic(nurb.flagu & CU_NURB_CYCLIC);
+
+  Span<const BezTriple> src_points{nurb.bezt, nurb.pntsu};
+  spline->resize(src_points.size());
+  MutableSpan<float3> positions = spline->positions();
+  MutableSpan<float3> handle_positions_left = spline->handle_positions_left();
+  MutableSpan<float3> handle_positions_right = spline->handle_positions_right();
+  MutableSpan<BezierSpline::HandleType> handle_types_left = spline->handle_types_left();
+  MutableSpan<BezierSpline::HandleType> handle_types_right = spline->handle_types_right();
+  MutableSpan<float> radii = spline->radii();
+  MutableSpan<float> tilts = spline->tilts();
+
+  blender::threading::parallel_for(src_points.index_range(), 2048, [&](IndexRange range) {
+    for (const int i : range) {
+      const BezTriple &bezt = src_points[i];
+      positions[i] = bezt.vec[1];
+      handle_positions_left[i] = bezt.vec[0];
+      handle_types_left[i] = handle_type_from_dna_bezt((eBezTriple_Handle)bezt.h1);
+      handle_positions_right[i] = bezt.vec[2];
+      handle_types_right[i] = handle_type_from_dna_bezt((eBezTriple_Handle)bezt.h2);
+      radii[i] = bezt.radius;
+      tilts[i] = bezt.tilt;
+    }
+  });
+
+  return spline;
+}
+
+static SplinePtr spline_from_dna_nurbs(const Nurb &nurb)
+{
+  std::unique_ptr<NURBSpline> spline = std::make_unique<NURBSpline>();
+  spline->set_resolution(nurb.resolu);
+  spline->set_cyclic(nurb.flagu & CU_NURB_CYCLIC);
+  spline->set_order(nurb.orderu);
+  spline->knots_mode = knots_mode_from_dna_nurb(nurb.flagu);
+
+  Span<const BPoint> src_points{nurb.bp, nurb.pntsu};
+  spline->resize(src_points.size());
+  MutableSpan<float3> positions = spline->positions();
+  MutableSpan<float> weights = spline->weights();
+  MutableSpan<float> radii = spline->radii();
+  MutableSpan<float> tilts = spline->tilts();
+
+  blender::threading::parallel_for(src_points.index_range(), 2048, [&](IndexRange range) {
+    for (const int i : range) {
+      const BPoint &bp = src_points[i];
+      positions[i] = bp.vec;
+      weights[i] = bp.vec[3];
+      radii[i] = bp.radius;
+      tilts[i] = bp.tilt;
+    }
+  });
+
+  return spline;
+}
+
+static SplinePtr spline_from_dna_poly(const Nurb &nurb)
+{
+  std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
+  spline->set_cyclic(nurb.flagu & CU_NURB_CYCLIC);
+
+  Span<const BPoint> src_points{nurb.bp, nurb.pntsu};
+  spline->resize(src_points.size());
+  MutableSpan<float3> positions = spline->positions();
+  MutableSpan<float> radii = spline->radii();
+  MutableSpan<float> tilts = spline->tilts();
+
+  blender::threading::parallel_for(src_points.index_range(), 2048, [&](IndexRange range) {
+    for (const int i : range) {
+      const BPoint &bp = src_points[i];
+      positions[i] = bp.vec;
+      radii[i] = bp.radius;
+      tilts[i] = bp.tilt;
+    }
+  });
+
+  return spline;
+}
+
 std::unique_ptr<CurveEval> curve_eval_from_dna_curve(const Curve &dna_curve)
 {
+  Vector<const Nurb *> nurbs(*BKE_curve_nurbs_get(&const_cast<Curve &>(dna_curve)));
+
   std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
+  curve->resize(nurbs.size());
+  MutableSpan<SplinePtr> splines = curve->splines();
 
-  const ListBase *nurbs = BKE_curve_nurbs_get(&const_cast<Curve &>(dna_curve));
-
-  /* TODO: Optimize by reserving the correct points size. */
-  LISTBASE_FOREACH (const Nurb *, nurb, nurbs) {
-    switch (nurb->type) {
-      case CU_BEZIER: {
-        std::unique_ptr<BezierSpline> spline = std::make_unique<BezierSpline>();
-        spline->set_resolution(nurb->resolu);
-        spline->set_cyclic(nurb->flagu & CU_NURB_CYCLIC);
-
-        for (const BezTriple &bezt : Span(nurb->bezt, nurb->pntsu)) {
-          spline->add_point(bezt.vec[1],
-                            handle_type_from_dna_bezt((eBezTriple_Handle)bezt.h1),
-                            bezt.vec[0],
-                            handle_type_from_dna_bezt((eBezTriple_Handle)bezt.h2),
-                            bezt.vec[2],
-                            bezt.radius,
-                            bezt.tilt);
-        }
-        spline->attributes.reallocate(spline->size());
-        curve->add_spline(std::move(spline));
-        break;
-      }
-      case CU_NURBS: {
-        std::unique_ptr<NURBSpline> spline = std::make_unique<NURBSpline>();
-        spline->set_resolution(nurb->resolu);
-        spline->set_cyclic(nurb->flagu & CU_NURB_CYCLIC);
-        spline->set_order(nurb->orderu);
-        spline->knots_mode = knots_mode_from_dna_nurb(nurb->flagu);
-
-        for (const BPoint &bp : Span(nurb->bp, nurb->pntsu)) {
-          spline->add_point(bp.vec, bp.radius, bp.tilt, bp.vec[3]);
-        }
-        spline->attributes.reallocate(spline->size());
-        curve->add_spline(std::move(spline));
-        break;
-      }
-      case CU_POLY: {
-        std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
-        spline->set_cyclic(nurb->flagu & CU_NURB_CYCLIC);
-
-        for (const BPoint &bp : Span(nurb->bp, nurb->pntsu)) {
-          spline->add_point(bp.vec, bp.radius, bp.tilt);
-        }
-        spline->attributes.reallocate(spline->size());
-        curve->add_spline(std::move(spline));
-        break;
-      }
-      default: {
-        BLI_assert_unreachable();
-        break;
+  blender::threading::parallel_for(nurbs.index_range(), 256, [&](IndexRange range) {
+    for (const int i : range) {
+      switch (nurbs[i]->type) {
+        case CU_BEZIER:
+          splines[i] = spline_from_dna_bezier(*nurbs[i]);
+          break;
+        case CU_NURBS:
+          splines[i] = spline_from_dna_nurbs(*nurbs[i]);
+          break;
+        case CU_POLY:
+          splines[i] = spline_from_dna_poly(*nurbs[i]);
+          break;
+        default:
+          BLI_assert_unreachable();
+          break;
       }
     }
-  }
-
-  /* Though the curve has no attributes, this is necessary to properly set the custom data size. */
-  curve->attributes.reallocate(curve->splines().size());
+  });
 
-  /* Note: Normal mode is stored separately in each spline to facilitate combining splines
-   * from multiple curve objects, where the value may be different. */
+  /* Normal mode is stored separately in each spline to facilitate combining
+   * splines from multiple curve objects, where the value may be different. */
   const Spline::NormalCalculationMode normal_mode = normal_mode_from_dna_curve(
       dna_curve.twist_mode);
   for (SplinePtr &spline : curve->splines()) {



More information about the Bf-blender-cvs mailing list