Curves: Port endpoint selection node to new data-block
The node should be faster than in 3.1, for a few reasons: - It doesn't need to calculate and allocate the curve offsets. - It doesn't need to de-reference a pointer for each curve. - The inputs are accessed from the virual arrays fewer times. On top of that, I added two other performance improvements: - The node is multi-threaded when there are many curves. - There are generated special cases for single value and span inputs. **Performance** With a set position node affecting 1 million splines with a selection based on this node, on an Intel i5 8250U (times are approximate): | Before | After | Speedup | | 760 ms | 60 ms | 13x | Differential Revision: https://developer.blender.org/D14233
This commit is contained in:
parent
908ac7dce2
commit
471f27d66b
Notes:
blender-bot
2023-02-14 00:57:33 +01:00
Referenced by issue #95443, Refactor curve nodes to use new data structure
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_spline.hh"
|
||||
#include "BKE_curves.hh"
|
||||
|
||||
#include "UI_interface.h"
|
||||
#include "UI_resources.h"
|
||||
|
@ -27,16 +27,6 @@ static void node_declare(NodeDeclarationBuilder &b)
|
|||
N_("The selection from the start and end of the splines based on the input sizes"));
|
||||
}
|
||||
|
||||
static void select_by_spline(const int start, const int end, MutableSpan<bool> r_selection)
|
||||
{
|
||||
const int size = r_selection.size();
|
||||
const int start_use = std::min(start, size);
|
||||
const int end_use = std::min(end, size);
|
||||
|
||||
r_selection.slice(0, start_use).fill(true);
|
||||
r_selection.slice(size - end_use, end_use).fill(true);
|
||||
}
|
||||
|
||||
class EndpointFieldInput final : public GeometryFieldInput {
|
||||
Field<int> start_size_;
|
||||
Field<int> end_size_;
|
||||
|
@ -63,37 +53,35 @@ class EndpointFieldInput final : public GeometryFieldInput {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component.get_for_read());
|
||||
|
||||
Array<int> control_point_offsets = curve->control_point_offsets();
|
||||
if (curve == nullptr || control_point_offsets.last() == 0) {
|
||||
const Curves &curves_id = *curve_component.get_for_read();
|
||||
const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
|
||||
if (curves.points_size() == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GeometryComponentFieldContext size_context{curve_component, ATTR_DOMAIN_CURVE};
|
||||
fn::FieldEvaluator evaluator{size_context, curve->splines().size()};
|
||||
fn::FieldEvaluator evaluator{size_context, curves.curves_size()};
|
||||
evaluator.add(start_size_);
|
||||
evaluator.add(end_size_);
|
||||
evaluator.evaluate();
|
||||
const VArray<int> &start_size = evaluator.get_evaluated<int>(0);
|
||||
const VArray<int> &end_size = evaluator.get_evaluated<int>(1);
|
||||
|
||||
const int point_size = control_point_offsets.last();
|
||||
Array<bool> selection(point_size, false);
|
||||
int current_point = 0;
|
||||
Array<bool> selection(curves.points_size(), false);
|
||||
MutableSpan<bool> selection_span = selection.as_mutable_span();
|
||||
for (int i : IndexRange(curve->splines().size())) {
|
||||
const SplinePtr &spline = curve->splines()[i];
|
||||
if (start_size[i] <= 0 && end_size[i] <= 0) {
|
||||
selection_span.slice(current_point, spline->size()).fill(false);
|
||||
}
|
||||
else {
|
||||
int start_use = std::max(start_size[i], 0);
|
||||
int end_use = std::max(end_size[i], 0);
|
||||
select_by_spline(start_use, end_use, selection_span.slice(current_point, spline->size()));
|
||||
}
|
||||
current_point += spline->size();
|
||||
}
|
||||
devirtualize_varray2(start_size, end_size, [&](const auto &start_size, const auto &end_size) {
|
||||
threading::parallel_for(curves.curves_range(), 1024, [&](IndexRange curves_range) {
|
||||
for (const int i : curves_range) {
|
||||
const IndexRange range = curves.range_for_curve(i);
|
||||
const int start = std::max(start_size[i], 0);
|
||||
const int end = std::max(end_size[i], 0);
|
||||
|
||||
selection_span.slice(range.take_front(start)).fill(true);
|
||||
selection_span.slice(range.take_back(end)).fill(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return VArray<bool>::ForContainer(std::move(selection));
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue