[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