[Bf-blender-cvs] [d6224db8f17] master: Geometry Nodes: improve multi socket handling in evaluator

Jacques Lucke noreply at git.blender.org
Wed Dec 22 13:16:54 CET 2021


Commit: d6224db8f17f7035d8240bb5b9d28ce709cd3cb4
Author: Jacques Lucke
Date:   Wed Dec 22 13:16:01 2021 +0100
Branches: master
https://developer.blender.org/rBd6224db8f17f7035d8240bb5b9d28ce709cd3cb4

Geometry Nodes: improve multi socket handling in evaluator

Previously, the values passed to a multi-input socket were stored
in the order that they arrived in. Then, when the values are accessed,
they are sorted depending on the link order.

Now, the ordering is determined in the beginning before execution starts.
Every value is assigned to the right index directly, avoiding the sort
in the end. This makes the ordering more explicit.

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

M	source/blender/modifiers/intern/MOD_nodes_evaluator.cc

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

diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
index 4e808120f4a..89987f261db 100644
--- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
+++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
@@ -66,31 +66,55 @@ struct SingleInputValue {
   void *value = nullptr;
 };
 
-struct MultiInputValueItem {
-  /**
-   * The socket where this value is coming from. This is required to sort the inputs correctly
-   * based on the link order later on.
-   */
-  DSocket origin;
+struct MultiInputValue {
   /**
-   * Should only be null directly after construction. After that it should always point to a value
-   * of the correct type.
+   * Ordered sockets connected to this multi-input.
    */
-  void *value = nullptr;
-};
-
-struct MultiInputValue {
+  Vector<DSocket> origins;
   /**
-   * Collection of all the inputs that have been provided already. Note, the same origin can occur
-   * multiple times. However, it is guaranteed that if two items have the same origin, they will
-   * also have the same value (the pointer is different, but they point to values that would
-   * compare equal).
+   * A value for every origin socket. The order is determined by #origins.
+   * Note, the same origin can occur multiple times. However, it is guaranteed that values coming
+   * from the same origin have the same value (the pointer is different, but they point to values
+   * that would compare equal).
    */
-  Vector<MultiInputValueItem> items;
+  Vector<void *> values;
   /**
-   * Number of items that need to be added until all inputs have been provided.
+   * Number of non-null values.
    */
-  int expected_size = 0;
+  int provided_value_count = 0;
+
+  bool all_values_available() const
+  {
+    return this->missing_values() == 0;
+  }
+
+  int missing_values() const
+  {
+    return this->values.size() - this->provided_value_count;
+  }
+
+  void add_value(const DSocket origin, void *value)
+  {
+    const int index = this->find_available_index(origin);
+    this->values[index] = value;
+    this->provided_value_count++;
+  }
+
+ private:
+  int find_available_index(DSocket origin) const
+  {
+    for (const int i : origins.index_range()) {
+      if (values[i] != nullptr) {
+        continue;
+      }
+      if (origins[i] != origin) {
+        continue;
+      }
+      return i;
+    }
+    BLI_assert_unreachable();
+    return -1;
+  }
 };
 
 struct InputState {
@@ -556,13 +580,14 @@ class GeometryNodesEvaluator {
       /* Construct the correct struct that can hold the input(s). */
       if (socket->is_multi_input_socket()) {
         input_state.value.multi = allocator.construct<MultiInputValue>().release();
+        MultiInputValue &multi_value = *input_state.value.multi;
         /* Count how many values should be added until the socket is complete. */
-        socket.foreach_origin_socket(
-            [&](DSocket UNUSED(origin)) { input_state.value.multi->expected_size++; });
+        socket.foreach_origin_socket([&](DSocket origin) { multi_value.origins.append(origin); });
         /* If no links are connected, we do read the value from socket itself. */
-        if (input_state.value.multi->expected_size == 0) {
-          input_state.value.multi->expected_size = 1;
+        if (multi_value.origins.is_empty()) {
+          multi_value.origins.append(socket);
         }
+        multi_value.values.resize(multi_value.origins.size(), nullptr);
       }
       else {
         input_state.value.single = allocator.construct<SingleInputValue>().release();
@@ -623,8 +648,10 @@ class GeometryNodesEvaluator {
       const InputSocketRef &socket_ref = node->input(i);
       if (socket_ref.is_multi_input_socket()) {
         MultiInputValue &multi_value = *input_state.value.multi;
-        for (MultiInputValueItem &item : multi_value.items) {
-          input_state.type->destruct(item.value);
+        for (void *value : multi_value.values) {
+          if (value != nullptr) {
+            input_state.type->destruct(value);
+          }
         }
         multi_value.~MultiInputValue();
       }
@@ -892,7 +919,7 @@ class GeometryNodesEvaluator {
       if (socket->is_multi_input_socket()) {
         MultiInputValue &multi_value = *input_state.value.multi;
         /* Checks if all the linked sockets have been provided already. */
-        if (multi_value.items.size() == multi_value.expected_size) {
+        if (multi_value.all_values_available()) {
           input_state.was_ready_for_execution = true;
         }
         else if (is_required) {
@@ -1243,7 +1270,7 @@ class GeometryNodesEvaluator {
     int missing_values = 0;
     if (input_socket->is_multi_input_socket()) {
       MultiInputValue &multi_value = *input_state.value.multi;
-      missing_values = multi_value.expected_size - multi_value.items.size();
+      missing_values = multi_value.missing_values();
     }
     else {
       SingleInputValue &single_value = *input_state.value.single;
@@ -1501,10 +1528,10 @@ class GeometryNodesEvaluator {
       if (socket->is_multi_input_socket()) {
         /* Add a new value to the multi-input. */
         MultiInputValue &multi_value = *input_state.value.multi;
-        multi_value.items.append({origin, value.get()});
+        multi_value.add_value(origin, value.get());
 
-        if (multi_value.expected_size == multi_value.items.size()) {
-          this->log_socket_value({socket}, input_state, multi_value.items);
+        if (multi_value.all_values_available()) {
+          this->log_socket_value({socket}, input_state, multi_value.values);
         }
       }
       else {
@@ -1543,9 +1570,9 @@ class GeometryNodesEvaluator {
     GMutablePointer value = this->get_value_from_socket(origin_socket, *input_state.type);
     if (input_socket->is_multi_input_socket()) {
       MultiInputValue &multi_value = *input_state.value.multi;
-      multi_value.items.append({origin_socket, value.get()});
-      if (multi_value.expected_size == multi_value.items.size()) {
-        this->log_socket_value({input_socket}, input_state, multi_value.items);
+      multi_value.add_value(origin_socket, value.get());
+      if (multi_value.all_values_available()) {
+        this->log_socket_value({input_socket}, input_state, multi_value.values);
       }
     }
     else {
@@ -1568,10 +1595,13 @@ class GeometryNodesEvaluator {
     InputState &input_state = locked_node.node_state.inputs[socket->index()];
     if (socket->is_multi_input_socket()) {
       MultiInputValue &multi_value = *input_state.value.multi;
-      for (MultiInputValueItem &item : multi_value.items) {
-        input_state.type->destruct(item.value);
+      for (void *&value : multi_value.values) {
+        if (value != nullptr) {
+          input_state.type->destruct(value);
+          value = nullptr;
+        }
       }
-      multi_value.items.clear();
+      multi_value.provided_value_count = 0;
     }
     else {
       SingleInputValue &single_value = *input_state.value.single;
@@ -1653,7 +1683,7 @@ class GeometryNodesEvaluator {
     return *node_states_.lookup_key_as(node).state;
   }
 
-  void log_socket_value(DSocket socket, InputState &input_state, Span<MultiInputValueItem> values)
+  void log_socket_value(DSocket socket, InputState &input_state, Span<void *> values)
   {
     if (params_.geo_logger == nullptr) {
       return;
@@ -1662,8 +1692,8 @@ class GeometryNodesEvaluator {
     Vector<GPointer, 16> value_pointers;
     value_pointers.reserve(values.size());
     const CPPType &type = *input_state.type;
-    for (const MultiInputValueItem &item : values) {
-      value_pointers.append({type, item.value});
+    for (const void *value : values) {
+      value_pointers.append({type, value});
     }
     params_.geo_logger->local().log_multi_value_socket(socket, value_pointers);
   }
@@ -1749,7 +1779,7 @@ bool NodeParamsProvider::can_get_input(StringRef identifier) const
 
   if (socket->is_multi_input_socket()) {
     MultiInputValue &multi_value = *input_state.value.multi;
-    return multi_value.items.size() == multi_value.expected_size;
+    return multi_value.all_values_available();
   }
   SingleInputValue &single_value = *input_state.value.single;
   return single_value.value != nullptr;
@@ -1789,25 +1819,11 @@ Vector<GMutablePointer> NodeParamsProvider::extract_multi_input(StringRef identi
   MultiInputValue &multi_value = *input_state.value.multi;
 
   Vector<GMutablePointer> ret_values;
-  socket.foreach_origin_socket([&](DSocket origin) {
-    for (MultiInputValueItem &item : multi_value.items) {
-      if (item.origin == origin && item.value != nullptr) {
-        ret_values.append({*input_state.type, item.value});
-        /* Make sure we do not use the same value again if two values have the same origin. */
-        item.value = nullptr;
-        return;
-      }
-    }
-    BLI_assert_unreachable();
-  });
-  if (ret_values.is_empty()) {
-    /* If the socket is not linked, we just use the value from the socket itself. */
-    BLI_assert(multi_value.items.size() == 1);
-    MultiInputValueItem &item = multi_value.items[0];
-    BLI_assert(item.origin == socket);
-    ret_values.append({*input_state.type, item.value});
-  }
-  multi_value.items.clear();
+  for (void *&value : multi_value.values) {
+    BLI_assert(value != nullptr);
+    ret_values.append({*input_state.type, value});
+    value = nullptr;
+  }
   return ret_values;
 }



More information about the Bf-blender-cvs mailing list