[Bf-blender-cvs] [460fe4a10cc] master: Curves: Improve sculpting performance by reducing allocations

Hans Goudey noreply at git.blender.org
Wed Sep 14 18:18:49 CEST 2022


Commit: 460fe4a10cccf697c742431de89ee2e577e11902
Author: Hans Goudey
Date:   Wed Sep 14 11:18:20 2022 -0500
Branches: master
https://developer.blender.org/rB460fe4a10cccf697c742431de89ee2e577e11902

Curves: Improve sculpting performance by reducing allocations

The snake hook and grow/shrink brushes need some arrays for input
to the length paramterization code. These were allocated and freed
for every curve. Instead, use a local buffer for each task execution.

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

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

M	source/blender/editors/sculpt_paint/curves_sculpt_brush.cc
M	source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc
M	source/blender/editors/sculpt_paint/curves_sculpt_intern.hh
M	source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc

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

diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc b/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc
index 95261f29914..02bf7aacd93 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc
@@ -352,33 +352,37 @@ float transform_brush_radius(const float4x4 &transform,
   return math::distance(new_position, new_offset_position);
 }
 
-void move_last_point_and_resample(MutableSpan<float3> positions, const float3 &new_last_position)
+void move_last_point_and_resample(MoveAndResampleBuffers &buffer,
+                                  MutableSpan<float3> positions,
+                                  const float3 &new_last_position)
 {
   /* Find the accumulated length of each point in the original curve,
    * treating it as a poly curve for performance reasons and simplicity. */
-  Array<float> orig_lengths(length_parameterize::segments_num(positions.size(), false));
-  length_parameterize::accumulate_lengths<float3>(positions, false, orig_lengths);
-  const float orig_total_length = orig_lengths.last();
+  buffer.orig_lengths.reinitialize(length_parameterize::segments_num(positions.size(), false));
+  length_parameterize::accumulate_lengths<float3>(positions, false, buffer.orig_lengths);
+  const float orig_total_length = buffer.orig_lengths.last();
 
   /* Find the factor by which the new curve is shorter or longer than the original. */
   const float new_last_segment_length = math::distance(positions.last(1), new_last_position);
-  const float new_total_length = orig_lengths.last(1) + new_last_segment_length;
+  const float new_total_length = buffer.orig_lengths.last(1) + new_last_segment_length;
   const float length_factor = safe_divide(new_total_length, orig_total_length);
 
   /* Calculate the lengths to sample the original curve with by scaling the original lengths. */
-  Array<float> new_lengths(positions.size() - 1);
-  new_lengths.first() = 0.0f;
-  for (const int i : new_lengths.index_range().drop_front(1)) {
-    new_lengths[i] = orig_lengths[i - 1] * length_factor;
+  buffer.new_lengths.reinitialize(positions.size() - 1);
+  buffer.new_lengths.first() = 0.0f;
+  for (const int i : buffer.new_lengths.index_range().drop_front(1)) {
+    buffer.new_lengths[i] = buffer.orig_lengths[i - 1] * length_factor;
   }
 
-  Array<int> indices(positions.size() - 1);
-  Array<float> factors(positions.size() - 1);
-  length_parameterize::sample_at_lengths(orig_lengths, new_lengths, indices, factors);
+  buffer.sample_indices.reinitialize(positions.size() - 1);
+  buffer.sample_factors.reinitialize(positions.size() - 1);
+  length_parameterize::sample_at_lengths(
+      buffer.orig_lengths, buffer.new_lengths, buffer.sample_indices, buffer.sample_factors);
 
-  Array<float3> new_positions(positions.size() - 1);
-  length_parameterize::interpolate<float3>(positions, indices, factors, new_positions);
-  positions.drop_back(1).copy_from(new_positions);
+  buffer.new_positions.reinitialize(positions.size() - 1);
+  length_parameterize::interpolate<float3>(
+      positions, buffer.sample_indices, buffer.sample_factors, buffer.new_positions);
+  positions.drop_back(1).copy_from(buffer.new_positions);
   positions.last() = new_last_position;
 }
 
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc b/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc
index 0ca22004540..bc354ed66f4 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc
@@ -141,11 +141,11 @@ class ExtrapolateCurvesEffect : public CurvesEffect {
   {
     MutableSpan<float3> positions_cu = curves.positions_for_write();
     threading::parallel_for(curve_indices.index_range(), 256, [&](const IndexRange range) {
+      MoveAndResampleBuffers resample_buffer;
       for (const int influence_i : range) {
         const int curve_i = curve_indices[influence_i];
         const float move_distance_cu = move_distances_cu[influence_i];
         const IndexRange points = curves.points_for_curve(curve_i);
-
         if (points.size() <= 1) {
           continue;
         }
@@ -157,7 +157,7 @@ class ExtrapolateCurvesEffect : public CurvesEffect {
         const float3 direction = math::normalize(old_last_pos_cu - direction_reference_point);
 
         const float3 new_last_pos_cu = old_last_pos_cu + direction * move_distance_cu;
-        move_last_point_and_resample(positions_cu.slice(points), new_last_pos_cu);
+        move_last_point_and_resample(resample_buffer, positions_cu.slice(points), new_last_pos_cu);
       }
     });
   }
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh b/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh
index 5c8c0cedc6f..61e2559f303 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh
@@ -102,7 +102,23 @@ VArray<float> get_curves_selection(const Curves &curves_id);
  */
 VArray<float> get_point_selection(const Curves &curves_id);
 
-void move_last_point_and_resample(MutableSpan<float3> positions, const float3 &new_last_position);
+/** See #move_last_point_and_resample. */
+struct MoveAndResampleBuffers {
+  Array<float> orig_lengths;
+  Array<float> new_lengths;
+
+  Array<int> sample_indices;
+  Array<float> sample_factors;
+
+  Array<float3> new_positions;
+};
+
+/**
+ * \param buffer: Reused memory to avoid reallocations when the function is called many times.
+ */
+void move_last_point_and_resample(MoveAndResampleBuffers &buffer,
+                                  MutableSpan<float3> positions,
+                                  const float3 &new_last_position);
 
 class CurvesSculptCommonContext {
  public:
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc b/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc
index 54b81fa221d..67757ce5f4a 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc
@@ -188,6 +188,7 @@ struct SnakeHookOperatorExecutor {
     const float brush_radius_sq_re = pow2f(brush_radius_re);
 
     threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
+      MoveAndResampleBuffers resample_buffer;
       for (const int curve_i : curves_range) {
         const IndexRange points = curves_->points_for_curve(curve_i);
         const int last_point_i = points.last();
@@ -221,8 +222,8 @@ struct SnakeHookOperatorExecutor {
         const float3 translation_orig = deformation.translation_from_deformed_to_original(
             last_point_i, translation_eval);
 
-        move_last_point_and_resample(positions_cu.slice(points),
-                                     positions_cu[last_point_i] + translation_orig);
+        const float3 last_point_cu = positions_cu[last_point_i] + translation_orig;
+        move_last_point_and_resample(resample_buffer, positions_cu.slice(points), last_point_cu);
       }
     });
   }
@@ -268,6 +269,7 @@ struct SnakeHookOperatorExecutor {
     const float brush_radius_sq_cu = pow2f(brush_radius_cu);
 
     threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
+      MoveAndResampleBuffers resample_buffer;
       for (const int curve_i : curves_range) {
         const IndexRange points = curves_->points_for_curve(curve_i);
         const int last_point_i = points.last();
@@ -289,8 +291,8 @@ struct SnakeHookOperatorExecutor {
         const float3 translation_orig = deformation.translation_from_deformed_to_original(
             last_point_i, translation_eval);
 
-        move_last_point_and_resample(positions_cu.slice(points),
-                                     positions_cu[last_point_i] + translation_orig);
+        const float3 last_point_cu = positions_cu[last_point_i] + translation_orig;
+        move_last_point_and_resample(resample_buffer, positions_cu.slice(points), last_point_cu);
       }
     });
   }



More information about the Bf-blender-cvs mailing list