Refactoring: Geometry Node: Avoid copy last buffer in result for Blur Attribute node #106860
|
@ -246,16 +246,19 @@ static Array<Vector<int>> create_mesh_map(const Mesh &mesh,
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static void blur_on_mesh_exec(const Span<float> neighbor_weights,
|
static Span<T> blur_on_mesh_exec(const Span<float> neighbor_weights,
|
||||||
const Span<Vector<int>> neighbors_map,
|
const Span<Vector<int>> neighbors_map,
|
||||||
const int iterations,
|
const int iterations,
|
||||||
MutableSpan<T> main_buffer,
|
const MutableSpan<T> buffer_a,
|
||||||
MutableSpan<T> tmp_buffer)
|
const MutableSpan<T> buffer_b)
|
||||||
{
|
{
|
||||||
MutableSpan<T> src = main_buffer;
|
/* Source is set to buffer_b even though it is actually in buffer_a because the loop below starts
|
||||||
mod_moder marked this conversation as resolved
Outdated
|
|||||||
MutableSpan<T> dst = tmp_buffer;
|
* with swapping both. */
|
||||||
|
MutableSpan<T> src = buffer_b;
|
||||||
|
MutableSpan<T> dst = buffer_a;
|
||||||
|
|
||||||
for ([[maybe_unused]] const int64_t iteration : IndexRange(iterations)) {
|
for ([[maybe_unused]] const int64_t iteration : IndexRange(iterations)) {
|
||||||
|
std::swap(src, dst);
|
||||||
attribute_math::DefaultMixer<T> mixer{dst, IndexMask(0)};
|
attribute_math::DefaultMixer<T> mixer{dst, IndexMask(0)};
|
||||||
threading::parallel_for(dst.index_range(), 1024, [&](const IndexRange range) {
|
threading::parallel_for(dst.index_range(), 1024, [&](const IndexRange range) {
|
||||||
for (const int64_t index : range) {
|
for (const int64_t index : range) {
|
||||||
|
@ -268,56 +271,48 @@ static void blur_on_mesh_exec(const Span<float> neighbor_weights,
|
||||||
}
|
}
|
||||||
mixer.finalize(range);
|
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
|
return dst;
|
||||||
* 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());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void blur_on_mesh(const Mesh &mesh,
|
static GSpan blur_on_mesh(const Mesh &mesh,
|
||||||
const eAttrDomain domain,
|
const eAttrDomain domain,
|
||||||
const int iterations,
|
const int iterations,
|
||||||
const Span<float> neighbor_weights,
|
const Span<float> neighbor_weights,
|
||||||
GMutableSpan main_buffer,
|
const GMutableSpan buffer_a,
|
||||||
GMutableSpan tmp_buffer)
|
const GMutableSpan buffer_b)
|
||||||
{
|
{
|
||||||
Array<Vector<int>> neighbors_map = create_mesh_map(mesh, domain, neighbor_weights.index_range());
|
Array<Vector<int>> neighbors_map = create_mesh_map(mesh, domain, neighbor_weights.index_range());
|
||||||
if (neighbors_map.is_empty()) {
|
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);
|
using T = decltype(dummy);
|
||||||
if constexpr (!std::is_same_v<T, bool>) {
|
if constexpr (!std::is_same_v<T, bool>) {
|
||||||
blur_on_mesh_exec<T>(neighbor_weights,
|
result_buffer = blur_on_mesh_exec<T>(
|
||||||
neighbors_map,
|
neighbor_weights, neighbors_map, iterations, buffer_a.typed<T>(), buffer_b.typed<T>());
|
||||||
iterations,
|
|
||||||
main_buffer.typed<T>(),
|
|
||||||
tmp_buffer.typed<T>());
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
return result_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static void blur_on_curve_exec(const bke::CurvesGeometry &curves,
|
static Span<T> blur_on_curve_exec(const bke::CurvesGeometry &curves,
|
||||||
const Span<float> neighbor_weights,
|
const Span<float> neighbor_weights,
|
||||||
const int iterations,
|
const int iterations,
|
||||||
MutableSpan<T> main_buffer,
|
const MutableSpan<T> buffer_a,
|
||||||
MutableSpan<T> tmp_buffer)
|
const MutableSpan<T> buffer_b)
|
||||||
{
|
{
|
||||||
MutableSpan<T> src = main_buffer;
|
MutableSpan<T> src = buffer_b;
|
||||||
MutableSpan<T> dst = tmp_buffer;
|
MutableSpan<T> dst = buffer_a;
|
||||||
|
|
||||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||||
const VArray<bool> cyclic = curves.cyclic();
|
const VArray<bool> cyclic = curves.cyclic();
|
||||||
|
|
||||||
for ([[maybe_unused]] const int iteration : IndexRange(iterations)) {
|
for ([[maybe_unused]] const int iteration : IndexRange(iterations)) {
|
||||||
|
std::swap(src, dst);
|
||||||
attribute_math::DefaultMixer<T> mixer{dst, IndexMask(0)};
|
attribute_math::DefaultMixer<T> mixer{dst, IndexMask(0)};
|
||||||
threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange range) {
|
threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange range) {
|
||||||
for (const int curve_i : 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 float first_neighbor_weight = neighbor_weights[first_i];
|
||||||
const int last_i = points.last();
|
const int last_i = points.last();
|
||||||
const float last_neighbor_weight = neighbor_weights[last_i];
|
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]) {
|
if (cyclic[curve_i]) {
|
||||||
/* First point. */
|
/* 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);
|
mixer.mix_in(first_i, src[last_i], first_neighbor_weight);
|
||||||
/* Last point. */
|
/* 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);
|
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]);
|
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
|
return dst;
|
||||||
* 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());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void blur_on_curves(const bke::CurvesGeometry &curves,
|
static GSpan blur_on_curves(const bke::CurvesGeometry &curves,
|
||||||
const int iterations,
|
const int iterations,
|
||||||
const Span<float> neighbor_weights,
|
const Span<float> neighbor_weights,
|
||||||
GMutableSpan main_buffer,
|
const GMutableSpan buffer_a,
|
||||||
GMutableSpan tmp_buffer)
|
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);
|
using T = decltype(dummy);
|
||||||
if constexpr (!std::is_same_v<T, bool>) {
|
if constexpr (!std::is_same_v<T, bool>) {
|
||||||
blur_on_curve_exec<T>(
|
result_buffer = blur_on_curve_exec<T>(
|
||||||
curves, neighbor_weights, iterations, main_buffer.typed<T>(), tmp_buffer.typed<T>());
|
curves, neighbor_weights, iterations, buffer_a.typed<T>(), buffer_b.typed<T>());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
return result_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
class BlurAttributeFieldInput final : public bke::GeometryFieldInput {
|
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());
|
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);
|
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.add(weight_field_);
|
||||||
evaluator.evaluate();
|
evaluator.evaluate();
|
||||||
|
|
||||||
/* Blurring does not make sense with a less than 2 elements. */
|
/* Blurring does not make sense with a less than 2 elements. */
|
||||||
if (domain_size <= 1) {
|
if (domain_size <= 1) {
|
||||||
return GVArray::ForGArray(std::move(main_buffer));
|
return GVArray::ForGArray(std::move(buffer_a));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iterations_ <= 0) {
|
if (iterations_ <= 0) {
|
||||||
return GVArray::ForGArray(std::move(main_buffer));
|
return GVArray::ForGArray(std::move(buffer_a));
|
||||||
}
|
}
|
||||||
|
|
||||||
VArraySpan<float> neighbor_weights = evaluator.get_evaluated<float>(1);
|
VArraySpan<float> neighbor_weights = evaluator.get_evaluated<float>(1);
|
||||||
GArray<> tmp_buffer(*type_, domain_size);
|
GArray<> buffer_b(*type_, domain_size);
|
||||||
|
|
||||||
|
GSpan result_buffer;
|
||||||
switch (context.type()) {
|
switch (context.type()) {
|
||||||
case GEO_COMPONENT_TYPE_MESH:
|
case GEO_COMPONENT_TYPE_MESH:
|
||||||
if (ELEM(context.domain(), ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_FACE)) {
|
if (ELEM(context.domain(), ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_FACE)) {
|
||||||
if (const Mesh *mesh = context.mesh()) {
|
if (const Mesh *mesh = context.mesh()) {
|
||||||
blur_on_mesh(
|
result_buffer = blur_on_mesh(
|
||||||
*mesh, context.domain(), iterations_, neighbor_weights, main_buffer, tmp_buffer);
|
*mesh, context.domain(), iterations_, neighbor_weights, buffer_a, buffer_b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GEO_COMPONENT_TYPE_CURVE:
|
case GEO_COMPONENT_TYPE_CURVE:
|
||||||
if (context.domain() == ATTR_DOMAIN_POINT) {
|
if (context.domain() == ATTR_DOMAIN_POINT) {
|
||||||
if (const bke::CurvesGeometry *curves = context.curves()) {
|
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;
|
break;
|
||||||
|
@ -448,7 +435,11 @@ class BlurAttributeFieldInput final : public bke::GeometryFieldInput {
|
||||||
break;
|
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<void(const FieldInput &)> fn) const override
|
void for_each_field_input_recursive(FunctionRef<void(const FieldInput &)> fn) const override
|
||||||
|
|
Loading…
Reference in New Issue
Add comment
Source is set to buffer_b even though it is actually in buffer_a because the loop below starts with swapping both.