[Bf-blender-cvs] [3e5a4d14124] master: Geometry Nodes: Optimize selection for virtual array input

Hans Goudey noreply at git.blender.org
Thu Jun 23 18:51:48 CEST 2022


Commit: 3e5a4d14124029dd3ccb111de2db299bb405d668
Author: Hans Goudey
Date:   Thu Jun 23 11:50:53 2022 -0500
Branches: master
https://developer.blender.org/rB3e5a4d14124029dd3ccb111de2db299bb405d668

Geometry Nodes: Optimize selection for virtual array input

This makes calculation of selected indices slightly faster when the
input is a virtual array (the direct output of various nodes like
Face Area, etc). The utility can be helpful for other areas that
need to find selected indices besides field evaluation.

With the face area node used as a selection with 4 million faces,
the speedup is 3.51 ms to 3.39 ms, just a slight speedup.

Differential Revision: https://developer.blender.org/D15127

===================================================================

M	source/blender/blenlib/BLI_index_mask_ops.hh
M	source/blender/blenlib/intern/index_mask.cc
M	source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc
M	source/blender/functions/intern/field.cc

===================================================================

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;



More information about the Bf-blender-cvs mailing list