From 25e307d725d0b924fb0e87e4ffde84f915b74310 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Wed, 31 Aug 2022 12:15:57 +0200 Subject: 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 --- source/blender/blenkernel/BKE_node_runtime.hh | 439 +++++++++++- source/blender/blenkernel/CMakeLists.txt | 1 + source/blender/blenkernel/intern/node.cc | 2 - source/blender/blenkernel/intern/node_runtime.cc | 403 +++++++++++ .../blender/blenkernel/intern/node_tree_update.cc | 534 +++++++-------- source/blender/blenlib/BLI_multi_value_map.hh | 5 + .../realtime_compositor/COM_evaluator.hh | 3 - .../realtime_compositor/COM_utilities.hh | 4 +- .../realtime_compositor/intern/compile_state.cc | 10 +- .../realtime_compositor/intern/evaluator.cc | 21 +- .../intern/input_single_value_operation.cc | 10 +- .../realtime_compositor/intern/node_operation.cc | 18 +- .../realtime_compositor/intern/scheduler.cc | 67 +- .../realtime_compositor/intern/shader_node.cc | 30 +- .../realtime_compositor/intern/shader_operation.cc | 38 +- .../realtime_compositor/intern/utilities.cc | 15 +- .../editors/space_node/node_relationships.cc | 83 ++- .../io/wavefront_obj/exporter/obj_export_mtl.cc | 104 ++- source/blender/makesdna/DNA_node_types.h | 180 ++++- source/blender/makesdna/intern/makesdna.c | 64 ++ source/blender/modifiers/intern/MOD_nodes.cc | 84 +-- .../modifiers/intern/MOD_nodes_evaluator.cc | 194 +++--- source/blender/nodes/CMakeLists.txt | 2 - source/blender/nodes/NOD_derived_node_tree.hh | 172 +++-- source/blender/nodes/NOD_geometry_exec.hh | 2 +- source/blender/nodes/NOD_multi_function.hh | 18 +- source/blender/nodes/NOD_node_tree_ref.hh | 760 --------------------- .../nodes/composite/nodes/node_composite_image.cc | 18 +- .../nodes/composite/nodes/node_composite_normal.cc | 7 +- .../blender/nodes/function/node_function_util.hh | 2 + .../nodes/node_fn_align_euler_to_vector.cc | 2 +- .../nodes/function/nodes/node_fn_boolean_math.cc | 2 +- .../nodes/function/nodes/node_fn_combine_color.cc | 2 +- .../nodes/function/nodes/node_fn_compare.cc | 2 +- .../nodes/function/nodes/node_fn_float_to_int.cc | 2 +- .../nodes/function/nodes/node_fn_input_bool.cc | 2 +- .../nodes/function/nodes/node_fn_input_color.cc | 2 +- .../nodes/function/nodes/node_fn_input_int.cc | 2 +- .../nodes/function/nodes/node_fn_input_string.cc | 2 +- .../nodes/function/nodes/node_fn_input_vector.cc | 2 +- .../nodes/function/nodes/node_fn_rotate_euler.cc | 2 +- .../blender/nodes/geometry/node_geometry_util.hh | 2 + source/blender/nodes/intern/derived_node_tree.cc | 139 ++-- .../nodes/intern/geometry_nodes_eval_log.cc | 8 +- source/blender/nodes/intern/node_geometry_exec.cc | 34 +- source/blender/nodes/intern/node_multi_function.cc | 8 +- source/blender/nodes/intern/node_tree_ref.cc | 679 ------------------ source/blender/nodes/shader/node_shader_util.hh | 2 + .../nodes/shader/nodes/node_shader_color_ramp.cc | 2 +- .../nodes/shader/nodes/node_shader_curves.cc | 6 +- .../blender/nodes/shader/nodes/node_shader_math.cc | 2 +- .../blender/nodes/shader/nodes/node_shader_mix.cc | 2 +- .../nodes/shader/nodes/node_shader_mix_rgb.cc | 2 +- .../nodes/shader/nodes/node_shader_tex_brick.cc | 2 +- .../nodes/shader/nodes/node_shader_tex_gradient.cc | 2 +- .../nodes/shader/nodes/node_shader_tex_magic.cc | 2 +- .../nodes/shader/nodes/node_shader_tex_musgrave.cc | 2 +- .../nodes/shader/nodes/node_shader_tex_wave.cc | 2 +- .../shader/nodes/node_shader_tex_white_noise.cc | 2 +- .../nodes/shader/nodes/node_shader_vector_math.cc | 2 +- .../shader/nodes/node_shader_vector_rotate.cc | 2 +- 61 files changed, 1865 insertions(+), 2349 deletions(-) create mode 100644 source/blender/blenkernel/intern/node_runtime.cc delete mode 100644 source/blender/nodes/NOD_node_tree_ref.hh delete mode 100644 source/blender/nodes/intern/node_tree_ref.cc (limited to 'source') 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 +#include -#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 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 allow_use_dirty_topology_cache = 0; + + /** Only valid when #topology_cache_is_dirty is false. */ + Vector nodes; + Vector links; + Vector sockets; + Vector input_sockets; + Vector output_sockets; + MultiValueMap nodes_by_type; + Vector toposort_left_to_right; + Vector 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 directly_linked_links; + Vector directly_linked_sockets; + Vector logically_linked_sockets; + Vector 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 inputs; + Vector outputs; + Vector internal_links; + Map inputs_by_identifier; + Map 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 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 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 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 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 bNodeTree::all_nodes() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->nodes; +} + +inline blender::Span 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 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 bNodeTree::all_input_sockets() +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->input_sockets; +} + +inline blender::Span 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 bNodeTree::all_output_sockets() +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->output_sockets; +} + +inline blender::Span bNodeTree::all_sockets() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->sockets; +} + +inline blender::Span 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 bNode::input_sockets() +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->inputs; +} + +inline blender::Span bNode::output_sockets() +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->outputs; +} + +inline blender::Span bNode::input_sockets() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->inputs; +} + +inline blender::Span 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->label; +} + +inline bool bNode::is_muted() const +{ + return this->flag & NODE_MUTED; +} + +inline bool bNode::is_reroute() const +{ + return this->type == NODE_REROUTE; +} + +inline bool bNode::is_frame() const +{ + return this->type == NODE_FRAME; +} + +inline bool bNode::is_group() const +{ + return ELEM(this->type, NODE_GROUP, NODE_CUSTOM_GROUP); +} + +inline bool bNode::is_group_input() const +{ + return this->type == NODE_GROUP_INPUT; +} + +inline bool bNode::is_group_output() const +{ + return this->type == NODE_GROUP_OUTPUT; +} + +inline blender::Span bNode::internal_links_span() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->internal_links; +} + +inline const blender::nodes::NodeDeclaration *bNode::declaration() const +{ + BLI_assert(this->runtime->declaration != nullptr); + return this->runtime->declaration; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #bNodeLink Inline Methods + * \{ */ + +inline bool bNodeLink::is_muted() const +{ + return this->flag & NODE_LINK_MUTED; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #bNodeSocket Inline Methods + * \{ */ + +inline int bNodeSocket::index() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->index_in_node; +} + +inline int bNodeSocket::index_in_tree() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->index_in_all_sockets; +} + +inline bool bNodeSocket::is_available() const +{ + return (this->flag & SOCK_UNAVAIL) == 0; +} + +inline bNode &bNodeSocket::owner_node() +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return *this->runtime->owner_node; +} + +inline const bNodeTree &bNodeSocket::owner_tree() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return *this->runtime->owner_node->runtime->owner_tree; +} + +inline blender::Span bNodeSocket::logically_linked_sockets() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->logically_linked_sockets; +} + +inline blender::Span bNodeSocket::directly_linked_links() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->directly_linked_links; +} + +inline blender::Span bNodeSocket::directly_linked_links() +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->directly_linked_links; +} + +inline blender::Span bNodeSocket::directly_linked_sockets() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->directly_linked_sockets; +} + +inline bool bNodeSocket::is_directly_linked() const +{ + return !this->directly_linked_links().is_empty(); +} + +inline bool bNodeSocket::is_logically_linked() const +{ + return !this->logically_linked_sockets().is_empty(); +} + +inline const bNodeSocket *bNodeSocket::internal_link_input() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + BLI_assert(this->in_out == SOCK_OUT); + return this->runtime->internal_link_input; +} + +template const T *bNodeSocket::default_value_typed() const +{ + return static_cast(this->default_value); +} + +inline bool bNodeSocket::is_input() const +{ + return this->in_out == SOCK_IN; +} + +inline bool bNodeSocket::is_output() const +{ + return this->in_out == SOCK_OUT; +} + +inline bool bNodeSocket::is_multi_input() const +{ + return this->flag & SOCK_MULTI_INPUT; +} + +inline const bNode &bNodeSocket::owner_node() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return *this->runtime->owner_node; +} + +/** \} */ diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 465573745ec..61549a66e1f 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -230,6 +230,7 @@ set(SRC intern/multires_versioning.c intern/nla.c intern/node.cc + intern/node_runtime.cc intern/node_tree_update.cc intern/object.cc intern/object_deform.c diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 1a40c0a18ed..4eb48e9edc9 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -72,7 +72,6 @@ #include "NOD_function.h" #include "NOD_geometry.h" #include "NOD_node_declaration.hh" -#include "NOD_node_tree_ref.hh" #include "NOD_shader.h" #include "NOD_socket.h" #include "NOD_texture.h" @@ -104,7 +103,6 @@ using blender::nodes::NodeDeclaration; using blender::nodes::OutputFieldDependency; using blender::nodes::OutputSocketFieldType; using blender::nodes::SocketDeclaration; -using namespace blender::nodes::node_tree_ref_types; /* Fallback types for undefined tree, nodes, sockets */ static bNodeTreeType NodeTreeTypeUndefined; diff --git a/source/blender/blenkernel/intern/node_runtime.cc b/source/blender/blenkernel/intern/node_runtime.cc new file mode 100644 index 00000000000..20ee3c41534 --- /dev/null +++ b/source/blender/blenkernel/intern/node_runtime.cc @@ -0,0 +1,403 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BKE_node.h" +#include "BKE_node_runtime.hh" + +#include "DNA_node_types.h" + +#include "BLI_function_ref.hh" +#include "BLI_stack.hh" +#include "BLI_task.hh" +#include "BLI_timeit.hh" + +namespace blender::bke::node_tree_runtime { + +static void double_checked_lock(std::mutex &mutex, bool &data_is_dirty, FunctionRef fn) +{ + if (!data_is_dirty) { + return; + } + std::lock_guard lock{mutex}; + if (!data_is_dirty) { + return; + } + fn(); + data_is_dirty = false; +} + +static void double_checked_lock_with_task_isolation(std::mutex &mutex, + bool &data_is_dirty, + FunctionRef fn) +{ + double_checked_lock(mutex, data_is_dirty, [&]() { threading::isolate_task(fn); }); +} + +static void update_node_vector(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + tree_runtime.nodes.clear(); + tree_runtime.has_undefined_nodes_or_sockets = false; + LISTBASE_FOREACH (bNode *, node, &ntree.nodes) { + node->runtime->index_in_tree = tree_runtime.nodes.append_and_get_index(node); + node->runtime->owner_tree = const_cast(&ntree); + tree_runtime.has_undefined_nodes_or_sockets |= node->typeinfo == &NodeTypeUndefined; + } +} + +static void update_link_vector(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + tree_runtime.links.clear(); + LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) { + tree_runtime.links.append(link); + } +} + +static void update_internal_links(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + for (bNode *node : tree_runtime.nodes) { + node->runtime->internal_links.clear(); + for (bNodeSocket *socket : node->runtime->outputs) { + socket->runtime->internal_link_input = nullptr; + } + LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) { + node->runtime->internal_links.append(link); + link->tosock->runtime->internal_link_input = link->fromsock; + } + } +} + +static void update_socket_vectors_and_owner_node(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + tree_runtime.sockets.clear(); + tree_runtime.input_sockets.clear(); + tree_runtime.output_sockets.clear(); + for (bNode *node : tree_runtime.nodes) { + bNodeRuntime &node_runtime = *node->runtime; + node_runtime.inputs.clear(); + node_runtime.outputs.clear(); + LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { + socket->runtime->index_in_node = node_runtime.inputs.append_and_get_index(socket); + socket->runtime->index_in_all_sockets = tree_runtime.sockets.append_and_get_index(socket); + socket->runtime->index_in_inout_sockets = tree_runtime.input_sockets.append_and_get_index( + socket); + socket->runtime->owner_node = node; + tree_runtime.has_undefined_nodes_or_sockets |= socket->typeinfo == &NodeSocketTypeUndefined; + } + LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) { + socket->runtime->index_in_node = node_runtime.outputs.append_and_get_index(socket); + socket->runtime->index_in_all_sockets = tree_runtime.sockets.append_and_get_index(socket); + socket->runtime->index_in_inout_sockets = tree_runtime.output_sockets.append_and_get_index( + socket); + socket->runtime->owner_node = node; + tree_runtime.has_undefined_nodes_or_sockets |= socket->typeinfo == &NodeSocketTypeUndefined; + } + } +} + +static void update_directly_linked_links_and_sockets(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + for (bNode *node : tree_runtime.nodes) { + for (bNodeSocket *socket : node->runtime->inputs) { + socket->runtime->directly_linked_links.clear(); + socket->runtime->directly_linked_sockets.clear(); + } + for (bNodeSocket *socket : node->runtime->outputs) { + socket->runtime->directly_linked_links.clear(); + socket->runtime->directly_linked_sockets.clear(); + } + node->runtime->has_linked_inputs = false; + node->runtime->has_linked_outputs = false; + } + for (bNodeLink *link : tree_runtime.links) { + link->fromsock->runtime->directly_linked_links.append(link); + link->fromsock->runtime->directly_linked_sockets.append(link->tosock); + link->tosock->runtime->directly_linked_links.append(link); + link->fromnode->runtime->has_linked_outputs = true; + link->tonode->runtime->has_linked_inputs = true; + } + for (bNodeSocket *socket : tree_runtime.input_sockets) { + if (socket->flag & SOCK_MULTI_INPUT) { + std::sort(socket->runtime->directly_linked_links.begin(), + socket->runtime->directly_linked_links.end(), + [&](const bNodeLink *a, const bNodeLink *b) { + return a->multi_input_socket_index > b->multi_input_socket_index; + }); + } + } + for (bNodeSocket *socket : tree_runtime.input_sockets) { + for (bNodeLink *link : socket->runtime->directly_linked_links) { + /* Do this after sorting the input links. */ + socket->runtime->directly_linked_sockets.append(link->fromsock); + } + } +} + +static void find_logical_origins_for_socket_recursive( + bNodeSocket &input_socket, + bool only_follow_first_input_link, + Vector &sockets_in_current_chain, + Vector &r_logical_origins, + Vector &r_skipped_origins) +{ + if (sockets_in_current_chain.contains(&input_socket)) { + /* Protect against reroute recursions. */ + return; + } + sockets_in_current_chain.append(&input_socket); + + Span links_to_check = input_socket.runtime->directly_linked_links; + if (only_follow_first_input_link) { + links_to_check = links_to_check.take_front(1); + } + for (bNodeLink *link : links_to_check) { + if (link->flag & NODE_LINK_MUTED) { + continue; + } + bNodeSocket &origin_socket = *link->fromsock; + bNode &origin_node = *link->fromnode; + if (!origin_socket.is_available()) { + /* Non available sockets are ignored. */ + continue; + } + if (origin_node.type == NODE_REROUTE) { + bNodeSocket &reroute_input = *origin_node.runtime->inputs[0]; + bNodeSocket &reroute_output = *origin_node.runtime->outputs[0]; + r_skipped_origins.append(&reroute_input); + r_skipped_origins.append(&reroute_output); + find_logical_origins_for_socket_recursive( + reroute_input, false, sockets_in_current_chain, r_logical_origins, r_skipped_origins); + continue; + } + if (origin_node.is_muted()) { + if (bNodeSocket *mute_input = origin_socket.runtime->internal_link_input) { + r_skipped_origins.append(&origin_socket); + r_skipped_origins.append(mute_input); + find_logical_origins_for_socket_recursive( + *mute_input, true, sockets_in_current_chain, r_logical_origins, r_skipped_origins); + } + continue; + } + r_logical_origins.append(&origin_socket); + } + + sockets_in_current_chain.pop_last(); +} + +static void update_logical_origins(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + threading::parallel_for(tree_runtime.nodes.index_range(), 128, [&](const IndexRange range) { + for (const int i : range) { + bNode &node = *tree_runtime.nodes[i]; + for (bNodeSocket *socket : node.runtime->inputs) { + Vector sockets_in_current_chain; + find_logical_origins_for_socket_recursive( + *socket, + false, + sockets_in_current_chain, + socket->runtime->logically_linked_sockets, + socket->runtime->logically_linked_skipped_sockets); + } + } + }); +} + +static void update_nodes_by_type(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + tree_runtime.nodes_by_type.clear(); + for (bNode *node : tree_runtime.nodes) { + tree_runtime.nodes_by_type.add(node->typeinfo, node); + } +} + +static void update_sockets_by_identifier(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + threading::parallel_for(tree_runtime.nodes.index_range(), 128, [&](const IndexRange range) { + for (bNode *node : tree_runtime.nodes.as_span().slice(range)) { + node->runtime->inputs_by_identifier.clear(); + node->runtime->outputs_by_identifier.clear(); + for (bNodeSocket *socket : node->runtime->inputs) { + node->runtime->inputs_by_identifier.add_new(socket->identifier, socket); + } + for (bNodeSocket *socket : node->runtime->outputs) { + node->runtime->outputs_by_identifier.add_new(socket->identifier, socket); + } + } + }); +} + +enum class ToposortDirection { + LeftToRight, + RightToLeft, +}; + +struct ToposortNodeState { + bool is_done = false; + bool is_in_stack = false; +}; + +static void toposort_from_start_node(const ToposortDirection direction, + bNode &start_node, + MutableSpan node_states, + Vector &r_sorted_nodes, + bool &r_cycle_detected) +{ + struct Item { + bNode *node; + int socket_index = 0; + int link_index = 0; + }; + + Stack nodes_to_check; + nodes_to_check.push({&start_node}); + while (!nodes_to_check.is_empty()) { + Item &item = nodes_to_check.peek(); + bNode &node = *item.node; + const Span sockets = (direction == ToposortDirection::LeftToRight) ? + node.runtime->inputs : + node.runtime->outputs; + while (true) { + if (item.socket_index == sockets.size()) { + /* All sockets have already been visited. */ + break; + } + bNodeSocket &socket = *sockets[item.socket_index]; + const Span linked_sockets = socket.runtime->directly_linked_sockets; + if (item.link_index == linked_sockets.size()) { + /* All links connected to this socket have already been visited. */ + item.socket_index++; + item.link_index = 0; + continue; + } + bNodeSocket &linked_socket = *linked_sockets[item.link_index]; + bNode &linked_node = *linked_socket.runtime->owner_node; + ToposortNodeState &linked_node_state = node_states[linked_node.runtime->index_in_tree]; + if (linked_node_state.is_done) { + /* The linked node has already been visited. */ + item.link_index++; + continue; + } + if (linked_node_state.is_in_stack) { + r_cycle_detected = true; + } + else { + nodes_to_check.push({&linked_node}); + linked_node_state.is_in_stack = true; + } + break; + } + + /* If no other element has been pushed, the current node can be pushed to the sorted list. */ + if (&item == &nodes_to_check.peek()) { + ToposortNodeState &node_state = node_states[node.runtime->index_in_tree]; + node_state.is_done = true; + node_state.is_in_stack = false; + r_sorted_nodes.append(&node); + nodes_to_check.pop(); + } + } +} + +static void update_toposort(const bNodeTree &ntree, + const ToposortDirection direction, + Vector &r_sorted_nodes, + bool &r_cycle_detected) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + r_sorted_nodes.clear(); + r_sorted_nodes.reserve(tree_runtime.nodes.size()); + r_cycle_detected = false; + + Array node_states(tree_runtime.nodes.size()); + for (bNode *node : tree_runtime.nodes) { + if (node_states[node->runtime->index_in_tree].is_done) { + /* Ignore nodes that are done already. */ + continue; + } + if ((direction == ToposortDirection::LeftToRight) ? node->runtime->has_linked_outputs : + node->runtime->has_linked_inputs) { + /* Ignore non-start nodes. */ + continue; + } + toposort_from_start_node(direction, *node, node_states, r_sorted_nodes, r_cycle_detected); + } + + if (r_sorted_nodes.size() < tree_runtime.nodes.size()) { + r_cycle_detected = true; + for (bNode *node : tree_runtime.nodes) { + if (node_states[node->runtime->index_in_tree].is_done) { + /* Ignore nodes that are done already. */ + continue; + } + /* Start toposort at this node which is somewhere in the middle of a loop. */ + toposort_from_start_node(direction, *node, node_states, r_sorted_nodes, r_cycle_detected); + } + } + + BLI_assert(tree_runtime.nodes.size() == r_sorted_nodes.size()); +} + +static void update_group_output_node(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + const bNodeType *node_type = nodeTypeFind("NodeGroupOutput"); + const Span group_output_nodes = tree_runtime.nodes_by_type.lookup(node_type); + if (group_output_nodes.is_empty()) { + tree_runtime.group_output_node = nullptr; + } + else if (group_output_nodes.size() == 1) { + tree_runtime.group_output_node = group_output_nodes[0]; + } + else { + for (bNode *group_output : group_output_nodes) { + if (group_output->flag & NODE_DO_OUTPUT) { + tree_runtime.group_output_node = group_output; + break; + } + } + } +} + +static void ensure_topology_cache(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + double_checked_lock_with_task_isolation( + tree_runtime.topology_cache_mutex, tree_runtime.topology_cache_is_dirty, [&]() { + update_node_vector(ntree); + update_link_vector(ntree); + update_socket_vectors_and_owner_node(ntree); + update_internal_links(ntree); + update_directly_linked_links_and_sockets(ntree); + threading::parallel_invoke([&]() { update_logical_origins(ntree); }, + [&]() { update_nodes_by_type(ntree); }, + [&]() { update_sockets_by_identifier(ntree); }, + [&]() { + update_toposort(ntree, + ToposortDirection::LeftToRight, + tree_runtime.toposort_left_to_right, + tree_runtime.has_link_cycle); + }, + [&]() { + bool dummy; + update_toposort(ntree, + ToposortDirection::RightToLeft, + tree_runtime.toposort_right_to_left, + dummy); + }); + update_group_output_node(ntree); + tree_runtime.topology_cache_exists = true; + }); +} + +} // namespace blender::bke::node_tree_runtime + +void bNodeTree::ensure_topology_cache() const +{ + blender::bke::node_tree_runtime::ensure_topology_cache(*this); +} diff --git a/source/blender/blenkernel/intern/node_tree_update.cc b/source/blender/blenkernel/intern/node_tree_update.cc index 58084226b00..716b8ce31d3 100644 --- a/source/blender/blenkernel/intern/node_tree_update.cc +++ b/source/blender/blenkernel/intern/node_tree_update.cc @@ -5,6 +5,7 @@ #include "BLI_noise.hh" #include "BLI_set.hh" #include "BLI_stack.hh" +#include "BLI_timeit.hh" #include "BLI_vector_set.hh" #include "DNA_anim_types.h" @@ -21,7 +22,6 @@ #include "MOD_nodes.h" #include "NOD_node_declaration.hh" -#include "NOD_node_tree_ref.hh" #include "NOD_texture.h" #include "DEG_depsgraph_query.h" @@ -50,6 +50,7 @@ enum eNodeTreeChangedFlag { static void add_tree_tag(bNodeTree *ntree, const eNodeTreeChangedFlag flag) { ntree->runtime->changed_flag |= flag; + ntree->runtime->topology_cache_is_dirty = true; } static void add_node_tag(bNodeTree *ntree, bNode *node, const eNodeTreeChangedFlag flag) @@ -73,31 +74,32 @@ static bool is_field_socket_type(eNodeSocketDatatype type) return ELEM(type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA); } -static bool is_field_socket_type(const SocketRef &socket) +static bool is_field_socket_type(const bNodeSocket &socket) { - return is_field_socket_type((eNodeSocketDatatype)socket.typeinfo()->type); + return is_field_socket_type((eNodeSocketDatatype)socket.typeinfo->type); } -static InputSocketFieldType get_interface_input_field_type(const NodeRef &node, - const InputSocketRef &socket) +static InputSocketFieldType get_interface_input_field_type(const bNode &node, + const bNodeSocket &socket) { if (!is_field_socket_type(socket)) { return InputSocketFieldType::None; } - if (node.is_reroute_node()) { + if (node.type == NODE_REROUTE) { return InputSocketFieldType::IsSupported; } - if (node.is_group_output_node()) { + if (node.type == NODE_GROUP_OUTPUT) { /* Outputs always support fields when the data type is correct. */ return InputSocketFieldType::IsSupported; } - if (node.is_undefined()) { + if (node.typeinfo == &NodeTypeUndefined) { return InputSocketFieldType::None; } - if (node.bnode()->type == NODE_CUSTOM) { + if (node.type == NODE_CUSTOM) { return InputSocketFieldType::None; } + /* TODO: Ensure declaration exists. */ const NodeDeclaration *node_decl = node.declaration(); /* Node declarations should be implemented for nodes involved here. */ @@ -116,25 +118,25 @@ static InputSocketFieldType get_interface_input_field_type(const NodeRef &node, return field_type; } -static OutputFieldDependency get_interface_output_field_dependency(const NodeRef &node, - const OutputSocketRef &socket) +static OutputFieldDependency get_interface_output_field_dependency(const bNode &node, + const bNodeSocket &socket) { if (!is_field_socket_type(socket)) { /* Non-field sockets always output data. */ return OutputFieldDependency::ForDataSource(); } - if (node.is_reroute_node()) { + if (node.type == NODE_REROUTE) { /* The reroute just forwards what is passed in. */ return OutputFieldDependency::ForDependentField(); } - if (node.is_group_input_node()) { + if (node.type == NODE_GROUP_INPUT) { /* Input nodes get special treatment in #determine_group_input_states. */ return OutputFieldDependency::ForDependentField(); } - if (node.is_undefined()) { + if (node.typeinfo == &NodeTypeUndefined) { return OutputFieldDependency::ForDataSource(); } - if (node.bnode()->type == NODE_CUSTOM) { + if (node.type == NODE_CUSTOM) { return OutputFieldDependency::ForDataSource(); } @@ -153,12 +155,13 @@ static OutputFieldDependency get_interface_output_field_dependency(const NodeRef return socket_decl.output_field_dependency(); } -static FieldInferencingInterface get_dummy_field_inferencing_interface(const NodeRef &node) +static FieldInferencingInterface get_dummy_field_inferencing_interface(const bNode &node) { FieldInferencingInterface inferencing_interface; - inferencing_interface.inputs.append_n_times(InputSocketFieldType::None, node.inputs().size()); + inferencing_interface.inputs.append_n_times(InputSocketFieldType::None, + node.input_sockets().size()); inferencing_interface.outputs.append_n_times(OutputFieldDependency::ForDataSource(), - node.outputs().size()); + node.output_sockets().size()); return inferencing_interface; } @@ -167,11 +170,11 @@ static FieldInferencingInterface get_dummy_field_inferencing_interface(const Nod * In the future, this information can be stored in the node declaration. This would allow this * function to return a reference, making it more efficient. */ -static FieldInferencingInterface get_node_field_inferencing_interface(const NodeRef &node) +static FieldInferencingInterface get_node_field_inferencing_interface(const bNode &node) { /* Node groups already reference all required information, so just return that. */ - if (node.is_group_node()) { - bNodeTree *group = (bNodeTree *)node.bnode()->id; + if (node.is_group()) { + bNodeTree *group = (bNodeTree *)node.id; if (group == nullptr) { return FieldInferencingInterface(); } @@ -187,11 +190,11 @@ static FieldInferencingInterface get_node_field_inferencing_interface(const Node } FieldInferencingInterface inferencing_interface; - for (const InputSocketRef *input_socket : node.inputs()) { + for (const bNodeSocket *input_socket : node.input_sockets()) { inferencing_interface.inputs.append(get_interface_input_field_type(node, *input_socket)); } - for (const OutputSocketRef *output_socket : node.outputs()) { + for (const bNodeSocket *output_socket : node.output_sockets()) { inferencing_interface.outputs.append( get_interface_output_field_dependency(node, *output_socket)); } @@ -215,11 +218,11 @@ struct SocketFieldState { bool requires_single = false; }; -static Vector gather_input_socket_dependencies( - const OutputFieldDependency &field_dependency, const NodeRef &node) +static Vector gather_input_socket_dependencies( + const OutputFieldDependency &field_dependency, const bNode &node) { const OutputSocketFieldType type = field_dependency.field_type(); - Vector input_sockets; + Vector input_sockets; switch (type) { case OutputSocketFieldType::FieldSource: case OutputSocketFieldType::None: { @@ -227,13 +230,13 @@ static Vector gather_input_socket_dependencies( } case OutputSocketFieldType::DependentField: { /* This output depends on all inputs. */ - input_sockets.extend(node.inputs()); + input_sockets.extend(node.input_sockets()); break; } case OutputSocketFieldType::PartiallyDependent: { /* This output depends only on a few inputs. */ for (const int i : field_dependency.linked_input_indices()) { - input_sockets.append(&node.input(i)); + input_sockets.append(&node.input_socket(i)); } break; } @@ -246,8 +249,7 @@ static Vector gather_input_socket_dependencies( * to figure out if it is always a field or if it depends on any group inputs. */ static OutputFieldDependency find_group_output_dependencies( - const InputSocketRef &group_output_socket, - const Span field_state_by_socket_id) + const bNodeSocket &group_output_socket, const Span field_state_by_socket_id) { if (!is_field_socket_type(group_output_socket)) { return OutputFieldDependency::ForDataSource(); @@ -255,8 +257,8 @@ static OutputFieldDependency find_group_output_dependencies( /* Use a Set here instead of an array indexed by socket id, because we my only need to look at * very few sockets. */ - Set handled_sockets; - Stack sockets_to_check; + Set handled_sockets; + Stack sockets_to_check; handled_sockets.add(&group_output_socket); sockets_to_check.push(&group_output_socket); @@ -265,20 +267,21 @@ static OutputFieldDependency find_group_output_dependencies( Vector linked_input_indices; while (!sockets_to_check.is_empty()) { - const InputSocketRef *input_socket = sockets_to_check.pop(); + const bNodeSocket *input_socket = sockets_to_check.pop(); if (!input_socket->is_directly_linked() && - !field_state_by_socket_id[input_socket->id()].is_single) { + !field_state_by_socket_id[input_socket->index_in_tree()].is_single) { /* This socket uses a field as input by default. */ return OutputFieldDependency::ForFieldSource(); } - for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) { - const NodeRef &origin_node = origin_socket->node(); - const SocketFieldState &origin_state = field_state_by_socket_id[origin_socket->id()]; + for (const bNodeSocket *origin_socket : input_socket->directly_linked_sockets()) { + const bNode &origin_node = origin_socket->owner_node(); + const SocketFieldState &origin_state = + field_state_by_socket_id[origin_socket->index_in_tree()]; if (origin_state.is_field_source) { - if (origin_node.is_group_input_node()) { + if (origin_node.type == NODE_GROUP_INPUT) { /* Found a group input that the group output depends on. */ linked_input_indices.append_non_duplicates(origin_socket->index()); } @@ -294,12 +297,12 @@ static OutputFieldDependency find_group_output_dependencies( inferencing_interface.outputs[origin_socket->index()]; /* Propagate search further to the left. */ - for (const InputSocketRef *origin_input_socket : + for (const bNodeSocket *origin_input_socket : gather_input_socket_dependencies(field_dependency, origin_node)) { if (!origin_input_socket->is_available()) { continue; } - if (!field_state_by_socket_id[origin_input_socket->id()].is_single) { + if (!field_state_by_socket_id[origin_input_socket->index_in_tree()].is_single) { if (handled_sockets.add(origin_input_socket)) { sockets_to_check.push(origin_input_socket); } @@ -312,17 +315,16 @@ static OutputFieldDependency find_group_output_dependencies( } static void propagate_data_requirements_from_right_to_left( - const NodeTreeRef &tree, const MutableSpan field_state_by_socket_id) + const bNodeTree &tree, const MutableSpan field_state_by_socket_id) { - const NodeTreeRef::ToposortResult toposort_result = tree.toposort( - NodeTreeRef::ToposortDirection::RightToLeft); + const Span toposort_result = tree.toposort_right_to_left(); - for (const NodeRef *node : toposort_result.sorted_nodes) { + for (const bNode *node : toposort_result) { const FieldInferencingInterface inferencing_interface = get_node_field_inferencing_interface( *node); - for (const OutputSocketRef *output_socket : node->outputs()) { - SocketFieldState &state = field_state_by_socket_id[output_socket->id()]; + for (const bNodeSocket *output_socket : node->output_sockets()) { + SocketFieldState &state = field_state_by_socket_id[output_socket->index_in_tree()]; const OutputFieldDependency &field_dependency = inferencing_interface.outputs[output_socket->index()]; @@ -338,17 +340,18 @@ static void propagate_data_requirements_from_right_to_left( /* The output is required to be a single value when it is connected to any input that does * not support fields. */ - for (const InputSocketRef *target_socket : output_socket->directly_linked_sockets()) { + for (const bNodeSocket *target_socket : output_socket->directly_linked_sockets()) { if (target_socket->is_available()) { - state.requires_single |= field_state_by_socket_id[target_socket->id()].requires_single; + state.requires_single |= + field_state_by_socket_id[target_socket->index_in_tree()].requires_single; } } if (state.requires_single) { bool any_input_is_field_implicitly = false; - const Vector connected_inputs = gather_input_socket_dependencies( + const Vector connected_inputs = gather_input_socket_dependencies( field_dependency, *node); - for (const InputSocketRef *input_socket : connected_inputs) { + for (const bNodeSocket *input_socket : connected_inputs) { if (!input_socket->is_available()) { continue; } @@ -367,16 +370,16 @@ static void propagate_data_requirements_from_right_to_left( else { /* If the output is required to be a single value, the connected inputs in the same node * must not be fields as well. */ - for (const InputSocketRef *input_socket : connected_inputs) { - field_state_by_socket_id[input_socket->id()].requires_single = true; + for (const bNodeSocket *input_socket : connected_inputs) { + field_state_by_socket_id[input_socket->index_in_tree()].requires_single = true; } } } } /* Some inputs do not require fields independent of what the outputs are connected to. */ - for (const InputSocketRef *input_socket : node->inputs()) { - SocketFieldState &state = field_state_by_socket_id[input_socket->id()]; + for (const bNodeSocket *input_socket : node->input_sockets()) { + SocketFieldState &state = field_state_by_socket_id[input_socket->index_in_tree()]; if (inferencing_interface.inputs[input_socket->index()] == InputSocketFieldType::None) { state.requires_single = true; state.is_always_single = true; @@ -386,14 +389,14 @@ static void propagate_data_requirements_from_right_to_left( } static void determine_group_input_states( - const NodeTreeRef &tree, + const bNodeTree &tree, FieldInferencingInterface &new_inferencing_interface, const MutableSpan field_state_by_socket_id) { { /* Non-field inputs never support fields. */ int index; - LISTBASE_FOREACH_INDEX (bNodeSocket *, group_input, &tree.btree()->inputs, index) { + LISTBASE_FOREACH_INDEX (bNodeSocket *, group_input, &tree.inputs, index) { if (!is_field_socket_type((eNodeSocketDatatype)group_input->type)) { new_inferencing_interface.inputs[index] = InputSocketFieldType::None; } @@ -401,18 +404,18 @@ static void determine_group_input_states( } /* Check if group inputs are required to be single values, because they are (indirectly) * connected to some socket that does not support fields. */ - for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) { - for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) { - SocketFieldState &state = field_state_by_socket_id[output_socket->id()]; + for (const bNode *node : tree.nodes_by_type("NodeGroupInput")) { + for (const bNodeSocket *output_socket : node->output_sockets().drop_back(1)) { + SocketFieldState &state = field_state_by_socket_id[output_socket->index_in_tree()]; if (state.requires_single) { new_inferencing_interface.inputs[output_socket->index()] = InputSocketFieldType::None; } } } /* If an input does not support fields, this should be reflected in all Group Input nodes. */ - for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) { - for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) { - SocketFieldState &state = field_state_by_socket_id[output_socket->id()]; + for (const bNode *node : tree.nodes_by_type("NodeGroupInput")) { + for (const bNodeSocket *output_socket : node->output_sockets().drop_back(1)) { + SocketFieldState &state = field_state_by_socket_id[output_socket->index_in_tree()]; const bool supports_field = new_inferencing_interface.inputs[output_socket->index()] != InputSocketFieldType::None; if (supports_field) { @@ -423,19 +426,19 @@ static void determine_group_input_states( state.requires_single = true; } } - SocketFieldState &dummy_socket_state = field_state_by_socket_id[node->outputs().last()->id()]; + SocketFieldState &dummy_socket_state = + field_state_by_socket_id[node->output_sockets().last()->index_in_tree()]; dummy_socket_state.requires_single = true; } } static void propagate_field_status_from_left_to_right( - const NodeTreeRef &tree, const MutableSpan field_state_by_socket_id) + const bNodeTree &tree, const MutableSpan field_state_by_socket_id) { - const NodeTreeRef::ToposortResult toposort_result = tree.toposort( - NodeTreeRef::ToposortDirection::LeftToRight); + const Span toposort_result = tree.toposort_left_to_right(); - for (const NodeRef *node : toposort_result.sorted_nodes) { - if (node->is_group_input_node()) { + for (const bNode *node : toposort_result) { + if (node->type == NODE_GROUP_INPUT) { continue; } @@ -443,22 +446,22 @@ static void propagate_field_status_from_left_to_right( *node); /* Update field state of input sockets, also taking into account linked origin sockets. */ - for (const InputSocketRef *input_socket : node->inputs()) { - SocketFieldState &state = field_state_by_socket_id[input_socket->id()]; + for (const bNodeSocket *input_socket : node->input_sockets()) { + SocketFieldState &state = field_state_by_socket_id[input_socket->index_in_tree()]; if (state.is_always_single) { state.is_single = true; continue; } state.is_single = true; - if (input_socket->directly_linked_sockets().is_empty()) { + if (!input_socket->is_directly_linked()) { if (inferencing_interface.inputs[input_socket->index()] == InputSocketFieldType::Implicit) { state.is_single = false; } } else { - for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) { - if (!field_state_by_socket_id[origin_socket->id()].is_single) { + for (const bNodeSocket *origin_socket : input_socket->directly_linked_sockets()) { + if (!field_state_by_socket_id[origin_socket->index_in_tree()].is_single) { state.is_single = false; break; } @@ -467,8 +470,8 @@ static void propagate_field_status_from_left_to_right( } /* Update field state of output sockets, also taking into account input sockets. */ - for (const OutputSocketRef *output_socket : node->outputs()) { - SocketFieldState &state = field_state_by_socket_id[output_socket->id()]; + for (const bNodeSocket *output_socket : node->output_sockets()) { + SocketFieldState &state = field_state_by_socket_id[output_socket->index_in_tree()]; const OutputFieldDependency &field_dependency = inferencing_interface.outputs[output_socket->index()]; @@ -484,12 +487,12 @@ static void propagate_field_status_from_left_to_right( } case OutputSocketFieldType::PartiallyDependent: case OutputSocketFieldType::DependentField: { - for (const InputSocketRef *input_socket : + for (const bNodeSocket *input_socket : gather_input_socket_dependencies(field_dependency, *node)) { if (!input_socket->is_available()) { continue; } - if (!field_state_by_socket_id[input_socket->id()].is_single) { + if (!field_state_by_socket_id[input_socket->index_in_tree()].is_single) { state.is_single = false; break; } @@ -501,17 +504,18 @@ static void propagate_field_status_from_left_to_right( } } -static void determine_group_output_states(const NodeTreeRef &tree, +static void determine_group_output_states(const bNodeTree &tree, FieldInferencingInterface &new_inferencing_interface, const Span field_state_by_socket_id) { - for (const NodeRef *group_output_node : tree.nodes_by_type("NodeGroupOutput")) { + for (const bNode *group_output_node : tree.nodes_by_type("NodeGroupOutput")) { /* Ignore inactive group output nodes. */ - if (!(group_output_node->bnode()->flag & NODE_DO_OUTPUT)) { + if (!(group_output_node->flag & NODE_DO_OUTPUT)) { continue; } /* Determine dependencies of all group outputs. */ - for (const InputSocketRef *group_output_socket : group_output_node->inputs().drop_back(1)) { + for (const bNodeSocket *group_output_socket : + group_output_node->input_sockets().drop_back(1)) { OutputFieldDependency field_dependency = find_group_output_dependencies( *group_output_socket, field_state_by_socket_id); new_inferencing_interface.outputs[group_output_socket->index()] = std::move( @@ -521,7 +525,7 @@ static void determine_group_output_states(const NodeTreeRef &tree, } } -static void update_socket_shapes(const NodeTreeRef &tree, +static void update_socket_shapes(const bNodeTree &tree, const Span field_state_by_socket_id) { const eNodeSocketDisplayShape requires_data_shape = SOCK_DISPLAY_SHAPE_CIRCLE; @@ -541,32 +545,30 @@ static void update_socket_shapes(const NodeTreeRef &tree, return data_but_can_be_field_shape; }; - for (const InputSocketRef *socket : tree.input_sockets()) { - bNodeSocket *bsocket = socket->bsocket(); - const SocketFieldState &state = field_state_by_socket_id[socket->id()]; - bsocket->display_shape = get_shape_for_state(state); + for (const bNodeSocket *socket : tree.all_input_sockets()) { + const SocketFieldState &state = field_state_by_socket_id[socket->index_in_tree()]; + const_cast(socket)->display_shape = get_shape_for_state(state); } - for (const OutputSocketRef *socket : tree.output_sockets()) { - bNodeSocket *bsocket = socket->bsocket(); - const SocketFieldState &state = field_state_by_socket_id[socket->id()]; - bsocket->display_shape = get_shape_for_state(state); + for (const bNodeSocket *socket : tree.all_sockets()) { + const SocketFieldState &state = field_state_by_socket_id[socket->index_in_tree()]; + const_cast(socket)->display_shape = get_shape_for_state(state); } } -static bool update_field_inferencing(const NodeTreeRef &tree) +static bool update_field_inferencing(const bNodeTree &tree) { - bNodeTree &btree = *tree.btree(); + tree.ensure_topology_cache(); /* Create new inferencing interface for this node group. */ std::unique_ptr new_inferencing_interface = std::make_unique(); - new_inferencing_interface->inputs.resize(BLI_listbase_count(&btree.inputs), + new_inferencing_interface->inputs.resize(BLI_listbase_count(&tree.inputs), InputSocketFieldType::IsSupported); - new_inferencing_interface->outputs.resize(BLI_listbase_count(&btree.outputs), + new_inferencing_interface->outputs.resize(BLI_listbase_count(&tree.outputs), OutputFieldDependency::ForDataSource()); /* Keep track of the state of all sockets. The index into this array is #SocketRef::id(). */ - Array field_state_by_socket_id(tree.sockets().size()); + Array field_state_by_socket_id(tree.all_sockets().size()); propagate_data_requirements_from_right_to_left(tree, field_state_by_socket_id); determine_group_input_states(tree, *new_inferencing_interface, field_state_by_socket_id); @@ -575,10 +577,10 @@ static bool update_field_inferencing(const NodeTreeRef &tree) update_socket_shapes(tree, field_state_by_socket_id); /* Update the previous group interface. */ - const bool group_interface_changed = !btree.runtime->field_inferencing_interface || - *btree.runtime->field_inferencing_interface != + const bool group_interface_changed = !tree.runtime->field_inferencing_interface || + *tree.runtime->field_inferencing_interface != *new_inferencing_interface; - btree.runtime->field_inferencing_interface = std::move(new_inferencing_interface); + tree.runtime->field_inferencing_interface = std::move(new_inferencing_interface); return group_interface_changed; } @@ -979,29 +981,22 @@ class NodeTreeMainUpdater { { TreeUpdateResult result; - /* Use a #NodeTreeRef to speedup certain queries. It is rebuilt whenever the node tree topology - * changes, which typically happens zero or one times during the entire update of the node - * tree. */ - std::unique_ptr tree_ref; - this->ensure_tree_ref(ntree, tree_ref); - - this->update_socket_link_and_use(*tree_ref); - this->update_individual_nodes(ntree, tree_ref); - this->update_internal_links(ntree, tree_ref); - this->update_generic_callback(ntree, tree_ref); + this->update_socket_link_and_use(ntree); + this->update_individual_nodes(ntree); + this->update_internal_links(ntree); + this->update_generic_callback(ntree); this->remove_unused_previews_when_necessary(ntree); - this->ensure_tree_ref(ntree, tree_ref); - this->propagate_runtime_flags(*tree_ref); + this->propagate_runtime_flags(ntree); if (ntree.type == NTREE_GEOMETRY) { - if (node_field_inferencing::update_field_inferencing(*tree_ref)) { + if (node_field_inferencing::update_field_inferencing(ntree)) { result.interface_changed = true; } } - result.output_changed = this->check_if_output_changed(*tree_ref); + result.output_changed = this->check_if_output_changed(ntree); - this->update_socket_link_and_use(*tree_ref); + this->update_socket_link_and_use(ntree); this->update_node_levels(ntree); this->update_link_validation(ntree); @@ -1021,86 +1016,69 @@ class NodeTreeMainUpdater { return result; } - void ensure_tree_ref(bNodeTree &ntree, std::unique_ptr &tree_ref) - { - if (!tree_ref) { - tree_ref = std::make_unique(&ntree); - } - } - - void update_socket_link_and_use(const NodeTreeRef &tree) + void update_socket_link_and_use(bNodeTree &tree) { - for (const InputSocketRef *socket : tree.input_sockets()) { - bNodeSocket *bsocket = socket->bsocket(); + tree.ensure_topology_cache(); + for (bNodeSocket *socket : tree.all_input_sockets()) { if (socket->directly_linked_links().is_empty()) { - bsocket->link = nullptr; + socket->link = nullptr; } else { - bsocket->link = socket->directly_linked_links()[0]->blink(); + socket->link = socket->directly_linked_links()[0]; } } this->update_socket_used_tags(tree); } - void update_socket_used_tags(const NodeTreeRef &tree) + void update_socket_used_tags(bNodeTree &tree) { - for (const SocketRef *socket : tree.sockets()) { - bNodeSocket *bsocket = socket->bsocket(); - bsocket->flag &= ~SOCK_IN_USE; - for (const LinkRef *link : socket->directly_linked_links()) { - if (!link->is_muted()) { - bsocket->flag |= SOCK_IN_USE; + tree.ensure_topology_cache(); + for (bNodeSocket *socket : tree.all_sockets()) { + socket->flag &= ~SOCK_IN_USE; + for (const bNodeLink *link : socket->directly_linked_links()) { + if ((link->flag & NODE_LINK_MUTED) != 0) { + socket->flag |= SOCK_IN_USE; break; } } } } - void update_individual_nodes(bNodeTree &ntree, std::unique_ptr &tree_ref) + void update_individual_nodes(bNodeTree &ntree) { - /* Iterate over nodes instead of #NodeTreeRef, because the #tree_ref might be outdated after - * some update functions. */ - LISTBASE_FOREACH (bNode *, bnode, &ntree.nodes) { - this->ensure_tree_ref(ntree, tree_ref); - const NodeRef &node = *tree_ref->find_node(*bnode); - if (this->should_update_individual_node(node)) { - const uint32_t old_changed_flag = ntree.runtime->changed_flag; - ntree.runtime->changed_flag = NTREE_CHANGED_NOTHING; - - /* This may set #ntree.runtime->changed_flag which is detected below. */ - this->update_individual_node(node); - - if (ntree.runtime->changed_flag != NTREE_CHANGED_NOTHING) { - /* The tree ref is outdated and needs to be rebuilt. Generally, only very few update - * functions change the node. Typically zero or one nodes change after an update. */ - tree_ref.reset(); + LISTBASE_FOREACH (bNode *, node, &ntree.nodes) { + if (this->should_update_individual_node(ntree, *node)) { + bNodeType &ntype = *node->typeinfo; + if (ntype.group_update_func) { + ntype.group_update_func(&ntree, node); + } + if (ntype.updatefunc) { + ntype.updatefunc(&ntree, node); } - ntree.runtime->changed_flag |= old_changed_flag; } } } - bool should_update_individual_node(const NodeRef &node) + bool should_update_individual_node(const bNodeTree &ntree, const bNode &node) { - bNodeTree &ntree = *node.btree(); - bNode &bnode = *node.bnode(); if (ntree.runtime->changed_flag & NTREE_CHANGED_ANY) { return true; } - if (bnode.runtime->changed_flag & NTREE_CHANGED_NODE_PROPERTY) { + if (node.runtime->changed_flag & NTREE_CHANGED_NODE_PROPERTY) { return true; } if (ntree.runtime->changed_flag & NTREE_CHANGED_LINK) { + ntree.ensure_topology_cache(); /* Node groups currently always rebuilt their sockets when they are updated. * So avoid calling the update method when no new link was added to it. */ - if (node.is_group_input_node()) { - if (node.outputs().last()->is_directly_linked()) { + if (node.type == NODE_GROUP_INPUT) { + if (node.output_sockets().last()->is_directly_linked()) { return true; } } - else if (node.is_group_output_node()) { - if (node.inputs().last()->is_directly_linked()) { + else if (node.type == NODE_GROUP_OUTPUT) { + if (node.input_sockets().last()->is_directly_linked()) { return true; } } @@ -1110,95 +1088,76 @@ class NodeTreeMainUpdater { } } if (ntree.runtime->changed_flag & NTREE_CHANGED_INTERFACE) { - if (node.is_group_input_node() || node.is_group_output_node()) { + if (ELEM(node.type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) { return true; } } return false; } - void update_individual_node(const NodeRef &node) - { - bNodeTree &ntree = *node.btree(); - bNode &bnode = *node.bnode(); - bNodeType &ntype = *bnode.typeinfo; - if (ntype.group_update_func) { - ntype.group_update_func(&ntree, &bnode); - } - if (ntype.updatefunc) { - ntype.updatefunc(&ntree, &bnode); - } - } - - void update_internal_links(bNodeTree &ntree, std::unique_ptr &tree_ref) + void update_internal_links(bNodeTree &ntree) { - bool any_internal_links_updated = false; - this->ensure_tree_ref(ntree, tree_ref); - for (const NodeRef *node : tree_ref->nodes()) { - if (!this->should_update_individual_node(*node)) { + bke::node_tree_runtime::AllowUsingOutdatedInfo allow_outdated_info{ntree}; + ntree.ensure_topology_cache(); + for (bNode *node : ntree.all_nodes()) { + if (!this->should_update_individual_node(ntree, *node)) { continue; } /* Find all expected internal links. */ Vector> expected_internal_links; - for (const OutputSocketRef *output_socket : node->outputs()) { + for (const bNodeSocket *output_socket : node->output_sockets()) { if (!output_socket->is_available()) { continue; } if (!output_socket->is_directly_linked()) { continue; } - if (output_socket->bsocket()->flag & SOCK_NO_INTERNAL_LINK) { + if (output_socket->flag & SOCK_NO_INTERNAL_LINK) { continue; } - const InputSocketRef *input_socket = this->find_internally_linked_input(output_socket); + const bNodeSocket *input_socket = this->find_internally_linked_input(output_socket); if (input_socket != nullptr) { - expected_internal_links.append({input_socket->bsocket(), output_socket->bsocket()}); + expected_internal_links.append( + {const_cast(input_socket), const_cast(output_socket)}); } } - /* rebuilt internal links if they have changed. */ - if (node->internal_links().size() != expected_internal_links.size()) { - this->update_internal_links_in_node(ntree, *node->bnode(), expected_internal_links); - any_internal_links_updated = true; + /* Rebuilt internal links if they have changed. */ + if (node->internal_links_span().size() != expected_internal_links.size()) { + this->update_internal_links_in_node(ntree, *node, expected_internal_links); } else { for (auto &item : expected_internal_links) { const bNodeSocket *from_socket = item.first; const bNodeSocket *to_socket = item.second; bool found = false; - for (const InternalLinkRef *internal_link : node->internal_links()) { - if (from_socket == internal_link->from().bsocket() && - to_socket == internal_link->to().bsocket()) { + for (const bNodeLink *internal_link : node->internal_links_span()) { + if (from_socket == internal_link->fromsock && to_socket == internal_link->tosock) { found = true; } } if (!found) { - this->update_internal_links_in_node(ntree, *node->bnode(), expected_internal_links); - any_internal_links_updated = true; + this->update_internal_links_in_node(ntree, *node, expected_internal_links); break; } } } } - - if (any_internal_links_updated) { - tree_ref.reset(); - } } - const InputSocketRef *find_internally_linked_input(const OutputSocketRef *output_socket) + const bNodeSocket *find_internally_linked_input(const bNodeSocket *output_socket) { - const InputSocketRef *selected_socket = nullptr; + const bNodeSocket *selected_socket = nullptr; int selected_priority = -1; bool selected_is_linked = false; - for (const InputSocketRef *input_socket : output_socket->node().inputs()) { + for (const bNodeSocket *input_socket : output_socket->owner_node().input_sockets()) { if (!input_socket->is_available()) { continue; } - if (input_socket->bsocket()->flag & SOCK_NO_INTERNAL_LINK) { + if (input_socket->flag & SOCK_NO_INTERNAL_LINK) { continue; } - const int priority = get_internal_link_type_priority(input_socket->bsocket()->typeinfo, - output_socket->bsocket()->typeinfo); + const int priority = get_internal_link_type_priority(input_socket->typeinfo, + output_socket->typeinfo); if (priority < 0) { continue; } @@ -1233,23 +1192,12 @@ class NodeTreeMainUpdater { BKE_ntree_update_tag_node_internal_link(&ntree, &node); } - void update_generic_callback(bNodeTree &ntree, std::unique_ptr &tree_ref) + void update_generic_callback(bNodeTree &ntree) { if (ntree.typeinfo->update == nullptr) { return; } - - /* Reset the changed_flag to allow detecting when the update callback changed the node tree. */ - const uint32_t old_changed_flag = ntree.runtime->changed_flag; - ntree.runtime->changed_flag = NTREE_CHANGED_NOTHING; - ntree.typeinfo->update(&ntree); - - if (ntree.runtime->changed_flag != NTREE_CHANGED_NOTHING) { - /* The tree ref is outdated and needs to be rebuilt. */ - tree_ref.reset(); - } - ntree.runtime->changed_flag |= old_changed_flag; } void remove_unused_previews_when_necessary(bNodeTree &ntree) @@ -1264,25 +1212,26 @@ class NodeTreeMainUpdater { BKE_node_preview_remove_unused(&ntree); } - void propagate_runtime_flags(const NodeTreeRef &tree_ref) + void propagate_runtime_flags(const bNodeTree &ntree) { - bNodeTree &ntree = *tree_ref.btree(); + ntree.ensure_topology_cache(); + ntree.runtime->runtime_flag = 0; if (ntree.type != NTREE_SHADER) { return; } /* Check if a used node group has an animated image. */ - for (const NodeRef *group_node : tree_ref.nodes_by_type("ShaderNodeGroup")) { - const bNodeTree *group = reinterpret_cast(group_node->bnode()->id); + for (const bNode *group_node : ntree.nodes_by_type("ShaderNodeGroup")) { + const bNodeTree *group = reinterpret_cast(group_node->id); if (group != nullptr) { ntree.runtime->runtime_flag |= group->runtime->runtime_flag; } } /* Check if the tree itself has an animated image. */ for (const StringRefNull idname : {"ShaderNodeTexImage", "ShaderNodeTexEnvironment"}) { - for (const NodeRef *node : tree_ref.nodes_by_type(idname)) { - Image *image = reinterpret_cast(node->bnode()->id); + for (const bNode *node : ntree.nodes_by_type(idname)) { + Image *image = reinterpret_cast(node->id); if (image != nullptr && BKE_image_is_animated(image)) { ntree.runtime->runtime_flag |= NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION; break; @@ -1294,7 +1243,7 @@ class NodeTreeMainUpdater { "ShaderNodeOutputLight", "ShaderNodeOutputWorld", "ShaderNodeOutputAOV"}) { - const Span nodes = tree_ref.nodes_by_type(idname); + const Span nodes = ntree.nodes_by_type(idname); if (!nodes.is_empty()) { ntree.runtime->runtime_flag |= NTREE_RUNTIME_FLAG_HAS_MATERIAL_OUTPUT; break; @@ -1325,20 +1274,20 @@ class NodeTreeMainUpdater { } } - bool check_if_output_changed(const NodeTreeRef &tree) + bool check_if_output_changed(const bNodeTree &tree) { - bNodeTree &btree = *tree.btree(); + tree.ensure_topology_cache(); /* Compute a hash that represents the node topology connected to the output. This always has to * be updated even if it is not used to detect changes right now. Otherwise * #btree.runtime.output_topology_hash will go out of date. */ - const Vector tree_output_sockets = this->find_output_sockets(tree); - const uint32_t old_topology_hash = btree.runtime->output_topology_hash; + const Vector tree_output_sockets = this->find_output_sockets(tree); + const uint32_t old_topology_hash = tree.runtime->output_topology_hash; const uint32_t new_topology_hash = this->get_combined_socket_topology_hash( tree, tree_output_sockets); - btree.runtime->output_topology_hash = new_topology_hash; + tree.runtime->output_topology_hash = new_topology_hash; - if (const AnimData *adt = BKE_animdata_from_id(&btree.id)) { + if (const AnimData *adt = BKE_animdata_from_id(&tree.id)) { /* Drivers may copy values in the node tree around arbitrarily and may cause the output to * change even if it wouldn't without drivers. Only some special drivers like `frame/5` can * be used without causing updates all the time currently. In the future we could try to @@ -1360,7 +1309,7 @@ class NodeTreeMainUpdater { } } - if (btree.runtime->changed_flag & NTREE_CHANGED_ANY) { + if (tree.runtime->changed_flag & NTREE_CHANGED_ANY) { return true; } @@ -1369,8 +1318,8 @@ class NodeTreeMainUpdater { } /* The topology hash can only be used when only topology-changing operations have been done. */ - if (btree.runtime->changed_flag == - (btree.runtime->changed_flag & (NTREE_CHANGED_LINK | NTREE_CHANGED_REMOVED_NODE))) { + if (tree.runtime->changed_flag == + (tree.runtime->changed_flag & (NTREE_CHANGED_LINK | NTREE_CHANGED_REMOVED_NODE))) { if (old_topology_hash == new_topology_hash) { return false; } @@ -1383,15 +1332,15 @@ class NodeTreeMainUpdater { return true; } - Vector find_output_sockets(const NodeTreeRef &tree) + Vector find_output_sockets(const bNodeTree &tree) { - Vector sockets; - for (const NodeRef *node : tree.nodes()) { + Vector sockets; + for (const bNode *node : tree.all_nodes()) { if (!this->is_output_node(*node)) { continue; } - for (const InputSocketRef *socket : node->inputs()) { - if (socket->idname() != "NodeSocketVirtual") { + for (const bNodeSocket *socket : node->input_sockets()) { + if (!STREQ(socket->idname, "NodeSocketVirtual")) { sockets.append(socket); } } @@ -1399,18 +1348,17 @@ class NodeTreeMainUpdater { return sockets; } - bool is_output_node(const NodeRef &node) const + bool is_output_node(const bNode &node) const { - const bNode &bnode = *node.bnode(); - if (bnode.typeinfo->nclass == NODE_CLASS_OUTPUT) { + if (node.typeinfo->nclass == NODE_CLASS_OUTPUT) { return true; } - if (bnode.type == NODE_GROUP_OUTPUT) { + if (node.type == NODE_GROUP_OUTPUT) { return true; } /* Assume node groups without output sockets are outputs. */ - if (bnode.type == NODE_GROUP) { - const bNodeTree *node_group = reinterpret_cast(bnode.id); + if (node.type == NODE_GROUP) { + const bNodeTree *node_group = reinterpret_cast(node.id); if (node_group != nullptr && node_group->runtime->runtime_flag & NTREE_RUNTIME_FLAG_HAS_MATERIAL_OUTPUT) { return true; @@ -1423,10 +1371,10 @@ class NodeTreeMainUpdater { * Computes a hash that changes when the node tree topology connected to an output node changes. * Adding reroutes does not have an effect on the hash. */ - uint32_t get_combined_socket_topology_hash(const NodeTreeRef &tree, - Span sockets) + uint32_t get_combined_socket_topology_hash(const bNodeTree &tree, + Span sockets) { - if (tree.has_link_cycles()) { + if (tree.has_link_cycle()) { /* Return dummy value when the link has any cycles. The algorithm below could be improved to * handle cycles more gracefully. */ return 0; @@ -1439,29 +1387,28 @@ class NodeTreeMainUpdater { return combined_hash; } - Array get_socket_topology_hashes(const NodeTreeRef &tree, - Span sockets) + Array get_socket_topology_hashes(const bNodeTree &tree, + Span sockets) { - BLI_assert(!tree.has_link_cycles()); - Array> hash_by_socket_id(tree.sockets().size()); - Stack sockets_to_check = sockets; + BLI_assert(!tree.has_link_cycle()); + Array> hash_by_socket_id(tree.all_sockets().size()); + Stack sockets_to_check = sockets; while (!sockets_to_check.is_empty()) { - const SocketRef &in_out_socket = *sockets_to_check.peek(); - const NodeRef &node = in_out_socket.node(); + const bNodeSocket &socket = *sockets_to_check.peek(); + const bNode &node = socket.owner_node(); - if (hash_by_socket_id[in_out_socket.id()].has_value()) { + if (hash_by_socket_id[socket.index_in_tree()].has_value()) { sockets_to_check.pop(); /* Socket is handled already. */ continue; } - if (in_out_socket.is_input()) { + if (socket.is_input()) { /* For input sockets, first compute the hashes of all linked sockets. */ - const InputSocketRef &socket = in_out_socket.as_input(); bool all_origins_computed = true; - for (const OutputSocketRef *origin_socket : socket.logically_linked_sockets()) { - if (!hash_by_socket_id[origin_socket->id()].has_value()) { + for (const bNodeSocket *origin_socket : socket.logically_linked_sockets()) { + if (!hash_by_socket_id[origin_socket->index_in_tree()].has_value()) { sockets_to_check.push(origin_socket); all_origins_computed = false; } @@ -1471,22 +1418,21 @@ class NodeTreeMainUpdater { } /* When the hashes for the linked sockets are ready, combine them into a hash for the input * socket. */ - const uint64_t socket_ptr = (uintptr_t)socket.bsocket(); + const uint64_t socket_ptr = (uintptr_t)&socket; uint32_t socket_hash = noise::hash(socket_ptr, socket_ptr >> 32); - for (const OutputSocketRef *origin_socket : socket.logically_linked_sockets()) { - const uint32_t origin_socket_hash = *hash_by_socket_id[origin_socket->id()]; + for (const bNodeSocket *origin_socket : socket.logically_linked_sockets()) { + const uint32_t origin_socket_hash = *hash_by_socket_id[origin_socket->index_in_tree()]; socket_hash = noise::hash(socket_hash, origin_socket_hash); } - hash_by_socket_id[socket.id()] = socket_hash; + hash_by_socket_id[socket.index_in_tree()] = socket_hash; sockets_to_check.pop(); } else { /* For output sockets, first compute the hashes of all available input sockets. */ - const OutputSocketRef &socket = in_out_socket.as_output(); bool all_available_inputs_computed = true; - for (const InputSocketRef *input_socket : node.inputs()) { + for (const bNodeSocket *input_socket : node.input_sockets()) { if (input_socket->is_available()) { - if (!hash_by_socket_id[input_socket->id()].has_value()) { + if (!hash_by_socket_id[input_socket->index_in_tree()].has_value()) { sockets_to_check.push(input_socket); all_available_inputs_computed = false; } @@ -1497,25 +1443,25 @@ class NodeTreeMainUpdater { } /* When all input socket hashes have been computed, combine them into a hash for the output * socket. */ - const uint64_t socket_ptr = (uintptr_t)socket.bsocket(); + const uint64_t socket_ptr = (uintptr_t)&socket; uint32_t socket_hash = noise::hash(socket_ptr, socket_ptr >> 32); - for (const InputSocketRef *input_socket : node.inputs()) { + for (const bNodeSocket *input_socket : node.input_sockets()) { if (input_socket->is_available()) { - const uint32_t input_socket_hash = *hash_by_socket_id[input_socket->id()]; + const uint32_t input_socket_hash = *hash_by_socket_id[input_socket->index_in_tree()]; socket_hash = noise::hash(socket_hash, input_socket_hash); } } /* The Image Texture node has a special case. The behavior of the color output changes * depending on whether the Alpha output is linked. */ - if (node.bnode()->type == SH_NODE_TEX_IMAGE && socket.index() == 0) { - BLI_assert(socket.name() == "Color"); - const OutputSocketRef &alpha_socket = node.output(1); - BLI_assert(alpha_socket.name() == "Alpha"); + if (node.type == SH_NODE_TEX_IMAGE && socket.index() == 0) { + BLI_assert(STREQ(socket.name, "Color")); + const bNodeSocket &alpha_socket = node.output_socket(1); + BLI_assert(STREQ(alpha_socket.name, "Alpha")); if (alpha_socket.is_directly_linked()) { socket_hash = noise::hash(socket_hash); } } - hash_by_socket_id[socket.id()] = socket_hash; + hash_by_socket_id[socket.index_in_tree()] = socket_hash; sockets_to_check.pop(); } } @@ -1523,7 +1469,7 @@ class NodeTreeMainUpdater { /* Create output array. */ Array hashes(sockets.size()); for (const int i : sockets.index_range()) { - hashes[i] = *hash_by_socket_id[sockets[i]->id()]; + hashes[i] = *hash_by_socket_id[sockets[i]->index_in_tree()]; } return hashes; } @@ -1532,37 +1478,34 @@ class NodeTreeMainUpdater { * Returns true when any of the provided sockets changed its values. A change is detected by * checking the #changed_flag on connected sockets and nodes. */ - bool check_if_socket_outputs_changed_based_on_flags(const NodeTreeRef &tree, - Span sockets) + bool check_if_socket_outputs_changed_based_on_flags(const bNodeTree &tree, + Span sockets) { /* Avoid visiting the same socket twice when multiple links point to the same socket. */ - Array pushed_by_socket_id(tree.sockets().size(), false); - Stack sockets_to_check = sockets; + Array pushed_by_socket_id(tree.all_sockets().size(), false); + Stack sockets_to_check = sockets; - for (const SocketRef *socket : sockets) { - pushed_by_socket_id[socket->id()] = true; + for (const bNodeSocket *socket : sockets) { + pushed_by_socket_id[socket->index_in_tree()] = true; } while (!sockets_to_check.is_empty()) { - const SocketRef &in_out_socket = *sockets_to_check.pop(); - const NodeRef &node = in_out_socket.node(); - const bNode &bnode = *node.bnode(); - const bNodeSocket &bsocket = *in_out_socket.bsocket(); - if (bsocket.runtime->changed_flag != NTREE_CHANGED_NOTHING) { + const bNodeSocket &socket = *sockets_to_check.pop(); + const bNode &node = socket.owner_node(); + if (socket.runtime->changed_flag != NTREE_CHANGED_NOTHING) { return true; } - if (bnode.runtime->changed_flag != NTREE_CHANGED_NOTHING) { - const bool only_unused_internal_link_changed = (bnode.flag & NODE_MUTED) == 0 && - bnode.runtime->changed_flag == + if (node.runtime->changed_flag != NTREE_CHANGED_NOTHING) { + const bool only_unused_internal_link_changed = !node.is_muted() && + node.runtime->changed_flag == NTREE_CHANGED_INTERNAL_LINK; if (!only_unused_internal_link_changed) { return true; } } - if (in_out_socket.is_input()) { - const InputSocketRef &socket = in_out_socket.as_input(); - for (const OutputSocketRef *origin_socket : socket.logically_linked_sockets()) { - bool &pushed = pushed_by_socket_id[origin_socket->id()]; + if (socket.is_input()) { + for (const bNodeSocket *origin_socket : socket.logically_linked_sockets()) { + bool &pushed = pushed_by_socket_id[origin_socket->index_in_tree()]; if (!pushed) { sockets_to_check.push(origin_socket); pushed = true; @@ -1570,10 +1513,9 @@ class NodeTreeMainUpdater { } } else { - const OutputSocketRef &socket = in_out_socket.as_output(); - for (const InputSocketRef *input_socket : node.inputs()) { + for (const bNodeSocket *input_socket : node.input_sockets()) { if (input_socket->is_available()) { - bool &pushed = pushed_by_socket_id[input_socket->id()]; + bool &pushed = pushed_by_socket_id[input_socket->index_in_tree()]; if (!pushed) { sockets_to_check.push(input_socket); pushed = true; @@ -1582,11 +1524,11 @@ class NodeTreeMainUpdater { } /* The Normal node has a special case, because the value stored in the first output socket * is used as input in the node. */ - if (bnode.type == SH_NODE_NORMAL && socket.index() == 1) { - BLI_assert(socket.name() == "Dot"); - const OutputSocketRef &normal_output = node.output(0); - BLI_assert(normal_output.name() == "Normal"); - bool &pushed = pushed_by_socket_id[normal_output.id()]; + if (node.type == SH_NODE_NORMAL && socket.index() == 1) { + BLI_assert(STREQ(socket.name, "Dot")); + const bNodeSocket &normal_output = node.output_socket(0); + BLI_assert(STREQ(normal_output.name, "Normal")); + bool &pushed = pushed_by_socket_id[normal_output.index_in_tree()]; if (!pushed) { sockets_to_check.push(&normal_output); pushed = true; diff --git a/source/blender/blenlib/BLI_multi_value_map.hh b/source/blender/blenlib/BLI_multi_value_map.hh index 4b6300c09aa..1fc5a797574 100644 --- a/source/blender/blenlib/BLI_multi_value_map.hh +++ b/source/blender/blenlib/BLI_multi_value_map.hh @@ -137,6 +137,11 @@ template class MultiValueMap { { return map_.values(); } + + void clear() + { + map_.clear(); + } }; } // namespace blender diff --git a/source/blender/compositor/realtime_compositor/COM_evaluator.hh b/source/blender/compositor/realtime_compositor/COM_evaluator.hh index fd6feb0948b..258a2a038c4 100644 --- a/source/blender/compositor/realtime_compositor/COM_evaluator.hh +++ b/source/blender/compositor/realtime_compositor/COM_evaluator.hh @@ -104,9 +104,6 @@ class Evaluator { Context &context_; /* A reference to the compositor node tree. */ bNodeTree &node_tree_; - /* The derived and reference node trees representing the compositor node tree. Those are - * initialized when the node tree is compiled and freed when the evaluator resets. */ - NodeTreeRefMap node_tree_reference_map_; std::unique_ptr derived_node_tree_; /* The compiled operations stream. This contains ordered pointers to the operations that were * compiled. This is initialized when the node tree is compiled and freed when the evaluator diff --git a/source/blender/compositor/realtime_compositor/COM_utilities.hh b/source/blender/compositor/realtime_compositor/COM_utilities.hh index 4bd61aab5cb..614384bd573 100644 --- a/source/blender/compositor/realtime_compositor/COM_utilities.hh +++ b/source/blender/compositor/realtime_compositor/COM_utilities.hh @@ -27,7 +27,7 @@ DSocket get_input_origin_socket(DInputSocket input); DOutputSocket get_output_linked_to_input(DInputSocket input); /* Get the result type that corresponds to the type of the given socket. */ -ResultType get_node_socket_result_type(const SocketRef *socket); +ResultType get_node_socket_result_type(const bNodeSocket *socket); /* Returns true if any of the nodes linked to the given output satisfies the given condition, and * false otherwise. */ @@ -46,7 +46,7 @@ bool is_shader_node(DNode node); bool is_node_supported(DNode node); /* Get the input descriptor of the given input socket. */ -InputDescriptor input_descriptor_from_input_socket(const InputSocketRef *socket); +InputDescriptor input_descriptor_from_input_socket(const bNodeSocket *socket); /* Dispatch the given compute shader in a 2D compute space such that the number of threads in both * dimensions is as small as possible but at least covers the entirety of threads_range assuming diff --git a/source/blender/compositor/realtime_compositor/intern/compile_state.cc b/source/blender/compositor/realtime_compositor/intern/compile_state.cc index 5b485224111..97c1e47e86e 100644 --- a/source/blender/compositor/realtime_compositor/intern/compile_state.cc +++ b/source/blender/compositor/realtime_compositor/intern/compile_state.cc @@ -46,7 +46,7 @@ Result &CompileState::get_result_from_output_socket(DOutputSocket output) * reference to the result from that operation using the output identifier. */ if (node_operations_.contains(output.node())) { NodeOperation *operation = node_operations_.lookup(output.node()); - return operation->get_result(output->identifier()); + return operation->get_result(output->identifier); } /* Otherwise, the output belongs to a node that was compiled into a shader operation, so @@ -113,17 +113,17 @@ Domain CompileState::compute_shader_node_domain(DNode node) /* Go over the inputs and find the domain of the non single value input with the highest domain * priority. */ - for (const InputSocketRef *input_ref : node->inputs()) { - const DInputSocket input{node.context(), input_ref}; + for (const bNodeSocket *input : node->input_sockets()) { + const DInputSocket dinput{node.context(), input}; /* Get the output linked to the input. If it is null, that means the input is unlinked, so skip * it. */ - const DOutputSocket output = get_output_linked_to_input(input); + const DOutputSocket output = get_output_linked_to_input(dinput); if (!output) { continue; } - const InputDescriptor input_descriptor = input_descriptor_from_input_socket(input_ref); + const InputDescriptor input_descriptor = input_descriptor_from_input_socket(input); /* If the output belongs to a node that is part of the shader compile unit, then the domain of * the input is the domain of the compile unit itself. */ diff --git a/source/blender/compositor/realtime_compositor/intern/evaluator.cc b/source/blender/compositor/realtime_compositor/intern/evaluator.cc index d358389f2e9..48457bec199 100644 --- a/source/blender/compositor/realtime_compositor/intern/evaluator.cc +++ b/source/blender/compositor/realtime_compositor/intern/evaluator.cc @@ -45,7 +45,6 @@ void Evaluator::reset() { operations_stream_.clear(); derived_node_tree_.reset(); - node_tree_reference_map_.clear(); is_compiled_ = false; } @@ -67,7 +66,7 @@ bool Evaluator::validate_node_tree() void Evaluator::compile_and_evaluate() { - derived_node_tree_ = std::make_unique(node_tree_, node_tree_reference_map_); + derived_node_tree_ = std::make_unique(node_tree_); if (!validate_node_tree()) { return; @@ -93,7 +92,7 @@ void Evaluator::compile_and_evaluate() void Evaluator::compile_and_evaluate_node(DNode node, CompileState &compile_state) { - NodeOperation *operation = node->typeinfo()->get_compositor_operation(context_, node); + NodeOperation *operation = node->typeinfo->get_compositor_operation(context_, node); compile_state.map_node_to_node_operation(node, operation); @@ -113,16 +112,16 @@ void Evaluator::map_node_operation_inputs_to_their_results(DNode node, NodeOperation *operation, CompileState &compile_state) { - for (const InputSocketRef *input_ref : node->inputs()) { - const DInputSocket input{node.context(), input_ref}; + for (const bNodeSocket *input : node->input_sockets()) { + const DInputSocket dinput{node.context(), input}; - DSocket origin = get_input_origin_socket(input); + DSocket dorigin = get_input_origin_socket(dinput); /* The origin socket is an output, which means the input is linked. So map the input to the * result we get from the output. */ - if (origin->is_output()) { - Result &result = compile_state.get_result_from_output_socket(DOutputSocket(origin)); - operation->map_input_to_result(input->identifier(), &result); + if (dorigin->is_output()) { + Result &result = compile_state.get_result_from_output_socket(DOutputSocket(dorigin)); + operation->map_input_to_result(input->identifier, &result); continue; } @@ -130,8 +129,8 @@ void Evaluator::map_node_operation_inputs_to_their_results(DNode node, * origin is the input socket itself or the input is connected to an unlinked input of a group * input node and the origin is the input of the group input node. So map the input to the * result of a newly created Input Single Value Operation. */ - auto *input_operation = new InputSingleValueOperation(context_, DInputSocket(origin)); - operation->map_input_to_result(input->identifier(), &input_operation->get_result()); + auto *input_operation = new InputSingleValueOperation(context_, DInputSocket(dorigin)); + operation->map_input_to_result(input->identifier, &input_operation->get_result()); operations_stream_.append(std::unique_ptr(input_operation)); diff --git a/source/blender/compositor/realtime_compositor/intern/input_single_value_operation.cc b/source/blender/compositor/realtime_compositor/intern/input_single_value_operation.cc index 0bdd40e3636..b3cc86b5f79 100644 --- a/source/blender/compositor/realtime_compositor/intern/input_single_value_operation.cc +++ b/source/blender/compositor/realtime_compositor/intern/input_single_value_operation.cc @@ -14,7 +14,7 @@ const StringRef InputSingleValueOperation::output_identifier_ = StringRef("Outpu InputSingleValueOperation::InputSingleValueOperation(Context &context, DInputSocket input_socket) : Operation(context), input_socket_(input_socket) { - const ResultType result_type = get_node_socket_result_type(input_socket_.socket_ref()); + const ResultType result_type = get_node_socket_result_type(input_socket_.bsocket()); Result result = Result(result_type, texture_pool()); /* The result of an input single value operation is guaranteed to have a single user. */ @@ -29,17 +29,19 @@ void InputSingleValueOperation::execute() Result &result = get_result(); result.allocate_single_value(); + const bNodeSocket *bsocket = input_socket_.bsocket(); + /* Set the value of the result to the default value of the input socket. */ switch (result.type()) { case ResultType::Float: - result.set_float_value(input_socket_->default_value()->value); + result.set_float_value(bsocket->default_value_typed()->value); break; case ResultType::Vector: result.set_vector_value( - float3(input_socket_->default_value()->value)); + float3(bsocket->default_value_typed()->value)); break; case ResultType::Color: - result.set_color_value(float4(input_socket_->default_value()->value)); + result.set_color_value(float4(bsocket->default_value_typed()->value)); break; } } diff --git a/source/blender/compositor/realtime_compositor/intern/node_operation.cc b/source/blender/compositor/realtime_compositor/intern/node_operation.cc index f02d0906447..1c20c967ddb 100644 --- a/source/blender/compositor/realtime_compositor/intern/node_operation.cc +++ b/source/blender/compositor/realtime_compositor/intern/node_operation.cc @@ -25,27 +25,27 @@ using namespace nodes::derived_node_tree_types; NodeOperation::NodeOperation(Context &context, DNode node) : Operation(context), node_(node) { - for (const OutputSocketRef *output : node->outputs()) { + for (const bNodeSocket *output : node->output_sockets()) { const ResultType result_type = get_node_socket_result_type(output); const Result result = Result(result_type, texture_pool()); - populate_result(output->identifier(), result); + populate_result(output->identifier, result); } - for (const InputSocketRef *input : node->inputs()) { + for (const bNodeSocket *input : node->input_sockets()) { const InputDescriptor input_descriptor = input_descriptor_from_input_socket(input); - declare_input_descriptor(input->identifier(), input_descriptor); + declare_input_descriptor(input->identifier, input_descriptor); } } void NodeOperation::compute_results_reference_counts(const Schedule &schedule) { - for (const OutputSocketRef *output_ref : node()->outputs()) { - const DOutputSocket output{node().context(), output_ref}; + for (const bNodeSocket *output : this->node()->output_sockets()) { + const DOutputSocket doutput{node().context(), output}; const int reference_count = number_of_inputs_linked_to_output_conditioned( - output, [&](DInputSocket input) { return schedule.contains(input.node()); }); + doutput, [&](DInputSocket input) { return schedule.contains(input.node()); }); - get_result(output->identifier()).set_initial_reference_count(reference_count); + get_result(doutput->identifier).set_initial_reference_count(reference_count); } } @@ -56,7 +56,7 @@ const DNode &NodeOperation::node() const const bNode &NodeOperation::bnode() const { - return *node_->bnode(); + return *node_; } bool NodeOperation::should_compute_output(StringRef identifier) diff --git a/source/blender/compositor/realtime_compositor/intern/scheduler.cc b/source/blender/compositor/realtime_compositor/intern/scheduler.cc index ce8b9330541..ac5cc55a73f 100644 --- a/source/blender/compositor/realtime_compositor/intern/scheduler.cc +++ b/source/blender/compositor/realtime_compositor/intern/scheduler.cc @@ -8,6 +8,8 @@ #include "NOD_derived_node_tree.hh" +#include "BKE_node_runtime.hh" + #include "COM_scheduler.hh" #include "COM_utilities.hh" @@ -21,22 +23,22 @@ using namespace nodes::derived_node_tree_types; * node will be returned. */ static DNode compute_output_node(DerivedNodeTree &tree) { - const NodeTreeRef &root_tree = tree.root_context().tree(); + const bNodeTree &root_tree = tree.root_context().btree(); - for (const NodeRef *node : root_tree.nodes_by_type("CompositorNodeComposite")) { - if (node->bnode()->flag & NODE_DO_OUTPUT) { + for (const bNode *node : root_tree.nodes_by_type("CompositorNodeComposite")) { + if (node->flag & NODE_DO_OUTPUT) { return DNode(&tree.root_context(), node); } } - for (const NodeRef *node : root_tree.nodes_by_type("CompositorNodeViewer")) { - if (node->bnode()->flag & NODE_DO_OUTPUT) { + for (const bNode *node : root_tree.nodes_by_type("CompositorNodeViewer")) { + if (node->flag & NODE_DO_OUTPUT) { return DNode(&tree.root_context(), node); } } - for (const NodeRef *node : root_tree.nodes_by_type("CompositorNodeSplitViewer")) { - if (node->bnode()->flag & NODE_DO_OUTPUT) { + for (const bNode *node : root_tree.nodes_by_type("CompositorNodeSplitViewer")) { + if (node->flag & NODE_DO_OUTPUT) { return DNode(&tree.root_context(), node); } } @@ -120,25 +122,25 @@ static NeededBuffers compute_number_of_needed_buffers(DNode output_node) /* Go over the node dependencies connected to the inputs of the node and push them to the node * stack if they were not computed already. */ Set pushed_nodes; - for (const InputSocketRef *input_ref : node->inputs()) { - const DInputSocket input{node.context(), input_ref}; + for (const bNodeSocket *input : node->input_sockets()) { + const DInputSocket dinput{node.context(), input}; /* Get the output linked to the input. If it is null, that means the input is unlinked and * has no dependency node. */ - const DOutputSocket output = get_output_linked_to_input(input); - if (!output) { + const DOutputSocket doutput = get_output_linked_to_input(dinput); + if (!doutput) { continue; } /* The node dependency was already computed or pushed before, so skip it. */ - if (needed_buffers.contains(output.node()) || pushed_nodes.contains(output.node())) { + if (needed_buffers.contains(doutput.node()) || pushed_nodes.contains(doutput.node())) { continue; } /* The output node needs to be computed, push the node dependency to the node stack and * indicate that it was pushed. */ - node_stack.push(output.node()); - pushed_nodes.add_new(output.node()); + node_stack.push(doutput.node()); + pushed_nodes.add_new(doutput.node()); } /* If any of the node dependencies were pushed, that means that not all of them were computed @@ -154,26 +156,26 @@ static NeededBuffers compute_number_of_needed_buffers(DNode output_node) * buffers needed to compute the most demanding of the node dependencies. */ int number_of_input_buffers = 0; int buffers_needed_by_dependencies = 0; - for (const InputSocketRef *input_ref : node->inputs()) { - const DInputSocket input{node.context(), input_ref}; + for (const bNodeSocket *input : node->input_sockets()) { + const DInputSocket dinput{node.context(), input}; /* Get the output linked to the input. If it is null, that means the input is unlinked. * Unlinked inputs do not take a buffer, so skip those inputs. */ - const DOutputSocket output = get_output_linked_to_input(input); - if (!output) { + const DOutputSocket doutput = get_output_linked_to_input(dinput); + if (!doutput) { continue; } /* Since this input is linked, if the link is not between two shader nodes, it means that the * node takes a buffer through this input and so we increment the number of input buffers. */ - if (!is_shader_node(node) || !is_shader_node(output.node())) { + if (!is_shader_node(node) || !is_shader_node(doutput.node())) { number_of_input_buffers++; } /* If the number of buffers needed by the node dependency is more than the total number of * buffers needed by the dependencies, then update the latter to be the former. This is * computing the "d" in the aforementioned equation "max(n + m, d)". */ - const int buffers_needed_by_dependency = needed_buffers.lookup(output.node()); + const int buffers_needed_by_dependency = needed_buffers.lookup(doutput.node()); if (buffers_needed_by_dependency > buffers_needed_by_dependencies) { buffers_needed_by_dependencies = buffers_needed_by_dependency; } @@ -181,17 +183,18 @@ static NeededBuffers compute_number_of_needed_buffers(DNode output_node) /* Compute the number of buffers that will be computed/output by this node. */ int number_of_output_buffers = 0; - for (const OutputSocketRef *output_ref : node->outputs()) { - const DOutputSocket output{node.context(), output_ref}; + for (const bNodeSocket *output : node->output_sockets()) { + const DOutputSocket doutput{node.context(), output}; /* The output is not linked, it outputs no buffer. */ - if (output->logically_linked_sockets().is_empty()) { + if (!output->is_logically_linked()) { continue; } /* If any of the links is not between two shader nodes, it means that the node outputs * a buffer through this output and so we increment the number of output buffers. */ - if (!is_output_linked_to_node_conditioned(output, is_shader_node) || !is_shader_node(node)) { + if (!is_output_linked_to_node_conditioned(doutput, is_shader_node) || + !is_shader_node(node)) { number_of_output_buffers++; } } @@ -255,24 +258,24 @@ Schedule compute_schedule(DerivedNodeTree &tree) * want the node with the highest number of needed buffers to be schedule first, but since * those are pushed to the traversal stack, we need to push them in reverse order. */ Vector sorted_dependency_nodes; - for (const InputSocketRef *input_ref : node->inputs()) { - const DInputSocket input{node.context(), input_ref}; + for (const bNodeSocket *input : node->input_sockets()) { + const DInputSocket dinput{node.context(), input}; /* Get the output linked to the input. If it is null, that means the input is unlinked and * has no dependency node, so skip it. */ - const DOutputSocket output = get_output_linked_to_input(input); - if (!output) { + const DOutputSocket doutput = get_output_linked_to_input(dinput); + if (!doutput) { continue; } /* The dependency node was added before, so skip it. The number of dependency nodes is very * small, typically less than 3, so a linear search is okay. */ - if (sorted_dependency_nodes.contains(output.node())) { + if (sorted_dependency_nodes.contains(doutput.node())) { continue; } /* The dependency node was already schedule, so skip it. */ - if (schedule.contains(output.node())) { + if (schedule.contains(doutput.node())) { continue; } @@ -280,7 +283,7 @@ Schedule compute_schedule(DerivedNodeTree &tree) * typically less than 3, so insertion sort is okay. */ int insertion_position = 0; for (int i = 0; i < sorted_dependency_nodes.size(); i++) { - if (needed_buffers.lookup(output.node()) > + if (needed_buffers.lookup(doutput.node()) > needed_buffers.lookup(sorted_dependency_nodes[i])) { insertion_position++; } @@ -288,7 +291,7 @@ Schedule compute_schedule(DerivedNodeTree &tree) break; } } - sorted_dependency_nodes.insert(insertion_position, output.node()); + sorted_dependency_nodes.insert(insertion_position, doutput.node()); } /* Push the sorted dependency nodes to the node stack in order. */ diff --git a/source/blender/compositor/realtime_compositor/intern/shader_node.cc b/source/blender/compositor/realtime_compositor/intern/shader_node.cc index f23485cee96..9310de3cbf4 100644 --- a/source/blender/compositor/realtime_compositor/intern/shader_node.cc +++ b/source/blender/compositor/realtime_compositor/intern/shader_node.cc @@ -59,7 +59,7 @@ const DNode &ShaderNode::node() const bNode &ShaderNode::bnode() const { - return *node_->bnode(); + return const_cast(*node_); } static eGPUType gpu_type_from_socket_type(eNodeSocketDatatype type) @@ -77,17 +77,17 @@ static eGPUType gpu_type_from_socket_type(eNodeSocketDatatype type) } } -static void gpu_stack_vector_from_socket(float *vector, const SocketRef *socket) +static void gpu_stack_vector_from_socket(float *vector, const bNodeSocket *socket) { - switch (socket->bsocket()->type) { + switch (socket->type) { case SOCK_FLOAT: - vector[0] = socket->default_value()->value; + vector[0] = socket->default_value_typed()->value; return; case SOCK_VECTOR: - copy_v3_v3(vector, socket->default_value()->value); + copy_v3_v3(vector, socket->default_value_typed()->value); return; case SOCK_RGBA: - copy_v4_v4(vector, socket->default_value()->value); + copy_v4_v4(vector, socket->default_value_typed()->value); return; default: BLI_assert_unreachable(); @@ -101,8 +101,8 @@ static void populate_gpu_node_stack(DSocket socket, GPUNodeStack &stack) /* This will be initialized later by the GPU material compiler or the compile method. */ stack.link = nullptr; - stack.sockettype = socket->bsocket()->type; - stack.type = gpu_type_from_socket_type((eNodeSocketDatatype)socket->bsocket()->type); + stack.sockettype = socket->type; + stack.type = gpu_type_from_socket_type((eNodeSocketDatatype)socket->type); if (socket->is_input()) { const DInputSocket input(socket); @@ -117,10 +117,10 @@ static void populate_gpu_node_stack(DSocket socket, GPUNodeStack &stack) * unlinked input or an unlinked input of a group input node that the socket is linked to, * otherwise, get the value from the socket itself. */ if (origin->is_input()) { - gpu_stack_vector_from_socket(stack.vec, origin.socket_ref()); + gpu_stack_vector_from_socket(stack.vec, origin.bsocket()); } else { - gpu_stack_vector_from_socket(stack.vec, socket.socket_ref()); + gpu_stack_vector_from_socket(stack.vec, socket.bsocket()); } } else { @@ -132,10 +132,11 @@ void ShaderNode::populate_inputs() { /* Reserve a stack for each input in addition to an extra stack at the end to mark the end of the * array, as this is what the GPU module functions expect. */ - inputs_.resize(node_->inputs().size() + 1); + const int num_input_sockets = node_->input_sockets().size(); + inputs_.resize(num_input_sockets + 1); inputs_.last().end = true; - for (int i = 0; i < node_->inputs().size(); i++) { + for (int i = 0; i < num_input_sockets; i++) { populate_gpu_node_stack(node_.input(i), inputs_[i]); } } @@ -144,10 +145,11 @@ void ShaderNode::populate_outputs() { /* Reserve a stack for each output in addition to an extra stack at the end to mark the end of * the array, as this is what the GPU module functions expect. */ - outputs_.resize(node_->outputs().size() + 1); + const int num_output_sockets = node_->output_sockets().size(); + outputs_.resize(num_output_sockets + 1); outputs_.last().end = true; - for (int i = 0; i < node_->outputs().size(); i++) { + for (int i = 0; i < num_output_sockets; i++) { populate_gpu_node_stack(node_.output(i), outputs_[i]); } } diff --git a/source/blender/compositor/realtime_compositor/intern/shader_operation.cc b/source/blender/compositor/realtime_compositor/intern/shader_operation.cc index 5749d8c5f2e..8e52baf63ec 100644 --- a/source/blender/compositor/realtime_compositor/intern/shader_operation.cc +++ b/source/blender/compositor/realtime_compositor/intern/shader_operation.cc @@ -128,7 +128,7 @@ void ShaderOperation::construct_material(void *thunk, GPUMaterial *material) { ShaderOperation *operation = static_cast(thunk); for (DNode node : operation->compile_unit_) { - ShaderNode *shader_node = node->typeinfo()->get_compositor_shader_node(node); + ShaderNode *shader_node = node->typeinfo->get_compositor_shader_node(node); operation->shader_nodes_.add_new(node, std::unique_ptr(shader_node)); operation->link_node_inputs(node, material); @@ -141,27 +141,27 @@ void ShaderOperation::construct_material(void *thunk, GPUMaterial *material) void ShaderOperation::link_node_inputs(DNode node, GPUMaterial *material) { - for (const InputSocketRef *input_ref : node->inputs()) { - const DInputSocket input{node.context(), input_ref}; + for (const bNodeSocket *input : node->input_sockets()) { + const DInputSocket dinput{node.context(), input}; /* Get the output linked to the input. If it is null, that means the input is unlinked. * Unlinked inputs are linked by the node compile method, so skip this here. */ - const DOutputSocket output = get_output_linked_to_input(input); - if (!output) { + const DOutputSocket doutput = get_output_linked_to_input(dinput); + if (!doutput) { continue; } /* If the origin node is part of the shader operation, then the link is internal to the GPU * material graph and is linked appropriately. */ - if (compile_unit_.contains(output.node())) { - link_node_input_internal(input, output); + if (compile_unit_.contains(doutput.node())) { + link_node_input_internal(dinput, doutput); continue; } /* Otherwise, the origin node is not part of the shader operation, then the link is external to * the GPU material graph and an input to the shader operation must be declared and linked to * the node input. */ - link_node_input_external(input, output, material); + link_node_input_external(dinput, doutput, material); } } @@ -169,10 +169,10 @@ void ShaderOperation::link_node_input_internal(DInputSocket input_socket, DOutputSocket output_socket) { ShaderNode &output_node = *shader_nodes_.lookup(output_socket.node()); - GPUNodeStack &output_stack = output_node.get_output(output_socket->identifier()); + GPUNodeStack &output_stack = output_node.get_output(output_socket->identifier); ShaderNode &input_node = *shader_nodes_.lookup(input_socket.node()); - GPUNodeStack &input_stack = input_node.get_input(input_socket->identifier()); + GPUNodeStack &input_stack = input_node.get_input(input_socket->identifier); input_stack.link = output_stack.link; } @@ -183,7 +183,7 @@ void ShaderOperation::link_node_input_external(DInputSocket input_socket, { ShaderNode &node = *shader_nodes_.lookup(input_socket.node()); - GPUNodeStack &stack = node.get_input(input_socket->identifier()); + GPUNodeStack &stack = node.get_input(input_socket->identifier); /* An input was already declared for that same output socket, so no need to declare it again. */ if (!output_to_material_attribute_map_.contains(output_socket)) { @@ -219,8 +219,8 @@ void ShaderOperation::declare_operation_input(DInputSocket input_socket, /* Declare the input descriptor for this input and prefer to declare its type to be the same as * the type of the output socket because doing type conversion in the shader is much cheaper. */ - InputDescriptor input_descriptor = input_descriptor_from_input_socket(input_socket.socket_ref()); - input_descriptor.type = get_node_socket_result_type(output_socket.socket_ref()); + InputDescriptor input_descriptor = input_descriptor_from_input_socket(input_socket.bsocket()); + input_descriptor.type = get_node_socket_result_type(output_socket.bsocket()); declare_input_descriptor(input_identifier, input_descriptor); /* Add a new GPU attribute representing an input to the GPU material. Instead of using the @@ -242,16 +242,16 @@ void ShaderOperation::declare_operation_input(DInputSocket input_socket, void ShaderOperation::populate_results_for_node(DNode node, GPUMaterial *material) { - for (const OutputSocketRef *output_ref : node->outputs()) { - const DOutputSocket output{node.context(), output_ref}; + for (const bNodeSocket *output : node->output_sockets()) { + const DOutputSocket doutput{node.context(), output}; /* If any of the nodes linked to the output are not part of the shader operation, then an * output result needs to be populated for it. */ const bool need_to_populate_result = is_output_linked_to_node_conditioned( - output, [&](DNode node) { return !compile_unit_.contains(node); }); + doutput, [&](DNode node) { return !compile_unit_.contains(node); }); if (need_to_populate_result) { - populate_operation_result(output, material); + populate_operation_result(doutput, material); } } } @@ -276,7 +276,7 @@ void ShaderOperation::populate_operation_result(DOutputSocket output_socket, GPU const unsigned int output_id = output_sockets_to_output_identifiers_map_.size(); std::string output_identifier = "output" + std::to_string(output_id); - const ResultType result_type = get_node_socket_result_type(output_socket.socket_ref()); + const ResultType result_type = get_node_socket_result_type(output_socket.bsocket()); const Result result = Result(result_type, texture_pool()); populate_result(output_identifier, result); @@ -284,7 +284,7 @@ void ShaderOperation::populate_operation_result(DOutputSocket output_socket, GPU output_sockets_to_output_identifiers_map_.add_new(output_socket, output_identifier); ShaderNode &node = *shader_nodes_.lookup(output_socket.node()); - GPUNodeLink *output_link = node.get_output(output_socket->identifier()).link; + GPUNodeLink *output_link = node.get_output(output_socket->identifier).link; /* Link the output node stack to an output storer storing in the appropriate result. The result * is identified by its index in the operation and the index is encoded as a float to be passed diff --git a/source/blender/compositor/realtime_compositor/intern/utilities.cc b/source/blender/compositor/realtime_compositor/intern/utilities.cc index 169ba70e9eb..2e1baec98a8 100644 --- a/source/blender/compositor/realtime_compositor/intern/utilities.cc +++ b/source/blender/compositor/realtime_compositor/intern/utilities.cc @@ -26,7 +26,7 @@ using TargetSocketPathInfo = DOutputSocket::TargetSocketPathInfo; DSocket get_input_origin_socket(DInputSocket input) { /* The input is unlinked. Return the socket itself. */ - if (input->logically_linked_sockets().is_empty()) { + if (!input->is_logically_linked()) { return input; } @@ -52,9 +52,9 @@ DOutputSocket get_output_linked_to_input(DInputSocket input) return DOutputSocket(origin); } -ResultType get_node_socket_result_type(const SocketRef *socket) +ResultType get_node_socket_result_type(const bNodeSocket *socket) { - switch (socket->bsocket()->type) { + switch (socket->type) { case SOCK_FLOAT: return ResultType::Float; case SOCK_VECTOR: @@ -95,21 +95,20 @@ int number_of_inputs_linked_to_output_conditioned(DOutputSocket output, bool is_shader_node(DNode node) { - return node->typeinfo()->get_compositor_shader_node; + return node->typeinfo->get_compositor_shader_node; } bool is_node_supported(DNode node) { - return node->typeinfo()->get_compositor_operation || - node->typeinfo()->get_compositor_shader_node; + return node->typeinfo->get_compositor_operation || node->typeinfo->get_compositor_shader_node; } -InputDescriptor input_descriptor_from_input_socket(const InputSocketRef *socket) +InputDescriptor input_descriptor_from_input_socket(const bNodeSocket *socket) { using namespace nodes; InputDescriptor input_descriptor; input_descriptor.type = get_node_socket_result_type(socket); - const NodeDeclaration *node_declaration = socket->node().declaration(); + const NodeDeclaration *node_declaration = socket->owner_node().declaration(); /* Not every node have a declaration, in which case, we assume the default values for the rest of * the properties. */ if (!node_declaration) { diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index d911e53be7f..3a8bb56bc5e 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -18,6 +18,7 @@ #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_node.h" +#include "BKE_node_runtime.hh" #include "BKE_node_tree_update.h" #include "BKE_screen.h" @@ -46,14 +47,11 @@ #include "BLT_translation.h" #include "NOD_node_declaration.hh" -#include "NOD_node_tree_ref.hh" #include "NOD_socket_declarations.hh" #include "NOD_socket_declarations_geometry.hh" #include "node_intern.hh" /* own include */ -using namespace blender::nodes::node_tree_ref_types; - struct bNodeListItem { struct bNodeListItem *next, *prev; struct bNode *node; @@ -434,18 +432,18 @@ namespace viewer_linking { * \{ */ /* Depending on the node tree type, different socket types are supported by viewer nodes. */ -static bool socket_can_be_viewed(const OutputSocketRef &socket) +static bool socket_can_be_viewed(const bNodeSocket &socket) { - if (nodeSocketIsHidden(socket.bsocket())) { + if (nodeSocketIsHidden(&socket)) { return false; } - if (socket.idname() == "NodeSocketVirtual") { + if (STREQ(socket.idname, "NodeSocketVirtual")) { return false; } - if (socket.tree().btree()->type != NTREE_GEOMETRY) { + if (socket.owner_tree().type != NTREE_GEOMETRY) { return true; } - return ELEM(socket.typeinfo()->type, + return ELEM(socket.typeinfo->type, SOCK_GEOMETRY, SOCK_FLOAT, SOCK_VECTOR, @@ -502,15 +500,15 @@ static bNodeSocket *node_link_viewer_get_socket(bNodeTree &ntree, return nullptr; } -static bool is_viewer_node(const NodeRef &node) +static bool is_viewer_node(const bNode &node) { - return ELEM(node.bnode()->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER); + return ELEM(node.type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER); } -static Vector find_viewer_nodes(const NodeTreeRef &tree) +static Vector find_viewer_nodes(const bNodeTree &tree) { - Vector viewer_nodes; - for (const NodeRef *node : tree.nodes()) { + Vector viewer_nodes; + for (const bNode *node : tree.all_nodes()) { if (is_viewer_node(*node)) { viewer_nodes.append(node); } @@ -518,20 +516,20 @@ static Vector find_viewer_nodes(const NodeTreeRef &tree) return viewer_nodes; } -static bool is_viewer_socket_in_viewer(const InputSocketRef &socket) +static bool is_viewer_socket_in_viewer(const bNodeSocket &socket) { - const NodeRef &node = socket.node(); + const bNode &node = socket.owner_node(); BLI_assert(is_viewer_node(node)); - if (node.typeinfo()->type == GEO_NODE_VIEWER) { + if (node.typeinfo->type == GEO_NODE_VIEWER) { return true; } return socket.index() == 0; } -static bool is_linked_to_viewer(const OutputSocketRef &socket, const NodeRef &viewer_node) +static bool is_linked_to_viewer(const bNodeSocket &socket, const bNode &viewer_node) { - for (const InputSocketRef *target_socket : socket.directly_linked_sockets()) { - if (&target_socket->node() != &viewer_node) { + for (const bNodeSocket *target_socket : socket.directly_linked_sockets()) { + if (&target_socket->owner_node() != &viewer_node) { continue; } if (!target_socket->is_available()) { @@ -561,39 +559,39 @@ static void remove_links_to_unavailable_viewer_sockets(bNodeTree &btree, bNode & } } -static const NodeRef *get_existing_viewer(const NodeTreeRef &tree) +static const bNode *get_existing_viewer(const bNodeTree &tree) { - Vector viewer_nodes = find_viewer_nodes(tree); + Vector viewer_nodes = find_viewer_nodes(tree); /* Check if there is already an active viewer node that should be used. */ - for (const NodeRef *viewer_node : viewer_nodes) { - if (viewer_node->bnode()->flag & NODE_DO_OUTPUT) { + for (const bNode *viewer_node : viewer_nodes) { + if (viewer_node->flag & NODE_DO_OUTPUT) { return viewer_node; } } /* If no active but non-active viewers exist, make one active. */ if (!viewer_nodes.is_empty()) { - viewer_nodes[0]->bnode()->flag |= NODE_DO_OUTPUT; + const_cast(viewer_nodes[0])->flag |= NODE_DO_OUTPUT; return viewer_nodes[0]; } return nullptr; } -static const OutputSocketRef *find_output_socket_to_be_viewed(const NodeRef *active_viewer_node, - const NodeRef &node_to_view) +static const bNodeSocket *find_output_socket_to_be_viewed(const bNode *active_viewer_node, + const bNode &node_to_view) { /* Check if any of the output sockets is selected, which is the case when the user just clicked * on the socket. */ - for (const OutputSocketRef *output_socket : node_to_view.outputs()) { - if (output_socket->bsocket()->flag & SELECT) { + for (const bNodeSocket *output_socket : node_to_view.output_sockets()) { + if (output_socket->flag & SELECT) { return output_socket; } } - const OutputSocketRef *last_socket_linked_to_viewer = nullptr; + const bNodeSocket *last_socket_linked_to_viewer = nullptr; if (active_viewer_node != nullptr) { - for (const OutputSocketRef *output_socket : node_to_view.outputs()) { + for (const bNodeSocket *output_socket : node_to_view.output_sockets()) { if (!socket_can_be_viewed(*output_socket)) { continue; } @@ -604,7 +602,7 @@ static const OutputSocketRef *find_output_socket_to_be_viewed(const NodeRef *act } if (last_socket_linked_to_viewer == nullptr) { /* If no output is connected to a viewer, use the first output that can be viewed. */ - for (const OutputSocketRef *output_socket : node_to_view.outputs()) { + for (const bNodeSocket *output_socket : node_to_view.output_sockets()) { if (socket_can_be_viewed(*output_socket)) { return output_socket; } @@ -612,10 +610,10 @@ static const OutputSocketRef *find_output_socket_to_be_viewed(const NodeRef *act } else { /* Pick the next socket to be linked to the viewer. */ - const int tot_outputs = node_to_view.outputs().size(); + const int tot_outputs = node_to_view.output_sockets().size(); for (const int offset : IndexRange(1, tot_outputs - 1)) { const int index = (last_socket_linked_to_viewer->index() + offset) % tot_outputs; - const OutputSocketRef &output_socket = node_to_view.output(index); + const bNodeSocket &output_socket = node_to_view.output_socket(index); if (!socket_can_be_viewed(output_socket)) { continue; } @@ -682,20 +680,15 @@ static int node_link_viewer(const bContext &C, bNode &bnode_to_view) { SpaceNode &snode = *CTX_wm_space_node(&C); bNodeTree *btree = snode.edittree; + btree->ensure_topology_cache(); - const NodeTreeRef tree{btree}; - const NodeRef &node_to_view = *tree.find_node(bnode_to_view); - const NodeRef *active_viewer_node = get_existing_viewer(tree); - - const OutputSocketRef *socket_to_view = find_output_socket_to_be_viewed(active_viewer_node, - node_to_view); - if (socket_to_view == nullptr) { + bNode *active_viewer_bnode = const_cast(get_existing_viewer(*btree)); + bNodeSocket *bsocket_to_view = const_cast( + find_output_socket_to_be_viewed(active_viewer_bnode, bnode_to_view)); + if (bsocket_to_view == nullptr) { return OPERATOR_FINISHED; } - - bNodeSocket &bsocket_to_view = *socket_to_view->bsocket(); - bNode *viewer_bnode = active_viewer_node ? active_viewer_node->bnode() : nullptr; - return link_socket_to_viewer(C, viewer_bnode, bnode_to_view, bsocket_to_view); + return link_socket_to_viewer(C, active_viewer_bnode, bnode_to_view, *bsocket_to_view); } /** \} */ @@ -2048,7 +2041,7 @@ static bNodeSocket *get_main_socket(bNodeTree &ntree, bNode &node, eNodeSocketIn /* Try to get the main socket based on the socket declaration. */ nodeDeclarationEnsure(&ntree, &node); - const nodes::NodeDeclaration *node_decl = node.runtime->declaration; + const nodes::NodeDeclaration *node_decl = node.declaration(); if (node_decl != nullptr) { Span socket_decls = (in_out == SOCK_IN) ? node_decl->inputs() : node_decl->outputs(); diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc index dafbca0f995..0b228ef8c37 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc @@ -6,6 +6,7 @@ #include "BKE_image.h" #include "BKE_node.h" +#include "BKE_node_runtime.hh" #include "BLI_map.hh" #include "BLI_math_vector.h" @@ -15,8 +16,6 @@ #include "DNA_material_types.h" #include "DNA_node_types.h" -#include "NOD_node_tree_ref.hh" - #include "obj_export_mesh.hh" #include "obj_export_mtl.hh" @@ -84,25 +83,25 @@ static void copy_property_from_node(const eNodeSocketDatatype property_type, * Collect all the source sockets linked to the destination socket in a destination node. */ static void linked_sockets_to_dest_id(const bNode *dest_node, - const nodes::NodeTreeRef &node_tree, + const bNodeTree &node_tree, const char *dest_socket_id, - Vector &r_linked_sockets) + Vector &r_linked_sockets) { r_linked_sockets.clear(); if (!dest_node) { return; } - Span object_dest_nodes = node_tree.nodes_by_type(dest_node->idname); - Span dest_inputs = object_dest_nodes.first()->inputs(); - const nodes::InputSocketRef *dest_socket = nullptr; - for (const nodes::InputSocketRef *curr_socket : dest_inputs) { - if (STREQ(curr_socket->bsocket()->identifier, dest_socket_id)) { + Span object_dest_nodes = node_tree.nodes_by_type(dest_node->idname); + Span dest_inputs = object_dest_nodes.first()->input_sockets(); + const bNodeSocket *dest_socket = nullptr; + for (const bNodeSocket *curr_socket : dest_inputs) { + if (STREQ(curr_socket->identifier, dest_socket_id)) { dest_socket = curr_socket; break; } } if (dest_socket) { - Span linked_sockets = dest_socket->directly_linked_sockets(); + Span linked_sockets = dest_socket->directly_linked_sockets(); r_linked_sockets.resize(linked_sockets.size()); r_linked_sockets = linked_sockets; } @@ -111,13 +110,12 @@ static void linked_sockets_to_dest_id(const bNode *dest_node, /** * From a list of sockets, get the parent node which is of the given node type. */ -static const bNode *get_node_of_type(Span sockets_list, - const int node_type) +static const bNode *get_node_of_type(Span sockets_list, const int node_type) { - for (const nodes::SocketRef *socket : sockets_list) { - const bNode *parent_node = socket->bnode(); - if (parent_node->typeinfo->type == node_type) { - return parent_node; + for (const bNodeSocket *socket : sockets_list) { + const bNode &parent_node = socket->owner_node(); + if (parent_node.typeinfo->type == node_type) { + return &parent_node; } } return nullptr; @@ -153,16 +151,16 @@ static const char *get_image_filepath(const bNode *tex_node) * We only want one that feeds directly into a Material Output node * (that is the behavior of the legacy Python exporter). */ -static const nodes::NodeRef *find_bsdf_node(const nodes::NodeTreeRef *nodetree) +static const bNode *find_bsdf_node(const bNodeTree *nodetree) { if (!nodetree) { return nullptr; } - for (const nodes::NodeRef *node : nodetree->nodes_by_type("ShaderNodeOutputMaterial")) { - const nodes::InputSocketRef *node_input_socket0 = node->inputs()[0]; - for (const nodes::OutputSocketRef *out_sock : node_input_socket0->directly_linked_sockets()) { - const nodes::NodeRef &in_node = out_sock->node(); - if (in_node.typeinfo()->type == SH_NODE_BSDF_PRINCIPLED) { + for (const bNode *node : nodetree->nodes_by_type("ShaderNodeOutputMaterial")) { + const bNodeSocket &node_input_socket0 = node->input_socket(0); + for (const bNodeSocket *out_sock : node_input_socket0.directly_linked_sockets()) { + const bNode &in_node = out_sock->owner_node(); + if (in_node.typeinfo->type == SH_NODE_BSDF_PRINCIPLED) { return &in_node; } } @@ -173,55 +171,50 @@ static const nodes::NodeRef *find_bsdf_node(const nodes::NodeTreeRef *nodetree) /** * Store properties found either in bNode or material into r_mtl_mat. */ -static void store_bsdf_properties(const nodes::NodeRef *bsdf_node, +static void store_bsdf_properties(const bNode *bsdf_node, const Material *material, MTLMaterial &r_mtl_mat) { - const bNode *bnode = nullptr; - if (bsdf_node) { - bnode = bsdf_node->bnode(); - } - /* If p-BSDF is not present, fallback to #Object.Material. */ float roughness = material->roughness; - if (bnode) { - copy_property_from_node(SOCK_FLOAT, bnode, "Roughness", {&roughness, 1}); + if (bsdf_node) { + copy_property_from_node(SOCK_FLOAT, bsdf_node, "Roughness", {&roughness, 1}); } /* Empirical approximation. Importer should use the inverse of this method. */ float spec_exponent = (1.0f - roughness); spec_exponent *= spec_exponent * 1000.0f; float specular = material->spec; - if (bnode) { - copy_property_from_node(SOCK_FLOAT, bnode, "Specular", {&specular, 1}); + if (bsdf_node) { + copy_property_from_node(SOCK_FLOAT, bsdf_node, "Specular", {&specular, 1}); } float metallic = material->metallic; - if (bnode) { - copy_property_from_node(SOCK_FLOAT, bnode, "Metallic", {&metallic, 1}); + if (bsdf_node) { + copy_property_from_node(SOCK_FLOAT, bsdf_node, "Metallic", {&metallic, 1}); } float refraction_index = 1.0f; - if (bnode) { - copy_property_from_node(SOCK_FLOAT, bnode, "IOR", {&refraction_index, 1}); + if (bsdf_node) { + copy_property_from_node(SOCK_FLOAT, bsdf_node, "IOR", {&refraction_index, 1}); } float dissolved = material->a; - if (bnode) { - copy_property_from_node(SOCK_FLOAT, bnode, "Alpha", {&dissolved, 1}); + if (bsdf_node) { + copy_property_from_node(SOCK_FLOAT, bsdf_node, "Alpha", {&dissolved, 1}); } const bool transparent = dissolved != 1.0f; float3 diffuse_col = {material->r, material->g, material->b}; - if (bnode) { - copy_property_from_node(SOCK_RGBA, bnode, "Base Color", {diffuse_col, 3}); + if (bsdf_node) { + copy_property_from_node(SOCK_RGBA, bsdf_node, "Base Color", {diffuse_col, 3}); } float3 emission_col{0.0f}; float emission_strength = 0.0f; - if (bnode) { - copy_property_from_node(SOCK_FLOAT, bnode, "Emission Strength", {&emission_strength, 1}); - copy_property_from_node(SOCK_RGBA, bnode, "Emission", {emission_col, 3}); + if (bsdf_node) { + copy_property_from_node(SOCK_FLOAT, bsdf_node, "Emission Strength", {&emission_strength, 1}); + copy_property_from_node(SOCK_RGBA, bsdf_node, "Emission", {emission_col, 3}); } mul_v3_fl(emission_col, emission_strength); @@ -265,8 +258,8 @@ static void store_bsdf_properties(const nodes::NodeRef *bsdf_node, /** * Store image texture options and file-paths in `r_mtl_mat`. */ -static void store_image_textures(const nodes::NodeRef *bsdf_node, - const nodes::NodeTreeRef *node_tree, +static void store_image_textures(const bNode *bsdf_node, + const bNodeTree *node_tree, const Material *material, MTLMaterial &r_mtl_mat) { @@ -274,7 +267,6 @@ static void store_image_textures(const nodes::NodeRef *bsdf_node, /* No nodetree, no images, or no Principled BSDF node. */ return; } - const bNode *bnode = bsdf_node->bnode(); /* Normal Map Texture has two extra tasks of: * - finding a Normal Map node before finding a texture node. @@ -283,12 +275,12 @@ static void store_image_textures(const nodes::NodeRef *bsdf_node, for (int key = 0; key < (int)MTLTexMapType::Count; ++key) { MTLTexMap &value = r_mtl_mat.texture_maps[key]; - Vector linked_sockets; + Vector linked_sockets; const bNode *normal_map_node{nullptr}; if (key == (int)MTLTexMapType::bump) { /* Find sockets linked to destination "Normal" socket in P-BSDF node. */ - linked_sockets_to_dest_id(bnode, *node_tree, "Normal", linked_sockets); + linked_sockets_to_dest_id(bsdf_node, *node_tree, "Normal", linked_sockets); /* Among the linked sockets, find Normal Map shader node. */ normal_map_node = get_node_of_type(linked_sockets, SH_NODE_NORMAL_MAP); @@ -299,13 +291,15 @@ static void store_image_textures(const nodes::NodeRef *bsdf_node, /* Skip emission map if emission strength is zero. */ if (key == (int)MTLTexMapType::Ke) { float emission_strength = 0.0f; - copy_property_from_node(SOCK_FLOAT, bnode, "Emission Strength", {&emission_strength, 1}); + copy_property_from_node( + SOCK_FLOAT, bsdf_node, "Emission Strength", {&emission_strength, 1}); if (emission_strength == 0.0f) { continue; } } /* Find sockets linked to the destination socket of interest, in P-BSDF node. */ - linked_sockets_to_dest_id(bnode, *node_tree, tex_map_type_to_socket_id[key], linked_sockets); + linked_sockets_to_dest_id( + bsdf_node, *node_tree, tex_map_type_to_socket_id[key], linked_sockets); } /* Among the linked sockets, find Image Texture shader node. */ @@ -341,14 +335,14 @@ MTLMaterial mtlmaterial_for_material(const Material *material) MTLMaterial mtlmat; mtlmat.name = std::string(material->id.name + 2); std::replace(mtlmat.name.begin(), mtlmat.name.end(), ' ', '_'); - const nodes::NodeTreeRef *nodetree = nullptr; - if (material->nodetree) { - nodetree = new nodes::NodeTreeRef(material->nodetree); + const bNodeTree *nodetree = material->nodetree; + if (nodetree != nullptr) { + nodetree->ensure_topology_cache(); } - const nodes::NodeRef *bsdf_node = find_bsdf_node(nodetree); + + const bNode *bsdf_node = find_bsdf_node(nodetree); store_bsdf_properties(bsdf_node, material, mtlmat); store_image_textures(bsdf_node, nodetree, material, mtlmat); - delete nodetree; return mtlmat; } diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 4ae06d0a5e4..92cc35908f2 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -12,8 +12,33 @@ #include "DNA_scene_types.h" /* for #ImageFormatData */ #include "DNA_vec_types.h" /* for #rctf */ +/** Workaround to forward-declare C++ type in C header. */ #ifdef __cplusplus -extern "C" { +namespace blender { +template class Span; +class StringRef; +class StringRefNull; +} // namespace blender +namespace blender::nodes { +class NodeDeclaration; +class SocketDeclaration; +} // namespace blender::nodes +namespace blender::bke { +class bNodeTreeRuntime; +class bNodeRuntime; +class bNodeSocketRuntime; +} // namespace blender::bke +using NodeDeclarationHandle = blender::nodes::NodeDeclaration; +using SocketDeclarationHandle = blender::nodes::SocketDeclaration; +using bNodeTreeRuntimeHandle = blender::bke::bNodeTreeRuntime; +using bNodeRuntimeHandle = blender::bke::bNodeRuntime; +using bNodeSocketRuntimeHandle = blender::bke::bNodeSocketRuntime; +#else +typedef struct NodeDeclarationHandle NodeDeclarationHandle; +typedef struct SocketDeclarationHandle SocketDeclarationHandle; +typedef struct bNodeTreeRuntimeHandle bNodeTreeRuntimeHandle; +typedef struct bNodeRuntimeHandle bNodeRuntimeHandle; +typedef struct bNodeSocketRuntimeHandle bNodeSocketRuntimeHandle; #endif struct AnimData; @@ -30,6 +55,7 @@ struct bNodeLink; struct bNodePreview; struct bNodeTreeExec; struct bNodeType; +struct bNode; struct uiBlock; #define NODE_MAXSTR 64 @@ -65,30 +91,6 @@ typedef struct bNodeStack { #define NS_CR_FIT 4 #define NS_CR_STRETCH 5 -/** Workaround to forward-declare C++ type in C header. */ -#ifdef __cplusplus -namespace blender::nodes { -class NodeDeclaration; -class SocketDeclaration; -} // namespace blender::nodes -namespace blender::bke { -class bNodeTreeRuntime; -class bNodeRuntime; -class bNodeSocketRuntime; -} // namespace blender::bke -using NodeDeclarationHandle = blender::nodes::NodeDeclaration; -using SocketDeclarationHandle = blender::nodes::SocketDeclaration; -using bNodeTreeRuntimeHandle = blender::bke::bNodeTreeRuntime; -using bNodeRuntimeHandle = blender::bke::bNodeRuntime; -using bNodeSocketRuntimeHandle = blender::bke::bNodeSocketRuntime; -#else -typedef struct NodeDeclarationHandle NodeDeclarationHandle; -typedef struct SocketDeclarationHandle SocketDeclarationHandle; -typedef struct bNodeTreeRuntimeHandle bNodeTreeRuntimeHandle; -typedef struct bNodeRuntimeHandle bNodeRuntimeHandle; -typedef struct bNodeSocketRuntimeHandle bNodeSocketRuntimeHandle; -#endif - typedef struct bNodeSocket { struct bNodeSocket *next, *prev; @@ -181,6 +183,49 @@ typedef struct bNodeSocket { bNodeStack ns DNA_DEPRECATED; bNodeSocketRuntimeHandle *runtime; + +#ifdef __cplusplus + bool is_available() const; + bool is_multi_input() const; + bool is_input() const; + bool is_output() const; + + /** Utility to access the value of the socket. */ + template const T *default_value_typed() const; + + /* The following methods are only available when #bNodeTree.ensure_topology_cache has been + * called. */ + + /** Zero based index for every input and output socket. */ + int index() const; + /** Socket index in the entire node tree. Inputs and outputs share the same index space. */ + int index_in_tree() const; + /** Node this socket belongs to. */ + bNode &owner_node(); + const bNode &owner_node() const; + /** Node tree this socket belongs to. */ + const bNodeTree &owner_tree() const; + + /** Links which are incident to this socket. */ + blender::Span directly_linked_links(); + blender::Span directly_linked_links() const; + /** Sockets which are connected to this socket with a link. */ + blender::Span directly_linked_sockets() const; + bool is_directly_linked() const; + /** + * Sockets which are connected to this socket when reroutes and muted nodes are taken into + * account. + */ + blender::Span logically_linked_sockets() const; + bool is_logically_linked() const; + + /** + * For output sockets, this is the corresponding input socket the value of which should be + * forwarded when the node is muted. + */ + const bNodeSocket *internal_link_input() const; + +#endif } bNodeSocket; /** #bNodeSocket.type & #bNodeSocketType.type */ @@ -333,6 +378,38 @@ typedef struct bNode { char iter_flag; bNodeRuntimeHandle *runtime; + +#ifdef __cplusplus + blender::StringRefNull label_or_name() const; + bool is_muted() const; + bool is_reroute() const; + bool is_frame() const; + bool is_group() const; + bool is_group_input() const; + bool is_group_output() const; + const blender::nodes::NodeDeclaration *declaration() const; + + /* The following methods are only available when #bNodeTree.ensure_topology_cache has been + * called. */ + + /** A span containing all input sockets of the node (including unavailable sockets). */ + blender::Span input_sockets(); + blender::Span input_sockets() const; + /** A span containing all output sockets of the node (including unavailable sockets). */ + blender::Span output_sockets(); + blender::Span output_sockets() const; + /** Utility to get an input socket by its index. */ + bNodeSocket &input_socket(int index); + const bNodeSocket &input_socket(int index) const; + /** Utility to get an output socket by its index. */ + bNodeSocket &output_socket(int index); + const bNodeSocket &output_socket(int index) const; + /** A span containing all internal links when the node is muted. */ + blender::Span internal_links_span() const; + /** Lookup socket of this node by its identifier. */ + const bNodeSocket &input_by_identifier(blender::StringRef identifier) const; + const bNodeSocket &output_by_identifier(blender::StringRef identifier) const; +#endif } bNode; /* node->flag */ @@ -422,6 +499,11 @@ typedef struct bNodeLink { int flag; int multi_input_socket_index; + +#ifdef __cplusplus + bool is_muted() const; +#endif + } bNodeLink; /* link->flag */ @@ -535,6 +617,50 @@ typedef struct bNodeTree { struct PreviewImage *preview; bNodeTreeRuntimeHandle *runtime; + +#ifdef __cplusplus + /** + * Update a run-time cache for the node tree based on it's current state. This makes many methods + * available which allow efficient lookup for topology information (like neighboring sockets). + */ + void ensure_topology_cache() const; + + /* The following methods are only available when #bNodeTree.ensure_topology_cache has been + * called. */ + + /** A span containing all nodes in the node tree. */ + blender::Span all_nodes(); + blender::Span all_nodes() const; + /** A span containing all input sockets in the node tree. */ + blender::Span all_input_sockets(); + blender::Span all_input_sockets() const; + /** A span containing all output sockets in the node tree. */ + blender::Span all_output_sockets(); + blender::Span all_output_sockets() const; + /** A span containing all sockets in the node tree. */ + blender::Span all_sockets(); + blender::Span all_sockets() const; + /** Efficient lookup of all nodes with a specific type. */ + blender::Span nodes_by_type(blender::StringRefNull type_idname); + blender::Span nodes_by_type(blender::StringRefNull type_idname) const; + /** + * Cached toposort of all nodes. If there are cycles, the returned array is not actually a + * toposort. However, if a connected component does not contain a cycle, this component is sorted + * correctly. Use #has_link_cycle to check for cycles. + */ + blender::Span toposort_left_to_right() const; + blender::Span toposort_right_to_left() const; + /** True when there are any cycles in the node tree. */ + bool has_link_cycle() const; + /** + * True when there are nodes or sockets in the node tree that don't use a known type. This can + * happen when nodes don't exist in the current Blender version that existed in the version where + * this node tree was saved. + */ + bool has_undefined_nodes_or_sockets() const; + /** Get the active group output node. */ + const bNode *group_output_node() const; +#endif } bNodeTree; /** #NodeTree.type, index */ @@ -2210,7 +2336,3 @@ typedef enum NodeCombSepColorMode { NODE_COMBSEP_COLOR_HSV = 1, NODE_COMBSEP_COLOR_HSL = 2, } NodeCombSepColorMode; - -#ifdef __cplusplus -} -#endif diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c index 806513009be..36abe970b31 100644 --- a/source/blender/makesdna/intern/makesdna.c +++ b/source/blender/makesdna/intern/makesdna.c @@ -506,6 +506,54 @@ static short *add_struct(int namecode) return sp; } +/* Copied from `BLI_str_startswith` string.c + * to avoid complicating the compilation process of makesdna. */ +static bool str_startswith(const char *__restrict str, const char *__restrict start) +{ + for (; *str && *start; str++, start++) { + if (*str != *start) { + return false; + } + } + + return (*start == '\0'); +} + +/** + * Check if `str` is a preprocessor string that starts with `start`. + * The `start` doesn't need the `#` prefix. + * `ifdef VALUE` will match `#ifdef VALUE` as well as `# ifdef VALUE`. + */ +static bool match_preproc_prefix(const char *__restrict str, const char *__restrict start) +{ + if (*str != '#') { + return false; + } + str++; + while (*str == ' ') { + str++; + } + return str_startswith(str, start); +} + +/** + * \return The point in `str` that starts with `start` or NULL when not found. + * + */ +static char *match_preproc_strstr(char *__restrict str, const char *__restrict start) +{ + while ((str = strchr(str, '#'))) { + str++; + while (*str == ' ') { + str++; + } + if (str_startswith(str, start)) { + return str; + } + } + return NULL; +} + static int preprocess_include(char *maindata, const int maindata_len) { /* NOTE: len + 1, last character is a dummy to prevent @@ -533,6 +581,10 @@ static int preprocess_include(char *maindata, const int maindata_len) cp++; } + /* No need for leading '#' character. */ + const char *cpp_block_start = "ifdef __cplusplus"; + const char *cpp_block_end = "endif"; + /* data from temp copy to maindata, remove comments and double spaces */ cp = temp; char *md = maindata; @@ -577,6 +629,18 @@ static int preprocess_include(char *maindata, const int maindata_len) skip_until_closing_brace = false; } } + else if (match_preproc_prefix(cp, cpp_block_start)) { + char *end_ptr = match_preproc_strstr(cp, cpp_block_end); + + if (end_ptr == NULL) { + fprintf(stderr, "Error: '%s' block must end with '%s'\n", cpp_block_start, cpp_block_end); + } + else { + const int skip_offset = end_ptr - cp + strlen(cpp_block_end); + a -= skip_offset; + cp += skip_offset; + } + } else { md[0] = cp[0]; md++; diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index 56967e62d8a..2908fbf5597 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -756,18 +756,18 @@ void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd) } static void initialize_group_input(NodesModifierData &nmd, - const OutputSocketRef &socket, + const bNodeSocket &socket, void *r_value) { - const bNodeSocketType &socket_type = *socket.typeinfo(); - const bNodeSocket &bsocket = *socket.bsocket(); + const bNodeSocketType &socket_type = *socket.typeinfo; + const bNodeSocket &bsocket = socket; const eNodeSocketDatatype socket_data_type = static_cast(bsocket.type); if (nmd.settings.properties == nullptr) { socket_type.get_geometry_nodes_cpp_value(bsocket, r_value); return; } const IDProperty *property = IDP_GetPropertyFromGroup(nmd.settings.properties, - socket.identifier().c_str()); + socket.identifier); if (property == nullptr) { socket_type.get_geometry_nodes_cpp_value(bsocket, r_value); return; @@ -777,15 +777,15 @@ static void initialize_group_input(NodesModifierData &nmd, return; } - if (!input_has_attribute_toggle(*nmd.node_group, socket.index())) { + if (!input_has_attribute_toggle(*nmd.node_group, socket.runtime->index_in_node)) { init_socket_cpp_value_from_property(*property, socket_data_type, r_value); return; } const IDProperty *property_use_attribute = IDP_GetPropertyFromGroup( - nmd.settings.properties, (socket.identifier() + use_attribute_suffix).c_str()); + nmd.settings.properties, (socket.identifier + use_attribute_suffix).c_str()); const IDProperty *property_attribute_name = IDP_GetPropertyFromGroup( - nmd.settings.properties, (socket.identifier() + attribute_name_suffix).c_str()); + nmd.settings.properties, (socket.identifier + attribute_name_suffix).c_str()); if (property_use_attribute == nullptr || property_attribute_name == nullptr) { init_socket_cpp_value_from_property(*property, socket_data_type, r_value); return; @@ -867,11 +867,11 @@ static void find_sockets_to_preview_for_spreadsheet(SpaceSpreadsheet *sspreadshe const DTreeContext *context = &tree.root_context(); for (SpreadsheetContextNode *node_context : nested_group_contexts) { - const NodeTreeRef &tree_ref = context->tree(); - const NodeRef *found_node = nullptr; - for (const NodeRef *node_ref : tree_ref.nodes()) { - if (node_ref->name() == node_context->node_name) { - found_node = node_ref; + const bNodeTree &btree = context->btree(); + const bNode *found_node = nullptr; + for (const bNode *bnode : btree.all_nodes()) { + if (STREQ(bnode->name, node_context->node_name)) { + found_node = bnode; break; } } @@ -884,11 +884,11 @@ static void find_sockets_to_preview_for_spreadsheet(SpaceSpreadsheet *sspreadshe } } - const NodeTreeRef &tree_ref = context->tree(); - for (const NodeRef *node_ref : tree_ref.nodes_by_type("GeometryNodeViewer")) { - if (node_ref->name() == last_context->node_name) { - const DNode viewer_node{context, node_ref}; - for (const InputSocketRef *input_socket : node_ref->inputs()) { + const bNodeTree &btree = context->btree(); + for (const bNode *bnode : btree.nodes_by_type("GeometryNodeViewer")) { + if (STREQ(bnode->name, last_context->node_name)) { + const DNode viewer_node{context, bnode}; + for (const bNodeSocket *input_socket : bnode->input_sockets()) { if (input_socket->is_available() && input_socket->is_logically_linked()) { r_sockets_to_preview.add(DSocket{context, input_socket}); } @@ -937,15 +937,15 @@ struct OutputAttributeToStore { * can be evaluated together. */ static MultiValueMap find_output_attributes_to_store( - const NodesModifierData &nmd, const NodeRef &output_node, Span output_values) + const NodesModifierData &nmd, const bNode &output_node, Span output_values) { MultiValueMap outputs_by_domain; - for (const InputSocketRef *socket : output_node.inputs().drop_front(1).drop_back(1)) { - if (!socket_type_has_attribute_toggle(*socket->bsocket())) { + for (const bNodeSocket *socket : output_node.input_sockets().drop_front(1).drop_back(1)) { + if (!socket_type_has_attribute_toggle(*socket)) { continue; } - const std::string prop_name = socket->identifier() + attribute_name_suffix; + const std::string prop_name = socket->identifier + attribute_name_suffix; const IDProperty *prop = IDP_GetPropertyFromGroup(nmd.settings.properties, prop_name.c_str()); if (prop == nullptr) { continue; @@ -965,7 +965,7 @@ static MultiValueMap find_output_attributes_to const GField field = cpp_type->as_field(value.get()); const bNodeSocket *interface_socket = (const bNodeSocket *)BLI_findlink( - &nmd.node_group->outputs, socket->index()); + &nmd.node_group->outputs, index); const eAttrDomain domain = (eAttrDomain)interface_socket->attribute_domain; OutputAttributeInfo output_info; output_info.field = std::move(field); @@ -1064,7 +1064,7 @@ static void store_computed_output_attributes( static void store_output_attributes(GeometrySet &geometry, const NodesModifierData &nmd, - const NodeRef &output_node, + const bNode &output_node, Span output_values) { /* All new attribute values have to be computed before the geometry is actually changed. This is @@ -1080,8 +1080,8 @@ static void store_output_attributes(GeometrySet &geometry, * Evaluate a node group to compute the output geometry. */ static GeometrySet compute_geometry(const DerivedNodeTree &tree, - Span group_input_nodes, - const NodeRef &output_node, + Span group_input_nodes, + const bNode &output_node, GeometrySet input_geometry_set, NodesModifierData *nmd, const ModifierEvalContext *ctx) @@ -1093,18 +1093,19 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree, Map group_inputs; const DTreeContext *root_context = &tree.root_context(); - for (const NodeRef *group_input_node : group_input_nodes) { - Span group_input_sockets = group_input_node->outputs().drop_back(1); + for (const bNode *group_input_node : group_input_nodes) { + Span group_input_sockets = group_input_node->output_sockets().drop_back( + 1); if (group_input_sockets.is_empty()) { continue; } - Span remaining_input_sockets = group_input_sockets; + Span remaining_input_sockets = group_input_sockets; /* If the group expects a geometry as first input, use the geometry that has been passed to * modifier. */ - const OutputSocketRef *first_input_socket = group_input_sockets[0]; - if (first_input_socket->bsocket()->type == SOCK_GEOMETRY) { + const bNodeSocket *first_input_socket = group_input_sockets[0]; + if (first_input_socket->type == SOCK_GEOMETRY) { GeometrySet *geometry_set_in = allocator.construct(input_geometry_set).release(); group_inputs.add_new({root_context, first_input_socket}, geometry_set_in); @@ -1112,8 +1113,8 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree, } /* Initialize remaining group inputs. */ - for (const OutputSocketRef *socket : remaining_input_sockets) { - const CPPType &cpp_type = *socket->typeinfo()->geometry_nodes_cpp_type; + for (const bNodeSocket *socket : remaining_input_sockets) { + const CPPType &cpp_type = *socket->typeinfo->geometry_nodes_cpp_type; void *value_in = allocator.allocate(cpp_type.size(), cpp_type.alignment()); initialize_group_input(*nmd, *socket, value_in); group_inputs.add_new({root_context, socket}, {cpp_type, value_in}); @@ -1121,7 +1122,7 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree, } Vector group_outputs; - for (const InputSocketRef *socket_ref : output_node.inputs().drop_back(1)) { + for (const bNodeSocket *socket_ref : output_node.input_sockets().drop_back(1)) { group_outputs.append({root_context, socket_ref}); } @@ -1226,8 +1227,8 @@ static void modifyGeometry(ModifierData *md, check_property_socket_sync(ctx->object, md); - NodeTreeRefMap tree_refs; - DerivedNodeTree tree{*nmd->node_group, tree_refs}; + const bNodeTree &root_tree_ref = *nmd->node_group; + DerivedNodeTree tree{root_tree_ref}; if (tree.has_link_cycles()) { BKE_modifier_set_error(ctx->object, md, "Node group has cycles"); @@ -1235,25 +1236,24 @@ static void modifyGeometry(ModifierData *md, return; } - const NodeTreeRef &root_tree_ref = tree.root_context().tree(); - Span input_nodes = root_tree_ref.nodes_by_type("NodeGroupInput"); - Span output_nodes = root_tree_ref.nodes_by_type("NodeGroupOutput"); + Span input_nodes = root_tree_ref.nodes_by_type("NodeGroupInput"); + Span output_nodes = root_tree_ref.nodes_by_type("NodeGroupOutput"); if (output_nodes.size() != 1) { BKE_modifier_set_error(ctx->object, md, "Node group must have a single output node"); geometry_set.clear(); return; } - const NodeRef &output_node = *output_nodes[0]; - Span group_outputs = output_node.inputs().drop_back(1); + const bNode &output_node = *output_nodes[0]; + Span group_outputs = output_node.input_sockets().drop_back(1); if (group_outputs.is_empty()) { BKE_modifier_set_error(ctx->object, md, "Node group must have an output socket"); geometry_set.clear(); return; } - const InputSocketRef *first_output_socket = group_outputs[0]; - if (first_output_socket->idname() != "NodeSocketGeometry") { + const bNodeSocket *first_output_socket = group_outputs[0]; + if (!STREQ(first_output_socket->idname, "NodeSocketGeometry")) { BKE_modifier_set_error(ctx->object, md, "Node group's first output must be a geometry"); geometry_set.clear(); return; diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc index 5cf4e21ea68..dd7c87ca499 100644 --- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc +++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc @@ -2,6 +2,7 @@ #include "MOD_nodes_evaluator.hh" +#include "BKE_node.h" #include "BKE_type_conversions.hh" #include "NOD_geometry_exec.hh" @@ -319,9 +320,9 @@ class LockedNode : NonCopyable, NonMovable { } }; -static const CPPType *get_socket_cpp_type(const SocketRef &socket) +static const CPPType *get_socket_cpp_type(const bNodeSocket &socket) { - const bNodeSocketType *typeinfo = socket.typeinfo(); + const bNodeSocketType *typeinfo = socket.typeinfo; if (typeinfo->geometry_nodes_cpp_type == nullptr) { return nullptr; } @@ -338,24 +339,24 @@ static const CPPType *get_socket_cpp_type(const SocketRef &socket) static const CPPType *get_socket_cpp_type(const DSocket socket) { - return get_socket_cpp_type(*socket.socket_ref()); + return get_socket_cpp_type(*socket); } /** * \note This is not supposed to be a long term solution. Eventually we want that nodes can * specify more complex defaults (other than just single values) in their socket declarations. */ -static bool get_implicit_socket_input(const SocketRef &socket, void *r_value) +static bool get_implicit_socket_input(const bNodeSocket &socket, void *r_value) { - const NodeRef &node = socket.node(); - const nodes::NodeDeclaration *node_declaration = node.declaration(); + const bNode &node = socket.owner_node(); + const nodes::NodeDeclaration *node_declaration = node.runtime->declaration; if (node_declaration == nullptr) { return false; } const nodes::SocketDeclaration &socket_declaration = *node_declaration->inputs()[socket.index()]; if (socket_declaration.input_field_type() == nodes::InputSocketFieldType::Implicit) { - const bNode &bnode = *socket.bnode(); - if (socket.typeinfo()->type == SOCK_VECTOR) { + const bNode &bnode = socket.owner_node(); + if (socket.typeinfo->type == SOCK_VECTOR) { if (bnode.type == GEO_NODE_SET_CURVE_HANDLES) { StringRef side = ((NodeGeometrySetCurveHandlePositions *)bnode.storage)->mode == GEO_NODE_CURVE_HANDLE_LEFT ? @@ -372,7 +373,7 @@ static bool get_implicit_socket_input(const SocketRef &socket, void *r_value) new (r_value) ValueOrField(bke::AttributeFieldInput::Create("position")); return true; } - if (socket.typeinfo()->type == SOCK_INT) { + if (socket.typeinfo->type == SOCK_INT) { if (ELEM(bnode.type, FN_NODE_RANDOM_VALUE, GEO_NODE_INSTANCE_ON_POINTS)) { new (r_value) ValueOrField(Field(std::make_shared())); @@ -385,19 +386,19 @@ static bool get_implicit_socket_input(const SocketRef &socket, void *r_value) return false; } -static void get_socket_value(const SocketRef &socket, void *r_value) +static void get_socket_value(const bNodeSocket &socket, void *r_value) { if (get_implicit_socket_input(socket, r_value)) { return; } - const bNodeSocketType *typeinfo = socket.typeinfo(); - typeinfo->get_geometry_nodes_cpp_value(*socket.bsocket(), r_value); + const bNodeSocketType *typeinfo = socket.typeinfo; + typeinfo->get_geometry_nodes_cpp_value(socket, r_value); } static bool node_supports_laziness(const DNode node) { - return node->typeinfo()->geometry_node_execute_supports_laziness; + return node->typeinfo->geometry_node_execute_supports_laziness; } struct NodeTaskRunState { @@ -516,9 +517,9 @@ class GeometryNodesEvaluator { node_states_.add_new({node, &node_state}); /* Push all linked origins on the stack. */ - for (const InputSocketRef *input_ref : node->inputs()) { - const DInputSocket input{node.context(), input_ref}; - input.foreach_origin_socket( + for (const bNodeSocket *input : node->input_sockets()) { + const DInputSocket dinput{node.context(), input}; + dinput.foreach_origin_socket( [&](const DSocket origin) { nodes_to_check.push(origin.node()); }); } } @@ -546,11 +547,11 @@ class GeometryNodesEvaluator { void initialize_node_state(const DNode node, NodeState &node_state, LinearAllocator<> &allocator) { /* Construct arrays of the correct size. */ - node_state.inputs = allocator.construct_array(node->inputs().size()); - node_state.outputs = allocator.construct_array(node->outputs().size()); + node_state.inputs = allocator.construct_array(node->input_sockets().size()); + node_state.outputs = allocator.construct_array(node->output_sockets().size()); /* Initialize input states. */ - for (const int i : node->inputs().index_range()) { + for (const int i : node->input_sockets().index_range()) { InputState &input_state = node_state.inputs[i]; const DInputSocket socket = node.input(i); if (!socket->is_available()) { @@ -567,7 +568,7 @@ class GeometryNodesEvaluator { continue; } /* Construct the correct struct that can hold the input(s). */ - if (socket->is_multi_input_socket()) { + if (socket->is_multi_input()) { input_state.value.multi = allocator.construct().release(); MultiInputValue &multi_value = *input_state.value.multi; /* Count how many values should be added until the socket is complete. */ @@ -583,7 +584,7 @@ class GeometryNodesEvaluator { } } /* Initialize output states. */ - for (const int i : node->outputs().index_range()) { + for (const int i : node->output_sockets().index_range()) { OutputState &output_state = node_state.outputs[i]; const DOutputSocket socket = node.output(i); if (!socket->is_available()) { @@ -629,13 +630,13 @@ class GeometryNodesEvaluator { void destruct_node_state(const DNode node, NodeState &node_state) { /* Need to destruct stuff manually, because it's allocated by a custom allocator. */ - for (const int i : node->inputs().index_range()) { + for (const int i : node->input_sockets().index_range()) { InputState &input_state = node_state.inputs[i]; if (input_state.type == nullptr) { continue; } - const InputSocketRef &socket_ref = node->input(i); - if (socket_ref.is_multi_input_socket()) { + const bNodeSocket &bsocket = node->input_socket(i); + if (bsocket.is_multi_input()) { MultiInputValue &multi_value = *input_state.value.multi; for (void *value : multi_value.values) { if (value != nullptr) { @@ -756,7 +757,7 @@ class GeometryNodesEvaluator { { /* These nodes are sometimes scheduled. We could also check for them in other places, but * it's the easiest to do it here. */ - if (node->is_group_input_node() || node->is_group_output_node()) { + if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) { return; } @@ -837,7 +838,7 @@ class GeometryNodesEvaluator { /* If there are no remaining outputs, all the inputs can be destructed and/or can become * unused. This can also trigger a chain reaction where nodes to the left become finished * too. */ - for (const int i : locked_node.node->inputs().index_range()) { + for (const int i : locked_node.node->input_sockets().index_range()) { const DInputSocket socket = locked_node.node.input(i); InputState &input_state = locked_node.node_state.inputs[i]; if (input_state.usage == ValueUsage::Maybe) { @@ -883,7 +884,7 @@ class GeometryNodesEvaluator { return; } /* Nodes that don't support laziness require all inputs. */ - for (const int i : locked_node.node->inputs().index_range()) { + for (const int i : locked_node.node->input_sockets().index_range()) { InputState &input_state = locked_node.node_state.inputs[i]; if (input_state.type == nullptr) { /* Ignore unavailable/non-data sockets. */ @@ -915,7 +916,7 @@ class GeometryNodesEvaluator { continue; } - if (socket->is_multi_input_socket()) { + if (socket->is_multi_input()) { MultiInputValue &multi_value = *input_state.value.multi; /* Checks if all the linked sockets have been provided already. */ if (multi_value.all_values_available()) { @@ -949,7 +950,7 @@ class GeometryNodesEvaluator { */ void execute_node(const DNode node, NodeState &node_state, NodeTaskRunState *run_state) { - const bNode &bnode = *node->bnode(); + const bNode &bnode = *node; if (node_state.has_been_executed) { if (!node_supports_laziness(node)) { @@ -978,7 +979,7 @@ class GeometryNodesEvaluator { void execute_geometry_node(const DNode node, NodeState &node_state, NodeTaskRunState *run_state) { using Clock = std::chrono::steady_clock; - const bNode &bnode = *node->bnode(); + const bNode &bnode = *node; NodeParamsProvider params_provider{*this, node, node_state, run_state}; GeoNodeExecParams params{params_provider}; @@ -1002,12 +1003,12 @@ class GeometryNodesEvaluator { bool any_input_is_field = false; Vector input_values; Vector input_types; - for (const int i : node->inputs().index_range()) { - const InputSocketRef &socket_ref = node->input(i); - if (!socket_ref.is_available()) { + for (const int i : node->input_sockets().index_range()) { + const bNodeSocket &bsocket = node->input_socket(i); + if (!bsocket.is_available()) { continue; } - BLI_assert(!socket_ref.is_multi_input_socket()); + BLI_assert(!bsocket.is_multi_input()); InputState &input_state = node_state.inputs[i]; BLI_assert(input_state.was_ready_for_execution); SingleInputValue &single_value = *input_state.value.single; @@ -1055,15 +1056,15 @@ class GeometryNodesEvaluator { } int output_index = 0; - for (const int i : node->outputs().index_range()) { - const OutputSocketRef &socket_ref = node->output(i); - if (!socket_ref.is_available()) { + for (const int i : node->output_sockets().index_range()) { + const bNodeSocket &bsocket = node->output_socket(i); + if (!bsocket.is_available()) { continue; } OutputState &output_state = node_state.outputs[i]; - const DOutputSocket socket{node.context(), &socket_ref}; + const DOutputSocket socket{node.context(), &bsocket}; const ValueOrFieldCPPType *cpp_type = static_cast( - get_socket_cpp_type(socket_ref)); + get_socket_cpp_type(bsocket)); GField new_field{operation, output_index}; void *buffer = allocator.allocate(cpp_type->size(), cpp_type->alignment()); cpp_type->construct_from_field(buffer, std::move(new_field)); @@ -1091,7 +1092,7 @@ class GeometryNodesEvaluator { } Vector output_buffers; - for (const int i : node->outputs().index_range()) { + for (const int i : node->output_sockets().index_range()) { const DOutputSocket socket = node.output(i); if (!socket->is_available()) { output_buffers.append({}); @@ -1128,7 +1129,7 @@ class GeometryNodesEvaluator { void execute_unknown_node(const DNode node, NodeState &node_state, NodeTaskRunState *run_state) { LinearAllocator<> &allocator = local_allocators_.local(); - for (const OutputSocketRef *socket : node->outputs()) { + for (const bNodeSocket *socket : node->output_sockets()) { if (!socket->is_available()) { continue; } @@ -1182,8 +1183,8 @@ class GeometryNodesEvaluator { const bool supports_laziness = node_supports_laziness(locked_node.node); /* Iterating over sockets instead of the states directly, because that makes it easier to * figure out which socket is missing when one of the asserts is hit. */ - for (const OutputSocketRef *socket_ref : locked_node.node->outputs()) { - OutputState &output_state = locked_node.node_state.outputs[socket_ref->index()]; + for (const bNodeSocket *bsocket : locked_node.node->output_sockets()) { + OutputState &output_state = locked_node.node_state.outputs[bsocket->index()]; if (supports_laziness) { /* Expected that at least all required sockets have been computed. If more outputs become * required later, the node will be executed again. */ @@ -1208,7 +1209,7 @@ class GeometryNodesEvaluator { { for (const DInputSocket &socket : params_.output_sockets) { BLI_assert(socket->is_available()); - BLI_assert(!socket->is_multi_input_socket()); + BLI_assert(!socket->is_multi_input()); const DNode node = socket.node(); NodeState &node_state = this->get_node_state(node); @@ -1255,7 +1256,7 @@ class GeometryNodesEvaluator { /* Count how many values still have to be added to this input until it is "complete". */ int missing_values = 0; - if (input_socket->is_multi_input_socket()) { + if (input_socket->is_multi_input()) { MultiInputValue &multi_value = *input_state.value.multi; missing_values = multi_value.missing_values(); } @@ -1402,52 +1403,51 @@ class GeometryNodesEvaluator { Vector forward_original_value_sockets; log_original_value_sockets.append(from_socket); - from_socket.foreach_target_socket( - [&](const DInputSocket to_socket, const DOutputSocket::TargetSocketPathInfo &path_info) { - if (!this->should_forward_to_socket(to_socket)) { - return; - } - BLI_assert(to_socket == path_info.sockets.last()); - GMutablePointer current_value = value_to_forward; - for (const DSocket &next_socket : path_info.sockets) { - const DNode next_node = next_socket.node(); - const bool is_last_socket = to_socket == next_socket; - const bool do_conversion_if_necessary = is_last_socket || - next_node->is_group_output_node() || - (next_node->is_group_node() && - !next_node->is_muted()); - if (do_conversion_if_necessary) { - const CPPType &next_type = *get_socket_cpp_type(next_socket); - if (*current_value.type() != next_type) { - void *buffer = allocator.allocate(next_type.size(), next_type.alignment()); - this->convert_value(*current_value.type(), next_type, current_value.get(), buffer); - if (current_value.get() != value_to_forward.get()) { - current_value.destruct(); - } - current_value = {next_type, buffer}; - } - } - if (current_value.get() == value_to_forward.get()) { - /* Log the original value at the current socket. */ - log_original_value_sockets.append(next_socket); - } - else { - /* Multi-input sockets are logged when all values are available. */ - if (!(next_socket->is_input() && next_socket->as_input().is_multi_input_socket())) { - /* Log the converted value at the socket. */ - this->log_socket_value({next_socket}, current_value); - } + from_socket.foreach_target_socket([&](const DInputSocket to_socket, + const DOutputSocket::TargetSocketPathInfo &path_info) { + if (!this->should_forward_to_socket(to_socket)) { + return; + } + BLI_assert(to_socket == path_info.sockets.last()); + GMutablePointer current_value = value_to_forward; + for (const DSocket &next_socket : path_info.sockets) { + const DNode next_node = next_socket.node(); + const bool is_last_socket = to_socket == next_socket; + const bool do_conversion_if_necessary = is_last_socket || + next_node->type == NODE_GROUP_OUTPUT || + (next_node->is_group() && !next_node->is_muted()); + if (do_conversion_if_necessary) { + const CPPType &next_type = *get_socket_cpp_type(next_socket); + if (*current_value.type() != next_type) { + void *buffer = allocator.allocate(next_type.size(), next_type.alignment()); + this->convert_value(*current_value.type(), next_type, current_value.get(), buffer); + if (current_value.get() != value_to_forward.get()) { + current_value.destruct(); } + current_value = {next_type, buffer}; } - if (current_value.get() == value_to_forward.get()) { - /* The value has not been converted, so forward the original value. */ - forward_original_value_sockets.append(to_socket); - } - else { - /* The value has been converted. */ - this->add_value_to_input_socket(to_socket, from_socket, current_value, run_state); + } + if (current_value.get() == value_to_forward.get()) { + /* Log the original value at the current socket. */ + log_original_value_sockets.append(next_socket); + } + else { + /* Multi-input sockets are logged when all values are available. */ + if (!(next_socket->is_input() && next_socket->is_multi_input())) { + /* Log the converted value at the socket. */ + this->log_socket_value({next_socket}, current_value); } - }); + } + } + if (current_value.get() == value_to_forward.get()) { + /* The value has not been converted, so forward the original value. */ + forward_original_value_sockets.append(to_socket); + } + else { + /* The value has been converted. */ + this->add_value_to_input_socket(to_socket, from_socket, current_value, run_state); + } + }); this->log_socket_value(log_original_value_sockets, value_to_forward); this->forward_to_sockets_with_same_type( allocator, forward_original_value_sockets, value_to_forward, from_socket, run_state); @@ -1512,7 +1512,7 @@ class GeometryNodesEvaluator { InputState &input_state = node_state.inputs[socket->index()]; this->with_locked_node(node, node_state, run_state, [&](LockedNode &locked_node) { - if (socket->is_multi_input_socket()) { + if (socket->is_multi_input()) { /* Add a new value to the multi-input. */ MultiInputValue &multi_value = *input_state.value.multi; multi_value.add_value(origin, value.get()); @@ -1555,7 +1555,7 @@ class GeometryNodesEvaluator { UNUSED_VARS(locked_node); GMutablePointer value = this->get_value_from_socket(origin_socket, *input_state.type); - if (input_socket->is_multi_input_socket()) { + if (input_socket->is_multi_input()) { MultiInputValue &multi_value = *input_state.value.multi; multi_value.add_value(origin_socket, value.get()); if (multi_value.all_values_available()) { @@ -1580,7 +1580,7 @@ class GeometryNodesEvaluator { void destruct_input_value_if_exists(LockedNode &locked_node, const DInputSocket socket) { InputState &input_state = locked_node.node_state.inputs[socket->index()]; - if (socket->is_multi_input_socket()) { + if (socket->is_multi_input()) { MultiInputValue &multi_value = *input_state.value.multi; for (void *&value : multi_value.values) { if (value != nullptr) { @@ -1605,7 +1605,7 @@ class GeometryNodesEvaluator { const CPPType &type = *get_socket_cpp_type(socket); void *buffer = allocator.allocate(type.size(), type.alignment()); - get_socket_value(*socket.socket_ref(), buffer); + get_socket_value(*socket.bsocket(), buffer); if (type == required_type) { return {type, buffer}; @@ -1762,7 +1762,7 @@ bool NodeParamsProvider::can_get_input(StringRef identifier) const return false; } - if (socket->is_multi_input_socket()) { + if (socket->is_multi_input()) { MultiInputValue &multi_value = *input_state.value.multi; return multi_value.all_values_available(); } @@ -1783,7 +1783,7 @@ GMutablePointer NodeParamsProvider::extract_input(StringRef identifier) { const DInputSocket socket = this->dnode.input_by_identifier(identifier); BLI_assert(socket); - BLI_assert(!socket->is_multi_input_socket()); + BLI_assert(!socket->is_multi_input()); BLI_assert(this->can_get_input(identifier)); InputState &input_state = node_state_.inputs[socket->index()]; @@ -1797,7 +1797,7 @@ Vector NodeParamsProvider::extract_multi_input(StringRef identi { const DInputSocket socket = this->dnode.input_by_identifier(identifier); BLI_assert(socket); - BLI_assert(socket->is_multi_input_socket()); + BLI_assert(socket->is_multi_input()); BLI_assert(this->can_get_input(identifier)); InputState &input_state = node_state_.inputs[socket->index()]; @@ -1816,7 +1816,7 @@ GPointer NodeParamsProvider::get_input(StringRef identifier) const { const DInputSocket socket = this->dnode.input_by_identifier(identifier); BLI_assert(socket); - BLI_assert(!socket->is_multi_input_socket()); + BLI_assert(!socket->is_multi_input()); BLI_assert(this->can_get_input(identifier)); InputState &input_state = node_state_.inputs[socket->index()]; @@ -1901,7 +1901,7 @@ void NodeParamsProvider::set_default_remaining_outputs() { LinearAllocator<> &allocator = evaluator_.local_allocators_.local(); - for (const int i : this->dnode->outputs().index_range()) { + for (const int i : this->dnode->output_sockets().index_range()) { OutputState &output_state = node_state_.outputs[i]; if (output_state.has_been_computed) { continue; diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index ae31fd7ff5f..ff8bd27f8d7 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -49,7 +49,6 @@ set(SRC intern/node_multi_function.cc intern/node_socket.cc intern/node_socket_declarations.cc - intern/node_tree_ref.cc intern/node_util.c intern/socket_search_link.cc @@ -63,7 +62,6 @@ set(SRC NOD_math_functions.hh NOD_multi_function.hh NOD_node_declaration.hh - NOD_node_tree_ref.hh NOD_shader.h NOD_socket.h NOD_socket_declarations.hh diff --git a/source/blender/nodes/NOD_derived_node_tree.hh b/source/blender/nodes/NOD_derived_node_tree.hh index b0799d90dcd..b3775e729da 100644 --- a/source/blender/nodes/NOD_derived_node_tree.hh +++ b/source/blender/nodes/NOD_derived_node_tree.hh @@ -5,16 +5,17 @@ /** \file * \ingroup nodes * - * DerivedNodeTree builds on top of NodeTreeRef and makes working with (nested) node groups more - * convenient and safe. It does so by pairing nodes and sockets with a context. The context - * contains information about the current "instance" of the node or socket. A node might be - * "instanced" multiple times when it is in a node group that is used multiple times. + * DerivedNodeTree makes working with (nested) node groups more convenient and safe. It does so by + * pairing nodes and sockets with a context. The context contains information about the current + * "instance" of the node or socket. A node might be "instanced" multiple times when it is in a + * node group that is used multiple times. */ #include "BLI_function_ref.hh" +#include "BLI_linear_allocator.hh" #include "BLI_vector_set.hh" -#include "NOD_node_tree_ref.hh" +#include "BKE_node_runtime.hh" namespace blender::nodes { @@ -40,20 +41,20 @@ class DTreeContext { DTreeContext *parent_context_; /* Null when this context is for the root node group. Otherwise it points to the group node in * the parent node group that contains this context. */ - const NodeRef *parent_node_; + const bNode *parent_node_; /* The current node tree. */ - const NodeTreeRef *tree_; + const bNodeTree *btree_; /* All the children contexts of this context. */ - Map children_; + Map children_; DerivedNodeTree *derived_tree_; friend DerivedNodeTree; public: - const NodeTreeRef &tree() const; + const bNodeTree &btree() const; const DTreeContext *parent_context() const; - const NodeRef *parent_node() const; - const DTreeContext *child_context(const NodeRef &node) const; + const bNode *parent_node() const; + const DTreeContext *child_context(const bNode &node) const; const DerivedNodeTree &derived_tree() const; bool is_root() const; }; @@ -65,15 +66,16 @@ class DTreeContext { class DNode { private: const DTreeContext *context_ = nullptr; - const NodeRef *node_ref_ = nullptr; + const bNode *bnode_ = nullptr; public: DNode() = default; - DNode(const DTreeContext *context, const NodeRef *node); + DNode(const DTreeContext *context, const bNode *node); const DTreeContext *context() const; - const NodeRef *node_ref() const; - const NodeRef *operator->() const; + const bNode *bnode() const; + const bNode *operator->() const; + const bNode &operator*() const; friend bool operator==(const DNode &a, const DNode &b); friend bool operator!=(const DNode &a, const DNode &b); @@ -98,17 +100,18 @@ class DNode { class DSocket { protected: const DTreeContext *context_ = nullptr; - const SocketRef *socket_ref_ = nullptr; + const bNodeSocket *bsocket_ = nullptr; public: DSocket() = default; - DSocket(const DTreeContext *context, const SocketRef *socket); + DSocket(const DTreeContext *context, const bNodeSocket *socket); DSocket(const DInputSocket &input_socket); DSocket(const DOutputSocket &output_socket); const DTreeContext *context() const; - const SocketRef *socket_ref() const; - const SocketRef *operator->() const; + const bNodeSocket *bsocket() const; + const bNodeSocket *operator->() const; + const bNodeSocket &operator*() const; friend bool operator==(const DSocket &a, const DSocket &b); friend bool operator!=(const DSocket &a, const DSocket &b); @@ -123,12 +126,9 @@ class DSocket { class DInputSocket : public DSocket { public: DInputSocket() = default; - DInputSocket(const DTreeContext *context, const InputSocketRef *socket); + DInputSocket(const DTreeContext *context, const bNodeSocket *socket); explicit DInputSocket(const DSocket &base_socket); - const InputSocketRef *socket_ref() const; - const InputSocketRef *operator->() const; - DOutputSocket get_corresponding_group_node_output() const; Vector get_corresponding_group_input_sockets() const; @@ -144,12 +144,9 @@ class DInputSocket : public DSocket { class DOutputSocket : public DSocket { public: DOutputSocket() = default; - DOutputSocket(const DTreeContext *context, const OutputSocketRef *socket); + DOutputSocket(const DTreeContext *context, const bNodeSocket *socket); explicit DOutputSocket(const DSocket &base_socket); - const OutputSocketRef *socket_ref() const; - const OutputSocketRef *operator->() const; - DInputSocket get_corresponding_group_node_input() const; DInputSocket get_active_corresponding_group_output_socket() const; @@ -177,7 +174,7 @@ class DerivedNodeTree { private: LinearAllocator<> allocator_; DTreeContext *root_context_; - VectorSet used_node_tree_refs_; + VectorSet used_btrees_; public: /** @@ -186,11 +183,11 @@ class DerivedNodeTree { * has to make sure that the node tree refs added to #node_tree_refs live at least as long as the * derived node tree. */ - DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs); + DerivedNodeTree(const bNodeTree &btree); ~DerivedNodeTree(); const DTreeContext &root_context() const; - Span used_node_tree_refs() const; + Span used_btrees() const; /** * \return True when there is a link cycle. Unavailable sockets are ignored. @@ -205,9 +202,8 @@ class DerivedNodeTree { private: DTreeContext &construct_context_recursively(DTreeContext *parent_context, - const NodeRef *parent_node, - bNodeTree &btree, - NodeTreeRefMap &node_tree_refs); + const bNode *parent_node, + const bNodeTree &btree); void destruct_context_recursively(DTreeContext *context); void foreach_node_in_context_recursive(const DTreeContext &context, @@ -215,7 +211,6 @@ class DerivedNodeTree { }; namespace derived_node_tree_types { -using namespace node_tree_ref_types; using nodes::DerivedNodeTree; using nodes::DInputSocket; using nodes::DNode; @@ -228,9 +223,9 @@ using nodes::DTreeContext; /** \name #DTreeContext Inline Methods * \{ */ -inline const NodeTreeRef &DTreeContext::tree() const +inline const bNodeTree &DTreeContext::btree() const { - return *tree_; + return *btree_; } inline const DTreeContext *DTreeContext::parent_context() const @@ -238,12 +233,12 @@ inline const DTreeContext *DTreeContext::parent_context() const return parent_context_; } -inline const NodeRef *DTreeContext::parent_node() const +inline const bNode *DTreeContext::parent_node() const { return parent_node_; } -inline const DTreeContext *DTreeContext::child_context(const NodeRef &node) const +inline const DTreeContext *DTreeContext::child_context(const bNode &node) const { return children_.lookup_default(&node, nullptr); } @@ -264,10 +259,10 @@ inline bool DTreeContext::is_root() const /** \name #DNode Inline Methods * \{ */ -inline DNode::DNode(const DTreeContext *context, const NodeRef *node_ref) - : context_(context), node_ref_(node_ref) +inline DNode::DNode(const DTreeContext *context, const bNode *bnode) + : context_(context), bnode_(bnode) { - BLI_assert(node_ref == nullptr || &node_ref->tree() == &context->tree()); + BLI_assert(bnode == nullptr || bnode->runtime->owner_tree == &context->btree()); } inline const DTreeContext *DNode::context() const @@ -275,14 +270,14 @@ inline const DTreeContext *DNode::context() const return context_; } -inline const NodeRef *DNode::node_ref() const +inline const bNode *DNode::bnode() const { - return node_ref_; + return bnode_; } inline bool operator==(const DNode &a, const DNode &b) { - return a.context_ == b.context_ && a.node_ref_ == b.node_ref_; + return a.context_ == b.context_ && a.bnode_ == b.bnode_; } inline bool operator!=(const DNode &a, const DNode &b) @@ -292,37 +287,43 @@ inline bool operator!=(const DNode &a, const DNode &b) inline DNode::operator bool() const { - return node_ref_ != nullptr; + return bnode_ != nullptr; +} + +inline const bNode *DNode::operator->() const +{ + return bnode_; } -inline const NodeRef *DNode::operator->() const +inline const bNode &DNode::operator*() const { - return node_ref_; + BLI_assert(bnode_ != nullptr); + return *bnode_; } inline uint64_t DNode::hash() const { - return get_default_hash_2(context_, node_ref_); + return get_default_hash_2(context_, bnode_); } inline DInputSocket DNode::input(int index) const { - return {context_, &node_ref_->input(index)}; + return {context_, &bnode_->input_socket(index)}; } inline DOutputSocket DNode::output(int index) const { - return {context_, &node_ref_->output(index)}; + return {context_, &bnode_->output_socket(index)}; } inline DInputSocket DNode::input_by_identifier(StringRef identifier) const { - return {context_, &node_ref_->input_by_identifier(identifier)}; + return {context_, &bnode_->input_by_identifier(identifier)}; } inline DOutputSocket DNode::output_by_identifier(StringRef identifier) const { - return {context_, &node_ref_->output_by_identifier(identifier)}; + return {context_, &bnode_->output_by_identifier(identifier)}; } /** \} */ @@ -331,19 +332,20 @@ inline DOutputSocket DNode::output_by_identifier(StringRef identifier) const /** \name #DSocket Inline Methods * \{ */ -inline DSocket::DSocket(const DTreeContext *context, const SocketRef *socket_ref) - : context_(context), socket_ref_(socket_ref) +inline DSocket::DSocket(const DTreeContext *context, const bNodeSocket *bsocket) + : context_(context), bsocket_(bsocket) { - BLI_assert(socket_ref == nullptr || &socket_ref->tree() == &context->tree()); + BLI_assert(bsocket == nullptr || + bsocket->runtime->owner_node->runtime->owner_tree == &context->btree()); } inline DSocket::DSocket(const DInputSocket &input_socket) - : DSocket(input_socket.context_, input_socket.socket_ref_) + : DSocket(input_socket.context_, input_socket.bsocket_) { } inline DSocket::DSocket(const DOutputSocket &output_socket) - : DSocket(output_socket.context_, output_socket.socket_ref_) + : DSocket(output_socket.context_, output_socket.bsocket_) { } @@ -352,14 +354,14 @@ inline const DTreeContext *DSocket::context() const return context_; } -inline const SocketRef *DSocket::socket_ref() const +inline const bNodeSocket *DSocket::bsocket() const { - return socket_ref_; + return bsocket_; } inline bool operator==(const DSocket &a, const DSocket &b) { - return a.context_ == b.context_ && a.socket_ref_ == b.socket_ref_; + return a.context_ == b.context_ && a.bsocket_ == b.bsocket_; } inline bool operator!=(const DSocket &a, const DSocket &b) @@ -369,23 +371,29 @@ inline bool operator!=(const DSocket &a, const DSocket &b) inline DSocket::operator bool() const { - return socket_ref_ != nullptr; + return bsocket_ != nullptr; } -inline const SocketRef *DSocket::operator->() const +inline const bNodeSocket *DSocket::operator->() const { - return socket_ref_; + return bsocket_; +} + +inline const bNodeSocket &DSocket::operator*() const +{ + BLI_assert(bsocket_ != nullptr); + return *bsocket_; } inline uint64_t DSocket::hash() const { - return get_default_hash_2(context_, socket_ref_); + return get_default_hash_2(context_, bsocket_); } inline DNode DSocket::node() const { - BLI_assert(socket_ref_ != nullptr); - return {context_, &socket_ref_->node()}; + BLI_assert(bsocket_ != nullptr); + return {context_, bsocket_->runtime->owner_node}; } /** \} */ @@ -394,8 +402,8 @@ inline DNode DSocket::node() const /** \name #DInputSocket Inline Methods * \{ */ -inline DInputSocket::DInputSocket(const DTreeContext *context, const InputSocketRef *socket_ref) - : DSocket(context, socket_ref) +inline DInputSocket::DInputSocket(const DTreeContext *context, const bNodeSocket *bsocket) + : DSocket(context, bsocket) { } @@ -404,24 +412,14 @@ inline DInputSocket::DInputSocket(const DSocket &base_socket) : DSocket(base_soc BLI_assert(base_socket->is_input()); } -inline const InputSocketRef *DInputSocket::socket_ref() const -{ - return (const InputSocketRef *)socket_ref_; -} - -inline const InputSocketRef *DInputSocket::operator->() const -{ - return (const InputSocketRef *)socket_ref_; -} - /** \} */ /* -------------------------------------------------------------------- */ /** \name #DOutputSocket Inline Methods * \{ */ -inline DOutputSocket::DOutputSocket(const DTreeContext *context, const OutputSocketRef *socket_ref) - : DSocket(context, socket_ref) +inline DOutputSocket::DOutputSocket(const DTreeContext *context, const bNodeSocket *bsocket) + : DSocket(context, bsocket) { } @@ -430,16 +428,6 @@ inline DOutputSocket::DOutputSocket(const DSocket &base_socket) : DSocket(base_s BLI_assert(base_socket->is_output()); } -inline const OutputSocketRef *DOutputSocket::socket_ref() const -{ - return (const OutputSocketRef *)socket_ref_; -} - -inline const OutputSocketRef *DOutputSocket::operator->() const -{ - return (const OutputSocketRef *)socket_ref_; -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -451,9 +439,9 @@ inline const DTreeContext &DerivedNodeTree::root_context() const return *root_context_; } -inline Span DerivedNodeTree::used_node_tree_refs() const +inline Span DerivedNodeTree::used_btrees() const { - return used_node_tree_refs_; + return used_btrees_; } /** \} */ diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh index a7f5fbf1926..b5ffd3a317c 100644 --- a/source/blender/nodes/NOD_geometry_exec.hh +++ b/source/blender/nodes/NOD_geometry_exec.hh @@ -283,7 +283,7 @@ class GeoNodeExecParams { */ const bNode &node() const { - return *provider_->dnode->bnode(); + return *provider_->dnode; } const Object *self_object() const diff --git a/source/blender/nodes/NOD_multi_function.hh b/source/blender/nodes/NOD_multi_function.hh index b6d51578b1c..21a94d9192b 100644 --- a/source/blender/nodes/NOD_multi_function.hh +++ b/source/blender/nodes/NOD_multi_function.hh @@ -19,15 +19,15 @@ class NodeMultiFunctions; */ class NodeMultiFunctionBuilder : NonCopyable, NonMovable { private: - bNode &node_; - bNodeTree &tree_; + const bNode &node_; + const bNodeTree &tree_; std::shared_ptr owned_built_fn_; const MultiFunction *built_fn_ = nullptr; friend NodeMultiFunctions; public: - NodeMultiFunctionBuilder(bNode &node, bNodeTree &tree); + NodeMultiFunctionBuilder(const bNode &node, const bNodeTree &tree); /** * Assign a multi-function for the current node. The input and output parameters of the function @@ -42,8 +42,8 @@ class NodeMultiFunctionBuilder : NonCopyable, NonMovable { */ template void construct_and_set_matching_fn(Args &&...args); - bNode &node(); - bNodeTree &tree(); + const bNode &node(); + const bNodeTree &tree(); }; /** @@ -69,17 +69,17 @@ class NodeMultiFunctions { /** \name #NodeMultiFunctionBuilder Inline Methods * \{ */ -inline NodeMultiFunctionBuilder::NodeMultiFunctionBuilder(bNode &node, bNodeTree &tree) +inline NodeMultiFunctionBuilder::NodeMultiFunctionBuilder(const bNode &node, const bNodeTree &tree) : node_(node), tree_(tree) { } -inline bNode &NodeMultiFunctionBuilder::node() +inline const bNode &NodeMultiFunctionBuilder::node() { return node_; } -inline bNodeTree &NodeMultiFunctionBuilder::tree() +inline const bNodeTree &NodeMultiFunctionBuilder::tree() { return tree_; } @@ -110,7 +110,7 @@ inline void NodeMultiFunctionBuilder::construct_and_set_matching_fn(Args &&...ar inline const NodeMultiFunctions::Item &NodeMultiFunctions::try_get(const DNode &node) const { static Item empty_item; - const Item *item = map_.lookup_ptr(node->bnode()); + const Item *item = map_.lookup_ptr(node.bnode()); if (item == nullptr) { return empty_item; } diff --git a/source/blender/nodes/NOD_node_tree_ref.hh b/source/blender/nodes/NOD_node_tree_ref.hh deleted file mode 100644 index 257aa5f4110..00000000000 --- a/source/blender/nodes/NOD_node_tree_ref.hh +++ /dev/null @@ -1,760 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -#pragma once - -/** \file - * \ingroup nodes - * - * NodeTreeRef makes querying information about a bNodeTree more efficient. It is an immutable data - * structure. It should not be used after anymore, after the underlying node tree changed. - * - * The following queries are supported efficiently: - * - socket -> index of socket - * - socket -> directly linked sockets - * - socket -> directly linked links - * - socket -> linked sockets when skipping reroutes - * - socket -> node - * - socket/node -> rna pointer - * - node -> inputs/outputs - * - node -> tree - * - tree -> all nodes - * - tree -> all (input/output) sockets - * - idname -> nodes - * - * Every socket has an id. The id-space is shared between input and output sockets. - * When storing data per socket, it is often better to use the id as index into an array, instead - * of a hash table. - * - * Every node has an id as well. The same rule regarding hash tables applies. - * - * There is an utility to export this data structure as graph in dot format. - */ - -#include "BLI_array.hh" -#include "BLI_function_ref.hh" -#include "BLI_linear_allocator.hh" -#include "BLI_map.hh" -#include "BLI_multi_value_map.hh" -#include "BLI_string_ref.hh" -#include "BLI_timeit.hh" -#include "BLI_utility_mixins.hh" -#include "BLI_vector.hh" - -#include "BKE_node.h" -#include "BKE_node_runtime.hh" - -#include "DNA_node_types.h" - -#include "RNA_access.h" - -namespace blender::nodes { - -class SocketRef; -class InputSocketRef; -class OutputSocketRef; -class NodeRef; -class NodeTreeRef; -class LinkRef; -class InternalLinkRef; - -using SocketIndexByIdentifierMap = Map; - -class SocketRef : NonCopyable, NonMovable { - protected: - NodeRef *node_; - bNodeSocket *bsocket_; - bool is_input_; - int id_; - int index_; - Vector directly_linked_links_; - - /* These sockets are linked directly, i.e. with a single link in between. */ - MutableSpan directly_linked_sockets_; - /* These sockets are linked when reroutes, muted links and muted nodes have been taken into - * account. */ - MutableSpan logically_linked_sockets_; - /* These are the sockets that have been skipped when searching for logically linked sockets. - * That includes for example the input and output socket of an intermediate reroute node. */ - MutableSpan logically_linked_skipped_sockets_; - - friend NodeTreeRef; - - public: - Span logically_linked_sockets() const; - Span logically_linked_skipped_sockets() const; - Span directly_linked_sockets() const; - Span directly_linked_links() const; - - bool is_directly_linked() const; - bool is_logically_linked() const; - - const NodeRef &node() const; - const NodeTreeRef &tree() const; - - int id() const; - int index() const; - - bool is_input() const; - bool is_output() const; - - const SocketRef &as_base() const; - const InputSocketRef &as_input() const; - const OutputSocketRef &as_output() const; - - PointerRNA rna() const; - - StringRefNull idname() const; - StringRefNull name() const; - StringRefNull identifier() const; - bNodeSocketType *typeinfo() const; - - bNodeSocket *bsocket() const; - bNode *bnode() const; - bNodeTree *btree() const; - - bool is_available() const; - bool is_undefined() const; - - void *default_value() const; - template T *default_value() const; -}; - -class InputSocketRef final : public SocketRef { - public: - friend NodeTreeRef; - - Span logically_linked_sockets() const; - Span directly_linked_sockets() const; - - bool is_multi_input_socket() const; - - private: - void foreach_logical_origin(FunctionRef origin_fn, - FunctionRef skipped_fn, - bool only_follow_first_input_link, - Vector &seen_sockets_stack) const; -}; - -class OutputSocketRef final : public SocketRef { - public: - friend NodeTreeRef; - - Span logically_linked_sockets() const; - Span directly_linked_sockets() const; - - private: - void foreach_logical_target(FunctionRef target_fn, - FunctionRef skipped_fn, - Vector &seen_sockets_stack) const; -}; - -class NodeRef : NonCopyable, NonMovable { - private: - NodeTreeRef *tree_; - bNode *bnode_; - int id_; - Vector inputs_; - Vector outputs_; - Vector internal_links_; - SocketIndexByIdentifierMap *input_index_by_identifier_; - SocketIndexByIdentifierMap *output_index_by_identifier_; - - friend NodeTreeRef; - - public: - const NodeTreeRef &tree() const; - - Span inputs() const; - Span outputs() const; - Span internal_links() const; - Span sockets(eNodeSocketInOut in_out) const; - - const InputSocketRef &input(int index) const; - const OutputSocketRef &output(int index) const; - - const InputSocketRef &input_by_identifier(StringRef identifier) const; - const OutputSocketRef &output_by_identifier(StringRef identifier) const; - - bool any_input_is_directly_linked() const; - bool any_output_is_directly_linked() const; - bool any_socket_is_directly_linked(eNodeSocketInOut in_out) const; - - bNode *bnode() const; - bNodeTree *btree() const; - - PointerRNA rna() const; - StringRefNull idname() const; - StringRefNull name() const; - StringRefNull label() const; - StringRefNull label_or_name() const; - bNodeType *typeinfo() const; - const NodeDeclaration *declaration() const; - - int id() const; - - bool is_reroute_node() const; - bool is_group_node() const; - bool is_group_input_node() const; - bool is_group_output_node() const; - bool is_muted() const; - bool is_frame() const; - bool is_undefined() const; - - void *storage() const; - template T *storage() const; -}; - -class LinkRef : NonCopyable, NonMovable { - private: - OutputSocketRef *from_; - InputSocketRef *to_; - bNodeLink *blink_; - - friend NodeTreeRef; - - public: - const OutputSocketRef &from() const; - const InputSocketRef &to() const; - - bNodeLink *blink() const; - - bool is_muted() const; -}; - -class InternalLinkRef : NonCopyable, NonMovable { - private: - InputSocketRef *from_; - OutputSocketRef *to_; - bNodeLink *blink_; - - friend NodeTreeRef; - - public: - const InputSocketRef &from() const; - const OutputSocketRef &to() const; - - bNodeLink *blink() const; -}; - -class NodeTreeRef : NonCopyable, NonMovable { - private: - LinearAllocator<> allocator_; - bNodeTree *btree_; - Vector nodes_by_id_; - Vector sockets_by_id_; - Vector input_sockets_; - Vector output_sockets_; - Vector links_; - MultiValueMap nodes_by_type_; - Vector> owned_identifier_maps_; - const NodeRef *group_output_node_ = nullptr; - - public: - NodeTreeRef(bNodeTree *btree); - ~NodeTreeRef(); - - Span nodes() const; - Span nodes_by_type(StringRefNull idname) const; - Span nodes_by_type(const bNodeType *nodetype) const; - - Span sockets() const; - Span input_sockets() const; - Span output_sockets() const; - - Span links() const; - - const NodeRef *find_node(const bNode &bnode) const; - - /** - * This is the active group output node if there are multiple. - */ - const NodeRef *group_output_node() const; - - /** - * \return True when there is a link cycle. Unavailable sockets are ignored. - */ - bool has_link_cycles() const; - bool has_undefined_nodes_or_sockets() const; - - enum class ToposortDirection { - LeftToRight, - RightToLeft, - }; - - struct ToposortResult { - Vector sorted_nodes; - /** - * There can't be a correct topological sort of the nodes when there is a cycle. The nodes will - * still be sorted to some degree. The caller has to decide whether it can handle non-perfect - * sorts or not. - */ - bool has_cycle = false; - }; - - /** - * Sort nodes topologically from left to right or right to left. - * In the future the result if this could be cached on #NodeTreeRef. - */ - ToposortResult toposort(ToposortDirection direction) const; - - bNodeTree *btree() const; - StringRefNull name() const; - - std::string to_dot() const; - - private: - /* Utility functions used during construction. */ - InputSocketRef &find_input_socket(Map &node_mapping, - bNode *bnode, - bNodeSocket *bsocket); - OutputSocketRef &find_output_socket(Map &node_mapping, - bNode *bnode, - bNodeSocket *bsocket); - - void create_linked_socket_caches(); - void create_socket_identifier_maps(); -}; - -using NodeTreeRefMap = Map>; - -const NodeTreeRef &get_tree_ref_from_map(NodeTreeRefMap &node_tree_refs, bNodeTree &btree); - -namespace node_tree_ref_types { -using nodes::InputSocketRef; -using nodes::NodeRef; -using nodes::NodeTreeRef; -using nodes::NodeTreeRefMap; -using nodes::OutputSocketRef; -using nodes::SocketRef; -} // namespace node_tree_ref_types - -/* -------------------------------------------------------------------- */ -/** \name #SocketRef Inline Methods - * \{ */ - -inline Span SocketRef::logically_linked_sockets() const -{ - return logically_linked_sockets_; -} - -inline Span SocketRef::logically_linked_skipped_sockets() const -{ - return logically_linked_skipped_sockets_; -} - -inline Span SocketRef::directly_linked_sockets() const -{ - return directly_linked_sockets_; -} - -inline Span SocketRef::directly_linked_links() const -{ - return directly_linked_links_; -} - -inline bool SocketRef::is_directly_linked() const -{ - return directly_linked_sockets_.size() > 0; -} - -inline bool SocketRef::is_logically_linked() const -{ - return logically_linked_sockets_.size() > 0; -} - -inline const NodeRef &SocketRef::node() const -{ - return *node_; -} - -inline const NodeTreeRef &SocketRef::tree() const -{ - return node_->tree(); -} - -inline int SocketRef::id() const -{ - return id_; -} - -inline int SocketRef::index() const -{ - return index_; -} - -inline bool SocketRef::is_input() const -{ - return is_input_; -} - -inline bool SocketRef::is_output() const -{ - return !is_input_; -} - -inline const SocketRef &SocketRef::as_base() const -{ - return *this; -} - -inline const InputSocketRef &SocketRef::as_input() const -{ - BLI_assert(this->is_input()); - return static_cast(*this); -} - -inline const OutputSocketRef &SocketRef::as_output() const -{ - BLI_assert(this->is_output()); - return static_cast(*this); -} - -inline StringRefNull SocketRef::idname() const -{ - return bsocket_->idname; -} - -inline StringRefNull SocketRef::name() const -{ - return bsocket_->name; -} - -inline StringRefNull SocketRef::identifier() const -{ - return bsocket_->identifier; -} - -inline bNodeSocketType *SocketRef::typeinfo() const -{ - return bsocket_->typeinfo; -} - -inline bNodeSocket *SocketRef::bsocket() const -{ - return bsocket_; -} - -inline bNode *SocketRef::bnode() const -{ - return node_->bnode(); -} - -inline bNodeTree *SocketRef::btree() const -{ - return node_->btree(); -} - -inline bool SocketRef::is_available() const -{ - return (bsocket_->flag & SOCK_UNAVAIL) == 0; -} - -inline bool SocketRef::is_undefined() const -{ - return bsocket_->typeinfo == &NodeSocketTypeUndefined; -} - -inline void *SocketRef::default_value() const -{ - return bsocket_->default_value; -} - -template inline T *SocketRef::default_value() const -{ - return (T *)bsocket_->default_value; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name #InputSocketRef Inline Methods - * \{ */ - -inline Span InputSocketRef::logically_linked_sockets() const -{ - return logically_linked_sockets_.as_span().cast(); -} - -inline Span InputSocketRef::directly_linked_sockets() const -{ - return directly_linked_sockets_.cast(); -} - -inline bool InputSocketRef::is_multi_input_socket() const -{ - return bsocket_->flag & SOCK_MULTI_INPUT; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name #OutputSocketRef Inline Methods - * \{ */ - -inline Span OutputSocketRef::logically_linked_sockets() const -{ - return logically_linked_sockets_.as_span().cast(); -} - -inline Span OutputSocketRef::directly_linked_sockets() const -{ - return directly_linked_sockets_.cast(); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name #NodeRef Inline Methods - * \{ */ - -inline const NodeTreeRef &NodeRef::tree() const -{ - return *tree_; -} - -inline Span NodeRef::inputs() const -{ - return inputs_; -} - -inline Span NodeRef::outputs() const -{ - return outputs_; -} - -inline Span NodeRef::sockets(const eNodeSocketInOut in_out) const -{ - return in_out == SOCK_IN ? inputs_.as_span().cast() : - outputs_.as_span().cast(); -} - -inline Span NodeRef::internal_links() const -{ - return internal_links_; -} - -inline const InputSocketRef &NodeRef::input(int index) const -{ - return *inputs_[index]; -} - -inline const OutputSocketRef &NodeRef::output(int index) const -{ - return *outputs_[index]; -} - -inline const InputSocketRef &NodeRef::input_by_identifier(StringRef identifier) const -{ - const int index = input_index_by_identifier_->lookup_as(identifier); - return this->input(index); -} - -inline const OutputSocketRef &NodeRef::output_by_identifier(StringRef identifier) const -{ - const int index = output_index_by_identifier_->lookup_as(identifier); - return this->output(index); -} - -inline bNode *NodeRef::bnode() const -{ - return bnode_; -} - -inline bNodeTree *NodeRef::btree() const -{ - return tree_->btree(); -} - -inline StringRefNull NodeRef::idname() const -{ - return bnode_->idname; -} - -inline StringRefNull NodeRef::name() const -{ - return bnode_->name; -} - -inline StringRefNull NodeRef::label() const -{ - return bnode_->label; -} - -inline StringRefNull NodeRef::label_or_name() const -{ - const StringRefNull label = this->label(); - if (!label.is_empty()) { - return label; - } - return this->name(); -} - -inline bNodeType *NodeRef::typeinfo() const -{ - return bnode_->typeinfo; -} - -/* Returns a pointer because not all nodes have declarations currently. */ -inline const NodeDeclaration *NodeRef::declaration() const -{ - nodeDeclarationEnsure(this->tree().btree(), bnode_); - return bnode_->runtime->declaration; -} - -inline int NodeRef::id() const -{ - return id_; -} - -inline bool NodeRef::is_reroute_node() const -{ - return bnode_->type == NODE_REROUTE; -} - -inline bool NodeRef::is_group_node() const -{ - return bnode_->type == NODE_GROUP || bnode_->type == NODE_CUSTOM_GROUP; -} - -inline bool NodeRef::is_group_input_node() const -{ - return bnode_->type == NODE_GROUP_INPUT; -} - -inline bool NodeRef::is_group_output_node() const -{ - return bnode_->type == NODE_GROUP_OUTPUT; -} - -inline bool NodeRef::is_frame() const -{ - return bnode_->type == NODE_FRAME; -} - -inline bool NodeRef::is_undefined() const -{ - return bnode_->typeinfo == &NodeTypeUndefined; -} - -inline bool NodeRef::is_muted() const -{ - return (bnode_->flag & NODE_MUTED) != 0; -} - -inline void *NodeRef::storage() const -{ - return bnode_->storage; -} - -template inline T *NodeRef::storage() const -{ - return (T *)bnode_->storage; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name #LinkRef Inline Methods - * \{ */ - -inline const OutputSocketRef &LinkRef::from() const -{ - return *from_; -} - -inline const InputSocketRef &LinkRef::to() const -{ - return *to_; -} - -inline bNodeLink *LinkRef::blink() const -{ - return blink_; -} - -inline bool LinkRef::is_muted() const -{ - return blink_->flag & NODE_LINK_MUTED; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name #InternalLinkRef Inline Methods - * \{ */ - -inline const InputSocketRef &InternalLinkRef::from() const -{ - return *from_; -} - -inline const OutputSocketRef &InternalLinkRef::to() const -{ - return *to_; -} - -inline bNodeLink *InternalLinkRef::blink() const -{ - return blink_; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name #NodeTreeRef Inline Methods - * \{ */ - -inline Span NodeTreeRef::nodes() const -{ - return nodes_by_id_; -} - -inline Span NodeTreeRef::nodes_by_type(StringRefNull idname) const -{ - const bNodeType *nodetype = nodeTypeFind(idname.c_str()); - return this->nodes_by_type(nodetype); -} - -inline Span NodeTreeRef::nodes_by_type(const bNodeType *nodetype) const -{ - return nodes_by_type_.lookup(nodetype); -} - -inline Span NodeTreeRef::sockets() const -{ - return sockets_by_id_; -} - -inline Span NodeTreeRef::input_sockets() const -{ - return input_sockets_; -} - -inline Span NodeTreeRef::output_sockets() const -{ - return output_sockets_; -} - -inline Span NodeTreeRef::links() const -{ - return links_; -} - -inline const NodeRef *NodeTreeRef::group_output_node() const -{ - return group_output_node_; -} - -inline bNodeTree *NodeTreeRef::btree() const -{ - return btree_; -} - -inline StringRefNull NodeTreeRef::name() const -{ - return btree_->id.name + 2; -} - -/** \} */ - -} // namespace blender::nodes diff --git a/source/blender/nodes/composite/nodes/node_composite_image.cc b/source/blender/nodes/composite/nodes/node_composite_image.cc index d8852e9333f..b6bd263b150 100644 --- a/source/blender/nodes/composite/nodes/node_composite_image.cc +++ b/source/blender/nodes/composite/nodes/node_composite_image.cc @@ -457,8 +457,8 @@ class ImageOperation : public NodeOperation { update_image_frame_number(); - for (const OutputSocketRef *output : node()->outputs()) { - compute_output(output->identifier()); + for (const bNodeSocket *output : this->node()->output_sockets()) { + compute_output(output->identifier); } } @@ -488,12 +488,12 @@ class ImageOperation : public NodeOperation { /* Allocate all needed outputs as invalid. This should be called when is_valid returns false. */ void allocate_invalid() { - for (const OutputSocketRef *output : node()->outputs()) { - if (!should_compute_output(output->identifier())) { + for (const bNodeSocket *output : this->node()->output_sockets()) { + if (!should_compute_output(output->identifier)) { continue; } - Result &result = get_result(output->identifier()); + Result &result = get_result(output->identifier); result.allocate_invalid(); } } @@ -594,7 +594,7 @@ class ImageOperation : public NodeOperation { const char *get_pass_name(StringRef identifier) { DOutputSocket output = node().output_by_identifier(identifier); - return static_cast(output->bsocket()->storage)->pass_name; + return static_cast(output->storage)->pass_name; } /* Get the index of the pass with the given name in the selected render layer's passes list @@ -850,9 +850,9 @@ class RenderLayerOperation : public NodeOperation { alpha_result.unbind_as_image(); /* Other output passes are not supported for now, so allocate them as invalid. */ - for (const OutputSocketRef *output : node()->outputs()) { - if (output->identifier() != "Image" && output->identifier() != "Alpha") { - get_result(output->identifier()).allocate_invalid(); + for (const bNodeSocket *output : this->node()->output_sockets()) { + if (!STREQ(output->identifier, "Image") && !STREQ(output->identifier, "Alpha")) { + get_result(output->identifier).allocate_invalid(); } } } diff --git a/source/blender/nodes/composite/nodes/node_composite_normal.cc b/source/blender/nodes/composite/nodes/node_composite_normal.cc index f61ace01cfd..a1a6303e21b 100644 --- a/source/blender/nodes/composite/nodes/node_composite_normal.cc +++ b/source/blender/nodes/composite/nodes/node_composite_normal.cc @@ -51,9 +51,12 @@ class NormalShaderNode : public ShaderNode { } /* The vector value is stored in the default value of the output socket. */ - float *get_vector_value() + const float *get_vector_value() { - return node().output_by_identifier("Normal")->default_value()->value; + return node() + .output_by_identifier("Normal") + ->default_value_typed() + ->value; } }; diff --git a/source/blender/nodes/function/node_function_util.hh b/source/blender/nodes/function/node_function_util.hh index fd0b6c31b1d..059b2f9bc17 100644 --- a/source/blender/nodes/function/node_function_util.hh +++ b/source/blender/nodes/function/node_function_util.hh @@ -23,4 +23,6 @@ #include "FN_multi_function_builder.hh" +#include "RNA_access.h" + void fn_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass); diff --git a/source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc b/source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc index 7d08d57c503..e5c89567d44 100644 --- a/source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc +++ b/source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc @@ -190,7 +190,7 @@ class MF_AlignEulerToVector : public fn::MultiFunction { static void fn_node_align_euler_to_vector_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &node = builder.node(); + const bNode &node = builder.node(); builder.construct_and_set_matching_fn(node.custom1, node.custom2); } diff --git a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc index b6d7e6c9a5f..5fc28509a49 100644 --- a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc +++ b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc @@ -68,7 +68,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) } } -static const fn::MultiFunction *get_multi_function(bNode &bnode) +static const fn::MultiFunction *get_multi_function(const bNode &bnode) { static auto exec_preset = fn::CustomMF_presets::AllSpanOrSingle(); static fn::CustomMF_SI_SI_SO and_fn{ diff --git a/source/blender/nodes/function/nodes/node_fn_combine_color.cc b/source/blender/nodes/function/nodes/node_fn_combine_color.cc index c5fd3ce38a1..450cd166e78 100644 --- a/source/blender/nodes/function/nodes/node_fn_combine_color.cc +++ b/source/blender/nodes/function/nodes/node_fn_combine_color.cc @@ -49,7 +49,7 @@ static void fn_node_combine_color_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static const fn::MultiFunction *get_multi_function(bNode &bnode) +static const fn::MultiFunction *get_multi_function(const bNode &bnode) { const NodeCombSepColor &storage = node_storage(bnode); diff --git a/source/blender/nodes/function/nodes/node_fn_compare.cc b/source/blender/nodes/function/nodes/node_fn_compare.cc index e3f13dc7d6b..122d1a3c93e 100644 --- a/source/blender/nodes/function/nodes/node_fn_compare.cc +++ b/source/blender/nodes/function/nodes/node_fn_compare.cc @@ -167,7 +167,7 @@ static float component_average(float3 a) return (a.x + a.y + a.z) / 3.0f; } -static const fn::MultiFunction *get_multi_function(bNode &node) +static const fn::MultiFunction *get_multi_function(const bNode &node) { const NodeFunctionCompare *data = (NodeFunctionCompare *)node.storage; diff --git a/source/blender/nodes/function/nodes/node_fn_float_to_int.cc b/source/blender/nodes/function/nodes/node_fn_float_to_int.cc index 9c9d8620a7e..aad2f532d20 100644 --- a/source/blender/nodes/function/nodes/node_fn_float_to_int.cc +++ b/source/blender/nodes/function/nodes/node_fn_float_to_int.cc @@ -39,7 +39,7 @@ static void node_float_to_int_label(const bNodeTree *UNUSED(ntree), BLI_strncpy(label, IFACE_(name), maxlen); } -static const fn::MultiFunction *get_multi_function(bNode &bnode) +static const fn::MultiFunction *get_multi_function(const bNode &bnode) { static auto exec_preset = fn::CustomMF_presets::AllSpanOrSingle(); static fn::CustomMF_SI_SO round_fn{ diff --git a/source/blender/nodes/function/nodes/node_fn_input_bool.cc b/source/blender/nodes/function/nodes/node_fn_input_bool.cc index 5ced719627f..717f4d1ac6b 100644 --- a/source/blender/nodes/function/nodes/node_fn_input_bool.cc +++ b/source/blender/nodes/function/nodes/node_fn_input_bool.cc @@ -22,7 +22,7 @@ static void fn_node_input_bool_layout(uiLayout *layout, bContext *UNUSED(C), Poi static void fn_node_input_bool_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.node(); + const bNode &bnode = builder.node(); NodeInputBool *node_storage = static_cast(bnode.storage); builder.construct_and_set_matching_fn>(node_storage->boolean); } diff --git a/source/blender/nodes/function/nodes/node_fn_input_color.cc b/source/blender/nodes/function/nodes/node_fn_input_color.cc index 46787f7575d..cdad1542c66 100644 --- a/source/blender/nodes/function/nodes/node_fn_input_color.cc +++ b/source/blender/nodes/function/nodes/node_fn_input_color.cc @@ -23,7 +23,7 @@ static void fn_node_input_color_layout(uiLayout *layout, bContext *UNUSED(C), Po static void fn_node_input_color_build_multi_function( blender::nodes::NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.node(); + const bNode &bnode = builder.node(); NodeInputColor *node_storage = static_cast(bnode.storage); blender::ColorGeometry4f color = (ColorGeometry4f)node_storage->color; builder.construct_and_set_matching_fn>(color); diff --git a/source/blender/nodes/function/nodes/node_fn_input_int.cc b/source/blender/nodes/function/nodes/node_fn_input_int.cc index 1e5dcd5ae7a..16506b5f9b8 100644 --- a/source/blender/nodes/function/nodes/node_fn_input_int.cc +++ b/source/blender/nodes/function/nodes/node_fn_input_int.cc @@ -22,7 +22,7 @@ static void fn_node_input_int_layout(uiLayout *layout, bContext *UNUSED(C), Poin static void fn_node_input_int_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.node(); + const bNode &bnode = builder.node(); NodeInputInt *node_storage = static_cast(bnode.storage); builder.construct_and_set_matching_fn>(node_storage->integer); } diff --git a/source/blender/nodes/function/nodes/node_fn_input_string.cc b/source/blender/nodes/function/nodes/node_fn_input_string.cc index 124a8572f78..129d19f4f04 100644 --- a/source/blender/nodes/function/nodes/node_fn_input_string.cc +++ b/source/blender/nodes/function/nodes/node_fn_input_string.cc @@ -20,7 +20,7 @@ static void fn_node_input_string_layout(uiLayout *layout, bContext *UNUSED(C), P static void fn_node_input_string_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.node(); + const bNode &bnode = builder.node(); NodeInputString *node_storage = static_cast(bnode.storage); std::string string = std::string((node_storage->string) ? node_storage->string : ""); builder.construct_and_set_matching_fn>(std::move(string)); diff --git a/source/blender/nodes/function/nodes/node_fn_input_vector.cc b/source/blender/nodes/function/nodes/node_fn_input_vector.cc index 898c19e92f0..de894a4038d 100644 --- a/source/blender/nodes/function/nodes/node_fn_input_vector.cc +++ b/source/blender/nodes/function/nodes/node_fn_input_vector.cc @@ -22,7 +22,7 @@ static void fn_node_input_vector_layout(uiLayout *layout, bContext *UNUSED(C), P static void fn_node_input_vector_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.node(); + const bNode &bnode = builder.node(); NodeInputVector *node_storage = static_cast(bnode.storage); float3 vector(node_storage->vector); builder.construct_and_set_matching_fn>(vector); diff --git a/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc index a4fc1a6bfd1..299c0f7a932 100644 --- a/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc +++ b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc @@ -52,7 +52,7 @@ static void fn_node_rotate_euler_layout(uiLayout *layout, bContext *UNUSED(C), P uiItemR(layout, ptr, "space", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static const fn::MultiFunction *get_multi_function(bNode &bnode) +static const fn::MultiFunction *get_multi_function(const bNode &bnode) { static fn::CustomMF_SI_SI_SO obj_euler_rot{ "Rotate Euler by Euler/Object", [](const float3 &input, const float3 &rotation) { diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh index a4af608a40e..4db4d8bb097 100644 --- a/source/blender/nodes/geometry/node_geometry_util.hh +++ b/source/blender/nodes/geometry/node_geometry_util.hh @@ -20,6 +20,8 @@ #include "NOD_socket_declarations.hh" #include "NOD_socket_declarations_geometry.hh" +#include "RNA_access.h" + #include "node_util.h" void geo_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass); diff --git a/source/blender/nodes/intern/derived_node_tree.cc b/source/blender/nodes/intern/derived_node_tree.cc index e589da09b16..e8e0f0fa61c 100644 --- a/source/blender/nodes/intern/derived_node_tree.cc +++ b/source/blender/nodes/intern/derived_node_tree.cc @@ -2,38 +2,38 @@ #include "NOD_derived_node_tree.hh" +#include "BKE_node.h" + #include "BLI_dot_export.hh" namespace blender::nodes { -DerivedNodeTree::DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs) +DerivedNodeTree::DerivedNodeTree(const bNodeTree &btree) { /* Construct all possible contexts immediately. This is significantly cheaper than inlining all * node groups. If it still becomes a performance issue in the future, contexts could be * constructed lazily when they are needed. */ - root_context_ = &this->construct_context_recursively(nullptr, nullptr, btree, node_tree_refs); + root_context_ = &this->construct_context_recursively(nullptr, nullptr, btree); } DTreeContext &DerivedNodeTree::construct_context_recursively(DTreeContext *parent_context, - const NodeRef *parent_node, - bNodeTree &btree, - NodeTreeRefMap &node_tree_refs) + const bNode *parent_node, + const bNodeTree &btree) { + btree.ensure_topology_cache(); DTreeContext &context = *allocator_.construct().release(); context.parent_context_ = parent_context; context.parent_node_ = parent_node; context.derived_tree_ = this; - context.tree_ = &get_tree_ref_from_map(node_tree_refs, btree); - used_node_tree_refs_.add(context.tree_); + context.btree_ = &btree; + used_btrees_.add(context.btree_); - for (const NodeRef *node : context.tree_->nodes()) { - if (node->is_group_node()) { - bNode *bnode = node->bnode(); + for (const bNode *bnode : context.btree_->all_nodes()) { + if (bnode->is_group()) { bNodeTree *child_btree = reinterpret_cast(bnode->id); if (child_btree != nullptr) { - DTreeContext &child = this->construct_context_recursively( - &context, node, *child_btree, node_tree_refs); - context.children_.add_new(node, &child); + DTreeContext &child = this->construct_context_recursively(&context, bnode, *child_btree); + context.children_.add_new(bnode, &child); } } } @@ -57,8 +57,8 @@ void DerivedNodeTree::destruct_context_recursively(DTreeContext *context) bool DerivedNodeTree::has_link_cycles() const { - for (const NodeTreeRef *tree_ref : used_node_tree_refs_) { - if (tree_ref->has_link_cycles()) { + for (const bNodeTree *btree : used_btrees_) { + if (btree->has_link_cycle()) { return true; } } @@ -67,8 +67,8 @@ bool DerivedNodeTree::has_link_cycles() const bool DerivedNodeTree::has_undefined_nodes_or_sockets() const { - for (const NodeTreeRef *tree_ref : used_node_tree_refs_) { - if (tree_ref->has_undefined_nodes_or_sockets()) { + for (const bNodeTree *btree : used_btrees_) { + if (btree->has_undefined_nodes_or_sockets()) { return true; } } @@ -83,8 +83,8 @@ void DerivedNodeTree::foreach_node(FunctionRef callback) const void DerivedNodeTree::foreach_node_in_context_recursive(const DTreeContext &context, FunctionRef callback) const { - for (const NodeRef *node_ref : context.tree_->nodes()) { - callback(DNode(&context, node_ref)); + for (const bNode *bnode : context.btree_->all_nodes()) { + callback(DNode(&context, bnode)); } for (const DTreeContext *child_context : context.children_.values()) { this->foreach_node_in_context_recursive(*child_context, callback); @@ -94,32 +94,32 @@ void DerivedNodeTree::foreach_node_in_context_recursive(const DTreeContext &cont DOutputSocket DInputSocket::get_corresponding_group_node_output() const { BLI_assert(*this); - BLI_assert(socket_ref_->node().is_group_output_node()); - BLI_assert(socket_ref_->index() < socket_ref_->node().inputs().size() - 1); + BLI_assert(bsocket_->owner_node().is_group_output()); + BLI_assert(bsocket_->index() < bsocket_->owner_node().input_sockets().size() - 1); const DTreeContext *parent_context = context_->parent_context(); - const NodeRef *parent_node = context_->parent_node(); + const bNode *parent_node = context_->parent_node(); BLI_assert(parent_context != nullptr); BLI_assert(parent_node != nullptr); - const int socket_index = socket_ref_->index(); - return {parent_context, &parent_node->output(socket_index)}; + const int socket_index = bsocket_->index(); + return {parent_context, &parent_node->output_socket(socket_index)}; } Vector DInputSocket::get_corresponding_group_input_sockets() const { BLI_assert(*this); - BLI_assert(socket_ref_->node().is_group_node()); + BLI_assert(bsocket_->owner_node().is_group()); - const DTreeContext *child_context = context_->child_context(socket_ref_->node()); + const DTreeContext *child_context = context_->child_context(bsocket_->owner_node()); BLI_assert(child_context != nullptr); - const NodeTreeRef &child_tree = child_context->tree(); - Span group_input_nodes = child_tree.nodes_by_type("NodeGroupInput"); - const int socket_index = socket_ref_->index(); + const bNodeTree &child_tree = child_context->btree(); + Span group_input_nodes = child_tree.nodes_by_type("NodeGroupInput"); + const int socket_index = bsocket_->index(); Vector sockets; - for (const NodeRef *group_input_node : group_input_nodes) { - sockets.append(DOutputSocket(child_context, &group_input_node->output(socket_index))); + for (const bNode *group_input_node : group_input_nodes) { + sockets.append(DOutputSocket(child_context, &group_input_node->output_socket(socket_index))); } return sockets; } @@ -127,36 +127,36 @@ Vector DInputSocket::get_corresponding_group_input_sockets() cons DInputSocket DOutputSocket::get_corresponding_group_node_input() const { BLI_assert(*this); - BLI_assert(socket_ref_->node().is_group_input_node()); - BLI_assert(socket_ref_->index() < socket_ref_->node().outputs().size() - 1); + BLI_assert(bsocket_->owner_node().is_group_input()); + BLI_assert(bsocket_->index() < bsocket_->owner_node().output_sockets().size() - 1); const DTreeContext *parent_context = context_->parent_context(); - const NodeRef *parent_node = context_->parent_node(); + const bNode *parent_node = context_->parent_node(); BLI_assert(parent_context != nullptr); BLI_assert(parent_node != nullptr); - const int socket_index = socket_ref_->index(); - return {parent_context, &parent_node->input(socket_index)}; + const int socket_index = bsocket_->index(); + return {parent_context, &parent_node->input_socket(socket_index)}; } DInputSocket DOutputSocket::get_active_corresponding_group_output_socket() const { BLI_assert(*this); - BLI_assert(socket_ref_->node().is_group_node()); + BLI_assert(bsocket_->owner_node().is_group()); - const DTreeContext *child_context = context_->child_context(socket_ref_->node()); + const DTreeContext *child_context = context_->child_context(bsocket_->owner_node()); if (child_context == nullptr) { /* Can happen when the group node references a non-existent group (e.g. when the group is * linked but the original file is not found). */ return {}; } - const NodeTreeRef &child_tree = child_context->tree(); - Span group_output_nodes = child_tree.nodes_by_type("NodeGroupOutput"); - const int socket_index = socket_ref_->index(); - for (const NodeRef *group_output_node : group_output_nodes) { - if (group_output_node->bnode()->flag & NODE_DO_OUTPUT || group_output_nodes.size() == 1) { - return {child_context, &group_output_node->input(socket_index)}; + const bNodeTree &child_tree = child_context->btree(); + Span group_output_nodes = child_tree.nodes_by_type("NodeGroupOutput"); + const int socket_index = bsocket_->index(); + for (const bNode *group_output_node : group_output_nodes) { + if (group_output_node->flag & NODE_DO_OUTPUT || group_output_nodes.size() == 1) { + return {child_context, &group_output_node->input_socket(socket_index)}; } } return {}; @@ -165,11 +165,11 @@ DInputSocket DOutputSocket::get_active_corresponding_group_output_socket() const void DInputSocket::foreach_origin_socket(FunctionRef origin_fn) const { BLI_assert(*this); - for (const OutputSocketRef *linked_socket : socket_ref_->as_input().logically_linked_sockets()) { - const NodeRef &linked_node = linked_socket->node(); + for (const bNodeSocket *linked_socket : bsocket_->logically_linked_sockets()) { + const bNode &linked_node = linked_socket->owner_node(); DOutputSocket linked_dsocket{context_, linked_socket}; - if (linked_node.is_group_input_node()) { + if (linked_node.is_group_input()) { if (context_->is_root()) { /* This is a group input in the root node group. */ origin_fn(linked_dsocket); @@ -187,7 +187,7 @@ void DInputSocket::foreach_origin_socket(FunctionRef origin_fn) c } } } - else if (linked_node.is_group_node()) { + else if (linked_node.is_group()) { DInputSocket socket_in_group = linked_dsocket.get_active_corresponding_group_output_socket(); if (socket_in_group) { if (socket_in_group->is_logically_linked()) { @@ -217,16 +217,16 @@ void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn) const void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn, TargetSocketPathInfo &path_info) const { - for (const LinkRef *link : socket_ref_->as_output().directly_linked_links()) { + for (const bNodeLink *link : bsocket_->directly_linked_links()) { if (link->is_muted()) { continue; } - const DInputSocket &linked_socket{context_, &link->to()}; + const DInputSocket &linked_socket{context_, link->tosock}; if (!linked_socket->is_available()) { continue; } const DNode linked_node = linked_socket.node(); - if (linked_node->is_reroute_node()) { + if (linked_node->is_reroute()) { const DInputSocket reroute_input = linked_socket; const DOutputSocket reroute_output = linked_node.output(0); path_info.sockets.append(reroute_input); @@ -236,18 +236,18 @@ void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn, path_info.sockets.pop_last(); } else if (linked_node->is_muted()) { - for (const InternalLinkRef *internal_link : linked_node->internal_links()) { - if (&internal_link->from() != linked_socket.socket_ref()) { + for (const bNodeLink *internal_link : linked_node->internal_links_span()) { + if (internal_link->fromsock != linked_socket.bsocket()) { continue; } /* The internal link only forwards the first incoming link. */ - if (linked_socket->is_multi_input_socket()) { + if (linked_socket->is_multi_input()) { if (linked_socket->directly_linked_links()[0] != link) { continue; } } const DInputSocket mute_input = linked_socket; - const DOutputSocket mute_output{context_, &internal_link->to()}; + const DOutputSocket mute_output{context_, internal_link->tosock}; path_info.sockets.append(mute_input); path_info.sockets.append(mute_output); mute_output.foreach_target_socket(target_fn, path_info); @@ -255,8 +255,8 @@ void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn, path_info.sockets.pop_last(); } } - else if (linked_node->is_group_output_node()) { - if (linked_node.node_ref() != context_->tree().group_output_node()) { + else if (linked_node->is_group_output()) { + if (linked_node.bnode() != context_->btree().group_output_node()) { continue; } if (context_->is_root()) { @@ -276,7 +276,7 @@ void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn, path_info.sockets.pop_last(); } } - else if (linked_node->is_group_node()) { + else if (linked_node->is_group()) { /* Follow the links within the nested node group. */ path_info.sockets.append(linked_socket); const Vector sockets_in_group = @@ -310,7 +310,8 @@ static dot::Cluster *get_dot_cluster_for_context( } dot::Cluster *parent_cluster = get_dot_cluster_for_context( digraph, parent_context, dot_clusters); - std::string cluster_name = context->tree().name() + " / " + context->parent_node()->name(); + std::string cluster_name = StringRef(context->btree().id.name + 2) + " / " + + context->parent_node()->name; dot::Cluster &cluster = digraph.new_cluster(cluster_name); cluster.set_parent_cluster(parent_cluster); return &cluster; @@ -328,11 +329,11 @@ std::string DerivedNodeTree::to_dot() const this->foreach_node([&](DNode node) { /* Ignore nodes that should not show up in the final output. */ - if (node->is_muted() || node->is_group_node() || node->is_reroute_node() || node->is_frame()) { + if (node->is_muted() || node->is_group() || node->is_reroute() || node->is_frame()) { return; } if (!node.context()->is_root()) { - if (node->is_group_input_node() || node->is_group_output_node()) { + if (node->is_group_input() || node->is_group_output()) { return; } } @@ -345,22 +346,22 @@ std::string DerivedNodeTree::to_dot() const Vector input_names; Vector output_names; - for (const InputSocketRef *socket : node->inputs()) { + for (const bNodeSocket *socket : node->input_sockets()) { if (socket->is_available()) { - input_names.append(socket->name()); + input_names.append(socket->name); } } - for (const OutputSocketRef *socket : node->outputs()) { + for (const bNodeSocket *socket : node->output_sockets()) { if (socket->is_available()) { - output_names.append(socket->name()); + output_names.append(socket->name); } } dot::NodeWithSocketsRef dot_node_with_sockets = dot::NodeWithSocketsRef( - dot_node, node->name(), input_names, output_names); + dot_node, node->name, input_names, output_names); int input_index = 0; - for (const InputSocketRef *socket : node->inputs()) { + for (const bNodeSocket *socket : node->input_sockets()) { if (socket->is_available()) { dot_input_sockets.add_new(DInputSocket{node.context(), socket}, dot_node_with_sockets.input(input_index)); @@ -368,7 +369,7 @@ std::string DerivedNodeTree::to_dot() const } } int output_index = 0; - for (const OutputSocketRef *socket : node->outputs()) { + for (const bNodeSocket *socket : node->output_sockets()) { if (socket->is_available()) { dot_output_sockets.add_new(DOutputSocket{node.context(), socket}, dot_node_with_sockets.output(output_index)); @@ -392,7 +393,7 @@ std::string DerivedNodeTree::to_dot() const } } dot::Node &dot_node = *dot_floating_inputs.lookup_or_add_cb(from_socket, [&]() { - dot::Node &dot_node = digraph.new_node(from_socket->name()); + dot::Node &dot_node = digraph.new_node(from_socket->name); dot_node.set_background_color("white"); dot_node.set_shape(dot::Attr_shape::Ellipse); dot_node.set_parent_cluster( diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc index 55930dcb1ee..89bfa5834e8 100644 --- a/source/blender/nodes/intern/geometry_nodes_eval_log.cc +++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc @@ -89,17 +89,17 @@ TreeLog &ModifierLog::lookup_or_add_tree_log(LogByTreeContext &log_by_tree_conte destruct_ptr owned_tree_log = allocator_.construct(); tree_log = owned_tree_log.get(); log_by_tree_context.add_new(&tree_context, tree_log); - parent_log.child_logs_.add_new(tree_context.parent_node()->name(), std::move(owned_tree_log)); + parent_log.child_logs_.add_new(tree_context.parent_node()->name, std::move(owned_tree_log)); return *tree_log; } NodeLog &ModifierLog::lookup_or_add_node_log(LogByTreeContext &log_by_tree_context, DNode node) { TreeLog &tree_log = this->lookup_or_add_tree_log(log_by_tree_context, *node.context()); - NodeLog &node_log = *tree_log.node_logs_.lookup_or_add_cb(node->name(), [&]() { + NodeLog &node_log = *tree_log.node_logs_.lookup_or_add_cb(node->name, [&]() { destruct_ptr node_log = allocator_.construct(); - node_log->input_logs_.resize(node->inputs().size()); - node_log->output_logs_.resize(node->outputs().size()); + node_log->input_logs_.resize(node->input_sockets().size()); + node_log->output_logs_.resize(node->output_sockets().size()); return node_log; }); return node_log; diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc index c6ebc22c43c..953dce035c2 100644 --- a/source/blender/nodes/intern/node_geometry_exec.cc +++ b/source/blender/nodes/intern/node_geometry_exec.cc @@ -38,7 +38,7 @@ void GeoNodeExecParams::check_input_geometry_set(StringRef identifier, const GeometrySet &geometry_set) const { const SocketDeclaration &decl = - *provider_->dnode->input_by_identifier(identifier).bsocket()->runtime->declaration; + *provider_->dnode->input_by_identifier(identifier).runtime->declaration; const decl::Geometry *geo_decl = dynamic_cast(&decl); if (geo_decl == nullptr) { return; @@ -118,9 +118,9 @@ void GeoNodeExecParams::check_output_geometry_set(const GeometrySet &geometry_se const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name) const { - for (const InputSocketRef *socket : provider_->dnode->inputs()) { - if (socket->is_available() && socket->name() == name) { - return socket->bsocket(); + for (const bNodeSocket *socket : provider_->dnode->runtime->inputs) { + if (socket->is_available() && socket->name == name) { + return socket; } } @@ -140,10 +140,10 @@ void GeoNodeExecParams::set_default_remaining_outputs() void GeoNodeExecParams::check_input_access(StringRef identifier, const CPPType *requested_type) const { - bNodeSocket *found_socket = nullptr; - for (const InputSocketRef *socket : provider_->dnode->inputs()) { - if (socket->identifier() == identifier) { - found_socket = socket->bsocket(); + const bNodeSocket *found_socket = nullptr; + for (const bNodeSocket *socket : provider_->dnode->input_sockets()) { + if (socket->identifier == identifier) { + found_socket = socket; break; } } @@ -151,9 +151,9 @@ void GeoNodeExecParams::check_input_access(StringRef identifier, if (found_socket == nullptr) { std::cout << "Did not find an input socket with the identifier '" << identifier << "'.\n"; std::cout << "Possible identifiers are: "; - for (const InputSocketRef *socket : provider_->dnode->inputs()) { + for (const bNodeSocket *socket : provider_->dnode->input_sockets()) { if (socket->is_available()) { - std::cout << "'" << socket->identifier() << "', "; + std::cout << "'" << socket->identifier << "', "; } } std::cout << "\n"; @@ -182,10 +182,10 @@ void GeoNodeExecParams::check_input_access(StringRef identifier, void GeoNodeExecParams::check_output_access(StringRef identifier, const CPPType &value_type) const { - bNodeSocket *found_socket = nullptr; - for (const OutputSocketRef *socket : provider_->dnode->outputs()) { - if (socket->identifier() == identifier) { - found_socket = socket->bsocket(); + const bNodeSocket *found_socket = nullptr; + for (const bNodeSocket *socket : provider_->dnode->output_sockets()) { + if (socket->identifier == identifier) { + found_socket = socket; break; } } @@ -193,9 +193,9 @@ void GeoNodeExecParams::check_output_access(StringRef identifier, const CPPType if (found_socket == nullptr) { std::cout << "Did not find an output socket with the identifier '" << identifier << "'.\n"; std::cout << "Possible identifiers are: "; - for (const OutputSocketRef *socket : provider_->dnode->outputs()) { - if (socket->is_available()) { - std::cout << "'" << socket->identifier() << "', "; + for (const bNodeSocket *socket : provider_->dnode->output_sockets()) { + if (!(socket->flag & SOCK_UNAVAIL)) { + std::cout << "'" << socket->identifier << "', "; } } std::cout << "\n"; diff --git a/source/blender/nodes/intern/node_multi_function.cc b/source/blender/nodes/intern/node_multi_function.cc index 13bfdfbfac1..1f8397923e9 100644 --- a/source/blender/nodes/intern/node_multi_function.cc +++ b/source/blender/nodes/intern/node_multi_function.cc @@ -2,14 +2,14 @@ #include "NOD_multi_function.hh" +#include "BKE_node.h" + namespace blender::nodes { NodeMultiFunctions::NodeMultiFunctions(const DerivedNodeTree &tree) { - for (const NodeTreeRef *tree_ref : tree.used_node_tree_refs()) { - bNodeTree *btree = tree_ref->btree(); - for (const NodeRef *node : tree_ref->nodes()) { - bNode *bnode = node->bnode(); + for (const bNodeTree *btree : tree.used_btrees()) { + for (const bNode *bnode : btree->all_nodes()) { if (bnode->typeinfo->build_multi_function == nullptr) { continue; } diff --git a/source/blender/nodes/intern/node_tree_ref.cc b/source/blender/nodes/intern/node_tree_ref.cc deleted file mode 100644 index 05e7fe33776..00000000000 --- a/source/blender/nodes/intern/node_tree_ref.cc +++ /dev/null @@ -1,679 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -#include - -#include "NOD_node_tree_ref.hh" - -#include "BLI_dot_export.hh" -#include "BLI_stack.hh" - -#include "RNA_prototypes.h" - -namespace blender::nodes { - -NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree) -{ - Map node_mapping; - - LISTBASE_FOREACH (bNode *, bnode, &btree->nodes) { - NodeRef &node = *allocator_.construct().release(); - - node.tree_ = this; - node.bnode_ = bnode; - node.id_ = nodes_by_id_.append_and_get_index(&node); - - LISTBASE_FOREACH (bNodeSocket *, bsocket, &bnode->inputs) { - InputSocketRef &socket = *allocator_.construct().release(); - socket.node_ = &node; - socket.index_ = node.inputs_.append_and_get_index(&socket); - socket.is_input_ = true; - socket.bsocket_ = bsocket; - socket.id_ = sockets_by_id_.append_and_get_index(&socket); - } - - LISTBASE_FOREACH (bNodeSocket *, bsocket, &bnode->outputs) { - OutputSocketRef &socket = *allocator_.construct().release(); - socket.node_ = &node; - socket.index_ = node.outputs_.append_and_get_index(&socket); - socket.is_input_ = false; - socket.bsocket_ = bsocket; - socket.id_ = sockets_by_id_.append_and_get_index(&socket); - } - - LISTBASE_FOREACH (bNodeLink *, blink, &bnode->internal_links) { - InternalLinkRef &internal_link = *allocator_.construct().release(); - internal_link.blink_ = blink; - for (InputSocketRef *socket_ref : node.inputs_) { - if (socket_ref->bsocket_ == blink->fromsock) { - internal_link.from_ = socket_ref; - break; - } - } - for (OutputSocketRef *socket_ref : node.outputs_) { - if (socket_ref->bsocket_ == blink->tosock) { - internal_link.to_ = socket_ref; - break; - } - } - BLI_assert(internal_link.from_ != nullptr); - BLI_assert(internal_link.to_ != nullptr); - node.internal_links_.append(&internal_link); - } - - input_sockets_.extend(node.inputs_.as_span()); - output_sockets_.extend(node.outputs_.as_span()); - - node_mapping.add_new(bnode, &node); - } - - LISTBASE_FOREACH (bNodeLink *, blink, &btree->links) { - OutputSocketRef &from_socket = this->find_output_socket( - node_mapping, blink->fromnode, blink->fromsock); - InputSocketRef &to_socket = this->find_input_socket( - node_mapping, blink->tonode, blink->tosock); - - LinkRef &link = *allocator_.construct().release(); - link.from_ = &from_socket; - link.to_ = &to_socket; - link.blink_ = blink; - - links_.append(&link); - - from_socket.directly_linked_links_.append(&link); - to_socket.directly_linked_links_.append(&link); - } - - for (InputSocketRef *input_socket : input_sockets_) { - if (input_socket->is_multi_input_socket()) { - std::sort(input_socket->directly_linked_links_.begin(), - input_socket->directly_linked_links_.end(), - [&](const LinkRef *a, const LinkRef *b) -> bool { - int index_a = a->blink()->multi_input_socket_index; - int index_b = b->blink()->multi_input_socket_index; - return index_a > index_b; - }); - } - } - - this->create_socket_identifier_maps(); - this->create_linked_socket_caches(); - - for (NodeRef *node : nodes_by_id_) { - const bNodeType *nodetype = node->bnode_->typeinfo; - nodes_by_type_.add(nodetype, node); - } - - const Span group_output_nodes = this->nodes_by_type("NodeGroupOutput"); - if (group_output_nodes.is_empty()) { - group_output_node_ = nullptr; - } - else if (group_output_nodes.size() == 1) { - group_output_node_ = group_output_nodes.first(); - } - else { - for (const NodeRef *group_output : group_output_nodes) { - if (group_output->bnode_->flag & NODE_DO_OUTPUT) { - group_output_node_ = group_output; - break; - } - } - } -} - -NodeTreeRef::~NodeTreeRef() -{ - /* The destructor has to be called manually, because these types are allocated in a linear - * allocator. */ - for (NodeRef *node : nodes_by_id_) { - node->~NodeRef(); - } - for (InputSocketRef *socket : input_sockets_) { - socket->~InputSocketRef(); - } - for (OutputSocketRef *socket : output_sockets_) { - socket->~OutputSocketRef(); - } - for (LinkRef *link : links_) { - link->~LinkRef(); - } -} - -InputSocketRef &NodeTreeRef::find_input_socket(Map &node_mapping, - bNode *bnode, - bNodeSocket *bsocket) -{ - NodeRef *node = node_mapping.lookup(bnode); - for (InputSocketRef *socket : node->inputs_) { - if (socket->bsocket_ == bsocket) { - return *socket; - } - } - BLI_assert_unreachable(); - return *node->inputs_[0]; -} - -OutputSocketRef &NodeTreeRef::find_output_socket(Map &node_mapping, - bNode *bnode, - bNodeSocket *bsocket) -{ - NodeRef *node = node_mapping.lookup(bnode); - for (OutputSocketRef *socket : node->outputs_) { - if (socket->bsocket_ == bsocket) { - return *socket; - } - } - BLI_assert_unreachable(); - return *node->outputs_[0]; -} - -void NodeTreeRef::create_linked_socket_caches() -{ - for (InputSocketRef *socket : input_sockets_) { - /* Find directly linked socket based on incident links. */ - Vector directly_linked_sockets; - for (LinkRef *link : socket->directly_linked_links_) { - directly_linked_sockets.append(link->from_); - } - socket->directly_linked_sockets_ = allocator_.construct_array_copy( - directly_linked_sockets.as_span()); - - /* Find logically linked sockets. */ - Vector logically_linked_sockets; - Vector logically_linked_skipped_sockets; - Vector seen_sockets_stack; - socket->foreach_logical_origin( - [&](const OutputSocketRef &origin) { logically_linked_sockets.append(&origin); }, - [&](const SocketRef &socket) { logically_linked_skipped_sockets.append(&socket); }, - false, - seen_sockets_stack); - if (logically_linked_sockets == directly_linked_sockets) { - socket->logically_linked_sockets_ = socket->directly_linked_sockets_; - } - else { - socket->logically_linked_sockets_ = allocator_.construct_array_copy( - logically_linked_sockets.as_span()); - } - socket->logically_linked_skipped_sockets_ = allocator_.construct_array_copy( - logically_linked_skipped_sockets.as_span()); - } - - for (OutputSocketRef *socket : output_sockets_) { - /* Find directly linked socket based on incident links. */ - Vector directly_linked_sockets; - for (LinkRef *link : socket->directly_linked_links_) { - directly_linked_sockets.append(link->to_); - } - socket->directly_linked_sockets_ = allocator_.construct_array_copy( - directly_linked_sockets.as_span()); - - /* Find logically linked sockets. */ - Vector logically_linked_sockets; - Vector logically_linked_skipped_sockets; - Vector handled_sockets; - socket->foreach_logical_target( - [&](const InputSocketRef &target) { logically_linked_sockets.append(&target); }, - [&](const SocketRef &socket) { logically_linked_skipped_sockets.append(&socket); }, - handled_sockets); - if (logically_linked_sockets == directly_linked_sockets) { - socket->logically_linked_sockets_ = socket->directly_linked_sockets_; - } - else { - socket->logically_linked_sockets_ = allocator_.construct_array_copy( - logically_linked_sockets.as_span()); - } - socket->logically_linked_skipped_sockets_ = allocator_.construct_array_copy( - logically_linked_skipped_sockets.as_span()); - } -} - -void InputSocketRef::foreach_logical_origin( - FunctionRef origin_fn, - FunctionRef skipped_fn, - bool only_follow_first_input_link, - Vector &seen_sockets_stack) const -{ - /* Protect against loops. */ - if (seen_sockets_stack.contains(this)) { - return; - } - seen_sockets_stack.append(this); - - Span links_to_check = this->directly_linked_links(); - if (only_follow_first_input_link) { - links_to_check = links_to_check.take_front(1); - } - for (const LinkRef *link : links_to_check) { - if (link->is_muted()) { - continue; - } - const OutputSocketRef &origin = link->from(); - const NodeRef &origin_node = origin.node(); - if (!origin.is_available()) { - /* Non available sockets are ignored. */ - } - else if (origin_node.is_reroute_node()) { - const InputSocketRef &reroute_input = origin_node.input(0); - const OutputSocketRef &reroute_output = origin_node.output(0); - skipped_fn.call_safe(reroute_input); - skipped_fn.call_safe(reroute_output); - reroute_input.foreach_logical_origin(origin_fn, skipped_fn, false, seen_sockets_stack); - } - else if (origin_node.is_muted()) { - for (const InternalLinkRef *internal_link : origin_node.internal_links()) { - if (&internal_link->to() == &origin) { - const InputSocketRef &mute_input = internal_link->from(); - skipped_fn.call_safe(origin); - skipped_fn.call_safe(mute_input); - mute_input.foreach_logical_origin(origin_fn, skipped_fn, true, seen_sockets_stack); - } - } - } - else { - origin_fn(origin); - } - } - - seen_sockets_stack.pop_last(); -} - -void OutputSocketRef::foreach_logical_target( - FunctionRef target_fn, - FunctionRef skipped_fn, - Vector &seen_sockets_stack) const -{ - /* Protect against loops. */ - if (seen_sockets_stack.contains(this)) { - return; - } - seen_sockets_stack.append(this); - - for (const LinkRef *link : this->directly_linked_links()) { - if (link->is_muted()) { - continue; - } - const InputSocketRef &target = link->to(); - const NodeRef &target_node = target.node(); - if (!target.is_available()) { - /* Non available sockets are ignored. */ - } - else if (target_node.is_reroute_node()) { - const OutputSocketRef &reroute_output = target_node.output(0); - skipped_fn.call_safe(target); - skipped_fn.call_safe(reroute_output); - reroute_output.foreach_logical_target(target_fn, skipped_fn, seen_sockets_stack); - } - else if (target_node.is_muted()) { - skipped_fn.call_safe(target); - for (const InternalLinkRef *internal_link : target_node.internal_links()) { - if (&internal_link->from() == &target) { - /* The internal link only forwards the first incoming link. */ - if (target.is_multi_input_socket()) { - if (target.directly_linked_links()[0] != link) { - continue; - } - } - const OutputSocketRef &mute_output = internal_link->to(); - skipped_fn.call_safe(target); - skipped_fn.call_safe(mute_output); - mute_output.foreach_logical_target(target_fn, skipped_fn, seen_sockets_stack); - } - } - } - else { - target_fn(target); - } - } - - seen_sockets_stack.pop_last(); -} - -namespace { -struct SocketByIdentifierMap { - SocketIndexByIdentifierMap *map = nullptr; - std::unique_ptr owned_map; -}; -} // namespace - -static std::unique_ptr create_identifier_map(const ListBase &sockets) -{ - std::unique_ptr map = std::make_unique(); - int index; - LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &sockets, index) { - map->add_new(socket->identifier, index); - } - return map; -} - -/* This function is not threadsafe. */ -static SocketByIdentifierMap get_or_create_identifier_map( - const bNode &node, const ListBase &sockets, const bNodeSocketTemplate *sockets_template) -{ - SocketByIdentifierMap map; - if (sockets_template == nullptr) { - if (BLI_listbase_is_empty(&sockets)) { - static SocketIndexByIdentifierMap empty_map; - map.map = &empty_map; - } - else if (node.type == NODE_REROUTE) { - if (&node.inputs == &sockets) { - static SocketIndexByIdentifierMap reroute_input_map = [] { - SocketIndexByIdentifierMap map; - map.add_new("Input", 0); - return map; - }(); - map.map = &reroute_input_map; - } - else { - static SocketIndexByIdentifierMap reroute_output_map = [] { - SocketIndexByIdentifierMap map; - map.add_new("Output", 0); - return map; - }(); - map.map = &reroute_output_map; - } - } - else { - /* The node has a dynamic amount of sockets. Therefore we need to create a new map. */ - map.owned_map = create_identifier_map(sockets); - map.map = &*map.owned_map; - } - } - else { - /* Cache only one map for nodes that have the same sockets. */ - static Map> maps; - map.map = &*maps.lookup_or_add_cb(sockets_template, - [&]() { return create_identifier_map(sockets); }); - } - return map; -} - -void NodeTreeRef::create_socket_identifier_maps() -{ - /* `get_or_create_identifier_map` is not threadsafe, therefore we have to hold a lock here. */ - static std::mutex mutex; - std::lock_guard lock{mutex}; - - for (NodeRef *node : nodes_by_id_) { - bNode &bnode = *node->bnode_; - SocketByIdentifierMap inputs_map = get_or_create_identifier_map( - bnode, bnode.inputs, bnode.typeinfo->inputs); - SocketByIdentifierMap outputs_map = get_or_create_identifier_map( - bnode, bnode.outputs, bnode.typeinfo->outputs); - node->input_index_by_identifier_ = inputs_map.map; - node->output_index_by_identifier_ = outputs_map.map; - if (inputs_map.owned_map) { - owned_identifier_maps_.append(std::move(inputs_map.owned_map)); - } - if (outputs_map.owned_map) { - owned_identifier_maps_.append(std::move(outputs_map.owned_map)); - } - } -} - -static bool has_link_cycles_recursive(const NodeRef &node, - MutableSpan visited, - MutableSpan is_in_stack) -{ - const int node_id = node.id(); - if (is_in_stack[node_id]) { - return true; - } - if (visited[node_id]) { - return false; - } - - visited[node_id] = true; - is_in_stack[node_id] = true; - - for (const OutputSocketRef *from_socket : node.outputs()) { - if (!from_socket->is_available()) { - continue; - } - for (const InputSocketRef *to_socket : from_socket->directly_linked_sockets()) { - if (!to_socket->is_available()) { - continue; - } - const NodeRef &to_node = to_socket->node(); - if (has_link_cycles_recursive(to_node, visited, is_in_stack)) { - return true; - } - } - } - - is_in_stack[node_id] = false; - return false; -} - -bool NodeTreeRef::has_link_cycles() const -{ - const int node_amount = nodes_by_id_.size(); - Array visited(node_amount, false); - Array is_in_stack(node_amount, false); - - for (const NodeRef *node : nodes_by_id_) { - if (has_link_cycles_recursive(*node, visited, is_in_stack)) { - return true; - } - } - return false; -} - -bool NodeTreeRef::has_undefined_nodes_or_sockets() const -{ - for (const NodeRef *node : nodes_by_id_) { - if (node->is_undefined()) { - return true; - } - } - for (const SocketRef *socket : sockets_by_id_) { - if (socket->is_undefined()) { - return true; - } - } - return false; -} - -bool NodeRef::any_input_is_directly_linked() const -{ - for (const SocketRef *socket : inputs_) { - if (!socket->directly_linked_sockets().is_empty()) { - return true; - } - } - return false; -} - -bool NodeRef::any_output_is_directly_linked() const -{ - for (const SocketRef *socket : outputs_) { - if (!socket->directly_linked_sockets().is_empty()) { - return true; - } - } - return false; -} - -bool NodeRef::any_socket_is_directly_linked(eNodeSocketInOut in_out) const -{ - if (in_out == SOCK_IN) { - return this->any_input_is_directly_linked(); - } - return this->any_output_is_directly_linked(); -} - -struct ToposortNodeState { - bool is_done = false; - bool is_in_stack = false; -}; - -static void toposort_from_start_node(const NodeTreeRef::ToposortDirection direction, - const NodeRef &start_node, - MutableSpan node_states, - NodeTreeRef::ToposortResult &result) -{ - struct Item { - const NodeRef *node; - /* Index of the next socket that is checked in the depth-first search. */ - int socket_index = 0; - /* Link index in the next socket that is checked in the depth-first search. */ - int link_index = 0; - }; - - /* Do a depth-first search to sort nodes topologically. */ - Stack nodes_to_check; - nodes_to_check.push({&start_node}); - node_states[start_node.id()].is_in_stack = true; - while (!nodes_to_check.is_empty()) { - Item &item = nodes_to_check.peek(); - const NodeRef &node = *item.node; - const Span sockets = node.sockets( - direction == NodeTreeRef::ToposortDirection::LeftToRight ? SOCK_IN : SOCK_OUT); - - while (true) { - if (item.socket_index == sockets.size()) { - /* All sockets have already been visited. */ - break; - } - const SocketRef &socket = *sockets[item.socket_index]; - const Span linked_sockets = socket.directly_linked_sockets(); - if (item.link_index == linked_sockets.size()) { - /* All links connected to this socket have already been visited. */ - item.socket_index++; - item.link_index = 0; - continue; - } - const SocketRef &linked_socket = *linked_sockets[item.link_index]; - const NodeRef &linked_node = linked_socket.node(); - ToposortNodeState &linked_node_state = node_states[linked_node.id()]; - if (linked_node_state.is_done) { - /* The linked node has already been visited. */ - item.link_index++; - continue; - } - if (linked_node_state.is_in_stack) { - result.has_cycle = true; - } - else { - nodes_to_check.push({&linked_node}); - linked_node_state.is_in_stack = true; - } - break; - } - - /* If no other element has been pushed, the current node can be pushed to the sorted list. */ - if (&item == &nodes_to_check.peek()) { - ToposortNodeState &node_state = node_states[node.id()]; - node_state.is_done = true; - node_state.is_in_stack = false; - result.sorted_nodes.append(&node); - nodes_to_check.pop(); - } - } -} - -NodeTreeRef::ToposortResult NodeTreeRef::toposort(const ToposortDirection direction) const -{ - ToposortResult result; - result.sorted_nodes.reserve(nodes_by_id_.size()); - - Array node_states(nodes_by_id_.size()); - - for (const NodeRef *node : nodes_by_id_) { - if (node_states[node->id()].is_done) { - /* Ignore nodes that are done already. */ - continue; - } - if (node->any_socket_is_directly_linked( - direction == ToposortDirection::LeftToRight ? SOCK_OUT : SOCK_IN)) { - /* Ignore non-start nodes. */ - continue; - } - - toposort_from_start_node(direction, *node, node_states, result); - } - - /* Check if the loop above forgot some nodes because there is a cycle. */ - if (result.sorted_nodes.size() < nodes_by_id_.size()) { - result.has_cycle = true; - for (const NodeRef *node : nodes_by_id_) { - if (node_states[node->id()].is_done) { - /* Ignore nodes that are done already. */ - continue; - } - /* Start toposort at this node which is somewhere in the middle of a loop. */ - toposort_from_start_node(direction, *node, node_states, result); - } - } - - BLI_assert(result.sorted_nodes.size() == nodes_by_id_.size()); - return result; -} - -const NodeRef *NodeTreeRef::find_node(const bNode &bnode) const -{ - for (const NodeRef *node : this->nodes_by_type(bnode.typeinfo)) { - if (node->bnode_ == &bnode) { - return node; - } - } - return nullptr; -} - -std::string NodeTreeRef::to_dot() const -{ - dot::DirectedGraph digraph; - digraph.set_rankdir(dot::Attr_rankdir::LeftToRight); - - Map dot_nodes; - - for (const NodeRef *node : nodes_by_id_) { - dot::Node &dot_node = digraph.new_node(""); - dot_node.set_background_color("white"); - - Vector input_names; - Vector output_names; - for (const InputSocketRef *socket : node->inputs()) { - input_names.append(socket->name()); - } - for (const OutputSocketRef *socket : node->outputs()) { - output_names.append(socket->name()); - } - - dot_nodes.add_new(node, - dot::NodeWithSocketsRef(dot_node, node->name(), input_names, output_names)); - } - - for (const OutputSocketRef *from_socket : output_sockets_) { - for (const InputSocketRef *to_socket : from_socket->directly_linked_sockets()) { - dot::NodeWithSocketsRef &from_dot_node = dot_nodes.lookup(&from_socket->node()); - dot::NodeWithSocketsRef &to_dot_node = dot_nodes.lookup(&to_socket->node()); - - digraph.new_edge(from_dot_node.output(from_socket->index()), - to_dot_node.input(to_socket->index())); - } - } - - return digraph.to_dot_string(); -} - -const NodeTreeRef &get_tree_ref_from_map(NodeTreeRefMap &node_tree_refs, bNodeTree &btree) -{ - return *node_tree_refs.lookup_or_add_cb(&btree, - [&]() { return std::make_unique(&btree); }); -} - -PointerRNA NodeRef::rna() const -{ - PointerRNA rna; - RNA_pointer_create(&tree_->btree()->id, &RNA_Node, bnode_, &rna); - return rna; -} - -PointerRNA SocketRef::rna() const -{ - PointerRNA rna; - RNA_pointer_create(&this->tree().btree()->id, &RNA_NodeSocket, bsocket_, &rna); - return rna; -} - -} // namespace blender::nodes diff --git a/source/blender/nodes/shader/node_shader_util.hh b/source/blender/nodes/shader/node_shader_util.hh index d5f54d9cac9..38220634695 100644 --- a/source/blender/nodes/shader/node_shader_util.hh +++ b/source/blender/nodes/shader/node_shader_util.hh @@ -59,6 +59,8 @@ #include "RE_pipeline.h" #include "RE_texture.h" +#include "RNA_access.h" + bool sh_node_poll_default(struct bNodeType *ntype, struct bNodeTree *ntree, const char **r_disabled_hint); diff --git a/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc b/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc index 3723480ffa3..d73ffd89288 100644 --- a/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc +++ b/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc @@ -125,7 +125,7 @@ class ColorBandFunction : public fn::MultiFunction { static void sh_node_valtorgb_build_multi_function(nodes::NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.node(); + const bNode &bnode = builder.node(); const ColorBand *color_band = (const ColorBand *)bnode.storage; builder.construct_and_set_matching_fn(*color_band); } diff --git a/source/blender/nodes/shader/nodes/node_shader_curves.cc b/source/blender/nodes/shader/nodes/node_shader_curves.cc index eb47059063d..4725aef5991 100644 --- a/source/blender/nodes/shader/nodes/node_shader_curves.cc +++ b/source/blender/nodes/shader/nodes/node_shader_curves.cc @@ -95,7 +95,7 @@ class CurveVecFunction : public fn::MultiFunction { static void sh_node_curve_vec_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.node(); + const bNode &bnode = builder.node(); CurveMapping *cumap = (CurveMapping *)bnode.storage; BKE_curvemapping_init(cumap); builder.construct_and_set_matching_fn(*cumap); @@ -237,7 +237,7 @@ class CurveRGBFunction : public fn::MultiFunction { static void sh_node_curve_rgb_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.node(); + const bNode &bnode = builder.node(); CurveMapping *cumap = (CurveMapping *)bnode.storage; BKE_curvemapping_init(cumap); builder.construct_and_set_matching_fn(*cumap); @@ -356,7 +356,7 @@ class CurveFloatFunction : public fn::MultiFunction { static void sh_node_curve_float_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.node(); + const bNode &bnode = builder.node(); CurveMapping *cumap = (CurveMapping *)bnode.storage; BKE_curvemapping_init(cumap); builder.construct_and_set_matching_fn(*cumap); diff --git a/source/blender/nodes/shader/nodes/node_shader_math.cc b/source/blender/nodes/shader/nodes/node_shader_math.cc index 73ee6fb3f85..bd83f8dac37 100644 --- a/source/blender/nodes/shader/nodes/node_shader_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_math.cc @@ -102,7 +102,7 @@ static int gpu_shader_math(GPUMaterial *mat, return 0; } -static const fn::MultiFunction *get_base_multi_function(bNode &node) +static const fn::MultiFunction *get_base_multi_function(const bNode &node) { const int mode = node.custom1; const fn::MultiFunction *base_fn = nullptr; diff --git a/source/blender/nodes/shader/nodes/node_shader_mix.cc b/source/blender/nodes/shader/nodes/node_shader_mix.cc index 05aad262af8..918d9b747d5 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mix.cc +++ b/source/blender/nodes/shader/nodes/node_shader_mix.cc @@ -344,7 +344,7 @@ class MixColorFunction : public fn::MultiFunction { } }; -static const fn::MultiFunction *get_multi_function(bNode &node) +static const fn::MultiFunction *get_multi_function(const bNode &node) { const NodeShaderMix *data = (NodeShaderMix *)node.storage; bool uniform_factor = data->factor_mode == NODE_MIX_MODE_UNIFORM; diff --git a/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc index edbded43acf..46ac8f05803 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc +++ b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc @@ -136,7 +136,7 @@ class MixRGBFunction : public fn::MultiFunction { static void sh_node_mix_rgb_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &node = builder.node(); + const bNode &node = builder.node(); bool clamp = node.custom2 & SHD_MIXRGB_CLAMP; int mix_type = node.custom1; builder.construct_and_set_matching_fn(clamp, mix_type); diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc b/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc index cad9e1b33f2..a1c51a440d0 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc @@ -261,7 +261,7 @@ class BrickFunction : public fn::MultiFunction { static void sh_node_brick_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &node = builder.node(); + const bNode &node = builder.node(); NodeTexBrick *tex = (NodeTexBrick *)node.storage; builder.construct_and_set_matching_fn( diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc index 8478cbd406b..37c72ec1f17 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc @@ -139,7 +139,7 @@ class GradientFunction : public fn::MultiFunction { static void sh_node_gradient_tex_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &node = builder.node(); + const bNode &node = builder.node(); NodeTexGradient *tex = (NodeTexGradient *)node.storage; builder.construct_and_set_matching_fn(tex->gradient_type); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc b/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc index 95c4a8b8e46..205d3b89016 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc @@ -161,7 +161,7 @@ class MagicFunction : public fn::MultiFunction { static void sh_node_magic_tex_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &node = builder.node(); + const bNode &node = builder.node(); NodeTexMagic *tex = (NodeTexMagic *)node.storage; builder.construct_and_set_matching_fn(tex->depth); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc index c13ce3c3df3..a2241c2327f 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc @@ -516,7 +516,7 @@ class MusgraveFunction : public fn::MultiFunction { static void sh_node_musgrave_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &node = builder.node(); + const bNode &node = builder.node(); NodeTexMusgrave *tex = (NodeTexMusgrave *)node.storage; builder.construct_and_set_matching_fn(tex->dimensions, tex->musgrave_type); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc b/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc index ad24224dc7f..8475101dbaf 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc @@ -206,7 +206,7 @@ class WaveFunction : public fn::MultiFunction { static void sh_node_wave_tex_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &node = builder.node(); + const bNode &node = builder.node(); NodeTexWave *tex = (NodeTexWave *)node.storage; builder.construct_and_set_matching_fn( tex->wave_type, tex->bands_direction, tex->rings_direction, tex->wave_profile); diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc index 6d4c491046b..64075a903ab 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc @@ -176,7 +176,7 @@ class WhiteNoiseFunction : public fn::MultiFunction { static void sh_node_noise_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &node = builder.node(); + const bNode &node = builder.node(); builder.construct_and_set_matching_fn((int)node.custom1); } diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc index 21f5c44c640..d01e03f9d71 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc @@ -225,7 +225,7 @@ static void node_shader_update_vector_math(bNodeTree *ntree, bNode *node) } } -static const fn::MultiFunction *get_multi_function(bNode &node) +static const fn::MultiFunction *get_multi_function(const bNode &node) { NodeVectorMathOperation operation = NodeVectorMathOperation(node.custom1); diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc index b35f686e331..a036fc52d84 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc @@ -96,7 +96,7 @@ static float3 sh_node_vector_rotate_euler(const float3 &vector, return result + center; } -static const fn::MultiFunction *get_multi_function(bNode &node) +static const fn::MultiFunction *get_multi_function(const bNode &node) { bool invert = node.custom2; const int mode = node.custom1; -- cgit v1.2.3