[Bf-blender-cvs] [25e307d725d] master: Nodes: move NodeTreeRef functionality into node runtime data

Jacques Lucke noreply at git.blender.org
Wed Aug 31 12:18:33 CEST 2022


Commit: 25e307d725d0b924fb0e87e4ffde84f915b74310
Author: Jacques Lucke
Date:   Wed Aug 31 12:15:57 2022 +0200
Branches: master
https://developer.blender.org/rB25e307d725d0b924fb0e87e4ffde84f915b74310

Nodes: move NodeTreeRef functionality into node runtime data

The purpose of `NodeTreeRef` was to speed up various queries on a read-only
`bNodeTree`. Not that we have runtime data in nodes and sockets, we can also
store the result of some queries there. This has some benefits:
* No need for a read-only separate node tree data structure which increased
  complexity.
* Makes it easier to reuse cached queries in more parts of Blender that can
  benefit from it.

A downside is that we loose some type safety that we got by having different
types for input and output sockets, as well as internal and non-internal links.

This patch also refactors `DerivedNodeTree` so that it does not use
`NodeTreeRef` anymore, but uses `bNodeTree` directly instead.

To provide a convenient API (that is also close to what `NodeTreeRef` has), a
new approach is implemented: `bNodeTree`, `bNode`, `bNodeSocket` and `bNodeLink`
now have C++ methods declared in `DNA_node_types.h` which are implemented in
`BKE_node_runtime.hh`. To make this work, `makesdna` now skips c++ sections when
parsing dna header files.

No user visible changes are expected.

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

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

M	source/blender/blenkernel/BKE_node_runtime.hh
M	source/blender/blenkernel/CMakeLists.txt
M	source/blender/blenkernel/intern/node.cc
A	source/blender/blenkernel/intern/node_runtime.cc
M	source/blender/blenkernel/intern/node_tree_update.cc
M	source/blender/blenlib/BLI_multi_value_map.hh
M	source/blender/compositor/realtime_compositor/COM_evaluator.hh
M	source/blender/compositor/realtime_compositor/COM_utilities.hh
M	source/blender/compositor/realtime_compositor/intern/compile_state.cc
M	source/blender/compositor/realtime_compositor/intern/evaluator.cc
M	source/blender/compositor/realtime_compositor/intern/input_single_value_operation.cc
M	source/blender/compositor/realtime_compositor/intern/node_operation.cc
M	source/blender/compositor/realtime_compositor/intern/scheduler.cc
M	source/blender/compositor/realtime_compositor/intern/shader_node.cc
M	source/blender/compositor/realtime_compositor/intern/shader_operation.cc
M	source/blender/compositor/realtime_compositor/intern/utilities.cc
M	source/blender/editors/space_node/node_relationships.cc
M	source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc
M	source/blender/makesdna/DNA_node_types.h
M	source/blender/makesdna/intern/makesdna.c
M	source/blender/modifiers/intern/MOD_nodes.cc
M	source/blender/modifiers/intern/MOD_nodes_evaluator.cc
M	source/blender/nodes/CMakeLists.txt
M	source/blender/nodes/NOD_derived_node_tree.hh
M	source/blender/nodes/NOD_geometry_exec.hh
M	source/blender/nodes/NOD_multi_function.hh
D	source/blender/nodes/NOD_node_tree_ref.hh
M	source/blender/nodes/composite/nodes/node_composite_image.cc
M	source/blender/nodes/composite/nodes/node_composite_normal.cc
M	source/blender/nodes/function/node_function_util.hh
M	source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc
M	source/blender/nodes/function/nodes/node_fn_boolean_math.cc
M	source/blender/nodes/function/nodes/node_fn_combine_color.cc
M	source/blender/nodes/function/nodes/node_fn_compare.cc
M	source/blender/nodes/function/nodes/node_fn_float_to_int.cc
M	source/blender/nodes/function/nodes/node_fn_input_bool.cc
M	source/blender/nodes/function/nodes/node_fn_input_color.cc
M	source/blender/nodes/function/nodes/node_fn_input_int.cc
M	source/blender/nodes/function/nodes/node_fn_input_string.cc
M	source/blender/nodes/function/nodes/node_fn_input_vector.cc
M	source/blender/nodes/function/nodes/node_fn_rotate_euler.cc
M	source/blender/nodes/geometry/node_geometry_util.hh
M	source/blender/nodes/intern/derived_node_tree.cc
M	source/blender/nodes/intern/geometry_nodes_eval_log.cc
M	source/blender/nodes/intern/node_geometry_exec.cc
M	source/blender/nodes/intern/node_multi_function.cc
D	source/blender/nodes/intern/node_tree_ref.cc
M	source/blender/nodes/shader/node_shader_util.hh
M	source/blender/nodes/shader/nodes/node_shader_color_ramp.cc
M	source/blender/nodes/shader/nodes/node_shader_curves.cc
M	source/blender/nodes/shader/nodes/node_shader_math.cc
M	source/blender/nodes/shader/nodes/node_shader_mix.cc
M	source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc
M	source/blender/nodes/shader/nodes/node_shader_tex_brick.cc
M	source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc
M	source/blender/nodes/shader/nodes/node_shader_tex_magic.cc
M	source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc
M	source/blender/nodes/shader/nodes/node_shader_tex_wave.cc
M	source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc
M	source/blender/nodes/shader/nodes/node_shader_vector_math.cc
M	source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc

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

