diff options
-rw-r--r-- | source/blender/blenlib/BLI_index_mask_ops.hh | 14 | ||||
-rw-r--r-- | source/blender/blenlib/intern/index_mask.cc | 49 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc | 12 | ||||
-rw-r--r-- | source/blender/functions/intern/field.cc | 21 |
4 files changed, 68 insertions, 28 deletions
diff --git a/source/blender/blenlib/BLI_index_mask_ops.hh b/source/blender/blenlib/BLI_index_mask_ops.hh index 48a1f27a2fa..f67abb1d550 100644 --- a/source/blender/blenlib/BLI_index_mask_ops.hh +++ b/source/blender/blenlib/BLI_index_mask_ops.hh @@ -13,6 +13,7 @@ #include "BLI_index_mask.hh" #include "BLI_task.hh" #include "BLI_vector.hh" +#include "BLI_virtual_array.hh" namespace blender::index_mask_ops { @@ -57,4 +58,17 @@ inline IndexMask find_indices_based_on_predicate(const IndexMask indices_to_chec return detail::find_indices_based_on_predicate__merge(indices_to_check, sub_masks, r_indices); } +/** + * Find the true indices in a virtual array. This is a version of + * #find_indices_based_on_predicate optimised for a virtual array input. + * + * \param parallel_grain_size: The grain size for when the virtual array isn't a span or a single + * value internally. This should be adjusted based on the expected cost of evaluating the virtual + * array-- more expensive virtual arrays should have smaller grain sizes. + */ +IndexMask find_indices_from_virtual_array(IndexMask indices_to_check, + const VArray<bool> &virtual_array, + int64_t parallel_grain_size, + Vector<int64_t> &r_indices); + } // namespace blender::index_mask_ops diff --git a/source/blender/blenlib/intern/index_mask.cc b/source/blender/blenlib/intern/index_mask.cc index 1e301bc5fb9..f3590e4a41c 100644 --- a/source/blender/blenlib/intern/index_mask.cc +++ b/source/blender/blenlib/intern/index_mask.cc @@ -128,7 +128,9 @@ Vector<IndexRange> IndexMask::extract_ranges_invert(const IndexRange full_range, } // namespace blender -namespace blender::index_mask_ops::detail { +namespace blender::index_mask_ops { + +namespace detail { IndexMask find_indices_based_on_predicate__merge( IndexMask indices_to_check, @@ -193,4 +195,47 @@ IndexMask find_indices_based_on_predicate__merge( return r_indices.as_span(); } -} // namespace blender::index_mask_ops::detail +} // namespace detail + +IndexMask find_indices_from_virtual_array(const IndexMask indices_to_check, + const VArray<bool> &virtual_array, + const int64_t parallel_grain_size, + Vector<int64_t> &r_indices) +{ + if (virtual_array.is_single()) { + return virtual_array.get_internal_single() ? indices_to_check : IndexMask(0); + } + if (virtual_array.is_span()) { + const Span<bool> span = virtual_array.get_internal_span(); + return find_indices_based_on_predicate( + indices_to_check, 4096, r_indices, [&](const int64_t i) { return span[i]; }); + } + + threading::EnumerableThreadSpecific<Vector<bool>> materialize_buffers; + threading::EnumerableThreadSpecific<Vector<Vector<int64_t>>> sub_masks; + + threading::parallel_for( + indices_to_check.index_range(), parallel_grain_size, [&](const IndexRange range) { + const IndexMask sliced_mask = indices_to_check.slice(range); + + /* To avoid virtual function call overhead from accessing the virtual array, + * materialize the necessary indices for this chunk into a reused buffer. */ + Vector<bool> &buffer = materialize_buffers.local(); + buffer.reinitialize(sliced_mask.size()); + virtual_array.materialize_compressed(sliced_mask, buffer); + + Vector<int64_t> masked_indices; + sliced_mask.to_best_mask_type([&](auto best_mask) { + for (const int64_t i : IndexRange(best_mask.size())) { + if (buffer[i]) { + masked_indices.append(best_mask[i]); + } + } + }); + sub_masks.local().append(std::move(masked_indices)); + }); + + return detail::find_indices_based_on_predicate__merge(indices_to_check, sub_masks, r_indices); +} + +} // namespace blender::index_mask_ops diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc index bd015784ad7..0fb4ded3b2a 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc +++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc @@ -177,10 +177,8 @@ static IndexMask get_selected_indices(const Mesh &mesh, ATTR_DOMAIN_FACE, domain); - return index_mask_ops::find_indices_based_on_predicate( - IndexMask(component.attribute_domain_num(domain)), 4096, indices, [&](const int i) { - return selection[i]; - }); + return index_mask_ops::find_indices_from_virtual_array( + IndexMask(component.attribute_domain_num(domain)), selection, 4096, indices); } if (mesh.editflag & ME_EDIT_PAINT_VERT_SEL) { const VArray<bool> selection = component.attribute_try_adapt_domain( @@ -188,10 +186,8 @@ static IndexMask get_selected_indices(const Mesh &mesh, ATTR_DOMAIN_POINT, domain); - return index_mask_ops::find_indices_based_on_predicate( - IndexMask(component.attribute_domain_num(domain)), 4096, indices, [&](const int i) { - return selection[i]; - }); + return index_mask_ops::find_indices_from_virtual_array( + IndexMask(component.attribute_domain_num(domain)), selection, 4096, indices); } return IndexMask(component.attribute_domain_num(domain)); } diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc index 47f6a0f19ca..fd5eab57d33 100644 --- a/source/blender/functions/intern/field.cc +++ b/source/blender/functions/intern/field.cc @@ -708,20 +708,11 @@ GPointer FieldConstant::value() const */ static IndexMask index_mask_from_selection(const IndexMask full_mask, - VArray<bool> &selection, + const VArray<bool> &selection, ResourceScope &scope) { - if (selection.is_span()) { - Span<bool> span = selection.get_internal_span(); - return index_mask_ops::find_indices_based_on_predicate( - full_mask, 4096, scope.construct<Vector<int64_t>>(), [&](const int curve_index) { - return span[curve_index]; - }); - } - return index_mask_ops::find_indices_based_on_predicate( - full_mask, 1024, scope.construct<Vector<int64_t>>(), [&](const int curve_index) { - return selection[curve_index]; - }); + return index_mask_ops::find_indices_from_virtual_array( + full_mask, selection, 1024, scope.construct<Vector<int64_t>>()); } int FieldEvaluator::add_with_destination(GField field, GVMutableArray dst) @@ -764,12 +755,6 @@ static IndexMask evaluate_selection(const Field<bool> &selection_field, if (selection_field) { VArray<bool> selection = evaluate_fields(scope, {selection_field}, full_mask, context)[0].typed<bool>(); - if (selection.is_single()) { - if (selection.get_internal_single()) { - return full_mask; - } - return IndexRange(0); - } return index_mask_from_selection(full_mask, selection, scope); } return full_mask; |