[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