diff --git a/source/blender/blenkernel/BKE_node_runtime.hh b/source/blender/blenkernel/BKE_node_runtime.hh
index f5fb53f962b..64325959ce5 100644
--- a/source/blender/blenkernel/BKE_node_runtime.hh
+++ b/source/blender/blenkernel/BKE_node_runtime.hh
@@ -3,9 +3,20 @@
 #pragma once
 
 #include <memory>
+#include <mutex>
 
-#include "BLI_sys_types.h"
+#include "BLI_multi_value_map.hh"
 #include "BLI_utility_mixins.hh"
+#include "BLI_vector.hh"
+
+#include "DNA_node_types.h"
+
+#include "BKE_node.h"
+
+struct bNode;
+struct bNodeSocket;
+struct bNodeTree;
+struct bNodeType;
 
 namespace blender::nodes {
 struct FieldInferencingInterface;
@@ -36,6 +47,32 @@ class bNodeTreeRuntime : NonCopyable, NonMovable {
 
   /** Information about how inputs and outputs of the node group interact with fields. */
   std::unique_ptr<nodes::FieldInferencingInterface> field_inferencing_interface;
+
+  /**
+   * Protects access to all topology cache variables below. This is necessary so that the cache can
+   * be updated on a const #bNodeTree.
+   */
+  std::mutex topology_cache_mutex;
+  bool topology_cache_is_dirty = true;
+  bool topology_cache_exists = false;
+  /**
+   * Under some circumstances, it can be useful to use the cached data while editing the
+   * #bNodeTree. By default, this is protected against using an assert.
+   */
+  mutable std::atomic<int> allow_use_dirty_topology_cache = 0;
+
+  /** Only valid when #topology_cache_is_dirty is false. */
+  Vector<bNode *> nodes;
+  Vector<bNodeLink *> links;
+  Vector<bNodeSocket *> sockets;
+  Vector<bNodeSocket *> input_sockets;
+  Vector<bNodeSocket *> output_sockets;
+  MultiValueMap<const bNodeType *, bNode *> nodes_by_type;
+  Vector<bNode *> toposort_left_to_right;
+  Vector<bNode *> toposort_right_to_left;
+  bool has_link_cycle = false;
+  bool has_undefined_nodes_or_sockets = false;
+  bNode *group_output_node = nullptr;
 };
 
 /**
@@ -47,12 +84,24 @@ class bNodeSocketRuntime : NonCopyable, NonMovable {
  public:
   /**
    * References a socket declaration that is owned by `node->declaration`. This is only runtime
-   * data. It has to be updated when the node declaration changes.
+   * data. It has to be updated when the node declaration changes. Access can be allowed by using
+   * #AllowUsingOutdatedInfo.
    */
   const SocketDeclarationHandle *declaration = nullptr;
 
   /** #eNodeTreeChangedFlag. */
   uint32_t changed_flag = 0;
+
+  /** Only valid when #topology_cache_is_dirty is false. */
+  Vector<bNodeLink *> directly_linked_links;
+  Vector<bNodeSocket *> directly_linked_sockets;
+  Vector<bNodeSocket *> logically_linked_sockets;
+  Vector<bNodeSocket *> logically_linked_skipped_sockets;
+  bNode *owner_node = nullptr;
+  bNodeSocket *internal_link_input = nullptr;
+  int index_in_node = -1;
+  int index_in_all_sockets = -1;
+  int index_in_inout_sockets = -1;
 };
 
 /**
@@ -84,6 +133,392 @@ class bNodeRuntime : NonCopyable, NonMovable {
 
   /** #eNodeTreeChangedFlag. */
   uint32_t changed_flag = 0;
