[Bf-blender-cvs] [1d7ee50fef7] master: Geometry Nodes: Parallelize attribute nodes

Hans Goudey noreply at git.blender.org
Mon May 3 15:00:36 CEST 2021


Commit: 1d7ee50fef71a2baaa2ebcfb8409b5eb33d1bc23
Author: Hans Goudey
Date:   Mon May 3 08:00:09 2021 -0500
Branches: master
https://developer.blender.org/rB1d7ee50fef71a2baaa2ebcfb8409b5eb33d1bc23

Geometry Nodes: Parallelize attribute nodes

This commit significantly speeds up many of the attribute nodes when
multiple threads are available in linear situations when parallelism
cannot be achieved elsewhere.

See the differential for a table of timing comparisons tested on a
Ryzen 3700x. For an attribute with 4 million elements, the nodes were
about 3 to 9 times faster.

The changes are not exhaustive, other nodes could still be parallelized
in the future. Also, it would be possible to further optimize the grain
size in `parallel_for`, but I'd rather make sure it isn't too small.
I tested some different values, but also relied on intuition--
increasing grain size for less complex operations and vice versa.

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

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

M	source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc
M	source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc
M	source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc
M	source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc
M	source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc
M	source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc
M	source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc
M	source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc

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

diff --git a/source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc b/source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc
index c4d37a82617..f5b79141703 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc
@@ -15,6 +15,7 @@
  */
 
 #include "BLI_math_rotation.h"
+#include "BLI_task.hh"
 
 #include "UI_interface.h"
 #include "UI_resources.h"
