[Bf-blender-cvs] [663bd38ed65] master: Curves: Port duplicate elements node to new data-block

Hans Goudey noreply at git.blender.org
Thu Mar 17 22:36:54 CET 2022


Commit: 663bd38ed65eb08013677bab2e581bc384a29efe
Author: Hans Goudey
Date:   Thu Mar 17 16:36:43 2022 -0500
Branches: master
https://developer.blender.org/rB663bd38ed65eb08013677bab2e581bc384a29efe

Curves: Port duplicate elements node to new data-block

Remove the conversion to and from `CurveEval` by supporting the
new Curves data-block in the node. This allows for some simplifications
to the code, as well as a fix for transfering curve domain attributes
when duplicating the curve domain.

The performance improvements (obverved through the timings overlay)
can be relatively massive with many curves. When duplicating 10000
4-point curves to become 2 million curves, I observed an approximate
150x improvement, from about 3 seconds to about 20ms.

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

M	source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc

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

diff --git a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
index 518d7650a74..535392fbca7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
@@ -10,9 +10,9 @@
 #include "DNA_pointcloud_types.h"
 
 #include "BKE_attribute_math.hh"
+#include "BKE_curves.hh"
 #include "BKE_mesh.h"
 #include "BKE_pointcloud.h"
-#include "BKE_spline.hh"
 
 #include "node_geometry_util.hh"
 
@@ -114,6 +114,13 @@ static void threaded_mapped_copy(const Span<int> mapping, const Span<T> src, Mut
   });
 }
 
+static void copy_hashed_ids(const Span<int> src, const int hash, MutableSpan<int> dst)
+{
+  for (const int i : src.index_range()) {
+    dst[i] = noise::hash(src[i], hash);
+  }
+}
+
 static void threaded_id_offset_copy(const Span<int> offsets,
                                     const Span<int> src,
                                     MutableSpan<int> dst)
