diff --git a/source/blender/nodes/geometry/nodes/node_geo_blur_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_blur_attribute.cc index 7adbdce52cb..633654923ed 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_blur_attribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_blur_attribute.cc @@ -246,16 +246,19 @@ static Array> create_mesh_map(const Mesh &mesh, } template -static void blur_on_mesh_exec(const Span neighbor_weights, - const Span> neighbors_map, - const int iterations, - MutableSpan main_buffer, - MutableSpan tmp_buffer) +static Span blur_on_mesh_exec(const Span neighbor_weights, + const Span> neighbors_map, + const int iterations, + const MutableSpan buffer_a, + const MutableSpan buffer_b) { - MutableSpan src = main_buffer; - MutableSpan dst = tmp_buffer; + /* Source is set to buffer_b even though it is actually in buffer_a because the loop below starts + * with swapping both. */ + MutableSpan src = buffer_b; + MutableSpan dst = buffer_a; for ([[maybe_unused]] const int64_t iteration : IndexRange(iterations)) { + std::swap(src, dst); attribute_math::DefaultMixer mixer{dst, IndexMask(0)}; threading::parallel_for(dst.index_range(), 1024, [&](const IndexRange range) { for (const int64_t index : range) { @@ -268,56 +271,48 @@ static void blur_on_mesh_exec(const Span neighbor_weights, } mixer.finalize(range); }); - std::swap(src, dst); } - /* The last computed values are in #src now. If the main buffer is #dst, the values have to be - * copied once more. */ - if (dst.data() == main_buffer.data()) { - threading::parallel_for(dst.index_range(), 1024, [&](const IndexRange range) { - initialized_copy_n( - src.data() + range.start(), range.size(), main_buffer.data() + range.start()); - }); - } + return dst; } -static void blur_on_mesh(const Mesh &mesh, - const eAttrDomain domain, - const int iterations, - const Span neighbor_weights, - GMutableSpan main_buffer, - GMutableSpan tmp_buffer) +static GSpan blur_on_mesh(const Mesh &mesh, + const eAttrDomain domain, + const int iterations, + const Span neighbor_weights, + const GMutableSpan buffer_a, + const GMutableSpan buffer_b) { Array> neighbors_map = create_mesh_map(mesh, domain, neighbor_weights.index_range()); if (neighbors_map.is_empty()) { - return; + return buffer_a; } - attribute_math::convert_to_static_type(main_buffer.type(), [&](auto dummy) { + GSpan result_buffer; + attribute_math::convert_to_static_type(buffer_a.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_same_v) { - blur_on_mesh_exec(neighbor_weights, - neighbors_map, - iterations, - main_buffer.typed(), - tmp_buffer.typed()); + result_buffer = blur_on_mesh_exec( + neighbor_weights, neighbors_map, iterations, buffer_a.typed(), buffer_b.typed()); } }); + return result_buffer; } template -static void blur_on_curve_exec(const bke::CurvesGeometry &curves, - const Span neighbor_weights, - const int iterations, - MutableSpan main_buffer, - MutableSpan tmp_buffer) +static Span blur_on_curve_exec(const bke::CurvesGeometry &curves, + const Span neighbor_weights, + const int iterations, + const MutableSpan buffer_a, + const MutableSpan buffer_b) { - MutableSpan src = main_buffer; - MutableSpan dst = tmp_buffer; + MutableSpan src = buffer_b; + MutableSpan dst = buffer_a; const OffsetIndices points_by_curve = curves.points_by_curve(); const VArray cyclic = curves.cyclic(); for ([[maybe_unused]] const int iteration : IndexRange(iterations)) { + std::swap(src, dst); attribute_math::DefaultMixer mixer{dst, IndexMask(0)}; threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange range) { for (const int curve_i : range) { @@ -339,53 +334,43 @@ static void blur_on_curve_exec(const bke::CurvesGeometry &curves, const float first_neighbor_weight = neighbor_weights[first_i]; const int last_i = points.last(); const float last_neighbor_weight = neighbor_weights[last_i]; + + /* First point. */ + mixer.set(first_i, src[first_i], 1.0f); + mixer.mix_in(first_i, src[first_i + 1], first_neighbor_weight); + /* Last point. */ + mixer.set(last_i, src[last_i], 1.0f); + mixer.mix_in(last_i, src[last_i - 1], last_neighbor_weight); + if (cyclic[curve_i]) { /* First point. */ - mixer.set(first_i, src[first_i], 1.0f); - mixer.mix_in(first_i, src[first_i + 1], first_neighbor_weight); mixer.mix_in(first_i, src[last_i], first_neighbor_weight); /* Last point. */ - mixer.set(last_i, src[last_i], 1.0f); - mixer.mix_in(last_i, src[last_i - 1], last_neighbor_weight); mixer.mix_in(last_i, src[first_i], last_neighbor_weight); } - else { - /* First point. */ - mixer.set(first_i, src[first_i], 1.0f); - mixer.mix_in(first_i, src[first_i + 1], first_neighbor_weight); - /* Last point. */ - mixer.set(last_i, src[last_i], 1.0f); - mixer.mix_in(last_i, src[last_i - 1], last_neighbor_weight); - } } mixer.finalize(points_by_curve[range]); }); - std::swap(src, dst); } - /* The last computed values are in #src now. If the main buffer is #dst, the values have to be - * copied once more. */ - if (dst.data() == main_buffer.data()) { - threading::parallel_for(dst.index_range(), 1024, [&](const IndexRange range) { - initialized_copy_n( - src.data() + range.start(), range.size(), main_buffer.data() + range.start()); - }); - } + return dst; } -static void blur_on_curves(const bke::CurvesGeometry &curves, - const int iterations, - const Span neighbor_weights, - GMutableSpan main_buffer, - GMutableSpan tmp_buffer) +static GSpan blur_on_curves(const bke::CurvesGeometry &curves, + const int iterations, + const Span neighbor_weights, + const GMutableSpan buffer_a, + const GMutableSpan buffer_b) { - attribute_math::convert_to_static_type(main_buffer.type(), [&](auto dummy) { + GSpan result_buffer; + attribute_math::convert_to_static_type(buffer_a.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_same_v) { - blur_on_curve_exec( - curves, neighbor_weights, iterations, main_buffer.typed(), tmp_buffer.typed()); + result_buffer = blur_on_curve_exec( + curves, neighbor_weights, iterations, buffer_a.typed(), buffer_b.typed()); } }); + return result_buffer; } class BlurAttributeFieldInput final : public bke::GeometryFieldInput { @@ -408,39 +393,41 @@ class BlurAttributeFieldInput final : public bke::GeometryFieldInput { { const int64_t domain_size = context.attributes()->domain_size(context.domain()); - GArray<> main_buffer(*type_, domain_size); + GArray<> buffer_a(*type_, domain_size); FieldEvaluator evaluator(context, domain_size); - evaluator.add_with_destination(value_field_, main_buffer.as_mutable_span()); + evaluator.add_with_destination(value_field_, buffer_a.as_mutable_span()); evaluator.add(weight_field_); evaluator.evaluate(); /* Blurring does not make sense with a less than 2 elements. */ if (domain_size <= 1) { - return GVArray::ForGArray(std::move(main_buffer)); + return GVArray::ForGArray(std::move(buffer_a)); } if (iterations_ <= 0) { - return GVArray::ForGArray(std::move(main_buffer)); + return GVArray::ForGArray(std::move(buffer_a)); } VArraySpan neighbor_weights = evaluator.get_evaluated(1); - GArray<> tmp_buffer(*type_, domain_size); + GArray<> buffer_b(*type_, domain_size); + GSpan result_buffer; switch (context.type()) { case GEO_COMPONENT_TYPE_MESH: if (ELEM(context.domain(), ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_FACE)) { if (const Mesh *mesh = context.mesh()) { - blur_on_mesh( - *mesh, context.domain(), iterations_, neighbor_weights, main_buffer, tmp_buffer); + result_buffer = blur_on_mesh( + *mesh, context.domain(), iterations_, neighbor_weights, buffer_a, buffer_b); } } break; case GEO_COMPONENT_TYPE_CURVE: if (context.domain() == ATTR_DOMAIN_POINT) { if (const bke::CurvesGeometry *curves = context.curves()) { - blur_on_curves(*curves, iterations_, neighbor_weights, main_buffer, tmp_buffer); + result_buffer = blur_on_curves( + *curves, iterations_, neighbor_weights, buffer_a, buffer_b); } } break; @@ -448,7 +435,11 @@ class BlurAttributeFieldInput final : public bke::GeometryFieldInput { break; } - return GVArray::ForGArray(std::move(main_buffer)); + BLI_assert(ELEM(result_buffer.data(), buffer_a.data(), buffer_b.data())); + if (result_buffer.data() == buffer_a.data()) { + return GVArray::ForGArray(std::move(buffer_a)); + } + return GVArray::ForGArray(std::move(buffer_b)); } void for_each_field_input_recursive(FunctionRef fn) const override