@@ -55,42 +56,44 @@ static void align_rotations_auto_pivot(const VArray<float3> &vectors,
                                        const float3 local_main_axis,
                                        const MutableSpan<float3> rotations)
 {
-  for (const int i : IndexRange(vectors.size())) {
-    const float3 vector = vectors[i];
-    if (is_zero_v3(vector)) {
-      continue;
-    }
+  parallel_for(IndexRange(vectors.size()), 128, [&](IndexRange range) {
+    for (const int i : range) {
+      const float3 vector = vectors[i];
+      if (is_zero_v3(vector)) {
+        continue;
+      }
 
-    float old_rotation[3][3];
-    eul_to_mat3(old_rotation, rotations[i]);
-    float3 old_axis;
-    mul_v3_m3v3(old_axis, old_rotation, local_main_axis);
+      float old_rotation[3][3];
+      eul_to_mat3(old_rotation, rotations[i]);
+      float3 old_axis;
+      mul_v3_m3v3(old_axis, old_rotation, local_main_axis);
 
-    const float3 new_axis = vector.normalized();
-    float3 rotation_axis = float3::cross_high_precision(old_axis, new_axis);
-    if (is_zero_v3(rotation_axis)) {
-      /* The vectors are linearly dependent, so we fall back to another axis. */
-      rotation_axis = float3::cross_high_precision(old_axis, float3(1, 0, 0));
+      const float3 new_axis = vector.normalized();
+      float3 rotation_axis = float3::cross_high_precision(old_axis, new_axis);
       if (is_zero_v3(rotation_axis)) {
-        /* This is now guaranteed to not be zero. */
-        rotation_axis = float3::cross_high_precision(old_axis, float3(0, 1, 0));
+        /* The vectors are linearly dependent, so we fall back to another axis. */
+        rotation_axis = float3::cross_high_precision(old_axis, float3(1, 0, 0));
+        if (is_zero_v3(rotation_axis)) {
+          /* This is now guaranteed to not be zero. */
+          rotation_axis = float3::cross_high_precision(old_axis, float3(0, 1, 0));
+        }
       }
-    }
 
-    const float full_angle = angle_normalized_v3v3(old_axis, new_axis);
-    const float angle = factors[i] * full_angle;
+      const float full_angle = angle_normalized_v3v3(old_axis, new_axis);
+      const float angle = factors[i] * full_angle;
 
-    float rotation[3][3];
-    axis_angle_to_mat3(rotation, rotation_axis, angle);
+      float rotation[3][3];
+      axis_angle_to_mat3(rotation, rotation_axis, angle);
 
-    float new_rotation_matrix[3][3];
-    mul_m3_m3m3(new_rotation_matrix, rotation, old_rotation);
+      float new_rotation_matrix[3][3];
+      mul_m3_m3m3(new_rotation_matrix, rotation, old_rotation);
 
-    float3 new_rotation;
-    mat3_to_eul(new_rotation, new_rotation_matrix);
+      float3 new_rotation;
+      mat3_to_eul(new_rotation, new_rotation_matrix);
 
-    rotations[i] = new_rotation;
-  }
+      rotations[i] = new_rotation;
+    }
+  });
 }
 
 static void align_rotations_fixed_pivot(const VArray<float3> &vectors,
@@ -104,37 +107,39 @@ static void align_rotations_fixed_pivot(const VArray<float3> &vectors,
     return;
   }
 
-  for (const int i : IndexRange(vectors.size())) {
-    const float3 vector = vectors[i];
-    if (is_zero_v3(vector)) {
-      continue;
-    }
+  parallel_for(IndexRange(vectors.size()), 128, [&](IndexRange range) {
+    for (const int i : range) {
+      const float3 vector = vectors[i];
+      if (is_zero_v3(vector)) {
+        continue;
+      }
 
-    float old_rotation[3][3];
-    eul_to_mat3(old_rotation, rotations[i]);
-    float3 old_axis;
-    mul_v3_m3v3(old_axis, old_rotation, local_main_axis);
-    float3 pivot_axis;
-    mul_v3_m3v3(pivot_axis, old_rotation, local_pivot_axis);
-
-    float full_angle = angle_signed_on_axis_v3v3_v3(vector, old_axis, pivot_axis);
-    if (full_angle > M_PI) {
-      /* Make sure the point is rotated as little as possible. */
-      full_angle -= 2.0f * M_PI;
-    }
-    const float angle = factors[i] * full_angle;
+      float old_rotation[3][3];
+      eul_to_mat3(old_rotation, rotations[i]);
+      float3 old_axis;
+      mul_v3_m3v3(old_axis, old_rotation, local_main_axis);
+      float3 pivot_axis;
+      mul_v3_m3v3(pivot_axis, old_rotation, local_pivot_axis);
+
+      float full_angle = angle_signed_on_axis_v3v3_v3(vector, old_axis, pivot_axis);
+      if (full_angle > M_PI) {
+        /* Make sure the point is rotated as little as possible. */
+        full_angle -= 2.0f * M_PI;
+      }
+      const float angle = factors[i] * full_angle;
 
-    float rotation[3][3];
-    axis_angle_to_mat3(rotation, pivot_axis, angle);
+      float rotation[3][3];
+      axis_angle_to_mat3(rotation, pivot_axis, angle);
 
-    float new_rotation_matrix[3][3];
-    mul_m3_m3m3(new_rotation_matrix, rotation, old_rotation);
+      float new_rotation_matrix[3][3];
+      mul_m3_m3m3(new_rotation_matrix, rotation, old_rotation);
 
-    float3 new_rotation;
-    mat3_to_eul(new_rotation, new_rotation_matrix);
+      float3 new_rotation;
+      mat3_to_eul(new_rotation, new_rotation_matrix);
 
-    rotations[i] = new_rotation;
-  }
+      rotations[i] = new_rotation;
+    }
+  });
 }
 
 static void align_rotations_on_component(GeometryComponent &component,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc
index 9e697226a01..f8c27ff55f4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc
@@ -14,6 +14,8 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
+#include "BLI_task.hh"
+
 #include "BKE_colorband.h"
 
 #include "UI_interface.h"
@@ -85,9 +87,11 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
   MutableSpan<Color4f> results = attribute_result.as_span();
 
   ColorBand *color_ramp = &node_storage->color_ramp;
-  for (const int i : IndexRange(attribute_in.size())) {
-    BKE_colorband_evaluate(color_ramp, attribute_in[i], results[i]);
-  }
+  parallel_for(IndexRange(attribute_in.size()), 512, [&](IndexRange range) {
+    for (const int i : range) {
+      BKE_colorband_evaluate(color_ramp, attribute_in[i], results[i]);
+    }
+  });
 
   attribute_result.save();
 }
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc
index 5d82897e9db..55b44db7afd 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc
@@ -15,6 +15,7 @@
  */
 
 #include "BLI_math_base_safe.h"