+
+  /** Only valid if #topology_cache_is_dirty is false. */
+  Vector<bNodeSocket *> inputs;
+  Vector<bNodeSocket *> outputs;
+  Vector<bNodeLink *> internal_links;
+  Map<StringRefNull, bNodeSocket *> inputs_by_identifier;
+  Map<StringRefNull, bNodeSocket *> outputs_by_identifier;
+  int index_in_tree = -1;
+  bool has_linked_inputs = false;
+  bool has_linked_outputs = false;
+  bNodeTree *owner_tree = nullptr;
 };
 
+namespace node_tree_runtime {
+
+class AllowUsingOutdatedInfo : NonCopyable, NonMovable {
+ private:
+  const bNodeTree &tree_;
+
+ public:
+  AllowUsingOutdatedInfo(const bNodeTree &tree) : tree_(tree)
+  {
+    tree_.runtime->allow_use_dirty_topology_cache.fetch_add(1);
+  }
+
+  ~AllowUsingOutdatedInfo()
+  {
+    tree_.runtime->allow_use_dirty_topology_cache.fetch_sub(1);
+  }
+};
+
+inline bool topology_cache_is_available(const bNodeTree &tree)
+{
+  if (!tree.runtime->topology_cache_exists) {
+    return false;
+  }
+  if (tree.runtime->allow_use_dirty_topology_cache.load() > 0) {
+    return true;
+  }
+  return !tree.runtime->topology_cache_is_dirty;
+}
+
+inline bool topology_cache_is_available(const bNode &node)
+{
+  const bNodeTree *ntree = node.runtime->owner_tree;
+  if (ntree == nullptr) {
+    return false;
+  }
+  return topology_cache_is_available(*ntree);
+}
+
+inline bool topology_cache_is_available(const bNodeSocket &socket)
+{
+  const bNode *node = socket.runtime->owner_node;
+  if (node == nullptr) {
+    return false;
+  }
+  return topology_cache_is_available(*node);
+}
+
+}  // namespace node_tree_runtime
+
 }  // namespace blender::bke
+
+/* -------------------------------------------------------------------- */
+/** \name #bNodeTree Inline Methods
+ * \{ */
+
+inline blender::Span<bNode *> bNodeTree::nodes_by_type(const blender::StringRefNull type_idname)
+{
+  BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
+  return this->runtime->nodes_by_type.lookup(nodeTypeFind(type_idname.c_str()));
+}
+
+inline blender::Span<const bNode *> bNodeTree::nodes_by_type(
+    const blender::StringRefNull type_idname) const
+{
+  BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
+  return this->runtime->nodes_by_type.lookup(nodeTypeFind(type_idname.c_str()));
+}
+
+inline blender::Span<const bNode *> bNodeTree::toposort_left_to_right() const
+{
+  BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
+  return this->runtime->toposort_left_to_right;
+}
+
+inline blender::Span<const bNode *> bNodeTree::toposort_right_to_left() const
+{
+  BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
+  return this->runtime->toposort_right_to_left;
+}
+
+inline blender::Span<const bNode *> bNodeTree::all_nodes() const
+{
+  BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
+  return this->runtime->nodes;
+}
+
+inline blender::Span<bNode *> bNodeTree::all_nodes()
+{
+  BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
+  return this->runtime->nodes;
+}
+
+inline bool bNodeTree::has_link_cycle() const
+{
+  BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
+  return this->runtime->has_link_cycle;
+}
+
+inline bool bNodeTree::has_undefined_nodes_or_sockets() const
+{
+  BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
+  return this->runtime->has_undefined_nodes_or_sockets;
+}
+
+inline const bNode *bNodeTree::group_output_node() const
+{
+  BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
+  return this->runtime->group_output_node;
+}
+
+inline blender::Span<const bNodeSocket *> bNodeTree::all_input_sockets() const
+{
+  BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
+  return this->runtime->input_sockets;
+}
+
+inline blender::Span<bNodeSocket *> bNodeTree::all_input_sockets()
+{
+  BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
+  return this->runtime->input_sockets;
+}
+
+inline blender::Span<const bNodeSocket *> bNodeTree::all_output_sockets() const
+{
+  BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
+  return this->runtime->output_sockets;
+}
+
+inline blender::Span<bNodeSocket *> bNodeTree::all_output_sockets()
+{
+  BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
+  return this->runtime->output_sockets;
+}
+
+inline blender::Span<const bNodeSocket *> bNodeTree::all_sockets() const
+{
+  BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
+  return this->runtime->sockets;
+}
+
+inline blender::Span<bNodeSocket *> bNodeTree::all_sockets()
+{
+  BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
+  return this->runtime->sockets;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #bNode Inline Methods
+ * \{ */
+
+inline blender::Span<bNodeSocket *> bNode::input_sockets()
+{
+  BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
+  return this->runtime->inputs;
+}
+
+inline blender::Span<bNodeSocket *> bNode::output_sockets()
+{
+  BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
+  return this->runtime->outputs;
+}
+
+inline blender::Span<const bNodeSocket *> bNode::input_sockets() const
+{
+  BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
+  return this->runtime->inputs;
+}
+
+inline blender::Span<const bNodeSocket *> bNode::output_sockets() const
+{
+  BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
+  return this->runtime->outputs;
+}
+
+inline bNodeSocket &bNode::input_socket(int index)
+{
+  BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
+  return *this->runtime->inputs[index];
+}
+
+inline bNodeSocket &bNode::output_socket(int index)
+{
+  BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
+  return *this->runtime->outputs[index];
+}
+
+inline const bNodeSocket &bNode::input_socket(int index) const
+{
+  BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
+  return *this->runtime->inputs[index];
+}
+
+inline const bNodeSocket &bNode::output_socket(int index) const
+{
+  BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
+  return *this->runtime->outputs[index];
+}
+
+inline const bNodeSocket &bNode::input_by_identifier(blender::StringRef identifier) const
+{
+  BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
+  return *this->runtime->inputs_by_identifier.lookup_as(identifier);
+}
+
+inline const bNodeSocket &bNode::output_by_identifier(blender::StringRef identifier) const
+{
+  BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
+  return *this->runtime->outputs_by_identifier.lookup_as(identifier);
+}
+
+inline blender::StringRefNull bNode::label_or_name() const
+{
+  if (this->label[0] == '\0') {
+    return this->name;
+  }
+  return this->l

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list