@@ -275,11 +282,12 @@ static void copy_stable_id_faces(const Mesh &mesh,
  * destination,
  * then loop over the remaining ones point by point, hashing their ids to the new ids.
  */
-static void copy_stable_id_splines(const CurveEval &curve,
+static void copy_stable_id_splines(const bke::CurvesGeometry &src_curves,
                                    const IndexMask selection,
                                    const Span<int> curve_offsets,
-                                   const GeometryComponent &src_component,
-                                   GeometryComponent &dst_component)
+                                   const CurveComponent &src_component,
+                                   bke::CurvesGeometry &dst_curves,
+                                   CurveComponent &dst_component)
 {
   ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read("id");
   if (!src_attribute) {
@@ -291,33 +299,18 @@ static void copy_stable_id_splines(const CurveEval &curve,
     return;
   }
 
-  Array<int> control_point_offsets = curve.control_point_offsets();
   VArray_Span<int> src{src_attribute.varray.typed<int>()};
   MutableSpan<int> dst = dst_attribute.as_span<int>();
 
-  Array<int> curve_point_offsets(selection.size() + 1);
-  int dst_point_size = 0;
-  for (const int i_curve : selection.index_range()) {
-    const int spline_size = curve.splines()[i_curve]->size();
-    const IndexRange curve_range = range_for_offsets_index(curve_offsets, i_curve);
-
-    curve_point_offsets[i_curve] = dst_point_size;
-    dst_point_size += curve_range.size() * spline_size;
-  }
-  curve_point_offsets.last() = dst_point_size;
-
-  threading::parallel_for(IndexRange(curve_point_offsets.size() - 1), 512, [&](IndexRange range) {
-    for (const int i_curve : range) {
-      const int spline_size = curve.splines()[i_curve]->size();
-      const IndexRange curve_range = range_for_offsets_index(curve_offsets, i_curve);
-
-      dst.slice(curve_point_offsets[i_curve], spline_size)
-          .copy_from(src.slice(control_point_offsets[i_curve], spline_size));
-      for (const int i_duplicate : IndexRange(1, curve_range.size() - 1)) {
-        for (const int i_point : IndexRange(spline_size)) {
-          dst[curve_point_offsets[i_curve] + i_duplicate * spline_size + i_point] = noise::hash(
-              src[control_point_offsets[i_curve] + i_point], i_duplicate);
-        }
+  threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
+    for (const int i_selection : range) {
+      const int i_src_curve = selection[i_selection];
+      const Span<int> curve_src = src.slice(src_curves.range_for_curve(i_src_curve));
+      const IndexRange duplicates_range = range_for_offsets_index(curve_offsets, i_selection);
+      for (const int i_duplicate : IndexRange(duplicates_range.size()).drop_front(1)) {
+        const int i_dst_curve = duplicates_range[i_duplicate];
+        copy_hashed_ids(
+            curve_src, i_duplicate, dst.slice(dst_curves.range_for_curve(i_dst_curve)));
       }
     }
   });
@@ -369,15 +362,16 @@ static void copy_point_attributes_without_id(GeometrySet &geometry_set,
  * copied with an offset fill, otherwise a mapping is used.
  */
 static void copy_spline_attributes_without_id(const GeometrySet &geometry_set,
-                                              const Span<int> point_mapping,
-                                              const Span<int> offsets,
-                                              const Span<std::string> attributes_to_ignore,
-                                              const GeometryComponent &src_component,
-                                              GeometryComponent &dst_component)
+                                              const CurveComponent &src_component,
+                                              const bke::CurvesGeometry &src_curves,
+                                              const IndexMask selection,
+                                              const Span<int> curve_offsets,
+                                              bke::CurvesGeometry &dst_curves,
+                                              CurveComponent &dst_component)
 {
   Map<AttributeIDRef, AttributeKind> gathered_attributes;
   gather_attributes_without_id(
-      geometry_set, GEO_COMPONENT_TYPE_CURVE, attributes_to_ignore, false, gathered_attributes);
+      geometry_set, GEO_COMPONENT_TYPE_CURVE, {}, false, gathered_attributes);
 
   for (const Map<AttributeIDRef, AttributeKind>::Item entry : gathered_attributes.items()) {
 
@@ -403,10 +397,18 @@ static void copy_spline_attributes_without_id(const GeometrySet &geometry_set,
 
       switch (out_domain) {
         case ATTR_DOMAIN_CURVE:
-          threaded_slice_fill<T>(offsets, src, dst);
+          threaded_slice_fill<T>(curve_offsets, src, dst);
           break;
         case ATTR_DOMAIN_POINT:
-          threaded_mapped_copy<T>(point_mapping, src, dst);
+          threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
+            for (const int i_selection : range) {
+              const int i_src_curve = selection[i_selection];
+              const Span<T> curve_src = src.slice(src_curves.range_for_curve(i_src_curve));
+              for (const int i_dst_curve : range_for_offsets_index(curve_offsets, i_selection)) {
+                dst.slice(dst_curves.range_for_curve(i_dst_curve)).copy_from(curve_src);
+              }
+            }
+          });
           break;
         default:
           break;
@@ -540,65 +542,67 @@ static void duplicate_splines(GeometrySet &geometry_set,
   }
   geometry_set.keep_only({GEO_COMPONENT_TYPE_CURVE, GEO_COMPONENT_TYPE_INSTANCES});
 
-  const GeometryComponent &src_component = *geometry_set.get_component_for_read(
-      GEO_COMPONENT_TYPE_CURVE);
-  const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
-      *geometry_set.get_curves_for_read());
-  const int domain_size = src_component.attribute_domain_size(ATTR_DOMAIN_CURVE);
+  const CurveComponent &src_component = *geometry_set.get_component_for_read<CurveComponent>();
+  const Curves &curves_id = *src_component.get_for_read();
+  const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
+
   GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_CURVE};
-  FieldEvaluator evaluator{field_context, domain_size};
+  FieldEvaluator evaluator{field_context, curves.curves_size()};
   evaluator.add(count_field);
   evaluator.set_selection(selection_field);
   evaluator.evaluate();
   const VArray<int> counts = evaluator.get_evaluated<int>(0);
   const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
 
+  /* The offset in the result curve domain at every selected input curve. */
   Array<int> curve_offsets(selection.size() + 1);
+  Array<int> point_offsets(selection.size() + 1);
 
   int dst_splines_size = 0;
   int dst_points_size = 0;
   for (const int i_spline : selection.index_range()) {
     const int count = std::max(counts[selection[i_spline]], 0);
     curve_offsets[i_spline] = dst_splines_size;
+    point_offsets[i_spline] = dst_points_size;
     dst_splines_size += count;
-    dst_points_size += count * curve->splines()[selection[i_spline]]->size();
+    dst_points_size += count * curves.range_for_curve(selection[i_spline]).size();
   }
   curve_offsets.last() = dst_splines_size;
-
-  Array<int> control_point_offsets = curve->control_point_offsets();
-  Array<int> point_mapping(dst_points_size);
-
-  std::unique_ptr<CurveEval> new_curve = std::make_unique<CurveEval>();
-  int point_index = 0;
-  for (const int i_spline : selection.index_range()) {
-    const IndexRange spline_range = range_for_offsets_index(curve_offsets, i_spline);
-    for ([[maybe_unused]] const int i_duplicate : IndexRange(spline_range.size())) {
-      SplinePtr spline = curve->splines()[selection[i_spline]]->copy();
-      for (const int i_point : IndexRange(curve->splines()[selection[i_spline]]->size())) {
-        point_mapping[point_index++] = control_point_offsets[selection[i_spline]] + i_point;
+  point_offsets.last() = dst_points_size;
+
+  Curves *new_curves_id = bke::curves_new_nomain(dst_points_size, dst_splines_size);
+  bke::CurvesGeometry &new_curves = bke::CurvesGeometry::wrap(new_curves_id->geometry);
+  MutableSpan<int> all_dst_offsets = new_curves.offsets();
+
+  threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
+    for (const int i_selection : range) {
+      const int i_src_curve = selection[i_selection];
+      const IndexRange src_curve_range = curves.range_for_curve(i_src_curve);
+      const IndexRange dst_curves_range = range_for_offsets_index(curve_offsets, i_selection);
+      MutableSpan<int> dst_offsets = all_dst_offsets.slice(dst_curves_range);
+      for (const int i_duplicate : IndexRange(dst_curves_range.size())) {
+        dst_offsets[i_duplicate] = point_offsets[i_selection] +
+                                   src_curve_range.size() * i_duplicate;
       }
-      new_curve->add_spline(std::move(spline));
     }
-  }
-  new_curve->attributes.reallocate(new_curve->splines().size());
+  });

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list