+#include "BLI_task.hh"
 
 #include "UI_interface.h"
 #include "UI_resources.h"
@@ -208,28 +209,36 @@ static void map_range_float(const VArray<float> &attribute_input,
 
   switch (interpolation_type) {
     case NODE_MAP_RANGE_LINEAR: {
-      for (int i : span.index_range()) {
-        results[i] = map_linear(span[i], min_from, max_from, min_to, max_to);
-      }
+      parallel_for(span.index_range(), 2048, [&](IndexRange range) {
+        for (const int i : range) {
+          results[i] = map_linear(span[i], min_from, max_from, min_to, max_to);
+        }
+      });
       break;
     }
     case NODE_MAP_RANGE_STEPPED: {
       const float steps = params.get_input<float>("Steps");
-      for (int i : span.index_range()) {
-        results[i] = map_stepped(span[i], min_from, max_from, min_to, max_to, steps);
-      }
+      parallel_for(span.index_range(), 1024, [&](IndexRange range) {
+        for (const int i : range) {
+          results[i] = map_stepped(span[i], min_from, max_from, min_to, max_to, steps);
+        }
+      });
       break;
     }
     case NODE_MAP_RANGE_SMOOTHSTEP: {
-      for (int i : span.index_range()) {
-        results[i] = map_smoothstep(span[i], min_from, max_from, min_to, max_to);
-      }
+      parallel_for(span.index_range(), 1024, [&](IndexRange range) {
+        for (const int i : range) {
+          results[i] = map_smoothstep(span[i], min_from, max_from, min_to, max_to);
+        }
+      });
       break;
     }
     case NODE_MAP_RANGE_SMOOTHERSTEP: {
-      for (int i : span.index_range()) {
-        results[i] = map_smootherstep(span[i], min_from, max_from, min_to, max_to);
-      }
+      parallel_for(span.index_range(), 1024, [&](IndexRange range) {
+        for (const int i : range) {
+          results[i] = map_smootherstep(span[i], min_from, max_from, min_to, max_to);
+        }
+      });
       break;
     }
   }
@@ -240,9 +249,11 @@ static void map_range_float(const VArray<float> &attribute_input,
     const float clamp_min = min_to < max_to ? min_to : max_to;
     const float clamp_max = min_to < max_to ? max_to : min_to;
 
-    for (int i : results.index_range()) {
-      results[i] = std::clamp(results[i], clamp_min, clamp_max);
-    }
+    parallel_for(results.index_range(), 2048, [&](IndexRange range) {
+      for (const int i : range) {
+        results[i] = std::clamp(results[i], clamp_min, clamp_max);
+      }
+    });
   }
 }
 
@@ -262,36 +273,47 @@ static void map_range_float3(const VArray<float3> &attribute_input,
 
   switch (interpolation_type) {
     case NODE_MAP_RANGE_LINEAR: {
-      for (int i : span.index_range()) {
-        results[i].x = map_linear(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x);
-        results[i].y = map_linear(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y);
-        results[i].z = map_linear(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z);
-      }
+      parallel_for(span.index_range(), 1024, [&](IndexRange range) {
+        for (const int i : range) {
+          results[i].x = map_linear(span[i].x, min_from.x, max_from.x, min_to.x, max_to.

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list