diff options
9 files changed, 92 insertions, 55 deletions
diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh index 6e4d4d560f7..dea9c17d159 100644 --- a/source/blender/blenkernel/BKE_curves.hh +++ b/source/blender/blenkernel/BKE_curves.hh @@ -60,6 +60,12 @@ struct BasisCache { class CurvesGeometryRuntime { public: /** + * The cached number of curves with each type. Unlike other caches here, this is not computed + * lazily, since it is needed so often and types are not adjusted much anyway. + */ + std::array<int, CURVE_TYPES_NUM> type_counts; + + /** * Cache of offsets into the evaluated array for each curve, accounting for all previous * evaluated points, Bezier curve vector segments, different resolutions per curve, etc. */ @@ -156,15 +162,23 @@ class CurvesGeometry : public ::CurvesGeometry { /** The type (#CurveType) of each curve, or potentially a single if all are the same type. */ VArray<int8_t> curve_types() const; - /** Mutable access to curve types. Call #tag_topology_changed after changing any type. */ + /** + * Mutable access to curve types. Call #tag_topology_changed and #update_curve_types after + * changing any type. Consider using the other methods to change types below. + * */ MutableSpan<int8_t> curve_types_for_write(); + /** Set all curve types to the value and call #update_curve_types. */ + void fill_curve_types(CurveType type); + /** Set the types for the curves in the selection and call #update_curve_types. */ + void fill_curve_types(IndexMask selection, CurveType type); + /** Update the cached count of curves of each type, necessary after #curve_types_for_write. */ + void update_curve_types(); bool has_curve_with_type(const CurveType type) const; - /** Return the number of curves with each type. */ - std::array<int, CURVE_TYPES_NUM> count_curve_types() const; - /** Return true if all of the curves have the provided type. */ bool is_single_type(CurveType type) const; + /** Return the number of curves with each type. */ + const std::array<int, CURVE_TYPES_NUM> &curve_type_counts() const; Span<float3> positions() const; MutableSpan<float3> positions_for_write(); @@ -624,6 +638,8 @@ Curves *curves_new_nomain(int points_num, int curves_num); */ Curves *curves_new_nomain_single(int points_num, CurveType type); +std::array<int, CURVE_TYPES_NUM> calculate_type_counts(const VArray<int8_t> &types); + /** \} */ /* -------------------------------------------------------------------- */ @@ -649,7 +665,18 @@ inline IndexRange CurvesGeometry::curves_range() const inline bool CurvesGeometry::is_single_type(const CurveType type) const { - return this->count_curve_types()[type] == this->curves_num(); + return this->curve_type_counts()[type] == this->curves_num(); +} + +inline bool CurvesGeometry::has_curve_with_type(const CurveType type) const +{ + return this->curve_type_counts()[type] > 0; +} + +inline const std::array<int, CURVE_TYPES_NUM> &CurvesGeometry::curve_type_counts() const +{ + BLI_assert(this->runtime->type_counts == calculate_type_counts(this->curve_types())); + return this->runtime->type_counts; } inline IndexRange CurvesGeometry::points_for_curve(const int index) const diff --git a/source/blender/blenkernel/intern/curve_eval.cc b/source/blender/blenkernel/intern/curve_eval.cc index d1ec9499298..3d9dd3ecf31 100644 --- a/source/blender/blenkernel/intern/curve_eval.cc +++ b/source/blender/blenkernel/intern/curve_eval.cc @@ -523,6 +523,8 @@ Curves *curve_eval_to_curves(const CurveEval &curve_eval) } } + geometry.update_curve_types(); + normal_mode.save(); nurbs_weight.save(); nurbs_order.save(); diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc index d7fd8f7a2b6..0dc46f87537 100644 --- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc +++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc @@ -229,19 +229,10 @@ struct CurvesInfo { /* Make sure these are spans because they are potentially accessed many times. */ VArray_Span<bool> main_cyclic; VArray_Span<bool> profile_cyclic; - - /* TODO: Remove once these are cached on #CurvesGeometry. */ - std::array<int, CURVE_TYPES_NUM> main_type_counts; - std::array<int, CURVE_TYPES_NUM> profile_type_counts; }; static CurvesInfo get_curves_info(const CurvesGeometry &main, const CurvesGeometry &profile) { - return {main, - profile, - main.cyclic(), - profile.cyclic(), - main.count_curve_types(), - profile.count_curve_types()}; + return {main, profile, main.cyclic(), profile.cyclic()}; } struct ResultOffsets { @@ -360,7 +351,7 @@ static bool should_add_attribute_to_mesh(const CurveComponent &curve_component, static GSpan evaluated_attribute_if_necessary(const GVArray &src, const CurvesGeometry &curves, - const Span<int> type_counts, + const std::array<int, CURVE_TYPES_NUM> &type_counts, Vector<std::byte> &buffer) { if (type_counts[CURVE_TYPE_POLY] == curves.curves_num() && src.is_span()) { @@ -691,7 +682,7 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main, radii = evaluated_attribute_if_necessary( main_component.attribute_get_for_read<float>("radius", ATTR_DOMAIN_POINT, 1.0f), main, - curves_info.main_type_counts, + main.curve_type_counts(), eval_buffer) .typed<float>(); } @@ -707,7 +698,7 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main, verts.slice(info.vert_range)); }); - if (curves_info.profile_type_counts[CURVE_TYPE_BEZIER] > 0) { + if (profile.curve_type_counts()[CURVE_TYPE_BEZIER] > 0) { const VArray<int8_t> curve_types = profile.curve_types(); const VArray_Span<int8_t> handle_types_left{profile.handle_types_left()}; const VArray_Span<int8_t> handle_types_right{profile.handle_types_right()}; @@ -752,7 +743,7 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main, curves_info, offsets, dst_domain, - evaluated_attribute_if_necessary(src, main, curves_info.main_type_counts, eval_buffer), + evaluated_attribute_if_necessary(src, main, main.curve_type_counts(), eval_buffer), dst.as_span()); } else if (src_domain == ATTR_DOMAIN_CURVE) { @@ -787,8 +778,7 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main, curves_info, offsets, dst_domain, - evaluated_attribute_if_necessary( - src, profile, curves_info.profile_type_counts, eval_buffer), + evaluated_attribute_if_necessary(src, profile, profile.curve_type_counts(), eval_buffer), dst.as_span()); } else if (src_domain == ATTR_DOMAIN_CURVE) { @@ -808,6 +798,7 @@ static CurvesGeometry get_curve_single_vert() CurvesGeometry curves(1, 1); curves.offsets_for_write().last() = 1; curves.positions_for_write().fill(float3(0)); + curves.fill_curve_types(CURVE_TYPE_POLY); return curves; } diff --git a/source/blender/blenkernel/intern/curves.cc b/source/blender/blenkernel/intern/curves.cc index 5b51fb8af31..a3b40b27583 100644 --- a/source/blender/blenkernel/intern/curves.cc +++ b/source/blender/blenkernel/intern/curves.cc @@ -370,7 +370,7 @@ Curves *curves_new_nomain_single(const int points_num, const CurveType type) Curves *curves = curves_new_nomain(points_num, 1); CurvesGeometry &geometry = CurvesGeometry::wrap(curves->geometry); geometry.offsets_for_write().last() = points_num; - geometry.curve_types_for_write().first() = type; + geometry.fill_curve_types(type); return curves; } diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index 8e97884516c..7a09b87490b 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -85,6 +85,9 @@ static void copy_curves_geometry(CurvesGeometry &dst, const CurvesGeometry &src) dst.tag_topology_changed(); + /* Though type counts are a cache, they must be copied because they are calculated eagerly. */ + dst.runtime->type_counts = src.runtime->type_counts; + dst.update_customdata_pointers(); } @@ -237,38 +240,38 @@ MutableSpan<int8_t> CurvesGeometry::curve_types_for_write() return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_CURVE_TYPE); } -bool CurvesGeometry::has_curve_with_type(const CurveType type) const +void CurvesGeometry::fill_curve_types(const CurveType type) { - const VArray<int8_t> curve_types = this->curve_types(); - if (curve_types.is_single()) { - return curve_types.get_internal_single() == type; - } - if (curve_types.is_span()) { - return curve_types.get_internal_span().contains(type); - } - /* The curves types array should be a single value or a span. */ - BLI_assert_unreachable(); - return false; + this->curve_types_for_write().fill(type); + this->runtime->type_counts.fill(0); + this->runtime->type_counts[type] = this->curves_num(); + this->tag_topology_changed(); } -std::array<int, CURVE_TYPES_NUM> CurvesGeometry::count_curve_types() const +void CurvesGeometry::fill_curve_types(const IndexMask selection, const CurveType type) { - using CountsType = std::array<int, CURVE_TYPES_NUM>; + /* A potential performance optimization is only counting the changed indices. */ + this->curve_types_for_write().fill_indices(selection, type); + this->update_curve_types(); + this->tag_topology_changed(); +} - CountsType identity; - identity.fill(0); +std::array<int, CURVE_TYPES_NUM> calculate_type_counts(const VArray<int8_t> &types) +{ + using CountsType = std::array<int, CURVE_TYPES_NUM>; + CountsType counts; + counts.fill(0); - const VArray<int8_t> types = this->curve_types(); if (types.is_single()) { - identity[types.get_internal_single()] = this->curves_num(); - return identity; + counts[types.get_internal_single()] = types.size(); + return counts; } Span<int8_t> types_span = types.get_internal_span(); return threading::parallel_reduce( - this->curves_range(), + types.index_range(), 2048, - identity, + counts, [&](const IndexRange curves_range, const CountsType &init) { CountsType result = init; for (const int curve_index : curves_range) { @@ -285,6 +288,11 @@ std::array<int, CURVE_TYPES_NUM> CurvesGeometry::count_curve_types() const }); } +void CurvesGeometry::update_curve_types() +{ + this->runtime->type_counts = calculate_type_counts(this->curve_types()); +} + Span<float3> CurvesGeometry::positions() const { return {(const float3 *)this->position, this->point_size}; diff --git a/source/blender/blenkernel/intern/curves_geometry_test.cc b/source/blender/blenkernel/intern/curves_geometry_test.cc index 56e488b9034..48493743cfc 100644 --- a/source/blender/blenkernel/intern/curves_geometry_test.cc +++ b/source/blender/blenkernel/intern/curves_geometry_test.cc @@ -78,7 +78,8 @@ TEST(curves_geometry, TypeCount) CURVE_TYPE_POLY, CURVE_TYPE_POLY, }); - std::array<int, CURVE_TYPES_NUM> counts = curves.count_curve_types(); + curves.update_curve_types(); + const std::array<int, CURVE_TYPES_NUM> &counts = curves.curve_type_counts(); EXPECT_EQ(counts[CURVE_TYPE_CATMULL_ROM], 3); EXPECT_EQ(counts[CURVE_TYPE_POLY], 3); EXPECT_EQ(counts[CURVE_TYPE_BEZIER], 1); @@ -88,7 +89,7 @@ TEST(curves_geometry, TypeCount) TEST(curves_geometry, CatmullRomEvaluation) { CurvesGeometry curves(4, 1); - curves.curve_types_for_write().fill(CURVE_TYPE_CATMULL_ROM); + curves.fill_curve_types(CURVE_TYPE_CATMULL_ROM); curves.resolution_for_write().fill(12); curves.offsets_for_write().last() = 4; curves.cyclic_for_write().fill(false); @@ -221,7 +222,7 @@ TEST(curves_geometry, CatmullRomEvaluation) TEST(curves_geometry, CatmullRomTwoPointCyclic) { CurvesGeometry curves(2, 1); - curves.curve_types_for_write().fill(CURVE_TYPE_CATMULL_ROM); + curves.fill_curve_types(CURVE_TYPE_CATMULL_ROM); curves.resolution_for_write().fill(12); curves.offsets_for_write().last() = 2; curves.cyclic_for_write().fill(true); @@ -233,7 +234,7 @@ TEST(curves_geometry, CatmullRomTwoPointCyclic) TEST(curves_geometry, BezierPositionEvaluation) { CurvesGeometry curves(2, 1); - curves.curve_types_for_write().fill(CURVE_TYPE_BEZIER); + curves.fill_curve_types(CURVE_TYPE_BEZIER); curves.resolution_for_write().fill(12); curves.offsets_for_write().last() = 2; @@ -270,7 +271,7 @@ TEST(curves_geometry, BezierPositionEvaluation) } curves.resize(4, 2); - curves.curve_types_for_write().fill(CURVE_TYPE_BEZIER); + curves.fill_curve_types(CURVE_TYPE_BEZIER); curves.resolution_for_write().fill(9); curves.offsets_for_write().last() = 4; handles_left = curves.handle_positions_left_for_write(); @@ -317,7 +318,7 @@ TEST(curves_geometry, BezierPositionEvaluation) TEST(curves_geometry, NURBSEvaluation) { CurvesGeometry curves(4, 1); - curves.curve_types_for_write().fill(CURVE_TYPE_NURBS); + curves.fill_curve_types(CURVE_TYPE_NURBS); curves.resolution_for_write().fill(10); curves.offsets_for_write().last() = 4; @@ -407,7 +408,7 @@ TEST(curves_geometry, NURBSEvaluation) TEST(curves_geometry, BezierGenericEvaluation) { CurvesGeometry curves(3, 1); - curves.curve_types_for_write().fill(CURVE_TYPE_BEZIER); + curves.fill_curve_types(CURVE_TYPE_BEZIER); curves.resolution_for_write().fill(8); curves.offsets_for_write().last() = 3; diff --git a/source/blender/blenkernel/intern/geometry_component_curves.cc b/source/blender/blenkernel/intern/geometry_component_curves.cc index 4796135b32f..bc9bba3ee2f 100644 --- a/source/blender/blenkernel/intern/geometry_component_curves.cc +++ b/source/blender/blenkernel/intern/geometry_component_curves.cc @@ -291,6 +291,15 @@ static void tag_component_topology_changed(GeometryComponent &component) } } +static void tag_component_curve_types_changed(GeometryComponent &component) +{ + Curves *curves = get_curves_from_component_for_write(component); + if (curves) { + blender::bke::CurvesGeometry::wrap(curves->geometry).update_curve_types(); + blender::bke::CurvesGeometry::wrap(curves->geometry).tag_topology_changed(); + } +} + static void tag_component_positions_changed(GeometryComponent &component) { Curves *curves = get_curves_from_component_for_write(component); @@ -506,7 +515,7 @@ static ComponentAttributeProviders create_attribute_providers_for_curve() curve_access, make_array_read_attribute<int8_t>, make_array_write_attribute<int8_t>, - tag_component_topology_changed); + tag_component_curve_types_changed); static BuiltinCustomDataLayerProvider resolution("resolution", ATTR_DOMAIN_CURVE, diff --git a/source/blender/geometry/intern/mesh_to_curve_convert.cc b/source/blender/geometry/intern/mesh_to_curve_convert.cc index a8eaa828caf..a1e5f0216b6 100644 --- a/source/blender/geometry/intern/mesh_to_curve_convert.cc +++ b/source/blender/geometry/intern/mesh_to_curve_convert.cc @@ -38,7 +38,7 @@ static Curves *create_curve_from_vert_indices(const MeshComponent &mesh_componen bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry); curves.offsets_for_write().drop_back(1).copy_from(curve_offsets); curves.offsets_for_write().last() = vert_indices.size(); - curves.curve_types_for_write().fill(CURVE_TYPE_POLY); + curves.fill_curve_types(CURVE_TYPE_POLY); curves.cyclic_for_write().fill(false); curves.cyclic_for_write().slice(cyclic_curves).fill(true); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc index fababfd027b..121ee015d2d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc @@ -173,7 +173,6 @@ static void gather_point_attributes_to_interpolate(const CurveComponent &src_com { const Curves &dst_curves_id = *dst_component.get_for_read(); const bke::CurvesGeometry &dst_curves = bke::CurvesGeometry::wrap(dst_curves_id.geometry); - const std::array<int, CURVE_TYPES_NUM> type_counts = dst_curves.count_curve_types(); VectorSet<AttributeIDRef> ids; VectorSet<AttributeIDRef> ids_no_interpolation; @@ -182,7 +181,7 @@ static void gather_point_attributes_to_interpolate(const CurveComponent &src_com if (meta_data.domain != ATTR_DOMAIN_POINT) { return true; } - if (!interpolate_attribute_to_curves(id, type_counts)) { + if (!interpolate_attribute_to_curves(id, dst_curves.curve_type_counts())) { return true; } if (interpolate_attribute_to_poly_curve(id)) { @@ -318,7 +317,7 @@ static Curves *resample_to_uniform_count(const CurveComponent &src_component, dst_curves.resize(dst_offsets.last(), dst_curves.curves_num()); /* All resampled curves are poly curves. */ - dst_curves.curve_types_for_write().fill_indices(selection, CURVE_TYPE_POLY); + dst_curves.fill_curve_types(selection, CURVE_TYPE_POLY); VArray<bool> curves_cyclic = src_curves.cyclic(); VArray<int8_t> curve_types = src_curves.curve_types(); @@ -464,7 +463,7 @@ static Curves *resample_to_evaluated(const CurveComponent &src_component, CD_DUPLICATE, src_curves.curves_num()); /* All resampled curves are poly curves. */ - dst_curves.curve_types_for_write().fill_indices(selection, CURVE_TYPE_POLY); + dst_curves.fill_curve_types(selection, CURVE_TYPE_POLY); MutableSpan<int> dst_offsets = dst_curves.offsets_for_write(); src_curves.ensure_evaluated_offsets(); |