From 460fe4a10cccf697c742431de89ee2e577e11902 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 14 Sep 2022 11:18:20 -0500 Subject: 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 --- .../editors/sculpt_paint/curves_sculpt_brush.cc | 34 ++++++++++++---------- .../sculpt_paint/curves_sculpt_grow_shrink.cc | 4 +-- .../editors/sculpt_paint/curves_sculpt_intern.hh | 18 +++++++++++- .../sculpt_paint/curves_sculpt_snake_hook.cc | 10 ++++--- 4 files changed, 44 insertions(+), 22 deletions(-) (limited to 'source') 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 positions, const float3 &new_last_position) +void move_last_point_and_resample(MoveAndResampleBuffers &buffer, + MutableSpan 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 orig_lengths(length_parameterize::segments_num(positions.size(), false)); - length_parameterize::accumulate_lengths(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(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 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 indices(positions.size() - 1); - Array 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 new_positions(positions.size() - 1); - length_parameterize::interpolate(positions, indices, factors, new_positions); - positions.drop_back(1).copy_from(new_positions); + buffer.new_positions.reinitialize(positions.size() - 1); + length_parameterize::interpolate( + 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 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 get_curves_selection(const Curves &curves_id); */ VArray get_point_selection(const Curves &curves_id); -void move_last_point_and_resample(MutableSpan positions, const float3 &new_last_position); +/** See #move_last_point_and_resample. */ +struct MoveAndResampleBuffers { + Array orig_lengths; + Array new_lengths; + + Array sample_indices; + Array sample_factors; + + Array 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 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); } }); } -- cgit v1.2.3