[Bf-blender-cvs] [cc08debc0cc] temp-geometry-nodes-evaluator-refactor: make nodes with side effects work

Jacques Lucke noreply at git.blender.org
Tue Sep 6 20:09:56 CEST 2022


Commit: cc08debc0cc76f63f9517a4a06581c475ae2eae4
Author: Jacques Lucke
Date:   Tue Sep 6 19:24:13 2022 +0200
Branches: temp-geometry-nodes-evaluator-refactor
https://developer.blender.org/rBcc08debc0cc76f63f9517a4a06581c475ae2eae4

make nodes with side effects work

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

M	source/blender/functions/FN_lazy_function.hh
M	source/blender/functions/FN_lazy_function_execute.hh
M	source/blender/functions/FN_lazy_function_graph_executor.hh
M	source/blender/functions/intern/lazy_function.cc
M	source/blender/functions/intern/lazy_function_graph_executor.cc
M	source/blender/functions/tests/FN_lazy_function_test.cc

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

diff --git a/source/blender/functions/FN_lazy_function.hh b/source/blender/functions/FN_lazy_function.hh
index f6528907c1b..3a332df34ce 100644
--- a/source/blender/functions/FN_lazy_function.hh
+++ b/source/blender/functions/FN_lazy_function.hh
@@ -79,6 +79,7 @@ class Params {
 
   template<typename T> T extract_input(int index);
   template<typename T> const T &get_input(int index);
+  template<typename T> T *try_get_input_data_ptr_or_request(int index);
   template<typename T> void set_output(int index, T &&value);
 
   void set_default_remaining_outputs();
@@ -134,7 +135,7 @@ class LazyFunction {
 
   void execute(Params &params, const Context &context) const;
 
-  bool valid_params_for_execution(const Params &params) const;
+  bool always_used_inputs_available(const Params &params) const;
 
  private:
   virtual void execute_impl(Params &params, const Context &context) const = 0;
@@ -156,7 +157,7 @@ inline Span<Output> LazyFunction::outputs() const
 
 inline void LazyFunction::execute(Params &params, const Context &context) const
 {
-  BLI_assert(this->valid_params_for_execution(params));
+  BLI_assert(this->always_used_inputs_available(params));
   this->execute_impl(params, context);
 }
 
@@ -170,42 +171,42 @@ inline Params::Params(const LazyFunction &fn) : fn_(fn)
 {
 }
 
-inline void *Params::try_get_input_data_ptr(int index) const
+inline void *Params::try_get_input_data_ptr(const int index) const
 {
   return this->try_get_input_data_ptr_impl(index);
 }
 
-inline void *Params::try_get_input_data_ptr_or_request(int index)
+inline void *Params::try_get_input_data_ptr_or_request(const int index)
 {
   return this->try_get_input_data_ptr_or_request_impl(index);
 }
 
-inline void *Params::get_output_data_ptr(int index)
+inline void *Params::get_output_data_ptr(const int index)
 {
   return this->get_output_data_ptr_impl(index);
 }
 
-inline void Params::output_set(int index)
+inline void Params::output_set(const int index)
 {
   this->output_set_impl(index);
 }
 
-inline bool Params::output_was_set(int index) const
+inline bool Params::output_was_set(const int index) const
 {
   return this->output_was_set_impl(index);
 }
 
-inline ValueUsage Params::get_output_usage(int index) const
+inline ValueUsage Params::get_output_usage(const int index) const
 {
   return this->get_output_usage_impl(index);
 }
 
-inline void Params::set_input_unused(int index)
+inline void Params::set_input_unused(const int index)
 {
   this->set_input_unused_impl(index);
 }
 
-template<typename T> inline T Params::extract_input(int index)
+template<typename T> inline T Params::extract_input(const int index)
 {
   void *data = this->try_get_input_data_ptr(index);
   BLI_assert(data != nullptr);
@@ -213,14 +214,19 @@ template<typename T> inline T Params::extract_input(int index)
   return return_value;
 }
 
-template<typename T> inline const T &Params::get_input(int index)
+template<typename T> inline const T &Params::get_input(const int index)
 {
   const void *data = this->try_get_input_data_ptr(index);
   BLI_assert(data != nullptr);
   return *static_cast<const T *>(data);
 }
 
-template<typename T> inline void Params::set_output(int index, T &&value)
+template<typename T> inline T *Params::try_get_input_data_ptr_or_request(const int index)
+{
+  return static_cast<T *>(this->try_get_input_data_ptr_or_request(index));
+}
+
+template<typename T> inline void Params::set_output(const int index, T &&value)
 {
   using DecayT = std::decay_t<T>;
   void *data = this->get_output_data_ptr(index);
diff --git a/source/blender/functions/FN_lazy_function_execute.hh b/source/blender/functions/FN_lazy_function_execute.hh
index c378e5fe2ac..d6a7ddcbd2a 100644
--- a/source/blender/functions/FN_lazy_function_execute.hh
+++ b/source/blender/functions/FN_lazy_function_execute.hh
@@ -75,6 +75,7 @@ inline void execute_lazy_function_eagerly_impl(
   set_outputs.fill(false);
   LinearAllocator<> allocator;
   Context context;
+  context.user_data = user_data;
   context.storage = fn.init_storage(allocator);
   BasicParams params{
       fn, input_pointers, output_pointers, input_usages, output_usages, set_outputs};
diff --git a/source/blender/functions/FN_lazy_function_graph_executor.hh b/source/blender/functions/FN_lazy_function_graph_executor.hh
index 86a7592e982..64f6059f7b6 100644
--- a/source/blender/functions/FN_lazy_function_graph_executor.hh
+++ b/source/blender/functions/FN_lazy_function_graph_executor.hh
@@ -15,6 +15,8 @@ namespace blender::fn::lazy_function {
 
 class LazyFunctionGraphExecutionLogger {
  public:
+  virtual ~LazyFunctionGraphExecutionLogger() = default;
+
   virtual void log_socket_value(const Context &context,
                                 const Socket &socket,
                                 GPointer value) const;
@@ -22,7 +24,8 @@ class LazyFunctionGraphExecutionLogger {
 
 class LazyFunctionGraphExecutionSideEffectProvider {
  public:
-  virtual Vector<const Node *> get_nodes_with_side_effects(const Context &context) const;
+  virtual ~LazyFunctionGraphExecutionSideEffectProvider() = default;
+  virtual Vector<const FunctionNode *> get_nodes_with_side_effects(const Context &context) const;
 };
 
 class LazyFunctionGraphExecutor : public LazyFunction {
diff --git a/source/blender/functions/intern/lazy_function.cc b/source/blender/functions/intern/lazy_function.cc
index 7bd37f5f462..7de733d5a35 100644
--- a/source/blender/functions/intern/lazy_function.cc
+++ b/source/blender/functions/intern/lazy_function.cc
@@ -36,30 +36,17 @@ void LazyFunction::destruct_storage(void *storage) const
   UNUSED_VARS_NDEBUG(storage);
 }
 
-bool LazyFunction::valid_params_for_execution(const Params &params) const
+bool LazyFunction::always_used_inputs_available(const Params &params) const
 {
-  bool all_required_inputs_available = true;
   for (const int i : inputs_.index_range()) {
     const Input &fn_input = inputs_[i];
     if (fn_input.usage == ValueUsage::Used) {
       if (params.try_get_input_data_ptr(i) == nullptr) {
-        all_required_inputs_available = false;
-        break;
+        return false;
       }
     }
   }
-  bool any_remaining_output_left = false;
-  for (const int i : outputs_.index_range()) {
-    if (params.get_output_usage(i) != ValueUsage::Unused) {
-      if (!params.output_was_set(i)) {
-        any_remaining_output_left = true;
-        break;
-      }
-    }
-  }
-  BLI_assert(all_required_inputs_available);
-  BLI_assert(any_remaining_output_left);
-  return all_required_inputs_available && any_remaining_output_left;
+  return true;
 }
 
 void Params::set_default_remaining_outputs()
diff --git a/source/blender/functions/intern/lazy_function_graph_executor.cc b/source/blender/functions/intern/lazy_function_graph_executor.cc
index 20e9fbd52fc..69de1345e61 100644
--- a/source/blender/functions/intern/lazy_function_graph_executor.cc
+++ b/source/blender/functions/intern/lazy_function_graph_executor.cc
@@ -114,6 +114,11 @@ struct NodeState {
    * Set to true once the node is done running for the first time.
    */
   bool had_initialization = true;
+  /**
+   * Nodes with side effects should always be executed when their required inputs have been
+   * computed.
+   */
+  bool has_side_effects = false;
   /**
    * A node is always in one specific schedule state. This helps to ensure that the same node does
    * not run twice at the same time accidentally.
@@ -170,12 +175,6 @@ class GraphExecutorLFParams;
 class Executor {
  private:
   const LazyFunctionGraphExecutor &self_;
-  /**
-   * Usually nodes are only executed when at least one of their outputs are required.
-   * Sometimes we want to execute nodes for their side effects though. So this is a list of all the
-   * nodes that should be executed even when their outputs are not required.
-   */
-  Vector<const Node *> side_effect_nodes_;
   /**
    * Remembers which inputs have been loaded from the caller already, to avoid loading them twice.
    * Atomics are used to make sure that every input is only retrieved once.
@@ -241,10 +240,8 @@ class Executor {
       is_first_execution_ = false;
     });
 
+    CurrentTask current_task;
     if (is_first_execution_) {
-      if (self_.side_effect_provider_ != nullptr) {
-        side_effect_nodes_ = self_.side_effect_provider_->get_nodes_with_side_effects(context);
-      }
       this->initialize_node_states();
       task_pool_ = BLI_task_pool_create(this, TASK_PRIORITY_HIGH);
 
@@ -253,9 +250,9 @@ class Executor {
 
       this->set_always_unused_graph_inputs();
       this->set_defaulted_graph_outputs();
+      this->schedule_side_effect_nodes(current_task);
     }
 
-    CurrentTask current_task;
     this->schedule_newly_requested_outputs(current_task);
     this->forward_newly_provided_inputs(current_task);
 
@@ -382,6 +379,21 @@ class Executor {
     }
   }
 
+  void schedule_side_effect_nodes(CurrentTask &current_task)
+  {
+    if (self_.side_effect_provider_ != nullptr) {
+      const Vector<const FunctionNode *> side_effect_nodes =
+          self_.side_effect_provider_->get_nodes_with_side_effects(*context_);
+      for (const FunctionNode *node : side_effect_nodes) {
+        NodeState &node_state = *node_states_[node->index_in_graph()];
+        node_state.has_side_effects = true;
+        this->with_locked_node(*node, node_state, current_task, [&](LockedNode &locked_node) {
+          this->schedule_node(locked_node);
+        });
+      }
+    }
+  }
+
   void forward_newly_provided_inputs(CurrentTask &current_task)
   {
     LinearAllocator<> &allocator = local_allocators_.local();
@@ -588,7 +600,7 @@ class Executor {
           required_uncomputed_output_exists = true;
         }
       }
-      if (!required_uncomputed_output_exists) {
+      if (!required_uncomputed_output_exists && !node_state.has_side_effects) {
         return;
       }
 
@@ -686,13 +698,16 @@ class Executor {
     NodeState &node_state = locked_node.node_state;
 
     if (node_state.node_has_finished) {
+      /* Was finished already. */
       return;
     }
+    /* If there are outputs that may still be used, the node is not done yet. */
     for (const OutputState &output_state : node_state.outputs) {
       if (output_state.usage != ValueUsag

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list