Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Lucke <jacques@blender.org>2021-08-20 14:14:39 +0300
committerJacques Lucke <jacques@blender.org>2021-08-20 14:14:39 +0300
commit00812008129bdab48d328775b09332af12118867 (patch)
tree344723847c164ce75f9f4cff22991ce69678b57c
parent7d8c71e8003ecb4d3a7fe2483a328d3f2d184faa (diff)
Functions: remove multi-function network
The multi-function network system was able to compose multiple multi-functions into a new one and to evaluate that efficiently. This functionality was heavily used by the particle nodes prototype a year ago. However, since then we only used multi-functions without the need to compose them in geometry nodes. The upcoming "fields" in geometry nodes will need a way to compose multi-functions again. Unfortunately, the code removed in this commit was not ideal for this different kind of function composition. I've been working on an alternative that will be added separately when it becomes needed. I've had to update all the function nodes, because their interface depended on the multi-function network data structure a bit. The actual multi-function implementations are still the same though.
-rw-r--r--source/blender/blenkernel/BKE_node.h15
-rw-r--r--source/blender/blenkernel/intern/simulation.cc4
-rw-r--r--source/blender/functions/CMakeLists.txt7
-rw-r--r--source/blender/functions/FN_generic_virtual_array.hh2
-rw-r--r--source/blender/functions/FN_multi_function_network.hh536
-rw-r--r--source/blender/functions/FN_multi_function_network_evaluation.hh62
-rw-r--r--source/blender/functions/FN_multi_function_network_optimization.hh29
-rw-r--r--source/blender/functions/FN_multi_function_signature.hh15
-rw-r--r--source/blender/functions/intern/multi_function_network.cc330
-rw-r--r--source/blender/functions/intern/multi_function_network_evaluation.cc1083
-rw-r--r--source/blender/functions/intern/multi_function_network_optimization.cc501
-rw-r--r--source/blender/functions/tests/FN_multi_function_network_test.cc280
-rw-r--r--source/blender/functions/tests/FN_multi_function_test.cc92
-rw-r--r--source/blender/functions/tests/FN_multi_function_test_common.hh174
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc5
-rw-r--r--source/blender/modifiers/intern/MOD_nodes_evaluator.cc2
-rw-r--r--source/blender/modifiers/intern/MOD_nodes_evaluator.hh6
-rw-r--r--source/blender/nodes/CMakeLists.txt6
-rw-r--r--source/blender/nodes/NOD_multi_function.hh130
-rw-r--r--source/blender/nodes/NOD_node_tree_multi_function.hh390
-rw-r--r--source/blender/nodes/function/node_function_util.hh2
-rw-r--r--source/blender/nodes/function/nodes/node_fn_boolean_math.cc19
-rw-r--r--source/blender/nodes/function/nodes/node_fn_float_compare.cc25
-rw-r--r--source/blender/nodes/function/nodes/node_fn_float_to_int.cc19
-rw-r--r--source/blender/nodes/function/nodes/node_fn_input_string.cc12
-rw-r--r--source/blender/nodes/function/nodes/node_fn_input_vector.cc10
-rw-r--r--source/blender/nodes/function/nodes/node_fn_random_float.cc9
-rw-r--r--source/blender/nodes/intern/node_geometry_exec.cc1
-rw-r--r--source/blender/nodes/intern/node_multi_function.cc (renamed from source/blender/nodes/NOD_type_callbacks.hh)32
-rw-r--r--source/blender/nodes/intern/node_socket.cc1
-rw-r--r--source/blender/nodes/intern/node_tree_multi_function.cc409
-rw-r--r--source/blender/nodes/intern/type_callbacks.cc60
-rw-r--r--source/blender/nodes/shader/node_shader_util.h2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_clamp.cc6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_curves.cc14
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_map_range.cc8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_math.cc67
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mixRgb.cc6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_valToRgb.cc7
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_value.cc6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_math.cc28
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc37
44 files changed, 513 insertions, 3952 deletions
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index caa7ab6de0a..c4393246926 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -111,8 +111,7 @@ typedef struct bNodeSocketTemplate {
#ifdef __cplusplus
namespace blender {
namespace nodes {
-class SocketMFNetworkBuilder;
-class NodeMFNetworkBuilder;
+class NodeMultiFunctionBuilder;
class GeoNodeExecParams;
} // namespace nodes
namespace fn {
@@ -121,18 +120,16 @@ class MFDataType;
} // namespace fn
} // namespace blender
-using NodeExpandInMFNetworkFunction = void (*)(blender::nodes::NodeMFNetworkBuilder &builder);
+using NodeMultiFunctionBuildFunction = void (*)(blender::nodes::NodeMultiFunctionBuilder &builder);
using NodeGeometryExecFunction = void (*)(blender::nodes::GeoNodeExecParams params);
using SocketGetCPPTypeFunction = const blender::fn::CPPType *(*)();
using SocketGetCPPValueFunction = void (*)(const struct bNodeSocket &socket, void *r_value);
using SocketGetGeometryNodesCPPTypeFunction = const blender::fn::CPPType *(*)();
using SocketGetGeometryNodesCPPValueFunction = void (*)(const struct bNodeSocket &socket,
void *r_value);
-using SocketExpandInMFNetworkFunction = void (*)(blender::nodes::SocketMFNetworkBuilder &builder);
#else
-typedef void *NodeExpandInMFNetworkFunction;
-typedef void *SocketExpandInMFNetworkFunction;
+typedef void *NodeMultiFunctionBuildFunction;
typedef void *NodeGeometryExecFunction;
typedef void *SocketGetCPPTypeFunction;
typedef void *SocketGetGeometryNodesCPPTypeFunction;
@@ -196,8 +193,6 @@ typedef struct bNodeSocketType {
/* Callback to free the socket type. */
void (*free_self)(struct bNodeSocketType *stype);
- /* Expands the socket into a multi-function node that outputs the socket value. */
- SocketExpandInMFNetworkFunction expand_in_mf_network;
/* Return the CPPType of this socket. */
SocketGetCPPTypeFunction get_base_cpp_type;
/* Get the value of this socket in a generic way. */
@@ -332,8 +327,8 @@ typedef struct bNodeType {
/* gpu */
NodeGPUExecFunction gpu_fn;
- /* Expands the bNode into nodes in a multi-function network, which will be evaluated later on. */
- NodeExpandInMFNetworkFunction expand_in_mf_network;
+ /* Build a multi-function for this node. */
+ NodeMultiFunctionBuildFunction build_multi_function;
/* Execute a geometry node. */
NodeGeometryExecFunction geometry_node_execute;
diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc
index 5aac29c19a7..4c97ccdf8b1 100644
--- a/source/blender/blenkernel/intern/simulation.cc
+++ b/source/blender/blenkernel/intern/simulation.cc
@@ -49,14 +49,10 @@
#include "BKE_simulation.h"
#include "NOD_geometry.h"
-#include "NOD_node_tree_multi_function.hh"
#include "BLI_map.hh"
#include "BLT_translation.h"
-#include "FN_multi_function_network_evaluation.hh"
-#include "FN_multi_function_network_optimization.hh"
-
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
diff --git a/source/blender/functions/CMakeLists.txt b/source/blender/functions/CMakeLists.txt
index 809294ad274..f8d2acc74a8 100644
--- a/source/blender/functions/CMakeLists.txt
+++ b/source/blender/functions/CMakeLists.txt
@@ -33,9 +33,6 @@ set(SRC
intern/generic_virtual_vector_array.cc
intern/multi_function.cc
intern/multi_function_builder.cc
- intern/multi_function_network.cc
- intern/multi_function_network_evaluation.cc
- intern/multi_function_network_optimization.cc
FN_cpp_type.hh
FN_cpp_type_make.hh
@@ -49,9 +46,6 @@ set(SRC
FN_multi_function_builder.hh
FN_multi_function_context.hh
FN_multi_function_data_type.hh
- FN_multi_function_network.hh
- FN_multi_function_network_evaluation.hh
- FN_multi_function_network_optimization.hh
FN_multi_function_param_type.hh
FN_multi_function_params.hh
FN_multi_function_signature.hh
@@ -68,7 +62,6 @@ if(WITH_GTESTS)
tests/FN_cpp_type_test.cc
tests/FN_generic_span_test.cc
tests/FN_generic_vector_array_test.cc
- tests/FN_multi_function_network_test.cc
tests/FN_multi_function_test.cc
)
set(TEST_LIB
diff --git a/source/blender/functions/FN_generic_virtual_array.hh b/source/blender/functions/FN_generic_virtual_array.hh
index c9398ceb547..f429243e2de 100644
--- a/source/blender/functions/FN_generic_virtual_array.hh
+++ b/source/blender/functions/FN_generic_virtual_array.hh
@@ -129,7 +129,7 @@ class GVArray {
}
/* Same as `get_internal_single`, but `r_value` points to initialized memory. */
- void get_single_to_uninitialized(void *r_value) const
+ void get_internal_single_to_uninitialized(void *r_value) const
{
type_->default_construct(r_value);
this->get_internal_single(r_value);
diff --git a/source/blender/functions/FN_multi_function_network.hh b/source/blender/functions/FN_multi_function_network.hh
deleted file mode 100644
index b303589106a..00000000000
--- a/source/blender/functions/FN_multi_function_network.hh
+++ /dev/null
@@ -1,536 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#pragma once
-
-/** \file
- * \ingroup fn
- *
- * A multi-function network (`MFNetwork`) allows you to connect multiple multi-functions. The
- * `MFNetworkEvaluator` is a multi-function that wraps an entire network into a new multi-function
- * (which can be used in another network and so on).
- *
- * A MFNetwork is a graph data structure with two kinds of nodes:
- * - MFFunctionNode: Represents a multi-function. Its input and output sockets correspond to
- * parameters of the referenced multi-function.
- * - MFDummyNode: Does not reference a multi-function. Instead it just has sockets that can be
- * used to represent node group inputs and outputs.
- *
- * Links represent data flow. Unlinked input sockets have no value. In order to execute a function
- * node, all its inputs have to be connected to something.
- *
- * Links are only allowed between sockets with the exact same MFDataType. There are no implicit
- * conversions.
- *
- * Every input and output parameter of a multi-function corresponds to exactly one input or output
- * socket respectively. A multiple parameter belongs to exactly one input AND one output socket.
- *
- * There is an .to_dot() method that generates a graph in dot format for debugging purposes.
- */
-
-#include "FN_multi_function.hh"
-
-#include "BLI_vector_set.hh"
-
-namespace blender::fn {
-
-class MFNode;
-class MFFunctionNode;
-class MFDummyNode;
-class MFSocket;
-class MFInputSocket;
-class MFOutputSocket;
-class MFNetwork;
-
-class MFNode : NonCopyable, NonMovable {
- protected:
- MFNetwork *network_;
- Span<MFInputSocket *> inputs_;
- Span<MFOutputSocket *> outputs_;
- bool is_dummy_;
- int id_;
-
- friend MFNetwork;
-
- public:
- StringRefNull name() const;
-
- int id() const;
-
- MFNetwork &network();
- const MFNetwork &network() const;
-
- bool is_dummy() const;
- bool is_function() const;
-
- MFDummyNode &as_dummy();
- const MFDummyNode &as_dummy() const;
-
- MFFunctionNode &as_function();
- const MFFunctionNode &as_function() const;
-
- MFInputSocket &input(int index);
- const MFInputSocket &input(int index) const;
-
- MFOutputSocket &output(int index);
- const MFOutputSocket &output(int index) const;
-
- Span<MFInputSocket *> inputs();
- Span<const MFInputSocket *> inputs() const;
-
- Span<MFOutputSocket *> outputs();
- Span<const MFOutputSocket *> outputs() const;
-
- bool has_unlinked_inputs() const;
-
- private:
- void destruct_sockets();
-};
-
-class MFFunctionNode : public MFNode {
- private:
- const MultiFunction *function_;
- Span<int> input_param_indices_;
- Span<int> output_param_indices_;
-
- friend MFNetwork;
-
- public:
- StringRefNull name() const;
-
- const MultiFunction &function() const;
-
- const MFInputSocket &input_for_param(int param_index) const;
- const MFOutputSocket &output_for_param(int param_index) const;
-};
-
-class MFDummyNode : public MFNode {
- protected:
- StringRefNull name_;
- MutableSpan<StringRefNull> input_names_;
- MutableSpan<StringRefNull> output_names_;
-
- friend MFNetwork;
-
- public:
- StringRefNull name() const;
-
- Span<StringRefNull> input_names() const;
- Span<StringRefNull> output_names() const;
-};
-
-class MFSocket : NonCopyable, NonMovable {
- protected:
- MFNode *node_;
- bool is_output_;
- int index_;
- MFDataType data_type_;
- int id_;
- StringRefNull name_;
-
- friend MFNetwork;
-
- public:
- StringRefNull name() const;
-
- int id() const;
- int index() const;
-
- const MFDataType &data_type() const;
-
- MFNode &node();
- const MFNode &node() const;
-
- bool is_input() const;
- bool is_output() const;
-
- MFInputSocket &as_input();
- const MFInputSocket &as_input() const;
-
- MFOutputSocket &as_output();
- const MFOutputSocket &as_output() const;
-};
-
-class MFInputSocket : public MFSocket {
- private:
- MFOutputSocket *origin_;
-
- friend MFNetwork;
-
- public:
- MFOutputSocket *origin();
- const MFOutputSocket *origin() const;
-};
-
-class MFOutputSocket : public MFSocket {
- private:
- Vector<MFInputSocket *, 1> targets_;
-
- friend MFNetwork;
-
- public:
- Span<MFInputSocket *> targets();
- Span<const MFInputSocket *> targets() const;
-};
-
-class MFNetwork : NonCopyable, NonMovable {
- private:
- LinearAllocator<> allocator_;
-
- VectorSet<MFFunctionNode *> function_nodes_;
- VectorSet<MFDummyNode *> dummy_nodes_;
-
- Vector<MFNode *> node_or_null_by_id_;
- Vector<MFSocket *> socket_or_null_by_id_;
-
- public:
- MFNetwork() = default;
- ~MFNetwork();
-
- MFFunctionNode &add_function(const MultiFunction &function);
- MFDummyNode &add_dummy(StringRef name,
- Span<MFDataType> input_types,
- Span<MFDataType> output_types,
- Span<StringRef> input_names,
- Span<StringRef> output_names);
- void add_link(MFOutputSocket &from, MFInputSocket &to);
-
- MFOutputSocket &add_input(StringRef name, MFDataType data_type);
- MFInputSocket &add_output(StringRef name, MFDataType data_type);
-
- void relink(MFOutputSocket &old_output, MFOutputSocket &new_output);
-
- void remove(MFNode &node);
- void remove(Span<MFNode *> nodes);
-
- int socket_id_amount() const;
- int node_id_amount() const;
-
- Span<MFDummyNode *> dummy_nodes();
- Span<MFFunctionNode *> function_nodes();
-
- MFNode *node_or_null_by_id(int id);
- const MFNode *node_or_null_by_id(int id) const;
-
- MFSocket *socket_or_null_by_id(int id);
- const MFSocket *socket_or_null_by_id(int id) const;
-
- void find_dependencies(Span<const MFInputSocket *> sockets,
- VectorSet<const MFOutputSocket *> &r_dummy_sockets,
- VectorSet<const MFInputSocket *> &r_unlinked_inputs) const;
-
- bool have_dummy_or_unlinked_dependencies(Span<const MFInputSocket *> sockets) const;
-
- std::string to_dot(Span<const MFNode *> marked_nodes = {}) const;
-};
-
-/* --------------------------------------------------------------------
- * MFNode inline methods.
- */
-
-inline StringRefNull MFNode::name() const
-{
- if (is_dummy_) {
- return this->as_dummy().name();
- }
- else {
- return this->as_function().name();
- }
-}
-
-inline int MFNode::id() const
-{
- return id_;
-}
-
-inline MFNetwork &MFNode::network()
-{
- return *network_;
-}
-
-inline const MFNetwork &MFNode::network() const
-{
- return *network_;
-}
-
-inline bool MFNode::is_dummy() const
-{
- return is_dummy_;
-}
-
-inline bool MFNode::is_function() const
-{
- return !is_dummy_;
-}
-
-inline MFDummyNode &MFNode::as_dummy()
-{
- BLI_assert(is_dummy_);
- return static_cast<MFDummyNode &>(*this);
-}
-
-inline const MFDummyNode &MFNode::as_dummy() const
-{
- BLI_assert(is_dummy_);
- return static_cast<const MFDummyNode &>(*this);
-}
-
-inline MFFunctionNode &MFNode::as_function()
-{
- BLI_assert(!is_dummy_);
- return static_cast<MFFunctionNode &>(*this);
-}
-
-inline const MFFunctionNode &MFNode::as_function() const
-{
- BLI_assert(!is_dummy_);
- return static_cast<const MFFunctionNode &>(*this);
-}
-
-inline MFInputSocket &MFNode::input(int index)
-{
- return *inputs_[index];
-}
-
-inline const MFInputSocket &MFNode::input(int index) const
-{
- return *inputs_[index];
-}
-
-inline MFOutputSocket &MFNode::output(int index)
-{
- return *outputs_[index];
-}
-
-inline const MFOutputSocket &MFNode::output(int index) const
-{
- return *outputs_[index];
-}
-
-inline Span<MFInputSocket *> MFNode::inputs()
-{
- return inputs_;
-}
-
-inline Span<const MFInputSocket *> MFNode::inputs() const
-{
- return inputs_;
-}
-
-inline Span<MFOutputSocket *> MFNode::outputs()
-{
- return outputs_;
-}
-
-inline Span<const MFOutputSocket *> MFNode::outputs() const
-{
- return outputs_;
-}
-
-inline bool MFNode::has_unlinked_inputs() const
-{
- for (const MFInputSocket *socket : inputs_) {
- if (socket->origin() == nullptr) {
- return true;
- }
- }
- return false;
-}
-
-/* --------------------------------------------------------------------
- * MFFunctionNode inline methods.
- */
-
-inline StringRefNull MFFunctionNode::name() const
-{
- return function_->name();
-}
-
-inline const MultiFunction &MFFunctionNode::function() const
-{
- return *function_;
-}
-
-inline const MFInputSocket &MFFunctionNode::input_for_param(int param_index) const
-{
- return this->input(input_param_indices_.first_index(param_index));
-}
-
-inline const MFOutputSocket &MFFunctionNode::output_for_param(int param_index) const
-{
- return this->output(output_param_indices_.first_index(param_index));
-}
-
-/* --------------------------------------------------------------------
- * MFDummyNode inline methods.
- */
-
-inline StringRefNull MFDummyNode::name() const
-{
- return name_;
-}
-
-inline Span<StringRefNull> MFDummyNode::input_names() const
-{
- return input_names_;
-}
-
-inline Span<StringRefNull> MFDummyNode::output_names() const
-{
- return output_names_;
-}
-
-/* --------------------------------------------------------------------
- * MFSocket inline methods.
- */
-
-inline StringRefNull MFSocket::name() const
-{
- return name_;
-}
-
-inline int MFSocket::id() const
-{
- return id_;
-}
-
-inline int MFSocket::index() const
-{
- return index_;
-}
-
-inline const MFDataType &MFSocket::data_type() const
-{
- return data_type_;
-}
-
-inline MFNode &MFSocket::node()
-{
- return *node_;
-}
-
-inline const MFNode &MFSocket::node() const
-{
- return *node_;
-}
-
-inline bool MFSocket::is_input() const
-{
- return !is_output_;
-}
-
-inline bool MFSocket::is_output() const
-{
- return is_output_;
-}
-
-inline MFInputSocket &MFSocket::as_input()
-{
- BLI_assert(this->is_input());
- return static_cast<MFInputSocket &>(*this);
-}
-
-inline const MFInputSocket &MFSocket::as_input() const
-{
- BLI_assert(this->is_input());
- return static_cast<const MFInputSocket &>(*this);
-}
-
-inline MFOutputSocket &MFSocket::as_output()
-{
- BLI_assert(this->is_output());
- return static_cast<MFOutputSocket &>(*this);
-}
-
-inline const MFOutputSocket &MFSocket::as_output() const
-{
- BLI_assert(this->is_output());
- return static_cast<const MFOutputSocket &>(*this);
-}
-
-/* --------------------------------------------------------------------
- * MFInputSocket inline methods.
- */
-
-inline MFOutputSocket *MFInputSocket::origin()
-{
- return origin_;
-}
-
-inline const MFOutputSocket *MFInputSocket::origin() const
-{
- return origin_;
-}
-
-/* --------------------------------------------------------------------
- * MFOutputSocket inline methods.
- */
-
-inline Span<MFInputSocket *> MFOutputSocket::targets()
-{
- return targets_;
-}
-
-inline Span<const MFInputSocket *> MFOutputSocket::targets() const
-{
- return targets_;
-}
-
-/* --------------------------------------------------------------------
- * MFNetwork inline methods.
- */
-
-inline Span<MFDummyNode *> MFNetwork::dummy_nodes()
-{
- return dummy_nodes_;
-}
-
-inline Span<MFFunctionNode *> MFNetwork::function_nodes()
-{
- return function_nodes_;
-}
-
-inline MFNode *MFNetwork::node_or_null_by_id(int id)
-{
- return node_or_null_by_id_[id];
-}
-
-inline const MFNode *MFNetwork::node_or_null_by_id(int id) const
-{
- return node_or_null_by_id_[id];
-}
-
-inline MFSocket *MFNetwork::socket_or_null_by_id(int id)
-{
- return socket_or_null_by_id_[id];
-}
-
-inline const MFSocket *MFNetwork::socket_or_null_by_id(int id) const
-{
- return socket_or_null_by_id_[id];
-}
-
-inline int MFNetwork::socket_id_amount() const
-{
- return socket_or_null_by_id_.size();
-}
-
-inline int MFNetwork::node_id_amount() const
-{
- return node_or_null_by_id_.size();
-}
-
-} // namespace blender::fn
diff --git a/source/blender/functions/FN_multi_function_network_evaluation.hh b/source/blender/functions/FN_multi_function_network_evaluation.hh
deleted file mode 100644
index 17cffa406f7..00000000000
--- a/source/blender/functions/FN_multi_function_network_evaluation.hh
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#pragma once
-
-/** \file
- * \ingroup fn
- */
-
-#include "FN_multi_function_network.hh"
-
-namespace blender::fn {
-
-class MFNetworkEvaluationStorage;
-
-class MFNetworkEvaluator : public MultiFunction {
- private:
- MFSignature signature_;
- Vector<const MFOutputSocket *> inputs_;
- Vector<const MFInputSocket *> outputs_;
-
- public:
- MFNetworkEvaluator(Vector<const MFOutputSocket *> inputs, Vector<const MFInputSocket *> outputs);
-
- void call(IndexMask mask, MFParams params, MFContext context) const override;
-
- private:
- using Storage = MFNetworkEvaluationStorage;
-
- void copy_inputs_to_storage(MFParams params, Storage &storage) const;
- void copy_outputs_to_storage(
- MFParams params,
- Storage &storage,
- Vector<const MFInputSocket *> &outputs_to_initialize_in_the_end) const;
-
- void evaluate_network_to_compute_outputs(MFContext &global_context, Storage &storage) const;
-
- void evaluate_function(MFContext &global_context,
- const MFFunctionNode &function_node,
- Storage &storage) const;
-
- bool can_do_single_value_evaluation(const MFFunctionNode &function_node, Storage &storage) const;
-
- void initialize_remaining_outputs(MFParams params,
- Storage &storage,
- Span<const MFInputSocket *> remaining_outputs) const;
-};
-
-} // namespace blender::fn
diff --git a/source/blender/functions/FN_multi_function_network_optimization.hh b/source/blender/functions/FN_multi_function_network_optimization.hh
deleted file mode 100644
index 96664fa368e..00000000000
--- a/source/blender/functions/FN_multi_function_network_optimization.hh
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#pragma once
-
-#include "FN_multi_function_network.hh"
-
-#include "BLI_resource_scope.hh"
-
-namespace blender::fn::mf_network_optimization {
-
-void dead_node_removal(MFNetwork &network);
-void constant_folding(MFNetwork &network, ResourceScope &scope);
-void common_subnetwork_elimination(MFNetwork &network);
-
-} // namespace blender::fn::mf_network_optimization
diff --git a/source/blender/functions/FN_multi_function_signature.hh b/source/blender/functions/FN_multi_function_signature.hh
index 23309c9a5e6..d05948cc645 100644
--- a/source/blender/functions/FN_multi_function_signature.hh
+++ b/source/blender/functions/FN_multi_function_signature.hh
@@ -160,6 +160,21 @@ class MFSignatureBuilder {
}
}
+ void add(StringRef name, const MFParamType &param_type)
+ {
+ switch (param_type.interface_type()) {
+ case MFParamType::Input:
+ this->input(name, param_type.data_type());
+ break;
+ case MFParamType::Mutable:
+ this->mutable_(name, param_type.data_type());
+ break;
+ case MFParamType::Output:
+ this->output(name, param_type.data_type());
+ break;
+ }
+ }
+
/* Context */
/** This indicates that the function accesses the context. This disables optimizations that
diff --git a/source/blender/functions/intern/multi_function_network.cc b/source/blender/functions/intern/multi_function_network.cc
deleted file mode 100644
index b5c2c09a35a..00000000000
--- a/source/blender/functions/intern/multi_function_network.cc
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include "BLI_dot_export.hh"
-#include "BLI_stack.hh"
-
-#include "FN_multi_function_network.hh"
-
-namespace blender::fn {
-
-MFNetwork::~MFNetwork()
-{
- for (MFFunctionNode *node : function_nodes_) {
- node->destruct_sockets();
- node->~MFFunctionNode();
- }
- for (MFDummyNode *node : dummy_nodes_) {
- node->destruct_sockets();
- node->~MFDummyNode();
- }
-}
-
-void MFNode::destruct_sockets()
-{
- for (MFInputSocket *socket : inputs_) {
- socket->~MFInputSocket();
- }
- for (MFOutputSocket *socket : outputs_) {
- socket->~MFOutputSocket();
- }
-}
-
-/**
- * Add a new function node to the network. The caller keeps the ownership of the function. The
- * function should not be freed before the network. A reference to the new node is returned. The
- * node is owned by the network.
- */
-MFFunctionNode &MFNetwork::add_function(const MultiFunction &function)
-{
- Vector<int, 16> input_param_indices, output_param_indices;
-
- for (int param_index : function.param_indices()) {
- switch (function.param_type(param_index).interface_type()) {
- case MFParamType::Input: {
- input_param_indices.append(param_index);
- break;
- }
- case MFParamType::Output: {
- output_param_indices.append(param_index);
- break;
- }
- case MFParamType::Mutable: {
- input_param_indices.append(param_index);
- output_param_indices.append(param_index);
- break;
- }
- }
- }
-
- MFFunctionNode &node = *allocator_.construct<MFFunctionNode>().release();
- function_nodes_.add_new(&node);
-
- node.network_ = this;
- node.is_dummy_ = false;
- node.id_ = node_or_null_by_id_.append_and_get_index(&node);
- node.function_ = &function;
- node.input_param_indices_ = allocator_.construct_array_copy<int>(input_param_indices);
- node.output_param_indices_ = allocator_.construct_array_copy<int>(output_param_indices);
-
- node.inputs_ = allocator_.construct_elements_and_pointer_array<MFInputSocket>(
- input_param_indices.size());
- node.outputs_ = allocator_.construct_elements_and_pointer_array<MFOutputSocket>(
- output_param_indices.size());
-
- for (int i : input_param_indices.index_range()) {
- int param_index = input_param_indices[i];
- MFParamType param = function.param_type(param_index);
- BLI_assert(param.is_input_or_mutable());
-
- MFInputSocket &socket = *node.inputs_[i];
- socket.data_type_ = param.data_type();
- socket.node_ = &node;
- socket.index_ = i;
- socket.is_output_ = false;
- socket.name_ = function.param_name(param_index);
- socket.origin_ = nullptr;
- socket.id_ = socket_or_null_by_id_.append_and_get_index(&socket);
- }
-
- for (int i : output_param_indices.index_range()) {
- int param_index = output_param_indices[i];
- MFParamType param = function.param_type(param_index);
- BLI_assert(param.is_output_or_mutable());
-
- MFOutputSocket &socket = *node.outputs_[i];
- socket.data_type_ = param.data_type();
- socket.node_ = &node;
- socket.index_ = i;
- socket.is_output_ = true;
- socket.name_ = function.param_name(param_index);
- socket.id_ = socket_or_null_by_id_.append_and_get_index(&socket);
- }
-
- return node;
-}
-
-/**
- * Add a dummy node with the given input and output sockets.
- */
-MFDummyNode &MFNetwork::add_dummy(StringRef name,
- Span<MFDataType> input_types,
- Span<MFDataType> output_types,
- Span<StringRef> input_names,
- Span<StringRef> output_names)
-{
- assert_same_size(input_types, input_names);
- assert_same_size(output_types, output_names);
-
- MFDummyNode &node = *allocator_.construct<MFDummyNode>().release();
- dummy_nodes_.add_new(&node);
-
- node.network_ = this;
- node.is_dummy_ = true;
- node.name_ = allocator_.copy_string(name);
- node.id_ = node_or_null_by_id_.append_and_get_index(&node);
-
- node.inputs_ = allocator_.construct_elements_and_pointer_array<MFInputSocket>(
- input_types.size());
- node.outputs_ = allocator_.construct_elements_and_pointer_array<MFOutputSocket>(
- output_types.size());
-
- node.input_names_ = allocator_.allocate_array<StringRefNull>(input_types.size());
- node.output_names_ = allocator_.allocate_array<StringRefNull>(output_types.size());
-
- for (int i : input_types.index_range()) {
- MFInputSocket &socket = *node.inputs_[i];
- socket.data_type_ = input_types[i];
- socket.node_ = &node;
- socket.index_ = i;
- socket.is_output_ = false;
- socket.name_ = allocator_.copy_string(input_names[i]);
- socket.id_ = socket_or_null_by_id_.append_and_get_index(&socket);
- node.input_names_[i] = socket.name_;
- }
-
- for (int i : output_types.index_range()) {
- MFOutputSocket &socket = *node.outputs_[i];
- socket.data_type_ = output_types[i];
- socket.node_ = &node;
- socket.index_ = i;
- socket.is_output_ = true;
- socket.name_ = allocator_.copy_string(output_names[i]);
- socket.id_ = socket_or_null_by_id_.append_and_get_index(&socket);
- node.output_names_[i] = socket.name_;
- }
-
- return node;
-}
-
-/**
- * Connect two sockets. This invokes undefined behavior if the sockets belong to different
- * networks, the sockets have a different data type, or the `to` socket is connected to something
- * else already.
- */
-void MFNetwork::add_link(MFOutputSocket &from, MFInputSocket &to)
-{
- BLI_assert(to.origin_ == nullptr);
- BLI_assert(from.node_->network_ == to.node_->network_);
- BLI_assert(from.data_type_ == to.data_type_);
- from.targets_.append(&to);
- to.origin_ = &from;
-}
-
-MFOutputSocket &MFNetwork::add_input(StringRef name, MFDataType data_type)
-{
- return this->add_dummy(name, {}, {data_type}, {}, {"Value"}).output(0);
-}
-
-MFInputSocket &MFNetwork::add_output(StringRef name, MFDataType data_type)
-{
- return this->add_dummy(name, {data_type}, {}, {"Value"}, {}).input(0);
-}
-
-void MFNetwork::relink(MFOutputSocket &old_output, MFOutputSocket &new_output)
-{
- BLI_assert(&old_output != &new_output);
- BLI_assert(old_output.data_type_ == new_output.data_type_);
- for (MFInputSocket *input : old_output.targets()) {
- input->origin_ = &new_output;
- }
- new_output.targets_.extend(old_output.targets_);
- old_output.targets_.clear();
-}
-
-void MFNetwork::remove(MFNode &node)
-{
- for (MFInputSocket *socket : node.inputs_) {
- if (socket->origin_ != nullptr) {
- socket->origin_->targets_.remove_first_occurrence_and_reorder(socket);
- }
- socket_or_null_by_id_[socket->id_] = nullptr;
- }
- for (MFOutputSocket *socket : node.outputs_) {
- for (MFInputSocket *other : socket->targets_) {
- other->origin_ = nullptr;
- }
- socket_or_null_by_id_[socket->id_] = nullptr;
- }
- node.destruct_sockets();
- if (node.is_dummy()) {
- MFDummyNode &dummy_node = node.as_dummy();
- dummy_node.~MFDummyNode();
- dummy_nodes_.remove_contained(&dummy_node);
- }
- else {
- MFFunctionNode &function_node = node.as_function();
- function_node.~MFFunctionNode();
- function_nodes_.remove_contained(&function_node);
- }
- node_or_null_by_id_[node.id_] = nullptr;
-}
-
-void MFNetwork::remove(Span<MFNode *> nodes)
-{
- for (MFNode *node : nodes) {
- this->remove(*node);
- }
-}
-
-void MFNetwork::find_dependencies(Span<const MFInputSocket *> sockets,
- VectorSet<const MFOutputSocket *> &r_dummy_sockets,
- VectorSet<const MFInputSocket *> &r_unlinked_inputs) const
-{
- Set<const MFNode *> visited_nodes;
- Stack<const MFInputSocket *> sockets_to_check;
- sockets_to_check.push_multiple(sockets);
-
- while (!sockets_to_check.is_empty()) {
- const MFInputSocket &socket = *sockets_to_check.pop();
- const MFOutputSocket *origin_socket = socket.origin();
- if (origin_socket == nullptr) {
- r_unlinked_inputs.add(&socket);
- continue;
- }
-
- const MFNode &origin_node = origin_socket->node();
-
- if (origin_node.is_dummy()) {
- r_dummy_sockets.add(origin_socket);
- continue;
- }
-
- if (visited_nodes.add(&origin_node)) {
- sockets_to_check.push_multiple(origin_node.inputs());
- }
- }
-}
-
-bool MFNetwork::have_dummy_or_unlinked_dependencies(Span<const MFInputSocket *> sockets) const
-{
- VectorSet<const MFOutputSocket *> dummy_sockets;
- VectorSet<const MFInputSocket *> unlinked_inputs;
- this->find_dependencies(sockets, dummy_sockets, unlinked_inputs);
- return dummy_sockets.size() + unlinked_inputs.size() > 0;
-}
-
-std::string MFNetwork::to_dot(Span<const MFNode *> marked_nodes) const
-{
- dot::DirectedGraph digraph;
- digraph.set_rankdir(dot::Attr_rankdir::LeftToRight);
-
- Map<const MFNode *, dot::NodeWithSocketsRef> dot_nodes;
-
- Vector<const MFNode *> all_nodes;
- all_nodes.extend(function_nodes_.as_span().cast<const MFNode *>());
- all_nodes.extend(dummy_nodes_.as_span().cast<const MFNode *>());
-
- for (const MFNode *node : all_nodes) {
- dot::Node &dot_node = digraph.new_node("");
-
- Vector<std::string> input_names, output_names;
- for (const MFInputSocket *socket : node->inputs_) {
- input_names.append(socket->name() + "(" + socket->data_type().to_string() + ")");
- }
- for (const MFOutputSocket *socket : node->outputs_) {
- output_names.append(socket->name() + " (" + socket->data_type().to_string() + ")");
- }
-
- dot::NodeWithSocketsRef dot_node_ref{dot_node, node->name(), input_names, output_names};
- dot_nodes.add_new(node, dot_node_ref);
- }
-
- for (const MFDummyNode *node : dummy_nodes_) {
- dot_nodes.lookup(node).node().set_background_color("#77EE77");
- }
- for (const MFNode *node : marked_nodes) {
- dot_nodes.lookup(node).node().set_background_color("#7777EE");
- }
-
- for (const MFNode *to_node : all_nodes) {
- dot::NodeWithSocketsRef to_dot_node = dot_nodes.lookup(to_node);
-
- for (const MFInputSocket *to_socket : to_node->inputs_) {
- const MFOutputSocket *from_socket = to_socket->origin_;
- if (from_socket != nullptr) {
- const MFNode *from_node = from_socket->node_;
- dot::NodeWithSocketsRef from_dot_node = dot_nodes.lookup(from_node);
- digraph.new_edge(from_dot_node.output(from_socket->index_),
- to_dot_node.input(to_socket->index_));
- }
- }
- }
-
- return digraph.to_dot_string();
-}
-
-} // namespace blender::fn
diff --git a/source/blender/functions/intern/multi_function_network_evaluation.cc b/source/blender/functions/intern/multi_function_network_evaluation.cc
deleted file mode 100644
index 9a0cb0c35ce..00000000000
--- a/source/blender/functions/intern/multi_function_network_evaluation.cc
+++ /dev/null
@@ -1,1083 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/** \file
- * \ingroup fn
- *
- * The `MFNetworkEvaluator` class is a multi-function that consists of potentially many smaller
- * multi-functions. When called, it traverses the underlying MFNetwork and executes the required
- * function nodes.
- *
- * There are many possible approaches to evaluate a function network. The approach implemented
- * below has the following features:
- * - It does not use recursion. Those could become problematic with long node chains.
- * - It can handle all existing parameter types (including mutable parameters).
- * - Avoids data copies in many cases.
- * - Every node is executed at most once.
- * - Can compute sub-functions on a single element, when the result is the same for all elements.
- *
- * Possible improvements:
- * - Cache and reuse buffers.
- * - Use "deepest depth first" heuristic to decide which order the inputs of a node should be
- * computed. This reduces the number of required temporary buffers when they are reused.
- */
-
-#include "FN_multi_function_network_evaluation.hh"
-
-#include "BLI_resource_scope.hh"
-#include "BLI_stack.hh"
-
-namespace blender::fn {
-
-struct Value;
-
-/**
- * This keeps track of all the values that flow through the multi-function network. Therefore it
- * maintains a mapping between output sockets and their corresponding values. Every `value`
- * references some memory, that is owned either by the caller or this storage.
- *
- * A value can be owned by different sockets over time to avoid unnecessary copies.
- */
-class MFNetworkEvaluationStorage {
- private:
- LinearAllocator<> allocator_;
- IndexMask mask_;
- Array<Value *> value_per_output_id_;
- int64_t min_array_size_;
-
- public:
- MFNetworkEvaluationStorage(IndexMask mask, int socket_id_amount);
- ~MFNetworkEvaluationStorage();
-
- /* Add the values that have been provided by the caller of the multi-function network. */
- void add_single_input_from_caller(const MFOutputSocket &socket, const GVArray &virtual_array);
- void add_vector_input_from_caller(const MFOutputSocket &socket,
- const GVVectorArray &virtual_vector_array);
- void add_single_output_from_caller(const MFOutputSocket &socket, GMutableSpan span);
- void add_vector_output_from_caller(const MFOutputSocket &socket, GVectorArray &vector_array);
-
- /* Get input buffers for function node evaluations. */
- const GVArray &get_single_input__full(const MFInputSocket &socket, ResourceScope &scope);
- const GVArray &get_single_input__single(const MFInputSocket &socket, ResourceScope &scope);
- const GVVectorArray &get_vector_input__full(const MFInputSocket &socket, ResourceScope &scope);
- const GVVectorArray &get_vector_input__single(const MFInputSocket &socket, ResourceScope &scope);
-
- /* Get output buffers for function node evaluations. */
- GMutableSpan get_single_output__full(const MFOutputSocket &socket);
- GMutableSpan get_single_output__single(const MFOutputSocket &socket);
- GVectorArray &get_vector_output__full(const MFOutputSocket &socket);
- GVectorArray &get_vector_output__single(const MFOutputSocket &socket);
-
- /* Get mutable buffers for function node evaluations. */
- GMutableSpan get_mutable_single__full(const MFInputSocket &input,
- const MFOutputSocket &output,
- ResourceScope &scope);
- GMutableSpan get_mutable_single__single(const MFInputSocket &input,
- const MFOutputSocket &output,
- ResourceScope &scope);
- GVectorArray &get_mutable_vector__full(const MFInputSocket &input,
- const MFOutputSocket &output,
- ResourceScope &scope);
- GVectorArray &get_mutable_vector__single(const MFInputSocket &input,
- const MFOutputSocket &output,
- ResourceScope &scope);
-
- /* Mark a node as being done with evaluation. This might free temporary buffers that are no
- * longer needed. */
- void finish_node(const MFFunctionNode &node);
- void finish_output_socket(const MFOutputSocket &socket);
- void finish_input_socket(const MFInputSocket &socket);
-
- IndexMask mask() const;
- bool socket_is_computed(const MFOutputSocket &socket);
- bool is_same_value_for_every_index(const MFOutputSocket &socket);
- bool socket_has_buffer_for_output(const MFOutputSocket &socket);
-};
-
-MFNetworkEvaluator::MFNetworkEvaluator(Vector<const MFOutputSocket *> inputs,
- Vector<const MFInputSocket *> outputs)
- : inputs_(std::move(inputs)), outputs_(std::move(outputs))
-{
- BLI_assert(outputs_.size() > 0);
- MFSignatureBuilder signature{"Function Tree"};
-
- for (const MFOutputSocket *socket : inputs_) {
- BLI_assert(socket->node().is_dummy());
-
- MFDataType type = socket->data_type();
- switch (type.category()) {
- case MFDataType::Single:
- signature.single_input(socket->name(), type.single_type());
- break;
- case MFDataType::Vector:
- signature.vector_input(socket->name(), type.vector_base_type());
- break;
- }
- }
-
- for (const MFInputSocket *socket : outputs_) {
- BLI_assert(socket->node().is_dummy());
-
- MFDataType type = socket->data_type();
- switch (type.category()) {
- case MFDataType::Single:
- signature.single_output(socket->name(), type.single_type());
- break;
- case MFDataType::Vector:
- signature.vector_output(socket->name(), type.vector_base_type());
- break;
- }
- }
-
- signature_ = signature.build();
- this->set_signature(&signature_);
-}
-
-void MFNetworkEvaluator::call(IndexMask mask, MFParams params, MFContext context) const
-{
- if (mask.size() == 0) {
- return;
- }
-
- const MFNetwork &network = outputs_[0]->node().network();
- Storage storage(mask, network.socket_id_amount());
-
- Vector<const MFInputSocket *> outputs_to_initialize_in_the_end;
-
- this->copy_inputs_to_storage(params, storage);
- this->copy_outputs_to_storage(params, storage, outputs_to_initialize_in_the_end);
- this->evaluate_network_to_compute_outputs(context, storage);
- this->initialize_remaining_outputs(params, storage, outputs_to_initialize_in_the_end);
-}
-
-BLI_NOINLINE void MFNetworkEvaluator::copy_inputs_to_storage(MFParams params,
- Storage &storage) const
-{
- for (int input_index : inputs_.index_range()) {
- int param_index = input_index + 0;
- const MFOutputSocket &socket = *inputs_[input_index];
- switch (socket.data_type().category()) {
- case MFDataType::Single: {
- const GVArray &input_list = params.readonly_single_input(param_index);
- storage.add_single_input_from_caller(socket, input_list);
- break;
- }
- case MFDataType::Vector: {
- const GVVectorArray &input_list_list = params.readonly_vector_input(param_index);
- storage.add_vector_input_from_caller(socket, input_list_list);
- break;
- }
- }
- }
-}
-
-BLI_NOINLINE void MFNetworkEvaluator::copy_outputs_to_storage(
- MFParams params,
- Storage &storage,
- Vector<const MFInputSocket *> &outputs_to_initialize_in_the_end) const
-{
- for (int output_index : outputs_.index_range()) {
- int param_index = output_index + inputs_.size();
- const MFInputSocket &socket = *outputs_[output_index];
- const MFOutputSocket &origin = *socket.origin();
-
- if (origin.node().is_dummy()) {
- BLI_assert(inputs_.contains(&origin));
- /* Don't overwrite input buffers. */
- outputs_to_initialize_in_the_end.append(&socket);
- continue;
- }
-
- if (storage.socket_has_buffer_for_output(origin)) {
- /* When two outputs will be initialized to the same values. */
- outputs_to_initialize_in_the_end.append(&socket);
- continue;
- }
-
- switch (socket.data_type().category()) {
- case MFDataType::Single: {
- GMutableSpan span = params.uninitialized_single_output(param_index);
- storage.add_single_output_from_caller(origin, span);
- break;
- }
- case MFDataType::Vector: {
- GVectorArray &vector_array = params.vector_output(param_index);
- storage.add_vector_output_from_caller(origin, vector_array);
- break;
- }
- }
- }
-}
-
-BLI_NOINLINE void MFNetworkEvaluator::evaluate_network_to_compute_outputs(
- MFContext &global_context, Storage &storage) const
-{
- Stack<const MFOutputSocket *, 32> sockets_to_compute;
- for (const MFInputSocket *socket : outputs_) {
- sockets_to_compute.push(socket->origin());
- }
-
- /* This is the main loop that traverses the MFNetwork. */
- while (!sockets_to_compute.is_empty()) {
- const MFOutputSocket &socket = *sockets_to_compute.peek();
- const MFNode &node = socket.node();
-
- if (storage.socket_is_computed(socket)) {
- sockets_to_compute.pop();
- continue;
- }
-
- BLI_assert(node.is_function());
- BLI_assert(!node.has_unlinked_inputs());
- const MFFunctionNode &function_node = node.as_function();
-
- bool all_origins_are_computed = true;
- for (const MFInputSocket *input_socket : function_node.inputs()) {
- const MFOutputSocket *origin = input_socket->origin();
- if (origin != nullptr) {
- if (!storage.socket_is_computed(*origin)) {
- sockets_to_compute.push(origin);
- all_origins_are_computed = false;
- }
- }
- }
-
- if (all_origins_are_computed) {
- this->evaluate_function(global_context, function_node, storage);
- sockets_to_compute.pop();
- }
- }
-}
-
-BLI_NOINLINE void MFNetworkEvaluator::evaluate_function(MFContext &global_context,
- const MFFunctionNode &function_node,
- Storage &storage) const
-{
-
- const MultiFunction &function = function_node.function();
- // std::cout << "Function: " << function.name() << "\n";
-
- if (this->can_do_single_value_evaluation(function_node, storage)) {
- /* The function output would be the same for all elements. Therefore, it is enough to call the
- * function only on a single element. This can avoid many duplicate computations. */
- MFParamsBuilder params{function, 1};
- ResourceScope &scope = params.resource_scope();
-
- for (int param_index : function.param_indices()) {
- MFParamType param_type = function.param_type(param_index);
- switch (param_type.category()) {
- case MFParamType::SingleInput: {
- const MFInputSocket &socket = function_node.input_for_param(param_index);
- const GVArray &values = storage.get_single_input__single(socket, scope);
- params.add_readonly_single_input(values);
- break;
- }
- case MFParamType::VectorInput: {
- const MFInputSocket &socket = function_node.input_for_param(param_index);
- const GVVectorArray &values = storage.get_vector_input__single(socket, scope);
- params.add_readonly_vector_input(values);
- break;
- }
- case MFParamType::SingleOutput: {
- const MFOutputSocket &socket = function_node.output_for_param(param_index);
- GMutableSpan values = storage.get_single_output__single(socket);
- params.add_uninitialized_single_output(values);
- break;
- }
- case MFParamType::VectorOutput: {
- const MFOutputSocket &socket = function_node.output_for_param(param_index);
- GVectorArray &values = storage.get_vector_output__single(socket);
- params.add_vector_output(values);
- break;
- }
- case MFParamType::SingleMutable: {
- const MFInputSocket &input = function_node.input_for_param(param_index);
- const MFOutputSocket &output = function_node.output_for_param(param_index);
- GMutableSpan values = storage.get_mutable_single__single(input, output, scope);
- params.add_single_mutable(values);
- break;
- }
- case MFParamType::VectorMutable: {
- const MFInputSocket &input = function_node.input_for_param(param_index);
- const MFOutputSocket &output = function_node.output_for_param(param_index);
- GVectorArray &values = storage.get_mutable_vector__single(input, output, scope);
- params.add_vector_mutable(values);
- break;
- }
- }
- }
-
- function.call(IndexRange(1), params, global_context);
- }
- else {
- MFParamsBuilder params{function, storage.mask().min_array_size()};
- ResourceScope &scope = params.resource_scope();
-
- for (int param_index : function.param_indices()) {
- MFParamType param_type = function.param_type(param_index);
- switch (param_type.category()) {
- case MFParamType::SingleInput: {
- const MFInputSocket &socket = function_node.input_for_param(param_index);
- const GVArray &values = storage.get_single_input__full(socket, scope);
- params.add_readonly_single_input(values);
- break;
- }
- case MFParamType::VectorInput: {
- const MFInputSocket &socket = function_node.input_for_param(param_index);
- const GVVectorArray &values = storage.get_vector_input__full(socket, scope);
- params.add_readonly_vector_input(values);
- break;
- }
- case MFParamType::SingleOutput: {
- const MFOutputSocket &socket = function_node.output_for_param(param_index);
- GMutableSpan values = storage.get_single_output__full(socket);
- params.add_uninitialized_single_output(values);
- break;
- }
- case MFParamType::VectorOutput: {
- const MFOutputSocket &socket = function_node.output_for_param(param_index);
- GVectorArray &values = storage.get_vector_output__full(socket);
- params.add_vector_output(values);
- break;
- }
- case MFParamType::SingleMutable: {
- const MFInputSocket &input = function_node.input_for_param(param_index);
- const MFOutputSocket &output = function_node.output_for_param(param_index);
- GMutableSpan values = storage.get_mutable_single__full(input, output, scope);
- params.add_single_mutable(values);
- break;
- }
- case MFParamType::VectorMutable: {
- const MFInputSocket &input = function_node.input_for_param(param_index);
- const MFOutputSocket &output = function_node.output_for_param(param_index);
- GVectorArray &values = storage.get_mutable_vector__full(input, output, scope);
- params.add_vector_mutable(values);
- break;
- }
- }
- }
-
- function.call(storage.mask(), params, global_context);
- }
-
- storage.finish_node(function_node);
-}
-
-bool MFNetworkEvaluator::can_do_single_value_evaluation(const MFFunctionNode &function_node,
- Storage &storage) const
-{
- for (const MFInputSocket *socket : function_node.inputs()) {
- if (!storage.is_same_value_for_every_index(*socket->origin())) {
- return false;
- }
- }
- if (storage.mask().min_array_size() >= 1) {
- for (const MFOutputSocket *socket : function_node.outputs()) {
- if (storage.socket_has_buffer_for_output(*socket)) {
- return false;
- }
- }
- }
- return true;
-}
-
-BLI_NOINLINE void MFNetworkEvaluator::initialize_remaining_outputs(
- MFParams params, Storage &storage, Span<const MFInputSocket *> remaining_outputs) const
-{
- ResourceScope scope;
- for (const MFInputSocket *socket : remaining_outputs) {
- int param_index = inputs_.size() + outputs_.first_index_of(socket);
-
- switch (socket->data_type().category()) {
- case MFDataType::Single: {
- const GVArray &values = storage.get_single_input__full(*socket, scope);
- GMutableSpan output_values = params.uninitialized_single_output(param_index);
- values.materialize_to_uninitialized(storage.mask(), output_values.data());
- break;
- }
- case MFDataType::Vector: {
- const GVVectorArray &values = storage.get_vector_input__full(*socket, scope);
- GVectorArray &output_values = params.vector_output(param_index);
- output_values.extend(storage.mask(), values);
- break;
- }
- }
- }
-}
-
-/* -------------------------------------------------------------------- */
-/** \name Value Types
- * \{ */
-
-enum class ValueType {
- InputSingle,
- InputVector,
- OutputSingle,
- OutputVector,
- OwnSingle,
- OwnVector,
-};
-
-struct Value {
- ValueType type;
-
- Value(ValueType type) : type(type)
- {
- }
-};
-
-struct InputSingleValue : public Value {
- /** This virtual array has been provided by the code that called the multi-function network. */
- const GVArray &virtual_array;
-
- InputSingleValue(const GVArray &virtual_array)
- : Value(ValueType::InputSingle), virtual_array(virtual_array)
- {
- }
-};
-
-struct InputVectorValue : public Value {
- /** This virtual vector has been provided by the code that called the multi-function network. */
- const GVVectorArray &virtual_vector_array;
-
- InputVectorValue(const GVVectorArray &virtual_vector_array)
- : Value(ValueType::InputVector), virtual_vector_array(virtual_vector_array)
- {
- }
-};
-
-struct OutputValue : public Value {
- bool is_computed = false;
-
- OutputValue(ValueType type) : Value(type)
- {
- }
-};
-
-struct OutputSingleValue : public OutputValue {
- /** This span has been provided by the code that called the multi-function network. */
- GMutableSpan span;
-
- OutputSingleValue(GMutableSpan span) : OutputValue(ValueType::OutputSingle), span(span)
- {
- }
-};
-
-struct OutputVectorValue : public OutputValue {
- /** This vector array has been provided by the code that called the multi-function network. */
- GVectorArray *vector_array;
-
- OutputVectorValue(GVectorArray &vector_array)
- : OutputValue(ValueType::OutputVector), vector_array(&vector_array)
- {
- }
-};
-
-struct OwnSingleValue : public Value {
- /** This span has been allocated during the evaluation of the multi-function network and contains
- * intermediate data. It has to be freed once the network evaluation is finished. */
- GMutableSpan span;
- int max_remaining_users;
- bool is_single_allocated;
-
- OwnSingleValue(GMutableSpan span, int max_remaining_users, bool is_single_allocated)
- : Value(ValueType::OwnSingle),
- span(span),
- max_remaining_users(max_remaining_users),
- is_single_allocated(is_single_allocated)
- {
- }
-};
-
-struct OwnVectorValue : public Value {
- /** This vector array has been allocated during the evaluation of the multi-function network and
- * contains intermediate data. It has to be freed once the network evaluation is finished. */
- GVectorArray *vector_array;
- int max_remaining_users;
-
- OwnVectorValue(GVectorArray &vector_array, int max_remaining_users)
- : Value(ValueType::OwnVector),
- vector_array(&vector_array),
- max_remaining_users(max_remaining_users)
- {
- }
-};
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Storage methods
- * \{ */
-
-MFNetworkEvaluationStorage::MFNetworkEvaluationStorage(IndexMask mask, int socket_id_amount)
- : mask_(mask),
- value_per_output_id_(socket_id_amount, nullptr),
- min_array_size_(mask.min_array_size())
-{
-}
-
-MFNetworkEvaluationStorage::~MFNetworkEvaluationStorage()
-{
- for (Value *any_value : value_per_output_id_) {
- if (any_value == nullptr) {
- continue;
- }
- if (any_value->type == ValueType::OwnSingle) {
- OwnSingleValue *value = static_cast<OwnSingleValue *>(any_value);
- GMutableSpan span = value->span;
- const CPPType &type = span.type();
- if (value->is_single_allocated) {
- type.destruct(span.data());
- }
- else {
- type.destruct_indices(span.data(), mask_);
- MEM_freeN(span.data());
- }
- }
- else if (any_value->type == ValueType::OwnVector) {
- OwnVectorValue *value = static_cast<OwnVectorValue *>(any_value);
- delete value->vector_array;
- }
- }
-}
-
-IndexMask MFNetworkEvaluationStorage::mask() const
-{
- return mask_;
-}
-
-bool MFNetworkEvaluationStorage::socket_is_computed(const MFOutputSocket &socket)
-{
- Value *any_value = value_per_output_id_[socket.id()];
- if (any_value == nullptr) {
- return false;
- }
- if (ELEM(any_value->type, ValueType::OutputSingle, ValueType::OutputVector)) {
- return static_cast<OutputValue *>(any_value)->is_computed;
- }
- return true;
-}
-
-bool MFNetworkEvaluationStorage::is_same_value_for_every_index(const MFOutputSocket &socket)
-{
- Value *any_value = value_per_output_id_[socket.id()];
- switch (any_value->type) {
- case ValueType::OwnSingle:
- return static_cast<OwnSingleValue *>(any_value)->span.size() == 1;
- case ValueType::OwnVector:
- return static_cast<OwnVectorValue *>(any_value)->vector_array->size() == 1;
- case ValueType::InputSingle:
- return static_cast<InputSingleValue *>(any_value)->virtual_array.is_single();
- case ValueType::InputVector:
- return static_cast<InputVectorValue *>(any_value)->virtual_vector_array.is_single_vector();
- case ValueType::OutputSingle:
- return static_cast<OutputSingleValue *>(any_value)->span.size() == 1;
- case ValueType::OutputVector:
- return static_cast<OutputVectorValue *>(any_value)->vector_array->size() == 1;
- }
- BLI_assert(false);
- return false;
-}
-
-bool MFNetworkEvaluationStorage::socket_has_buffer_for_output(const MFOutputSocket &socket)
-{
- Value *any_value = value_per_output_id_[socket.id()];
- if (any_value == nullptr) {
- return false;
- }
-
- BLI_assert(ELEM(any_value->type, ValueType::OutputSingle, ValueType::OutputVector));
- return true;
-}
-
-void MFNetworkEvaluationStorage::finish_node(const MFFunctionNode &node)
-{
- for (const MFInputSocket *socket : node.inputs()) {
- this->finish_input_socket(*socket);
- }
- for (const MFOutputSocket *socket : node.outputs()) {
- this->finish_output_socket(*socket);
- }
-}
-
-void MFNetworkEvaluationStorage::finish_output_socket(const MFOutputSocket &socket)
-{
- Value *any_value = value_per_output_id_[socket.id()];
- if (any_value == nullptr) {
- return;
- }
-
- if (ELEM(any_value->type, ValueType::OutputSingle, ValueType::OutputVector)) {
- static_cast<OutputValue *>(any_value)->is_computed = true;
- }
-}
-
-void MFNetworkEvaluationStorage::finish_input_socket(const MFInputSocket &socket)
-{
- const MFOutputSocket &origin = *socket.origin();
-
- Value *any_value = value_per_output_id_[origin.id()];
- if (any_value == nullptr) {
- /* Can happen when a value has been forward to the next node. */
- return;
- }
-
- switch (any_value->type) {
- case ValueType::InputSingle:
- case ValueType::OutputSingle:
- case ValueType::InputVector:
- case ValueType::OutputVector: {
- break;
- }
- case ValueType::OwnSingle: {
- OwnSingleValue *value = static_cast<OwnSingleValue *>(any_value);
- BLI_assert(value->max_remaining_users >= 1);
- value->max_remaining_users--;
- if (value->max_remaining_users == 0) {
- GMutableSpan span = value->span;
- const CPPType &type = span.type();
- if (value->is_single_allocated) {
- type.destruct(span.data());
- }
- else {
- type.destruct_indices(span.data(), mask_);
- MEM_freeN(span.data());
- }
- value_per_output_id_[origin.id()] = nullptr;
- }
- break;
- }
- case ValueType::OwnVector: {
- OwnVectorValue *value = static_cast<OwnVectorValue *>(any_value);
- BLI_assert(value->max_remaining_users >= 1);
- value->max_remaining_users--;
- if (value->max_remaining_users == 0) {
- delete value->vector_array;
- value_per_output_id_[origin.id()] = nullptr;
- }
- break;
- }
- }
-}
-
-void MFNetworkEvaluationStorage::add_single_input_from_caller(const MFOutputSocket &socket,
- const GVArray &virtual_array)
-{
- BLI_assert(value_per_output_id_[socket.id()] == nullptr);
- BLI_assert(virtual_array.size() >= min_array_size_);
-
- auto *value = allocator_.construct<InputSingleValue>(virtual_array).release();
- value_per_output_id_[socket.id()] = value;
-}
-
-void MFNetworkEvaluationStorage::add_vector_input_from_caller(
- const MFOutputSocket &socket, const GVVectorArray &virtual_vector_array)
-{
- BLI_assert(value_per_output_id_[socket.id()] == nullptr);
- BLI_assert(virtual_vector_array.size() >= min_array_size_);
-
- auto *value = allocator_.construct<InputVectorValue>(virtual_vector_array).release();
- value_per_output_id_[socket.id()] = value;
-}
-
-void MFNetworkEvaluationStorage::add_single_output_from_caller(const MFOutputSocket &socket,
- GMutableSpan span)
-{
- BLI_assert(value_per_output_id_[socket.id()] == nullptr);
- BLI_assert(span.size() >= min_array_size_);
-
- auto *value = allocator_.construct<OutputSingleValue>(span).release();
- value_per_output_id_[socket.id()] = value;
-}
-
-void MFNetworkEvaluationStorage::add_vector_output_from_caller(const MFOutputSocket &socket,
- GVectorArray &vector_array)
-{
- BLI_assert(value_per_output_id_[socket.id()] == nullptr);
- BLI_assert(vector_array.size() >= min_array_size_);
-
- auto *value = allocator_.construct<OutputVectorValue>(vector_array).release();
- value_per_output_id_[socket.id()] = value;
-}
-
-GMutableSpan MFNetworkEvaluationStorage::get_single_output__full(const MFOutputSocket &socket)
-{
- Value *any_value = value_per_output_id_[socket.id()];
- if (any_value == nullptr) {
- const CPPType &type = socket.data_type().single_type();
- void *buffer = MEM_mallocN_aligned(min_array_size_ * type.size(), type.alignment(), AT);
- GMutableSpan span(type, buffer, min_array_size_);
-
- auto *value =
- allocator_.construct<OwnSingleValue>(span, socket.targets().size(), false).release();
- value_per_output_id_[socket.id()] = value;
-
- return span;
- }
-
- BLI_assert(any_value->type == ValueType::OutputSingle);
- return static_cast<OutputSingleValue *>(any_value)->span;
-}
-
-GMutableSpan MFNetworkEvaluationStorage::get_single_output__single(const MFOutputSocket &socket)
-{
- Value *any_value = value_per_output_id_[socket.id()];
- if (any_value == nullptr) {
- const CPPType &type = socket.data_type().single_type();
- void *buffer = allocator_.allocate(type.size(), type.alignment());
- GMutableSpan span(type, buffer, 1);
-
- auto *value =
- allocator_.construct<OwnSingleValue>(span, socket.targets().size(), true).release();
- value_per_output_id_[socket.id()] = value;
-
- return value->span;
- }
-
- BLI_assert(any_value->type == ValueType::OutputSingle);
- GMutableSpan span = static_cast<OutputSingleValue *>(any_value)->span;
- BLI_assert(span.size() == 1);
- return span;
-}
-
-GVectorArray &MFNetworkEvaluationStorage::get_vector_output__full(const MFOutputSocket &socket)
-{
- Value *any_value = value_per_output_id_[socket.id()];
- if (any_value == nullptr) {
- const CPPType &type = socket.data_type().vector_base_type();
- GVectorArray *vector_array = new GVectorArray(type, min_array_size_);
-
- auto *value =
- allocator_.construct<OwnVectorValue>(*vector_array, socket.targets().size()).release();
- value_per_output_id_[socket.id()] = value;
-
- return *value->vector_array;
- }
-
- BLI_assert(any_value->type == ValueType::OutputVector);
- return *static_cast<OutputVectorValue *>(any_value)->vector_array;
-}
-
-GVectorArray &MFNetworkEvaluationStorage::get_vector_output__single(const MFOutputSocket &socket)
-{
- Value *any_value = value_per_output_id_[socket.id()];
- if (any_value == nullptr) {
- const CPPType &type = socket.data_type().vector_base_type();
- GVectorArray *vector_array = new GVectorArray(type, 1);
-
- auto *value =
- allocator_.construct<OwnVectorValue>(*vector_array, socket.targets().size()).release();
- value_per_output_id_[socket.id()] = value;
-
- return *value->vector_array;
- }
-
- BLI_assert(any_value->type == ValueType::OutputVector);
- GVectorArray &vector_array = *static_cast<OutputVectorValue *>(any_value)->vector_array;
- BLI_assert(vector_array.size() == 1);
- return vector_array;
-}
-
-GMutableSpan MFNetworkEvaluationStorage::get_mutable_single__full(const MFInputSocket &input,
- const MFOutputSocket &output,
- ResourceScope &scope)
-{
- const MFOutputSocket &from = *input.origin();
- const MFOutputSocket &to = output;
- const CPPType &type = from.data_type().single_type();
-
- Value *from_any_value = value_per_output_id_[from.id()];
- Value *to_any_value = value_per_output_id_[to.id()];
- BLI_assert(from_any_value != nullptr);
- BLI_assert(type == to.data_type().single_type());
-
- if (to_any_value != nullptr) {
- BLI_assert(to_any_value->type == ValueType::OutputSingle);
- GMutableSpan span = static_cast<OutputSingleValue *>(to_any_value)->span;
- const GVArray &virtual_array = this->get_single_input__full(input, scope);
- virtual_array.materialize_to_uninitialized(mask_, span.data());
- return span;
- }
-
- if (from_any_value->type == ValueType::OwnSingle) {
- OwnSingleValue *value = static_cast<OwnSingleValue *>(from_any_value);
- if (value->max_remaining_users == 1 && !value->is_single_allocated) {
- value_per_output_id_[to.id()] = value;
- value_per_output_id_[from.id()] = nullptr;
- value->max_remaining_users = to.targets().size();
- return value->span;
- }
- }
-
- const GVArray &virtual_array = this->get_single_input__full(input, scope);
- void *new_buffer = MEM_mallocN_aligned(min_array_size_ * type.size(), type.alignment(), AT);
- GMutableSpan new_array_ref(type, new_buffer, min_array_size_);
- virtual_array.materialize_to_uninitialized(mask_, new_array_ref.data());
-
- OwnSingleValue *new_value =
- allocator_.construct<OwnSingleValue>(new_array_ref, to.targets().size(), false).release();
- value_per_output_id_[to.id()] = new_value;
- return new_array_ref;
-}
-
-GMutableSpan MFNetworkEvaluationStorage::get_mutable_single__single(const MFInputSocket &input,
- const MFOutputSocket &output,
- ResourceScope &scope)
-{
- const MFOutputSocket &from = *input.origin();
- const MFOutputSocket &to = output;
- const CPPType &type = from.data_type().single_type();
-
- Value *from_any_value = value_per_output_id_[from.id()];
- Value *to_any_value = value_per_output_id_[to.id()];
- BLI_assert(from_any_value != nullptr);
- BLI_assert(type == to.data_type().single_type());
-
- if (to_any_value != nullptr) {
- BLI_assert(to_any_value->type == ValueType::OutputSingle);
- GMutableSpan span = static_cast<OutputSingleValue *>(to_any_value)->span;
- BLI_assert(span.size() == 1);
- const GVArray &virtual_array = this->get_single_input__single(input, scope);
- virtual_array.get_single_to_uninitialized(span[0]);
- return span;
- }
-
- if (from_any_value->type == ValueType::OwnSingle) {
- OwnSingleValue *value = static_cast<OwnSingleValue *>(from_any_value);
- if (value->max_remaining_users == 1) {
- value_per_output_id_[to.id()] = value;
- value_per_output_id_[from.id()] = nullptr;
- value->max_remaining_users = to.targets().size();
- BLI_assert(value->span.size() == 1);
- return value->span;
- }
- }
-
- const GVArray &virtual_array = this->get_single_input__single(input, scope);
-
- void *new_buffer = allocator_.allocate(type.size(), type.alignment());
- virtual_array.get_single_to_uninitialized(new_buffer);
- GMutableSpan new_array_ref(type, new_buffer, 1);
-
- OwnSingleValue *new_value =
- allocator_.construct<OwnSingleValue>(new_array_ref, to.targets().size(), true).release();
- value_per_output_id_[to.id()] = new_value;
- return new_array_ref;
-}
-
-GVectorArray &MFNetworkEvaluationStorage::get_mutable_vector__full(const MFInputSocket &input,
- const MFOutputSocket &output,
- ResourceScope &scope)
-{
- const MFOutputSocket &from = *input.origin();
- const MFOutputSocket &to = output;
- const CPPType &base_type = from.data_type().vector_base_type();
-
- Value *from_any_value = value_per_output_id_[from.id()];
- Value *to_any_value = value_per_output_id_[to.id()];
- BLI_assert(from_any_value != nullptr);
- BLI_assert(base_type == to.data_type().vector_base_type());
-
- if (to_any_value != nullptr) {
- BLI_assert(to_any_value->type == ValueType::OutputVector);
- GVectorArray &vector_array = *static_cast<OutputVectorValue *>(to_any_value)->vector_array;
- const GVVectorArray &virtual_vector_array = this->get_vector_input__full(input, scope);
- vector_array.extend(mask_, virtual_vector_array);
- return vector_array;
- }
-
- if (from_any_value->type == ValueType::OwnVector) {
- OwnVectorValue *value = static_cast<OwnVectorValue *>(from_any_value);
- if (value->max_remaining_users == 1) {
- value_per_output_id_[to.id()] = value;
- value_per_output_id_[from.id()] = nullptr;
- value->max_remaining_users = to.targets().size();
- return *value->vector_array;
- }
- }
-
- const GVVectorArray &virtual_vector_array = this->get_vector_input__full(input, scope);
-
- GVectorArray *new_vector_array = new GVectorArray(base_type, min_array_size_);
- new_vector_array->extend(mask_, virtual_vector_array);
-
- OwnVectorValue *new_value =
- allocator_.construct<OwnVectorValue>(*new_vector_array, to.targets().size()).release();
- value_per_output_id_[to.id()] = new_value;
-
- return *new_vector_array;
-}
-
-GVectorArray &MFNetworkEvaluationStorage::get_mutable_vector__single(const MFInputSocket &input,
- const MFOutputSocket &output,
- ResourceScope &scope)
-{
- const MFOutputSocket &from = *input.origin();
- const MFOutputSocket &to = output;
- const CPPType &base_type = from.data_type().vector_base_type();
-
- Value *from_any_value = value_per_output_id_[from.id()];
- Value *to_any_value = value_per_output_id_[to.id()];
- BLI_assert(from_any_value != nullptr);
- BLI_assert(base_type == to.data_type().vector_base_type());
-
- if (to_any_value != nullptr) {
- BLI_assert(to_any_value->type == ValueType::OutputVector);
- GVectorArray &vector_array = *static_cast<OutputVectorValue *>(to_any_value)->vector_array;
- BLI_assert(vector_array.size() == 1);
- const GVVectorArray &virtual_vector_array = this->get_vector_input__single(input, scope);
- vector_array.extend({0}, virtual_vector_array);
- return vector_array;
- }
-
- if (from_any_value->type == ValueType::OwnVector) {
- OwnVectorValue *value = static_cast<OwnVectorValue *>(from_any_value);
- if (value->max_remaining_users == 1) {
- value_per_output_id_[to.id()] = value;
- value_per_output_id_[from.id()] = nullptr;
- value->max_remaining_users = to.targets().size();
- return *value->vector_array;
- }
- }
-
- const GVVectorArray &virtual_vector_array = this->get_vector_input__single(input, scope);
-
- GVectorArray *new_vector_array = new GVectorArray(base_type, 1);
- new_vector_array->extend({0}, virtual_vector_array);
-
- OwnVectorValue *new_value =
- allocator_.construct<OwnVectorValue>(*new_vector_array, to.targets().size()).release();
- value_per_output_id_[to.id()] = new_value;
- return *new_vector_array;
-}
-
-const GVArray &MFNetworkEvaluationStorage::get_single_input__full(const MFInputSocket &socket,
- ResourceScope &scope)
-{
- const MFOutputSocket &origin = *socket.origin();
- Value *any_value = value_per_output_id_[origin.id()];
- BLI_assert(any_value != nullptr);
-
- if (any_value->type == ValueType::OwnSingle) {
- OwnSingleValue *value = static_cast<OwnSingleValue *>(any_value);
- if (value->is_single_allocated) {
- return scope.construct<GVArray_For_SingleValueRef>(
- __func__, value->span.type(), min_array_size_, value->span.data());
- }
-
- return scope.construct<GVArray_For_GSpan>(__func__, value->span);
- }
- if (any_value->type == ValueType::InputSingle) {
- InputSingleValue *value = static_cast<InputSingleValue *>(any_value);
- return value->virtual_array;
- }
- if (any_value->type == ValueType::OutputSingle) {
- OutputSingleValue *value = static_cast<OutputSingleValue *>(any_value);
- BLI_assert(value->is_computed);
- return scope.construct<GVArray_For_GSpan>(__func__, value->span);
- }
-
- BLI_assert(false);
- return scope.construct<GVArray_For_Empty>(__func__, CPPType::get<float>());
-}
-
-const GVArray &MFNetworkEvaluationStorage::get_single_input__single(const MFInputSocket &socket,
- ResourceScope &scope)
-{
- const MFOutputSocket &origin = *socket.origin();
- Value *any_value = value_per_output_id_[origin.id()];
- BLI_assert(any_value != nullptr);
-
- if (any_value->type == ValueType::OwnSingle) {
- OwnSingleValue *value = static_cast<OwnSingleValue *>(any_value);
- BLI_assert(value->span.size() == 1);
- return scope.construct<GVArray_For_GSpan>(__func__, value->span);
- }
- if (any_value->type == ValueType::InputSingle) {
- InputSingleValue *value = static_cast<InputSingleValue *>(any_value);
- BLI_assert(value->virtual_array.is_single());
- return value->virtual_array;
- }
- if (any_value->type == ValueType::OutputSingle) {
- OutputSingleValue *value = static_cast<OutputSingleValue *>(any_value);
- BLI_assert(value->is_computed);
- BLI_assert(value->span.size() == 1);
- return scope.construct<GVArray_For_GSpan>(__func__, value->span);
- }
-
- BLI_assert(false);
- return scope.construct<GVArray_For_Empty>(__func__, CPPType::get<float>());
-}
-
-const GVVectorArray &MFNetworkEvaluationStorage::get_vector_input__full(
- const MFInputSocket &socket, ResourceScope &scope)
-{
- const MFOutputSocket &origin = *socket.origin();
- Value *any_value = value_per_output_id_[origin.id()];
- BLI_assert(any_value != nullptr);
-
- if (any_value->type == ValueType::OwnVector) {
- OwnVectorValue *value = static_cast<OwnVectorValue *>(any_value);
- if (value->vector_array->size() == 1) {
- GSpan span = (*value->vector_array)[0];
- return scope.construct<GVVectorArray_For_SingleGSpan>(__func__, span, min_array_size_);
- }
-
- return scope.construct<GVVectorArray_For_GVectorArray>(__func__, *value->vector_array);
- }
- if (any_value->type == ValueType::InputVector) {
- InputVectorValue *value = static_cast<InputVectorValue *>(any_value);
- return value->virtual_vector_array;
- }
- if (any_value->type == ValueType::OutputVector) {
- OutputVectorValue *value = static_cast<OutputVectorValue *>(any_value);
- return scope.construct<GVVectorArray_For_GVectorArray>(__func__, *value->vector_array);
- }
-
- BLI_assert(false);
- return scope.construct<GVVectorArray_For_SingleGSpan>(__func__, GSpan(CPPType::get<float>()), 0);
-}
-
-const GVVectorArray &MFNetworkEvaluationStorage::get_vector_input__single(
- const MFInputSocket &socket, ResourceScope &scope)
-{
- const MFOutputSocket &origin = *socket.origin();
- Value *any_value = value_per_output_id_[origin.id()];
- BLI_assert(any_value != nullptr);
-
- if (any_value->type == ValueType::OwnVector) {
- OwnVectorValue *value = static_cast<OwnVectorValue *>(any_value);
- BLI_assert(value->vector_array->size() == 1);
- return scope.construct<GVVectorArray_For_GVectorArray>(__func__, *value->vector_array);
- }
- if (any_value->type == ValueType::InputVector) {
- InputVectorValue *value = static_cast<InputVectorValue *>(any_value);
- BLI_assert(value->virtual_vector_array.is_single_vector());
- return value->virtual_vector_array;
- }
- if (any_value->type == ValueType::OutputVector) {
- OutputVectorValue *value = static_cast<OutputVectorValue *>(any_value);
- BLI_assert(value->vector_array->size() == 1);
- return scope.construct<GVVectorArray_For_GVectorArray>(__func__, *value->vector_array);
- }
-
- BLI_assert(false);
- return scope.construct<GVVectorArray_For_SingleGSpan>(__func__, GSpan(CPPType::get<float>()), 0);
-}
-
-/** \} */
-
-} // namespace blender::fn
diff --git a/source/blender/functions/intern/multi_function_network_optimization.cc b/source/blender/functions/intern/multi_function_network_optimization.cc
deleted file mode 100644
index 75c3583c5e5..00000000000
--- a/source/blender/functions/intern/multi_function_network_optimization.cc
+++ /dev/null
@@ -1,501 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/** \file
- * \ingroup fn
- */
-
-/* Used to check if two multi-functions have the exact same type. */
-#include <typeinfo>
-
-#include "FN_multi_function_builder.hh"
-#include "FN_multi_function_network_evaluation.hh"
-#include "FN_multi_function_network_optimization.hh"
-
-#include "BLI_disjoint_set.hh"
-#include "BLI_ghash.h"
-#include "BLI_map.hh"
-#include "BLI_multi_value_map.hh"
-#include "BLI_rand.h"
-#include "BLI_stack.hh"
-
-namespace blender::fn::mf_network_optimization {
-
-/* -------------------------------------------------------------------- */
-/** \name Utility functions to find nodes in a network.
- * \{ */
-
-static bool set_tag_and_check_if_modified(bool &tag, bool new_value)
-{
- if (tag != new_value) {
- tag = new_value;
- return true;
- }
-
- return false;
-}
-
-static Array<bool> mask_nodes_to_the_left(MFNetwork &network, Span<MFNode *> nodes)
-{
- Array<bool> is_to_the_left(network.node_id_amount(), false);
- Stack<MFNode *> nodes_to_check;
-
- for (MFNode *node : nodes) {
- is_to_the_left[node->id()] = true;
- nodes_to_check.push(node);
- }
-
- while (!nodes_to_check.is_empty()) {
- MFNode &node = *nodes_to_check.pop();
-
- for (MFInputSocket *input_socket : node.inputs()) {
- MFOutputSocket *origin = input_socket->origin();
- if (origin != nullptr) {
- MFNode &origin_node = origin->node();
- if (set_tag_and_check_if_modified(is_to_the_left[origin_node.id()], true)) {
- nodes_to_check.push(&origin_node);
- }
- }
- }
- }
-
- return is_to_the_left;
-}
-
-static Array<bool> mask_nodes_to_the_right(MFNetwork &network, Span<MFNode *> nodes)
-{
- Array<bool> is_to_the_right(network.node_id_amount(), false);
- Stack<MFNode *> nodes_to_check;
-
- for (MFNode *node : nodes) {
- is_to_the_right[node->id()] = true;
- nodes_to_check.push(node);
- }
-
- while (!nodes_to_check.is_empty()) {
- MFNode &node = *nodes_to_check.pop();
-
- for (MFOutputSocket *output_socket : node.outputs()) {
- for (MFInputSocket *target_socket : output_socket->targets()) {
- MFNode &target_node = target_socket->node();
- if (set_tag_and_check_if_modified(is_to_the_right[target_node.id()], true)) {
- nodes_to_check.push(&target_node);
- }
- }
- }
- }
-
- return is_to_the_right;
-}
-
-static Vector<MFNode *> find_nodes_based_on_mask(MFNetwork &network,
- Span<bool> id_mask,
- bool mask_value)
-{
- Vector<MFNode *> nodes;
- for (int id : id_mask.index_range()) {
- if (id_mask[id] == mask_value) {
- MFNode *node = network.node_or_null_by_id(id);
- if (node != nullptr) {
- nodes.append(node);
- }
- }
- }
- return nodes;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Dead Node Removal
- * \{ */
-
-/**
- * Unused nodes are all those nodes that no dummy node depends upon.
- */
-void dead_node_removal(MFNetwork &network)
-{
- Array<bool> node_is_used_mask = mask_nodes_to_the_left(network,
- network.dummy_nodes().cast<MFNode *>());
- Vector<MFNode *> nodes_to_remove = find_nodes_based_on_mask(network, node_is_used_mask, false);
- network.remove(nodes_to_remove);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Constant Folding
- * \{ */
-
-static bool function_node_can_be_constant(MFFunctionNode *node)
-{
- if (node->has_unlinked_inputs()) {
- return false;
- }
- if (node->function().depends_on_context()) {
- return false;
- }
- return true;
-}
-
-static Vector<MFNode *> find_non_constant_nodes(MFNetwork &network)
-{
- Vector<MFNode *> non_constant_nodes;
- non_constant_nodes.extend(network.dummy_nodes().cast<MFNode *>());
-
- for (MFFunctionNode *node : network.function_nodes()) {
- if (!function_node_can_be_constant(node)) {
- non_constant_nodes.append(node);
- }
- }
- return non_constant_nodes;
-}
-
-static bool output_has_non_constant_target_node(MFOutputSocket *output_socket,
- Span<bool> is_not_constant_mask)
-{
- for (MFInputSocket *target_socket : output_socket->targets()) {
- MFNode &target_node = target_socket->node();
- bool target_is_not_constant = is_not_constant_mask[target_node.id()];
- if (target_is_not_constant) {
- return true;
- }
- }
- return false;
-}
-
-static MFInputSocket *try_find_dummy_target_socket(MFOutputSocket *output_socket)
-{
- for (MFInputSocket *target_socket : output_socket->targets()) {
- if (target_socket->node().is_dummy()) {
- return target_socket;
- }
- }
- return nullptr;
-}
-
-static Vector<MFInputSocket *> find_constant_inputs_to_fold(
- MFNetwork &network, Vector<MFDummyNode *> &r_temporary_nodes)
-{
- Vector<MFNode *> non_constant_nodes = find_non_constant_nodes(network);
- Array<bool> is_not_constant_mask = mask_nodes_to_the_right(network, non_constant_nodes);
- Vector<MFNode *> constant_nodes = find_nodes_based_on_mask(network, is_not_constant_mask, false);
-
- Vector<MFInputSocket *> sockets_to_compute;
- for (MFNode *node : constant_nodes) {
- if (node->inputs().size() == 0) {
- continue;
- }
-
- for (MFOutputSocket *output_socket : node->outputs()) {
- MFDataType data_type = output_socket->data_type();
- if (output_has_non_constant_target_node(output_socket, is_not_constant_mask)) {
- MFInputSocket *dummy_target = try_find_dummy_target_socket(output_socket);
- if (dummy_target == nullptr) {
- dummy_target = &network.add_output("Dummy", data_type);
- network.add_link(*output_socket, *dummy_target);
- r_temporary_nodes.append(&dummy_target->node().as_dummy());
- }
-
- sockets_to_compute.append(dummy_target);
- }
- }
- }
- return sockets_to_compute;
-}
-
-static void prepare_params_for_constant_folding(const MultiFunction &network_fn,
- MFParamsBuilder &params,
- ResourceScope &scope)
-{
- for (int param_index : network_fn.param_indices()) {
- MFParamType param_type = network_fn.param_type(param_index);
- MFDataType data_type = param_type.data_type();
-
- switch (data_type.category()) {
- case MFDataType::Single: {
- /* Allocates memory for a single constant folded value. */
- const CPPType &cpp_type = data_type.single_type();
- void *buffer = scope.linear_allocator().allocate(cpp_type.size(), cpp_type.alignment());
- GMutableSpan array{cpp_type, buffer, 1};
- params.add_uninitialized_single_output(array);
- break;
- }
- case MFDataType::Vector: {
- /* Allocates memory for a constant folded vector. */
- const CPPType &cpp_type = data_type.vector_base_type();
- GVectorArray &vector_array = scope.construct<GVectorArray>(AT, cpp_type, 1);
- params.add_vector_output(vector_array);
- break;
- }
- }
- }
-}
-
-static Array<MFOutputSocket *> add_constant_folded_sockets(const MultiFunction &network_fn,
- MFParamsBuilder &params,
- ResourceScope &scope,
- MFNetwork &network)
-{
- Array<MFOutputSocket *> folded_sockets{network_fn.param_indices().size(), nullptr};
-
- for (int param_index : network_fn.param_indices()) {
- MFParamType param_type = network_fn.param_type(param_index);
- MFDataType data_type = param_type.data_type();
-
- const MultiFunction *constant_fn = nullptr;
-
- switch (data_type.category()) {
- case MFDataType::Single: {
- const CPPType &cpp_type = data_type.single_type();
- GMutableSpan array = params.computed_array(param_index);
- void *buffer = array.data();
- scope.add(buffer, array.type().destruct_fn(), AT);
-
- constant_fn = &scope.construct<CustomMF_GenericConstant>(AT, cpp_type, buffer);
- break;
- }
- case MFDataType::Vector: {
- GVectorArray &vector_array = params.computed_vector_array(param_index);
- GSpan array = vector_array[0];
- constant_fn = &scope.construct<CustomMF_GenericConstantArray>(AT, array);
- break;
- }
- }
-
- MFFunctionNode &folded_node = network.add_function(*constant_fn);
- folded_sockets[param_index] = &folded_node.output(0);
- }
- return folded_sockets;
-}
-
-static Array<MFOutputSocket *> compute_constant_sockets_and_add_folded_nodes(
- MFNetwork &network, Span<const MFInputSocket *> sockets_to_compute, ResourceScope &scope)
-{
- MFNetworkEvaluator network_fn{{}, sockets_to_compute};
-
- MFContextBuilder context;
- MFParamsBuilder params{network_fn, 1};
- prepare_params_for_constant_folding(network_fn, params, scope);
- network_fn.call({0}, params, context);
- return add_constant_folded_sockets(network_fn, params, scope, network);
-}
-
-class MyClass {
- MFDummyNode node;
-};
-
-/**
- * Find function nodes that always output the same value and replace those with constant nodes.
- */
-void constant_folding(MFNetwork &network, ResourceScope &scope)
-{
- Vector<MFDummyNode *> temporary_nodes;
- Vector<MFInputSocket *> inputs_to_fold = find_constant_inputs_to_fold(network, temporary_nodes);
- if (inputs_to_fold.size() == 0) {
- return;
- }
-
- Array<MFOutputSocket *> folded_sockets = compute_constant_sockets_and_add_folded_nodes(
- network, inputs_to_fold, scope);
-
- for (int i : inputs_to_fold.index_range()) {
- MFOutputSocket &original_socket = *inputs_to_fold[i]->origin();
- network.relink(original_socket, *folded_sockets[i]);
- }
-
- network.remove(temporary_nodes.as_span().cast<MFNode *>());
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Common Sub-network Elimination
- * \{ */
-
-static uint64_t compute_node_hash(MFFunctionNode &node, RNG *rng, Span<uint64_t> node_hashes)
-{
- if (node.function().depends_on_context()) {
- return BLI_rng_get_uint(rng);
- }
- if (node.has_unlinked_inputs()) {
- return BLI_rng_get_uint(rng);
- }
-
- uint64_t combined_inputs_hash = 394659347u;
- for (MFInputSocket *input_socket : node.inputs()) {
- MFOutputSocket *origin_socket = input_socket->origin();
- uint64_t input_hash = BLI_ghashutil_combine_hash(node_hashes[origin_socket->node().id()],
- origin_socket->index());
- combined_inputs_hash = BLI_ghashutil_combine_hash(combined_inputs_hash, input_hash);
- }
-
- uint64_t function_hash = node.function().hash();
- uint64_t node_hash = BLI_ghashutil_combine_hash(combined_inputs_hash, function_hash);
- return node_hash;
-}
-
-/**
- * Produces a hash for every node. Two nodes with the same hash should have a high probability of
- * outputting the same values.
- */
-static Array<uint64_t> compute_node_hashes(MFNetwork &network)
-{
- RNG *rng = BLI_rng_new(0);
- Array<uint64_t> node_hashes(network.node_id_amount());
- Array<bool> node_is_hashed(network.node_id_amount(), false);
-
- /* No dummy nodes are not assumed to output the same values. */
- for (MFDummyNode *node : network.dummy_nodes()) {
- uint64_t node_hash = BLI_rng_get_uint(rng);
- node_hashes[node->id()] = node_hash;
- node_is_hashed[node->id()] = true;
- }
-
- Stack<MFFunctionNode *> nodes_to_check;
- nodes_to_check.push_multiple(network.function_nodes());
-
- while (!nodes_to_check.is_empty()) {
- MFFunctionNode &node = *nodes_to_check.peek();
- if (node_is_hashed[node.id()]) {
- nodes_to_check.pop();
- continue;
- }
-
- /* Make sure that origin nodes are hashed first. */
- bool all_dependencies_ready = true;
- for (MFInputSocket *input_socket : node.inputs()) {
- MFOutputSocket *origin_socket = input_socket->origin();
- if (origin_socket != nullptr) {
- MFNode &origin_node = origin_socket->node();
- if (!node_is_hashed[origin_node.id()]) {
- all_dependencies_ready = false;
- nodes_to_check.push(&origin_node.as_function());
- }
- }
- }
- if (!all_dependencies_ready) {
- continue;
- }
-
- uint64_t node_hash = compute_node_hash(node, rng, node_hashes);
- node_hashes[node.id()] = node_hash;
- node_is_hashed[node.id()] = true;
- nodes_to_check.pop();
- }
-
- BLI_rng_free(rng);
- return node_hashes;
-}
-
-static MultiValueMap<uint64_t, MFNode *> group_nodes_by_hash(MFNetwork &network,
- Span<uint64_t> node_hashes)
-{
- MultiValueMap<uint64_t, MFNode *> nodes_by_hash;
- for (int id : IndexRange(network.node_id_amount())) {
- MFNode *node = network.node_or_null_by_id(id);
- if (node != nullptr) {
- uint64_t node_hash = node_hashes[id];
- nodes_by_hash.add(node_hash, node);
- }
- }
- return nodes_by_hash;
-}
-
-static bool functions_are_equal(const MultiFunction &a, const MultiFunction &b)
-{
- if (&a == &b) {
- return true;
- }
- if (typeid(a) == typeid(b)) {
- return a.equals(b);
- }
- return false;
-}
-
-static bool nodes_output_same_values(DisjointSet &cache, const MFNode &a, const MFNode &b)
-{
- if (cache.in_same_set(a.id(), b.id())) {
- return true;
- }
-
- if (a.is_dummy() || b.is_dummy()) {
- return false;
- }
- if (!functions_are_equal(a.as_function().function(), b.as_function().function())) {
- return false;
- }
- for (int i : a.inputs().index_range()) {
- const MFOutputSocket *origin_a = a.input(i).origin();
- const MFOutputSocket *origin_b = b.input(i).origin();
- if (origin_a == nullptr || origin_b == nullptr) {
- return false;
- }
- if (!nodes_output_same_values(cache, origin_a->node(), origin_b->node())) {
- return false;
- }
- }
-
- cache.join(a.id(), b.id());
- return true;
-}
-
-static void relink_duplicate_nodes(MFNetwork &network,
- MultiValueMap<uint64_t, MFNode *> &nodes_by_hash)
-{
- DisjointSet same_node_cache{network.node_id_amount()};
-
- for (Span<MFNode *> nodes_with_same_hash : nodes_by_hash.values()) {
- if (nodes_with_same_hash.size() <= 1) {
- continue;
- }
-
- Vector<MFNode *, 16> nodes_to_check = nodes_with_same_hash;
- while (nodes_to_check.size() >= 2) {
- Vector<MFNode *, 16> remaining_nodes;
-
- MFNode &deduplicated_node = *nodes_to_check[0];
- for (MFNode *node : nodes_to_check.as_span().drop_front(1)) {
- /* This is true with fairly high probability, but hash collisions can happen. So we have to
- * check if the node actually output the same values. */
- if (nodes_output_same_values(same_node_cache, deduplicated_node, *node)) {
- for (int i : deduplicated_node.outputs().index_range()) {
- network.relink(node->output(i), deduplicated_node.output(i));
- }
- }
- else {
- remaining_nodes.append(node);
- }
- }
- nodes_to_check = std::move(remaining_nodes);
- }
- }
-}
-
-/**
- * Tries to detect duplicate sub-networks and eliminates them. This can help quite a lot when node
- * groups were used to create the network.
- */
-void common_subnetwork_elimination(MFNetwork &network)
-{
- Array<uint64_t> node_hashes = compute_node_hashes(network);
- MultiValueMap<uint64_t, MFNode *> nodes_by_hash = group_nodes_by_hash(network, node_hashes);
- relink_duplicate_nodes(network, nodes_by_hash);
-}
-
-/** \} */
-
-} // namespace blender::fn::mf_network_optimization
diff --git a/source/blender/functions/tests/FN_multi_function_network_test.cc b/source/blender/functions/tests/FN_multi_function_network_test.cc
deleted file mode 100644
index 7b9738e5ca4..00000000000
--- a/source/blender/functions/tests/FN_multi_function_network_test.cc
+++ /dev/null
@@ -1,280 +0,0 @@
-/* Apache License, Version 2.0 */
-
-#include "testing/testing.h"
-
-#include "FN_multi_function_builder.hh"
-#include "FN_multi_function_network.hh"
-#include "FN_multi_function_network_evaluation.hh"
-
-namespace blender::fn::tests {
-namespace {
-
-TEST(multi_function_network, Test1)
-{
- CustomMF_SI_SO<int, int> add_10_fn("add 10", [](int value) { return value + 10; });
- CustomMF_SI_SI_SO<int, int, int> multiply_fn("multiply", [](int a, int b) { return a * b; });
-
- MFNetwork network;
-
- MFNode &node1 = network.add_function(add_10_fn);
- MFNode &node2 = network.add_function(multiply_fn);
- MFOutputSocket &input_socket = network.add_input("Input", MFDataType::ForSingle<int>());
- MFInputSocket &output_socket = network.add_output("Output", MFDataType::ForSingle<int>());
- network.add_link(node1.output(0), node2.input(0));
- network.add_link(node1.output(0), node2.input(1));
- network.add_link(node2.output(0), output_socket);
- network.add_link(input_socket, node1.input(0));
-
- MFNetworkEvaluator network_fn{{&input_socket}, {&output_socket}};
-
- {
- Array<int> values = {4, 6, 1, 2, 0};
- Array<int> results(values.size(), 0);
-
- MFParamsBuilder params(network_fn, values.size());
- params.add_readonly_single_input(values.as_span());
- params.add_uninitialized_single_output(results.as_mutable_span());
-
- MFContextBuilder context;
-
- network_fn.call({0, 2, 3, 4}, params, context);
-
- EXPECT_EQ(results[0], 14 * 14);
- EXPECT_EQ(results[1], 0);
- EXPECT_EQ(results[2], 11 * 11);
- EXPECT_EQ(results[3], 12 * 12);
- EXPECT_EQ(results[4], 10 * 10);
- }
- {
- int value = 3;
- Array<int> results(5, 0);
-
- MFParamsBuilder params(network_fn, results.size());
- params.add_readonly_single_input(&value);
- params.add_uninitialized_single_output(results.as_mutable_span());
-
- MFContextBuilder context;
-
- network_fn.call({1, 2, 4}, params, context);
-
- EXPECT_EQ(results[0], 0);
- EXPECT_EQ(results[1], 13 * 13);
- EXPECT_EQ(results[2], 13 * 13);
- EXPECT_EQ(results[3], 0);
- EXPECT_EQ(results[4], 13 * 13);
- }
-}
-
-class ConcatVectorsFunction : public MultiFunction {
- public:
- ConcatVectorsFunction()
- {
- static MFSignature signature = create_signature();
- this->set_signature(&signature);
- }
-
- static MFSignature create_signature()
- {
- MFSignatureBuilder signature{"Concat Vectors"};
- signature.vector_mutable<int>("A");
- signature.vector_input<int>("B");
- return signature.build();
- }
-
- void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
- {
- GVectorArray &a = params.vector_mutable(0);
- const GVVectorArray &b = params.readonly_vector_input(1);
- a.extend(mask, b);
- }
-};
-
-class AppendFunction : public MultiFunction {
- public:
- AppendFunction()
- {
- static MFSignature signature = create_signature();
- this->set_signature(&signature);
- }
-
- static MFSignature create_signature()
- {
- MFSignatureBuilder signature{"Append"};
- signature.vector_mutable<int>("Vector");
- signature.single_input<int>("Value");
- return signature.build();
- }
-
- void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
- {
- GVectorArray_TypedMutableRef<int> vectors = params.vector_mutable<int>(0);
- const VArray<int> &values = params.readonly_single_input<int>(1);
-
- for (int64_t i : mask) {
- vectors.append(i, values[i]);
- }
- }
-};
-
-class SumVectorFunction : public MultiFunction {
- public:
- SumVectorFunction()
- {
- static MFSignature signature = create_signature();
- this->set_signature(&signature);
- }
-
- static MFSignature create_signature()
- {
- MFSignatureBuilder signature{"Sum Vectors"};
- signature.vector_input<int>("Vector");
- signature.single_output<int>("Sum");
- return signature.build();
- }
-
- void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
- {
- const VVectorArray<int> &vectors = params.readonly_vector_input<int>(0);
- MutableSpan<int> sums = params.uninitialized_single_output<int>(1);
-
- for (int64_t i : mask) {
- int sum = 0;
- for (int j : IndexRange(vectors.get_vector_size(i))) {
- sum += vectors.get_vector_element(i, j);
- }
- sums[i] = sum;
- }
- }
-};
-
-class CreateRangeFunction : public MultiFunction {
- public:
- CreateRangeFunction()
- {
- static MFSignature signature = create_signature();
- this->set_signature(&signature);
- }
-
- static MFSignature create_signature()
- {
- MFSignatureBuilder signature{"Create Range"};
- signature.single_input<int>("Size");
- signature.vector_output<int>("Range");
- return signature.build();
- }
-
- void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
- {
- const VArray<int> &sizes = params.readonly_single_input<int>(0, "Size");
- GVectorArray_TypedMutableRef<int> ranges = params.vector_output<int>(1, "Range");
-
- for (int64_t i : mask) {
- int size = sizes[i];
- for (int j : IndexRange(size)) {
- ranges.append(i, j);
- }
- }
- }
-};
-
-TEST(multi_function_network, Test2)
-{
- CustomMF_SI_SO<int, int> add_3_fn("add 3", [](int value) { return value + 3; });
-
- ConcatVectorsFunction concat_vectors_fn;
- AppendFunction append_fn;
- SumVectorFunction sum_fn;
- CreateRangeFunction create_range_fn;
-
- MFNetwork network;
-
- MFOutputSocket &input1 = network.add_input("Input 1", MFDataType::ForVector<int>());
- MFOutputSocket &input2 = network.add_input("Input 2", MFDataType::ForSingle<int>());
- MFInputSocket &output1 = network.add_output("Output 1", MFDataType::ForVector<int>());
- MFInputSocket &output2 = network.add_output("Output 2", MFDataType::ForSingle<int>());
-
- MFNode &node1 = network.add_function(add_3_fn);
- MFNode &node2 = network.add_function(create_range_fn);
- MFNode &node3 = network.add_function(concat_vectors_fn);
- MFNode &node4 = network.add_function(sum_fn);
- MFNode &node5 = network.add_function(append_fn);
- MFNode &node6 = network.add_function(sum_fn);
-
- network.add_link(input2, node1.input(0));
- network.add_link(node1.output(0), node2.input(0));
- network.add_link(node2.output(0), node3.input(1));
- network.add_link(input1, node3.input(0));
- network.add_link(input1, node4.input(0));
- network.add_link(node4.output(0), node5.input(1));
- network.add_link(node3.output(0), node5.input(0));
- network.add_link(node5.output(0), node6.input(0));
- network.add_link(node3.output(0), output1);
- network.add_link(node6.output(0), output2);
-
- // std::cout << network.to_dot() << "\n\n";
-
- MFNetworkEvaluator network_fn{{&input1, &input2}, {&output1, &output2}};
-
- {
- Array<int> input_value_1 = {3, 6};
- int input_value_2 = 4;
-
- GVectorArray output_value_1(CPPType::get<int32_t>(), 5);
- Array<int> output_value_2(5, -1);
-
- MFParamsBuilder params(network_fn, 5);
- GVVectorArray_For_SingleGSpan inputs_1{input_value_1.as_span(), 5};
- params.add_readonly_vector_input(inputs_1);
- params.add_readonly_single_input(&input_value_2);
- params.add_vector_output(output_value_1);
- params.add_uninitialized_single_output(output_value_2.as_mutable_span());
-
- MFContextBuilder context;
-
- network_fn.call({1, 2, 4}, params, context);
-
- EXPECT_EQ(output_value_1[0].size(), 0);
- EXPECT_EQ(output_value_1[1].size(), 9);
- EXPECT_EQ(output_value_1[2].size(), 9);
- EXPECT_EQ(output_value_1[3].size(), 0);
- EXPECT_EQ(output_value_1[4].size(), 9);
-
- EXPECT_EQ(output_value_2[0], -1);
- EXPECT_EQ(output_value_2[1], 39);
- EXPECT_EQ(output_value_2[2], 39);
- EXPECT_EQ(output_value_2[3], -1);
- EXPECT_EQ(output_value_2[4], 39);
- }
- {
- GVectorArray input_value_1(CPPType::get<int32_t>(), 3);
- GVectorArray_TypedMutableRef<int> input_value_1_ref{input_value_1};
- input_value_1_ref.extend(0, {3, 4, 5});
- input_value_1_ref.extend(1, {1, 2});
-
- Array<int> input_value_2 = {4, 2, 3};
-
- GVectorArray output_value_1(CPPType::get<int32_t>(), 3);
- Array<int> output_value_2(3, -1);
-
- MFParamsBuilder params(network_fn, 3);
- params.add_readonly_vector_input(input_value_1);
- params.add_readonly_single_input(input_value_2.as_span());
- params.add_vector_output(output_value_1);
- params.add_uninitialized_single_output(output_value_2.as_mutable_span());
-
- MFContextBuilder context;
-
- network_fn.call({0, 1, 2}, params, context);
-
- EXPECT_EQ(output_value_1[0].size(), 10);
- EXPECT_EQ(output_value_1[1].size(), 7);
- EXPECT_EQ(output_value_1[2].size(), 6);
-
- EXPECT_EQ(output_value_2[0], 45);
- EXPECT_EQ(output_value_2[1], 16);
- EXPECT_EQ(output_value_2[2], 15);
- }
-}
-
-} // namespace
-} // namespace blender::fn::tests
diff --git a/source/blender/functions/tests/FN_multi_function_test.cc b/source/blender/functions/tests/FN_multi_function_test.cc
index 3d73e020eb2..91c72a51dd6 100644
--- a/source/blender/functions/tests/FN_multi_function_test.cc
+++ b/source/blender/functions/tests/FN_multi_function_test.cc
@@ -4,6 +4,7 @@
#include "FN_multi_function.hh"
#include "FN_multi_function_builder.hh"
+#include "FN_multi_function_test_common.hh"
namespace blender::fn::tests {
namespace {
@@ -59,33 +60,6 @@ TEST(multi_function, AddFunction)
EXPECT_EQ(output[2], 36);
}
-class AddPrefixFunction : public MultiFunction {
- public:
- AddPrefixFunction()
- {
- static MFSignature signature = create_signature();
- this->set_signature(&signature);
- }
-
- static MFSignature create_signature()
- {
- MFSignatureBuilder signature{"Add Prefix"};
- signature.single_input<std::string>("Prefix");
- signature.single_mutable<std::string>("Strings");
- return signature.build();
- }
-
- void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
- {
- const VArray<std::string> &prefixes = params.readonly_single_input<std::string>(0, "Prefix");
- MutableSpan<std::string> strings = params.single_mutable<std::string>(1, "Strings");
-
- for (int64_t i : mask) {
- strings[i] = prefixes[i] + strings[i];
- }
- }
-};
-
TEST(multi_function, AddPrefixFunction)
{
AddPrefixFunction fn;
@@ -113,43 +87,13 @@ TEST(multi_function, AddPrefixFunction)
EXPECT_EQ(strings[3], "ABAnother much longer string to trigger an allocation");
}
-class CreateRangeFunction : public MultiFunction {
- public:
- CreateRangeFunction()
- {
- static MFSignature signature = create_signature();
- this->set_signature(&signature);
- }
-
- static MFSignature create_signature()
- {
- MFSignatureBuilder signature{"Create Range"};
- signature.single_input<uint>("Size");
- signature.vector_output<uint>("Range");
- return signature.build();
- }
-
- void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
- {
- const VArray<uint> &sizes = params.readonly_single_input<uint>(0, "Size");
- GVectorArray &ranges = params.vector_output(1, "Range");
-
- for (int64_t i : mask) {
- uint size = sizes[i];
- for (uint j : IndexRange(size)) {
- ranges.append(i, &j);
- }
- }
- }
-};
-
TEST(multi_function, CreateRangeFunction)
{
CreateRangeFunction fn;
- GVectorArray ranges(CPPType::get<uint>(), 5);
- GVectorArray_TypedMutableRef<uint> ranges_ref{ranges};
- Array<uint> sizes = {3, 0, 6, 1, 4};
+ GVectorArray ranges(CPPType::get<int>(), 5);
+ GVectorArray_TypedMutableRef<int> ranges_ref{ranges};
+ Array<int> sizes = {3, 0, 6, 1, 4};
MFParamsBuilder params(fn, ranges.size());
params.add_readonly_single_input(sizes.as_span());
@@ -172,34 +116,6 @@ TEST(multi_function, CreateRangeFunction)
EXPECT_EQ(ranges_ref[2][1], 1);
}
-class GenericAppendFunction : public MultiFunction {
- private:
- MFSignature signature_;
-
- public:
- GenericAppendFunction(const CPPType &type)
- {
- MFSignatureBuilder signature{"Append"};
- signature.vector_mutable("Vector", type);
- signature.single_input("Value", type);
- signature_ = signature.build();
- this->set_signature(&signature_);
- }
-
- void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
- {
- GVectorArray &vectors = params.vector_mutable(0, "Vector");
- const GVArray &values = params.readonly_single_input(1, "Value");
-
- for (int64_t i : mask) {
- BUFFER_FOR_CPP_TYPE_VALUE(values.type(), buffer);
- values.get(i, buffer);
- vectors.append(i, buffer);
- values.type().destruct(buffer);
- }
- }
-};
-
TEST(multi_function, GenericAppendFunction)
{
GenericAppendFunction fn(CPPType::get<int32_t>());
diff --git a/source/blender/functions/tests/FN_multi_function_test_common.hh b/source/blender/functions/tests/FN_multi_function_test_common.hh
new file mode 100644
index 00000000000..51c8fac8a96
--- /dev/null
+++ b/source/blender/functions/tests/FN_multi_function_test_common.hh
@@ -0,0 +1,174 @@
+/* Apache License, Version 2.0 */
+
+#include "FN_multi_function.hh"
+
+namespace blender::fn::tests {
+
+class AddPrefixFunction : public MultiFunction {
+ public:
+ AddPrefixFunction()
+ {
+ static MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static MFSignature create_signature()
+ {
+ MFSignatureBuilder signature{"Add Prefix"};
+ signature.single_input<std::string>("Prefix");
+ signature.single_mutable<std::string>("Strings");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
+ {
+ const VArray<std::string> &prefixes = params.readonly_single_input<std::string>(0, "Prefix");
+ MutableSpan<std::string> strings = params.single_mutable<std::string>(1, "Strings");
+
+ for (int64_t i : mask) {
+ strings[i] = prefixes[i] + strings[i];
+ }
+ }
+};
+
+class CreateRangeFunction : public MultiFunction {
+ public:
+ CreateRangeFunction()
+ {
+ static MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static MFSignature create_signature()
+ {
+ MFSignatureBuilder signature{"Create Range"};
+ signature.single_input<int>("Size");
+ signature.vector_output<int>("Range");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
+ {
+ const VArray<int> &sizes = params.readonly_single_input<int>(0, "Size");
+ GVectorArray &ranges = params.vector_output(1, "Range");
+
+ for (int64_t i : mask) {
+ int size = sizes[i];
+ for (int j : IndexRange(size)) {
+ ranges.append(i, &j);
+ }
+ }
+ }
+};
+
+class GenericAppendFunction : public MultiFunction {
+ private:
+ MFSignature signature_;
+
+ public:
+ GenericAppendFunction(const CPPType &type)
+ {
+ MFSignatureBuilder signature{"Append"};
+ signature.vector_mutable("Vector", type);
+ signature.single_input("Value", type);
+ signature_ = signature.build();
+ this->set_signature(&signature_);
+ }
+
+ void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
+ {
+ GVectorArray &vectors = params.vector_mutable(0, "Vector");
+ const GVArray &values = params.readonly_single_input(1, "Value");
+
+ for (int64_t i : mask) {
+ BUFFER_FOR_CPP_TYPE_VALUE(values.type(), buffer);
+ values.get(i, buffer);
+ vectors.append(i, buffer);
+ values.type().destruct(buffer);
+ }
+ }
+};
+
+class ConcatVectorsFunction : public MultiFunction {
+ public:
+ ConcatVectorsFunction()
+ {
+ static MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static MFSignature create_signature()
+ {
+ MFSignatureBuilder signature{"Concat Vectors"};
+ signature.vector_mutable<int>("A");
+ signature.vector_input<int>("B");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
+ {
+ GVectorArray &a = params.vector_mutable(0);
+ const GVVectorArray &b = params.readonly_vector_input(1);
+ a.extend(mask, b);
+ }
+};
+
+class AppendFunction : public MultiFunction {
+ public:
+ AppendFunction()
+ {
+ static MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static MFSignature create_signature()
+ {
+ MFSignatureBuilder signature{"Append"};
+ signature.vector_mutable<int>("Vector");
+ signature.single_input<int>("Value");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
+ {
+ GVectorArray_TypedMutableRef<int> vectors = params.vector_mutable<int>(0);
+ const VArray<int> &values = params.readonly_single_input<int>(1);
+
+ for (int64_t i : mask) {
+ vectors.append(i, values[i]);
+ }
+ }
+};
+
+class SumVectorFunction : public MultiFunction {
+ public:
+ SumVectorFunction()
+ {
+ static MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static MFSignature create_signature()
+ {
+ MFSignatureBuilder signature{"Sum Vectors"};
+ signature.vector_input<int>("Vector");
+ signature.single_output<int>("Sum");
+ return signature.build();
+ }
+
+ void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
+ {
+ const VVectorArray<int> &vectors = params.readonly_vector_input<int>(0);
+ MutableSpan<int> sums = params.uninitialized_single_output<int>(1);
+
+ for (int64_t i : mask) {
+ int sum = 0;
+ for (int j : IndexRange(vectors.get_vector_size(i))) {
+ sum += vectors.get_vector_element(i, j);
+ }
+ sums[i] = sum;
+ }
+ }
+};
+
+} // namespace blender::fn::tests
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index 3853b345c14..620c7ef438a 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -84,7 +84,8 @@
#include "NOD_derived_node_tree.hh"
#include "NOD_geometry.h"
#include "NOD_geometry_nodes_eval_log.hh"
-#include "NOD_node_tree_multi_function.hh"
+
+#include "FN_multi_function.hh"
using blender::destruct_ptr;
using blender::float3;
@@ -858,7 +859,7 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
{
blender::ResourceScope scope;
blender::LinearAllocator<> &allocator = scope.linear_allocator();
- blender::nodes::MultiFunctionByNode mf_by_node = get_multi_function_per_node(tree, scope);
+ blender::nodes::NodeMultiFunctions mf_by_node{tree, scope};
Map<DOutputSocket, GMutablePointer> group_inputs;
diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
index 47dfd9bc8f6..5646e37707c 100644
--- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
+++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
@@ -836,7 +836,7 @@ class GeometryNodesEvaluator {
}
/* Use the multi-function implementation if it exists. */
- const MultiFunction *multi_function = params_.mf_by_node->lookup_default(node, nullptr);
+ const MultiFunction *multi_function = params_.mf_by_node->try_get(node);
if (multi_function != nullptr) {
this->execute_multi_function_node(node, *multi_function, node_state);
return;
diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.hh b/source/blender/modifiers/intern/MOD_nodes_evaluator.hh
index d8c60d31986..5151be07aa2 100644
--- a/source/blender/modifiers/intern/MOD_nodes_evaluator.hh
+++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.hh
@@ -20,12 +20,14 @@
#include "NOD_derived_node_tree.hh"
#include "NOD_geometry_nodes_eval_log.hh"
-#include "NOD_node_tree_multi_function.hh"
+#include "NOD_multi_function.hh"
#include "FN_generic_pointer.hh"
#include "DNA_modifier_types.h"
+#include "FN_multi_function.hh"
+
namespace geo_log = blender::nodes::geometry_nodes_eval_log;
namespace blender::modifiers::geometry_nodes {
@@ -45,7 +47,7 @@ struct GeometryNodesEvaluationParams {
* necessary in all cases. Sometimes `log_socket_value_fn` might just want to look at the value
* and then it can be freed. */
Vector<DSocket> force_compute_sockets;
- nodes::MultiFunctionByNode *mf_by_node;
+ nodes::NodeMultiFunctions *mf_by_node;
const NodesModifierData *modifier_;
Depsgraph *depsgraph;
Object *self_object;
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 46fb9f54bfe..8680fcee49a 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -345,11 +345,10 @@ set(SRC
intern/node_common.c
intern/node_exec.cc
intern/node_geometry_exec.cc
+ intern/node_multi_function.cc
intern/node_socket.cc
- intern/node_tree_multi_function.cc
intern/node_tree_ref.cc
intern/node_util.c
- intern/type_callbacks.cc
intern/type_conversions.cc
composite/node_composite_util.h
@@ -366,13 +365,12 @@ set(SRC
NOD_geometry_exec.hh
NOD_geometry_nodes_eval_log.hh
NOD_math_functions.hh
- NOD_node_tree_multi_function.hh
+ NOD_multi_function.hh
NOD_node_tree_ref.hh
NOD_shader.h
NOD_socket.h
NOD_static_types.h
NOD_texture.h
- NOD_type_callbacks.hh
NOD_type_conversions.hh
intern/node_common.h
intern/node_exec.h
diff --git a/source/blender/nodes/NOD_multi_function.hh b/source/blender/nodes/NOD_multi_function.hh
new file mode 100644
index 00000000000..2f4b104fb4c
--- /dev/null
+++ b/source/blender/nodes/NOD_multi_function.hh
@@ -0,0 +1,130 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#include "FN_multi_function.hh"
+
+#include "DNA_node_types.h"
+
+#include "NOD_derived_node_tree.hh"
+
+namespace blender::nodes {
+
+using namespace fn::multi_function_types;
+
+class NodeMultiFunctions;
+
+/**
+ * Utility class to help nodes build a multi-function for themselves.
+ */
+class NodeMultiFunctionBuilder : NonCopyable, NonMovable {
+ private:
+ ResourceScope &resource_scope_;
+ bNode &node_;
+ bNodeTree &tree_;
+ const MultiFunction *built_fn_ = nullptr;
+
+ friend NodeMultiFunctions;
+
+ public:
+ NodeMultiFunctionBuilder(ResourceScope &resource_scope, bNode &node, bNodeTree &tree);
+
+ /**
+ * Assign a multi-function for the current node. The input and output parameters of the function
+ * have to match the available sockets in the node.
+ */
+ void set_matching_fn(const MultiFunction *fn);
+ void set_matching_fn(const MultiFunction &fn);
+
+ /**
+ * Utility method for creating and assigning a multi-function when it can't have a static
+ * lifetime.
+ */
+ template<typename T, typename... Args> void construct_and_set_matching_fn(Args &&...args);
+
+ bNode &node();
+ bNodeTree &tree();
+
+ ResourceScope &resource_scope();
+};
+
+/**
+ * Gives access to multi-functions for all nodes in a node tree that support them.
+ */
+class NodeMultiFunctions {
+ private:
+ Map<const bNode *, const MultiFunction *> map_;
+
+ public:
+ NodeMultiFunctions(const DerivedNodeTree &tree, ResourceScope &resource_scope);
+
+ const MultiFunction *try_get(const DNode &node) const;
+};
+
+/* --------------------------------------------------------------------
+ * NodeMultiFunctionBuilder inline methods.
+ */
+
+inline NodeMultiFunctionBuilder::NodeMultiFunctionBuilder(ResourceScope &resource_scope,
+ bNode &node,
+ bNodeTree &tree)
+ : resource_scope_(resource_scope), node_(node), tree_(tree)
+{
+}
+
+inline bNode &NodeMultiFunctionBuilder::node()
+{
+ return node_;
+}
+
+inline bNodeTree &NodeMultiFunctionBuilder::tree()
+{
+ return tree_;
+}
+
+inline ResourceScope &NodeMultiFunctionBuilder::resource_scope()
+{
+ return resource_scope_;
+}
+
+inline void NodeMultiFunctionBuilder::set_matching_fn(const MultiFunction *fn)
+{
+ built_fn_ = fn;
+}
+
+inline void NodeMultiFunctionBuilder::set_matching_fn(const MultiFunction &fn)
+{
+ this->set_matching_fn(&fn);
+}
+
+template<typename T, typename... Args>
+inline void NodeMultiFunctionBuilder::construct_and_set_matching_fn(Args &&...args)
+{
+ const T &fn = resource_scope_.construct<T>(__func__, std::forward<Args>(args)...);
+ this->set_matching_fn(&fn);
+}
+
+/* --------------------------------------------------------------------
+ * NodeMultiFunctions inline methods.
+ */
+
+inline const MultiFunction *NodeMultiFunctions::try_get(const DNode &node) const
+{
+ return map_.lookup_default(node->bnode(), nullptr);
+}
+
+} // namespace blender::nodes
diff --git a/source/blender/nodes/NOD_node_tree_multi_function.hh b/source/blender/nodes/NOD_node_tree_multi_function.hh
deleted file mode 100644
index 7eeeaef0b98..00000000000
--- a/source/blender/nodes/NOD_node_tree_multi_function.hh
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#pragma once
-
-/** \file
- * \ingroup nodes
- *
- * This file allows you to generate a multi-function network from a user-generated node tree.
- */
-
-#include "FN_multi_function_builder.hh"
-#include "FN_multi_function_network.hh"
-
-#include "NOD_derived_node_tree.hh"
-#include "NOD_type_callbacks.hh"
-
-#include "BLI_multi_value_map.hh"
-#include "BLI_resource_scope.hh"
-
-namespace blender::nodes {
-
-/**
- * A MFNetworkTreeMap maps various components of a node tree to components of a fn::MFNetwork. This
- * is necessary for further processing of a multi-function network that has been generated from a
- * node tree.
- */
-class MFNetworkTreeMap {
- private:
- /**
- * Store by id instead of using a hash table to avoid unnecessary hash table lookups.
- *
- * Input sockets in a node tree can have multiple corresponding sockets in the generated
- * MFNetwork. This is because nodes are allowed to expand into multiple multi-function nodes.
- */
- const DerivedNodeTree &tree_;
- fn::MFNetwork &network_;
- MultiValueMap<DSocket, fn::MFSocket *> sockets_by_dsocket_;
-
- public:
- MFNetworkTreeMap(const DerivedNodeTree &tree, fn::MFNetwork &network)
- : tree_(tree), network_(network)
- {
- }
-
- const DerivedNodeTree &tree() const
- {
- return tree_;
- }
-
- const fn::MFNetwork &network() const
- {
- return network_;
- }
-
- fn::MFNetwork &network()
- {
- return network_;
- }
-
- void add(const DSocket &dsocket, fn::MFSocket &socket)
- {
- BLI_assert(dsocket->is_input() == socket.is_input());
- BLI_assert(dsocket->is_input() || sockets_by_dsocket_.lookup(dsocket).is_empty());
- sockets_by_dsocket_.add(dsocket, &socket);
- }
-
- void add(const DInputSocket &dsocket, fn::MFInputSocket &socket)
- {
- sockets_by_dsocket_.add(dsocket, &socket);
- }
-
- void add(const DOutputSocket &dsocket, fn::MFOutputSocket &socket)
- {
- /* There can be at most one matching output socket. */
- BLI_assert(sockets_by_dsocket_.lookup(dsocket).is_empty());
- sockets_by_dsocket_.add(dsocket, &socket);
- }
-
- void add(const DTreeContext &context,
- Span<const InputSocketRef *> dsockets,
- Span<fn::MFInputSocket *> sockets)
- {
- assert_same_size(dsockets, sockets);
- for (int i : dsockets.index_range()) {
- this->add(DInputSocket(&context, dsockets[i]), *sockets[i]);
- }
- }
-
- void add(const DTreeContext &context,
- Span<const OutputSocketRef *> dsockets,
- Span<fn::MFOutputSocket *> sockets)
- {
- assert_same_size(dsockets, sockets);
- for (int i : dsockets.index_range()) {
- this->add(DOutputSocket(&context, dsockets[i]), *sockets[i]);
- }
- }
-
- void add_try_match(const DNode &dnode, fn::MFNode &node)
- {
- this->add_try_match(*dnode.context(),
- dnode->inputs().cast<const SocketRef *>(),
- node.inputs().cast<fn::MFSocket *>());
- this->add_try_match(*dnode.context(),
- dnode->outputs().cast<const SocketRef *>(),
- node.outputs().cast<fn::MFSocket *>());
- }
-
- void add_try_match(const DTreeContext &context,
- Span<const InputSocketRef *> dsockets,
- Span<fn::MFInputSocket *> sockets)
- {
- this->add_try_match(
- context, dsockets.cast<const SocketRef *>(), sockets.cast<fn::MFSocket *>());
- }
-
- void add_try_match(const DTreeContext &context,
- Span<const OutputSocketRef *> dsockets,
- Span<fn::MFOutputSocket *> sockets)
- {
- this->add_try_match(
- context, dsockets.cast<const SocketRef *>(), sockets.cast<fn::MFSocket *>());
- }
-
- void add_try_match(const DTreeContext &context,
- Span<const SocketRef *> dsockets,
- Span<fn::MFSocket *> sockets)
- {
- int used_sockets = 0;
- for (const SocketRef *dsocket : dsockets) {
- if (!dsocket->is_available()) {
- continue;
- }
- if (!socket_is_mf_data_socket(*dsocket->typeinfo())) {
- continue;
- }
- fn::MFSocket *socket = sockets[used_sockets];
- this->add(DSocket(&context, dsocket), *socket);
- used_sockets++;
- }
- }
-
- fn::MFOutputSocket &lookup(const DOutputSocket &dsocket)
- {
- return sockets_by_dsocket_.lookup(dsocket)[0]->as_output();
- }
-
- Span<fn::MFInputSocket *> lookup(const DInputSocket &dsocket)
- {
- return sockets_by_dsocket_.lookup(dsocket).cast<fn::MFInputSocket *>();
- }
-
- fn::MFInputSocket &lookup_dummy(const DInputSocket &dsocket)
- {
- Span<fn::MFInputSocket *> sockets = this->lookup(dsocket);
- BLI_assert(sockets.size() == 1);
- fn::MFInputSocket &socket = *sockets[0];
- BLI_assert(socket.node().is_dummy());
- return socket;
- }
-
- fn::MFOutputSocket &lookup_dummy(const DOutputSocket &dsocket)
- {
- fn::MFOutputSocket &socket = this->lookup(dsocket);
- BLI_assert(socket.node().is_dummy());
- return socket;
- }
-
- bool is_mapped(const DSocket &dsocket) const
- {
- return !sockets_by_dsocket_.lookup(dsocket).is_empty();
- }
-};
-
-/**
- * This data is necessary throughout the generation of a MFNetwork from a node tree.
- */
-struct CommonMFNetworkBuilderData {
- ResourceScope &scope;
- fn::MFNetwork &network;
- MFNetworkTreeMap &network_map;
- const DerivedNodeTree &tree;
-};
-
-class MFNetworkBuilderBase {
- protected:
- CommonMFNetworkBuilderData &common_;
-
- public:
- MFNetworkBuilderBase(CommonMFNetworkBuilderData &common) : common_(common)
- {
- }
-
- /**
- * Returns the network that is currently being built.
- */
- fn::MFNetwork &network()
- {
- return common_.network;
- }
-
- /**
- * Returns the map between the node tree and the multi-function network that is being built.
- */
- MFNetworkTreeMap &network_map()
- {
- return common_.network_map;
- }
-
- /**
- * Returns a resource collector that will only be destructed after the multi-function network is
- * destructed.
- */
- ResourceScope &resource_scope()
- {
- return common_.scope;
- }
-
- /**
- * Constructs a new function that will live at least as long as the MFNetwork.
- */
- template<typename T, typename... Args> T &construct_fn(Args &&...args)
- {
- BLI_STATIC_ASSERT((std::is_base_of_v<fn::MultiFunction, T>), "");
- void *buffer = common_.scope.linear_allocator().allocate(sizeof(T), alignof(T));
- T *fn = new (buffer) T(std::forward<Args>(args)...);
- common_.scope.add(destruct_ptr<T>(fn), fn->name().c_str());
- return *fn;
- }
-};
-
-/**
- * This class is used by socket implementations to define how an unlinked input socket is handled
- * in a multi-function network.
- */
-class SocketMFNetworkBuilder : public MFNetworkBuilderBase {
- private:
- bNodeSocket *bsocket_;
- fn::MFOutputSocket *built_socket_ = nullptr;
-
- public:
- SocketMFNetworkBuilder(CommonMFNetworkBuilderData &common, const DSocket &dsocket)
- : MFNetworkBuilderBase(common), bsocket_(dsocket->bsocket())
- {
- }
-
- /**
- * Returns the socket that is currently being built.
- */
- bNodeSocket &bsocket()
- {
- return *bsocket_;
- }
-
- /**
- * Utility method that returns bsocket->default_value for the current socket.
- */
- template<typename T> T *socket_default_value()
- {
- return static_cast<T *>(bsocket_->default_value);
- }
-
- /**
- * Builds a function node for that socket that outputs the given constant value.
- */
- template<typename T> void set_constant_value(T value)
- {
- this->construct_generator_fn<fn::CustomMF_Constant<T>>(std::move(value));
- }
- void set_constant_value(const CPPType &type, const void *value)
- {
- /* The value has live as long as the generated mf network. */
- this->construct_generator_fn<fn::CustomMF_GenericConstant>(type, value);
- }
-
- template<typename T, typename... Args> void construct_generator_fn(Args &&...args)
- {
- const fn::MultiFunction &fn = this->construct_fn<T>(std::forward<Args>(args)...);
- this->set_generator_fn(fn);
- }
-
- /**
- * Uses the first output of the given multi-function as value of the socket.
- */
- void set_generator_fn(const fn::MultiFunction &fn)
- {
- fn::MFFunctionNode &node = common_.network.add_function(fn);
- this->set_socket(node.output(0));
- }
-
- /**
- * Define a multi-function socket that outputs the value of the bsocket.
- */
- void set_socket(fn::MFOutputSocket &socket)
- {
- built_socket_ = &socket;
- }
-
- fn::MFOutputSocket *built_socket()
- {
- return built_socket_;
- }
-};
-
-/**
- * This class is used by node implementations to define how a user-level node expands into
- * multi-function nodes internally.
- */
-class NodeMFNetworkBuilder : public MFNetworkBuilderBase {
- private:
- DNode dnode_;
-
- public:
- NodeMFNetworkBuilder(CommonMFNetworkBuilderData &common, DNode dnode)
- : MFNetworkBuilderBase(common), dnode_(dnode)
- {
- }
-
- /**
- * Tells the builder to build a function that corresponds to the node that is being built. It
- * will try to match up sockets.
- */
- template<typename T, typename... Args> T &construct_and_set_matching_fn(Args &&...args)
- {
- T &function = this->construct_fn<T>(std::forward<Args>(args)...);
- this->set_matching_fn(function);
- return function;
- }
-
- const fn::MultiFunction &get_not_implemented_fn()
- {
- return this->get_default_fn("Not Implemented (" + dnode_->name() + ")");
- }
-
- const fn::MultiFunction &get_default_fn(StringRef name);
-
- const void set_not_implemented()
- {
- this->set_matching_fn(this->get_not_implemented_fn());
- }
-
- /**
- * Tells the builder that the given function corresponds to the node that is being built. It will
- * try to match up sockets. For that it skips unavailable and non-data sockets.
- */
- void set_matching_fn(const fn::MultiFunction &function)
- {
- fn::MFFunctionNode &node = common_.network.add_function(function);
- common_.network_map.add_try_match(dnode_, node);
- }
-
- /**
- * Returns the node that is currently being built.
- */
- bNode &bnode()
- {
- return *dnode_->bnode();
- }
-
- /**
- * Returns the node that is currently being built.
- */
- const DNode &dnode() const
- {
- return dnode_;
- }
-};
-
-MFNetworkTreeMap insert_node_tree_into_mf_network(fn::MFNetwork &network,
- const DerivedNodeTree &tree,
- ResourceScope &scope);
-
-using MultiFunctionByNode = Map<DNode, const fn::MultiFunction *>;
-MultiFunctionByNode get_multi_function_per_node(const DerivedNodeTree &tree, ResourceScope &scope);
-
-} // namespace blender::nodes
diff --git a/source/blender/nodes/function/node_function_util.hh b/source/blender/nodes/function/node_function_util.hh
index 9fbd6712827..96a8f29c3e9 100644
--- a/source/blender/nodes/function/node_function_util.hh
+++ b/source/blender/nodes/function/node_function_util.hh
@@ -30,7 +30,7 @@
#include "BLT_translation.h"
#include "NOD_function.h"
-#include "NOD_node_tree_multi_function.hh"
+#include "NOD_multi_function.hh"
#include "node_util.h"
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 7a83ff8e016..0ba9080918c 100644
--- a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
+++ b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
@@ -58,7 +58,7 @@ static void node_boolean_math_label(bNodeTree *UNUSED(ntree), bNode *node, char
BLI_strncpy(label, IFACE_(name), maxlen);
}
-static const blender::fn::MultiFunction &get_multi_function(bNode &bnode)
+static const blender::fn::MultiFunction *get_multi_function(bNode &bnode)
{
static blender::fn::CustomMF_SI_SI_SO<bool, bool, bool> and_fn{
"And", [](bool a, bool b) { return a && b; }};
@@ -68,20 +68,21 @@ static const blender::fn::MultiFunction &get_multi_function(bNode &bnode)
switch (bnode.custom1) {
case NODE_BOOLEAN_MATH_AND:
- return and_fn;
+ return &and_fn;
case NODE_BOOLEAN_MATH_OR:
- return or_fn;
+ return &or_fn;
case NODE_BOOLEAN_MATH_NOT:
- return not_fn;
+ return &not_fn;
}
- BLI_assert(false);
- return blender::fn::dummy_multi_function;
+ BLI_assert_unreachable();
+ return nullptr;
}
-static void node_boolean_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder)
+static void fn_node_boolean_math_build_multi_function(
+ blender::nodes::NodeMultiFunctionBuilder &builder)
{
- const blender::fn::MultiFunction &fn = get_multi_function(builder.bnode());
+ const blender::fn::MultiFunction *fn = get_multi_function(builder.node());
builder.set_matching_fn(fn);
}
@@ -93,7 +94,7 @@ void register_node_type_fn_boolean_math()
node_type_socket_templates(&ntype, fn_node_boolean_math_in, fn_node_boolean_math_out);
node_type_label(&ntype, node_boolean_math_label);
node_type_update(&ntype, node_boolean_math_update);
- ntype.expand_in_mf_network = node_boolean_expand_in_mf_network;
+ ntype.build_multi_function = fn_node_boolean_math_build_multi_function;
ntype.draw_buttons = fn_node_boolean_math_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_float_compare.cc b/source/blender/nodes/function/nodes/node_fn_float_compare.cc
index 6c8df8f2ea0..16ffb761a15 100644
--- a/source/blender/nodes/function/nodes/node_fn_float_compare.cc
+++ b/source/blender/nodes/function/nodes/node_fn_float_compare.cc
@@ -64,7 +64,7 @@ static void node_float_compare_label(bNodeTree *UNUSED(ntree),
BLI_strncpy(label, IFACE_(name), maxlen);
}
-static const blender::fn::MultiFunction &get_multi_function(bNode &node)
+static const blender::fn::MultiFunction *get_multi_function(bNode &node)
{
static blender::fn::CustomMF_SI_SI_SO<float, float, bool> less_than_fn{
"Less Than", [](float a, float b) { return a < b; }};
@@ -81,26 +81,27 @@ static const blender::fn::MultiFunction &get_multi_function(bNode &node)
switch (node.custom1) {
case NODE_FLOAT_COMPARE_LESS_THAN:
- return less_than_fn;
+ return &less_than_fn;
case NODE_FLOAT_COMPARE_LESS_EQUAL:
- return less_equal_fn;
+ return &less_equal_fn;
case NODE_FLOAT_COMPARE_GREATER_THAN:
- return greater_than_fn;
+ return &greater_than_fn;
case NODE_FLOAT_COMPARE_GREATER_EQUAL:
- return greater_equal_fn;
+ return &greater_equal_fn;
case NODE_FLOAT_COMPARE_EQUAL:
- return equal_fn;
+ return &equal_fn;
case NODE_FLOAT_COMPARE_NOT_EQUAL:
- return not_equal_fn;
+ return &not_equal_fn;
}
- BLI_assert(false);
- return blender::fn::dummy_multi_function;
+ BLI_assert_unreachable();
+ return nullptr;
}
-static void node_float_compare_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder)
+static void fn_node_float_compare_build_multi_function(
+ blender::nodes::NodeMultiFunctionBuilder &builder)
{
- const blender::fn::MultiFunction &fn = get_multi_function(builder.bnode());
+ const blender::fn::MultiFunction *fn = get_multi_function(builder.node());
builder.set_matching_fn(fn);
}
@@ -112,7 +113,7 @@ void register_node_type_fn_float_compare()
node_type_socket_templates(&ntype, fn_node_float_compare_in, fn_node_float_compare_out);
node_type_label(&ntype, node_float_compare_label);
node_type_update(&ntype, node_float_compare_update);
- ntype.expand_in_mf_network = node_float_compare_expand_in_mf_network;
+ ntype.build_multi_function = fn_node_float_compare_build_multi_function;
ntype.draw_buttons = geo_node_float_compare_layout;
nodeRegisterType(&ntype);
}
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 26cde576400..52acfefe615 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
@@ -50,7 +50,7 @@ static void node_float_to_int_label(bNodeTree *UNUSED(ntree), bNode *node, char
BLI_strncpy(label, IFACE_(name), maxlen);
}
-static const blender::fn::MultiFunction &get_multi_function(bNode &bnode)
+static const blender::fn::MultiFunction *get_multi_function(bNode &bnode)
{
static blender::fn::CustomMF_SI_SO<float, int> round_fn{"Round",
[](float a) { return (int)round(a); }};
@@ -63,22 +63,23 @@ static const blender::fn::MultiFunction &get_multi_function(bNode &bnode)
switch (static_cast<FloatToIntRoundingMode>(bnode.custom1)) {
case FN_NODE_FLOAT_TO_INT_ROUND:
- return round_fn;
+ return &round_fn;
case FN_NODE_FLOAT_TO_INT_FLOOR:
- return floor_fn;
+ return &floor_fn;
case FN_NODE_FLOAT_TO_INT_CEIL:
- return ceil_fn;
+ return &ceil_fn;
case FN_NODE_FLOAT_TO_INT_TRUNCATE:
- return trunc_fn;
+ return &trunc_fn;
}
BLI_assert_unreachable();
- return blender::fn::dummy_multi_function;
+ return nullptr;
}
-static void node_float_to_int_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder)
+static void fn_node_float_to_int_build_multi_function(
+ blender::nodes::NodeMultiFunctionBuilder &builder)
{
- const blender::fn::MultiFunction &fn = get_multi_function(builder.bnode());
+ const blender::fn::MultiFunction *fn = get_multi_function(builder.node());
builder.set_matching_fn(fn);
}
@@ -89,7 +90,7 @@ void register_node_type_fn_float_to_int()
fn_node_type_base(&ntype, FN_NODE_FLOAT_TO_INT, "Float to Integer", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, fn_node_float_to_int_in, fn_node_float_to_int_out);
node_type_label(&ntype, node_float_to_int_label);
- ntype.expand_in_mf_network = node_float_to_int_expand_in_mf_network;
+ ntype.build_multi_function = fn_node_float_to_int_build_multi_function;
ntype.draw_buttons = fn_node_float_to_int_layout;
nodeRegisterType(&ntype);
}
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 f16bdef2f38..560ace57aba 100644
--- a/source/blender/nodes/function/nodes/node_fn_input_string.cc
+++ b/source/blender/nodes/function/nodes/node_fn_input_string.cc
@@ -29,14 +29,14 @@ static void fn_node_input_string_layout(uiLayout *layout, bContext *UNUSED(C), P
uiItemR(layout, ptr, "string", 0, "", ICON_NONE);
}
-static void fn_node_input_string_expand_in_mf_network(
- blender::nodes::NodeMFNetworkBuilder &builder)
+static void fn_node_input_string_build_multi_function(
+ blender::nodes::NodeMultiFunctionBuilder &builder)
{
- bNode &bnode = builder.bnode();
+ bNode &bnode = builder.node();
NodeInputString *node_storage = static_cast<NodeInputString *>(bnode.storage);
std::string string = std::string((node_storage->string) ? node_storage->string : "");
-
- builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<std::string>>(string);
+ builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<std::string>>(
+ std::move(string));
}
static void fn_node_input_string_init(bNodeTree *UNUSED(ntree), bNode *node)
@@ -78,7 +78,7 @@ void register_node_type_fn_input_string()
node_type_socket_templates(&ntype, nullptr, fn_node_input_string_out);
node_type_init(&ntype, fn_node_input_string_init);
node_type_storage(&ntype, "NodeInputString", fn_node_input_string_free, fn_node_string_copy);
- ntype.expand_in_mf_network = fn_node_input_string_expand_in_mf_network;
+ ntype.build_multi_function = fn_node_input_string_build_multi_function;
ntype.draw_buttons = fn_node_input_string_layout;
nodeRegisterType(&ntype);
}
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 2cd4eb1d9df..244c045de9a 100644
--- a/source/blender/nodes/function/nodes/node_fn_input_vector.cc
+++ b/source/blender/nodes/function/nodes/node_fn_input_vector.cc
@@ -32,16 +32,14 @@ static void fn_node_input_vector_layout(uiLayout *layout, bContext *UNUSED(C), P
uiItemR(col, ptr, "vector", UI_ITEM_R_EXPAND, "", ICON_NONE);
}
-static void fn_node_vector_input_expand_in_mf_network(
- blender::nodes::NodeMFNetworkBuilder &builder)
+static void fn_node_vector_input_build_multi_function(
+ blender::nodes::NodeMultiFunctionBuilder &builder)
{
- bNode &bnode = builder.bnode();
+ bNode &bnode = builder.node();
NodeInputVector *node_storage = static_cast<NodeInputVector *>(bnode.storage);
blender::float3 vector(node_storage->vector);
-
builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<blender::float3>>(vector);
}
-
static void fn_node_input_vector_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeInputVector *data = (NodeInputVector *)MEM_callocN(sizeof(NodeInputVector),
@@ -58,7 +56,7 @@ void register_node_type_fn_input_vector()
node_type_init(&ntype, fn_node_input_vector_init);
node_type_storage(
&ntype, "NodeInputVector", node_free_standard_storage, node_copy_standard_storage);
- ntype.expand_in_mf_network = fn_node_vector_input_expand_in_mf_network;
+ ntype.build_multi_function = fn_node_vector_input_build_multi_function;
ntype.draw_buttons = fn_node_input_vector_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_random_float.cc b/source/blender/nodes/function/nodes/node_fn_random_float.cc
index a3c9f44b6a1..47ec9adf6bd 100644
--- a/source/blender/nodes/function/nodes/node_fn_random_float.cc
+++ b/source/blender/nodes/function/nodes/node_fn_random_float.cc
@@ -67,10 +67,11 @@ class RandomFloatFunction : public blender::fn::MultiFunction {
}
};
-static void fn_node_random_float_expand_in_mf_network(
- blender::nodes::NodeMFNetworkBuilder &builder)
+static void fn_node_random_float_build_multi_function(
+ blender::nodes::NodeMultiFunctionBuilder &builder)
{
- builder.construct_and_set_matching_fn<RandomFloatFunction>();
+ static RandomFloatFunction fn;
+ builder.set_matching_fn(fn);
}
void register_node_type_fn_random_float()
@@ -79,6 +80,6 @@ void register_node_type_fn_random_float()
fn_node_type_base(&ntype, FN_NODE_RANDOM_FLOAT, "Random Float", 0, 0);
node_type_socket_templates(&ntype, fn_node_random_float_in, fn_node_random_float_out);
- ntype.expand_in_mf_network = fn_node_random_float_expand_in_mf_network;
+ ntype.build_multi_function = fn_node_random_float_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc
index ffa20579acc..a3bbca90731 100644
--- a/source/blender/nodes/intern/node_geometry_exec.cc
+++ b/source/blender/nodes/intern/node_geometry_exec.cc
@@ -19,7 +19,6 @@
#include "DEG_depsgraph_query.h"
#include "NOD_geometry_exec.hh"
-#include "NOD_type_callbacks.hh"
#include "NOD_type_conversions.hh"
#include "node_geometry_util.hh"
diff --git a/source/blender/nodes/NOD_type_callbacks.hh b/source/blender/nodes/intern/node_multi_function.cc
index 2be78f929db..c91899ed8c2 100644
--- a/source/blender/nodes/NOD_type_callbacks.hh
+++ b/source/blender/nodes/intern/node_multi_function.cc
@@ -14,21 +14,27 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#pragma once
-
-#include <optional>
-
-#include "BKE_node.h"
-
-#include "FN_multi_function_data_type.hh"
+#include "NOD_multi_function.hh"
namespace blender::nodes {
-using fn::CPPType;
-using fn::MFDataType;
-
-std::optional<MFDataType> socket_mf_type_get(const bNodeSocketType &stype);
-bool socket_is_mf_data_socket(const bNodeSocketType &stype);
-void socket_expand_in_mf_network(SocketMFNetworkBuilder &builder);
+NodeMultiFunctions::NodeMultiFunctions(const DerivedNodeTree &tree, ResourceScope &resource_scope)
+{
+ 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();
+ if (bnode->typeinfo->build_multi_function == nullptr) {
+ continue;
+ }
+ NodeMultiFunctionBuilder builder{resource_scope, *bnode, *btree};
+ bnode->typeinfo->build_multi_function(builder);
+ const MultiFunction *fn = builder.built_fn_;
+ if (fn != nullptr) {
+ map_.add_new(bnode, fn);
+ }
+ }
+ }
+}
} // namespace blender::nodes
diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc
index 4be3fd2468b..528616eb23a 100644
--- a/source/blender/nodes/intern/node_socket.cc
+++ b/source/blender/nodes/intern/node_socket.cc
@@ -44,7 +44,6 @@
#include "MEM_guardedalloc.h"
-#include "NOD_node_tree_multi_function.hh"
#include "NOD_socket.h"
#include "FN_cpp_type_make.hh"
diff --git a/source/blender/nodes/intern/node_tree_multi_function.cc b/source/blender/nodes/intern/node_tree_multi_function.cc
deleted file mode 100644
index 7ab6495f733..00000000000
--- a/source/blender/nodes/intern/node_tree_multi_function.cc
+++ /dev/null
@@ -1,409 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include "NOD_node_tree_multi_function.hh"
-#include "NOD_type_conversions.hh"
-
-#include "FN_multi_function_network_evaluation.hh"
-
-#include "BLI_color.hh"
-#include "BLI_float2.hh"
-#include "BLI_float3.hh"
-
-namespace blender::nodes {
-
-const fn::MultiFunction &NodeMFNetworkBuilder::get_default_fn(StringRef name)
-{
- Vector<fn::MFDataType, 10> input_types;
- Vector<fn::MFDataType, 10> output_types;
-
- for (const InputSocketRef *dsocket : dnode_->inputs()) {
- if (dsocket->is_available()) {
- std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->typeinfo());
- if (data_type.has_value()) {
- input_types.append(*data_type);
- }
- }
- }
- for (const OutputSocketRef *dsocket : dnode_->outputs()) {
- if (dsocket->is_available()) {
- std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->typeinfo());
- if (data_type.has_value()) {
- output_types.append(*data_type);
- }
- }
- }
-
- const fn::MultiFunction &fn = this->construct_fn<fn::CustomMF_DefaultOutput>(
- name, input_types, output_types);
- return fn;
-}
-
-static void insert_dummy_node(CommonMFNetworkBuilderData &common, const DNode &dnode)
-{
- constexpr int stack_capacity = 10;
-
- Vector<fn::MFDataType, stack_capacity> input_types;
- Vector<StringRef, stack_capacity> input_names;
- Vector<const InputSocketRef *, stack_capacity> input_dsockets;
-
- for (const InputSocketRef *dsocket : dnode->inputs()) {
- if (dsocket->is_available()) {
- std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo);
- if (data_type.has_value()) {
- input_types.append(*data_type);
- input_names.append(dsocket->name());
- input_dsockets.append(dsocket);
- }
- }
- }
-
- Vector<fn::MFDataType, stack_capacity> output_types;
- Vector<StringRef, stack_capacity> output_names;
- Vector<const OutputSocketRef *, stack_capacity> output_dsockets;
-
- for (const OutputSocketRef *dsocket : dnode->outputs()) {
- if (dsocket->is_available()) {
- std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo);
- if (data_type.has_value()) {
- output_types.append(*data_type);
- output_names.append(dsocket->name());
- output_dsockets.append(dsocket);
- }
- }
- }
-
- fn::MFDummyNode &dummy_node = common.network.add_dummy(
- dnode->name(), input_types, output_types, input_names, output_names);
-
- common.network_map.add(*dnode.context(), input_dsockets, dummy_node.inputs());
- common.network_map.add(*dnode.context(), output_dsockets, dummy_node.outputs());
-}
-
-static bool has_data_sockets(const DNode &dnode)
-{
- for (const InputSocketRef *socket : dnode->inputs()) {
- if (socket_is_mf_data_socket(*socket->bsocket()->typeinfo)) {
- return true;
- }
- }
- for (const OutputSocketRef *socket : dnode->outputs()) {
- if (socket_is_mf_data_socket(*socket->bsocket()->typeinfo)) {
- return true;
- }
- }
- return false;
-}
-
-static void foreach_node_to_insert(CommonMFNetworkBuilderData &common,
- FunctionRef<void(DNode)> callback)
-{
- common.tree.foreach_node([&](const DNode dnode) {
- if (dnode->is_group_node()) {
- return;
- }
- /* Don't insert non-root group input/output nodes, because they will be inlined. */
- if (!dnode.context()->is_root()) {
- if (dnode->is_group_input_node() || dnode->is_group_output_node()) {
- return;
- }
- }
- callback(dnode);
- });
-}
-
-/**
- * Expands all function nodes in the multi-function network. Nodes that don't have an expand
- * function, but do have data sockets, will get corresponding dummy nodes.
- */
-static void insert_nodes(CommonMFNetworkBuilderData &common)
-{
- foreach_node_to_insert(common, [&](const DNode dnode) {
- const bNodeType *node_type = dnode->typeinfo();
- if (node_type->expand_in_mf_network != nullptr) {
- NodeMFNetworkBuilder builder{common, dnode};
- node_type->expand_in_mf_network(builder);
- }
- else if (has_data_sockets(dnode)) {
- insert_dummy_node(common, dnode);
- }
- });
-}
-
-static fn::MFOutputSocket &insert_default_value_for_type(CommonMFNetworkBuilderData &common,
- fn::MFDataType type)
-{
- const fn::MultiFunction *default_fn;
- if (type.is_single()) {
- default_fn = &common.scope.construct<fn::CustomMF_GenericConstant>(
- AT, type.single_type(), type.single_type().default_value());
- }
- else {
- default_fn = &common.scope.construct<fn::CustomMF_GenericConstantArray>(
- AT, fn::GSpan(type.vector_base_type()));
- }
-
- fn::MFNode &node = common.network.add_function(*default_fn);
- return node.output(0);
-}
-
-static fn::MFOutputSocket *insert_unlinked_input(CommonMFNetworkBuilderData &common,
- const DInputSocket &dsocket)
-{
- BLI_assert(socket_is_mf_data_socket(*dsocket->typeinfo()));
-
- SocketMFNetworkBuilder builder{common, dsocket};
- socket_expand_in_mf_network(builder);
-
- fn::MFOutputSocket *built_socket = builder.built_socket();
- BLI_assert(built_socket != nullptr);
- return built_socket;
-}
-
-static void insert_links_and_unlinked_inputs(CommonMFNetworkBuilderData &common)
-{
- foreach_node_to_insert(common, [&](const DNode dnode) {
- for (const InputSocketRef *socket_ref : dnode->inputs()) {
- const DInputSocket to_dsocket{dnode.context(), socket_ref};
- if (!to_dsocket->is_available()) {
- continue;
- }
- if (!socket_is_mf_data_socket(*to_dsocket->typeinfo())) {
- continue;
- }
-
- Span<fn::MFInputSocket *> to_sockets = common.network_map.lookup(to_dsocket);
- BLI_assert(to_sockets.size() >= 1);
- const fn::MFDataType to_type = to_sockets[0]->data_type();
-
- Vector<DSocket> from_dsockets;
- to_dsocket.foreach_origin_socket([&](DSocket socket) { from_dsockets.append(socket); });
- if (from_dsockets.size() > 1) {
- fn::MFOutputSocket &from_socket = insert_default_value_for_type(common, to_type);
- for (fn::MFInputSocket *to_socket : to_sockets) {
- common.network.add_link(from_socket, *to_socket);
- }
- continue;
- }
- if (from_dsockets.is_empty()) {
- /* The socket is not linked. Need to use the value of the socket itself. */
- fn::MFOutputSocket *built_socket = insert_unlinked_input(common, to_dsocket);
- for (fn::MFInputSocket *to_socket : to_sockets) {
- common.network.add_link(*built_socket, *to_socket);
- }
- continue;
- }
- if (from_dsockets[0]->is_input()) {
- DInputSocket from_dsocket{from_dsockets[0]};
- fn::MFOutputSocket *built_socket = insert_unlinked_input(common, from_dsocket);
- for (fn::MFInputSocket *to_socket : to_sockets) {
- common.network.add_link(*built_socket, *to_socket);
- }
- continue;
- }
- DOutputSocket from_dsocket{from_dsockets[0]};
- fn::MFOutputSocket *from_socket = &common.network_map.lookup(from_dsocket);
- const fn::MFDataType from_type = from_socket->data_type();
-
- if (from_type != to_type) {
- const fn::MultiFunction *conversion_fn =
- get_implicit_type_conversions().get_conversion_multi_function(from_type, to_type);
- if (conversion_fn != nullptr) {
- fn::MFNode &node = common.network.add_function(*conversion_fn);
- common.network.add_link(*from_socket, node.input(0));
- from_socket = &node.output(0);
- }
- else {
- from_socket = &insert_default_value_for_type(common, to_type);
- }
- }
-
- for (fn::MFInputSocket *to_socket : to_sockets) {
- common.network.add_link(*from_socket, *to_socket);
- }
- }
- });
-}
-
-/**
- * Expands all function nodes contained in the given node tree within the given multi-function
- * network.
- *
- * Returns a mapping between the original node tree and the generated nodes/sockets for further
- * processing.
- */
-MFNetworkTreeMap insert_node_tree_into_mf_network(fn::MFNetwork &network,
- const DerivedNodeTree &tree,
- ResourceScope &scope)
-{
- MFNetworkTreeMap network_map{tree, network};
-
- CommonMFNetworkBuilderData common{scope, network, network_map, tree};
-
- insert_nodes(common);
- insert_links_and_unlinked_inputs(common);
-
- return network_map;
-}
-
-/**
- * A single node is allowed to expand into multiple nodes before evaluation. Depending on what
- * nodes it expands to, it belongs a different type of the ones below.
- */
-enum class NodeExpandType {
- SingleFunctionNode,
- MultipleFunctionNodes,
- HasDummyNodes,
-};
-
-/**
- * Checks how the given node expanded in the multi-function network. If it is only a single
- * function node, the corresponding function is returned as well.
- */
-static NodeExpandType get_node_expand_type(MFNetworkTreeMap &network_map,
- const DNode &dnode,
- const fn::MultiFunction **r_single_function)
-{
- const fn::MFFunctionNode *single_function_node = nullptr;
- bool has_multiple_nodes = false;
- bool has_dummy_nodes = false;
-
- auto check_mf_node = [&](fn::MFNode &mf_node) {
- if (mf_node.is_function()) {
- if (single_function_node == nullptr) {
- single_function_node = &mf_node.as_function();
- }
- if (&mf_node != single_function_node) {
- has_multiple_nodes = true;
- }
- }
- else {
- BLI_assert(mf_node.is_dummy());
- has_dummy_nodes = true;
- }
- };
-
- for (const InputSocketRef *dsocket : dnode->inputs()) {
- if (dsocket->is_available()) {
- for (fn::MFInputSocket *mf_input :
- network_map.lookup(DInputSocket(dnode.context(), dsocket))) {
- check_mf_node(mf_input->node());
- }
- }
- }
- for (const OutputSocketRef *dsocket : dnode->outputs()) {
- if (dsocket->is_available()) {
- fn::MFOutputSocket &mf_output = network_map.lookup(DOutputSocket(dnode.context(), dsocket));
- check_mf_node(mf_output.node());
- }
- }
-
- if (has_dummy_nodes) {
- return NodeExpandType::HasDummyNodes;
- }
- if (has_multiple_nodes) {
- return NodeExpandType::MultipleFunctionNodes;
- }
- *r_single_function = &single_function_node->function();
- return NodeExpandType::SingleFunctionNode;
-}
-
-static const fn::MultiFunction &create_function_for_node_that_expands_into_multiple(
- const DNode &dnode,
- fn::MFNetwork &network,
- MFNetworkTreeMap &network_map,
- ResourceScope &scope)
-{
- Vector<const fn::MFOutputSocket *> dummy_fn_inputs;
- for (const InputSocketRef *dsocket : dnode->inputs()) {
- if (dsocket->is_available()) {
- MFDataType data_type = *socket_mf_type_get(*dsocket->typeinfo());
- fn::MFOutputSocket &fn_input = network.add_input(data_type.to_string(), data_type);
- for (fn::MFInputSocket *mf_input :
- network_map.lookup(DInputSocket(dnode.context(), dsocket))) {
- network.add_link(fn_input, *mf_input);
- dummy_fn_inputs.append(&fn_input);
- }
- }
- }
- Vector<const fn::MFInputSocket *> dummy_fn_outputs;
- for (const OutputSocketRef *dsocket : dnode->outputs()) {
- if (dsocket->is_available()) {
- fn::MFOutputSocket &mf_output = network_map.lookup(DOutputSocket(dnode.context(), dsocket));
- MFDataType data_type = mf_output.data_type();
- fn::MFInputSocket &fn_output = network.add_output(data_type.to_string(), data_type);
- network.add_link(mf_output, fn_output);
- dummy_fn_outputs.append(&fn_output);
- }
- }
-
- fn::MFNetworkEvaluator &fn_evaluator = scope.construct<fn::MFNetworkEvaluator>(
- __func__, std::move(dummy_fn_inputs), std::move(dummy_fn_outputs));
- return fn_evaluator;
-}
-
-/**
- * Returns a single multi-function for every node that supports it. This makes it easier to reuse
- * the multi-function implementation of nodes in different contexts.
- */
-MultiFunctionByNode get_multi_function_per_node(const DerivedNodeTree &tree, ResourceScope &scope)
-{
- /* Build a network that nodes can insert themselves into. However, the individual nodes are not
- * connected. */
- fn::MFNetwork &network = scope.construct<fn::MFNetwork>(__func__);
- MFNetworkTreeMap network_map{tree, network};
- MultiFunctionByNode functions_by_node;
-
- CommonMFNetworkBuilderData common{scope, network, network_map, tree};
-
- tree.foreach_node([&](DNode dnode) {
- const bNodeType *node_type = dnode->typeinfo();
- if (node_type->expand_in_mf_network == nullptr) {
- /* This node does not have a multi-function implementation. */
- return;
- }
-
- NodeMFNetworkBuilder builder{common, dnode};
- node_type->expand_in_mf_network(builder);
-
- const fn::MultiFunction *single_function = nullptr;
- const NodeExpandType expand_type = get_node_expand_type(network_map, dnode, &single_function);
-
- switch (expand_type) {
- case NodeExpandType::HasDummyNodes: {
- /* Dummy nodes cannot be executed, so skip them. */
- break;
- }
- case NodeExpandType::SingleFunctionNode: {
- /* This is the common case. Most nodes just expand to a single function. */
- functions_by_node.add_new(dnode, single_function);
- break;
- }
- case NodeExpandType::MultipleFunctionNodes: {
- /* If a node expanded into multiple functions, a new function has to be created that
- * combines those. */
- const fn::MultiFunction &fn = create_function_for_node_that_expands_into_multiple(
- dnode, network, network_map, scope);
- functions_by_node.add_new(dnode, &fn);
- break;
- }
- }
- });
-
- return functions_by_node;
-}
-
-} // namespace blender::nodes
diff --git a/source/blender/nodes/intern/type_callbacks.cc b/source/blender/nodes/intern/type_callbacks.cc
deleted file mode 100644
index 881a02c92e9..00000000000
--- a/source/blender/nodes/intern/type_callbacks.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include "NOD_node_tree_multi_function.hh"
-#include "NOD_type_callbacks.hh"
-
-namespace blender::nodes {
-
-std::optional<MFDataType> socket_mf_type_get(const bNodeSocketType &stype)
-{
- const CPPType *cpp_type = stype.get_base_cpp_type ? stype.get_base_cpp_type() : nullptr;
- if (cpp_type != nullptr) {
- return MFDataType::ForSingle(*cpp_type);
- }
- return {};
-}
-
-bool socket_is_mf_data_socket(const bNodeSocketType &stype)
-{
- if (!socket_mf_type_get(stype).has_value()) {
- return false;
- }
- if (stype.expand_in_mf_network == nullptr && stype.get_base_cpp_value == nullptr) {
- return false;
- }
- return true;
-}
-
-void socket_expand_in_mf_network(SocketMFNetworkBuilder &builder)
-{
- bNodeSocket &socket = builder.bsocket();
- if (socket.typeinfo->expand_in_mf_network != nullptr) {
- socket.typeinfo->expand_in_mf_network(builder);
- }
- else if (socket.typeinfo->get_base_cpp_value != nullptr) {
- const CPPType &type = *socket.typeinfo->get_base_cpp_type();
- void *buffer = builder.resource_scope().linear_allocator().allocate(type.size(),
- type.alignment());
- socket.typeinfo->get_base_cpp_value(socket, buffer);
- builder.set_constant_value(type, buffer);
- }
- else {
- BLI_assert_unreachable();
- }
-}
-
-} // namespace blender::nodes
diff --git a/source/blender/nodes/shader/node_shader_util.h b/source/blender/nodes/shader/node_shader_util.h
index dc44f0fa98f..a75354d3381 100644
--- a/source/blender/nodes/shader/node_shader_util.h
+++ b/source/blender/nodes/shader/node_shader_util.h
@@ -72,7 +72,7 @@
#ifdef __cplusplus
# include "FN_multi_function_builder.hh"
-# include "NOD_node_tree_multi_function.hh"
+# include "NOD_multi_function.hh"
# include "BLI_color.hh"
# include "BLI_float3.hh"
diff --git a/source/blender/nodes/shader/nodes/node_shader_clamp.cc b/source/blender/nodes/shader/nodes/node_shader_clamp.cc
index 4f77421cfe0..f105f8bcaf9 100644
--- a/source/blender/nodes/shader/nodes/node_shader_clamp.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_clamp.cc
@@ -51,7 +51,7 @@ static int gpu_shader_clamp(GPUMaterial *mat,
GPU_stack_link(mat, node, "clamp_range", in, out);
}
-static void sh_node_clamp_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder)
+static void sh_node_clamp_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
{
static blender::fn::CustomMF_SI_SI_SI_SO<float, float, float, float> minmax_fn{
"Clamp (Min Max)",
@@ -65,7 +65,7 @@ static void sh_node_clamp_expand_in_mf_network(blender::nodes::NodeMFNetworkBuil
return clamp_f(value, b, a);
}};
- int clamp_type = builder.bnode().custom1;
+ int clamp_type = builder.node().custom1;
if (clamp_type == NODE_CLAMP_MINMAX) {
builder.set_matching_fn(minmax_fn);
}
@@ -82,7 +82,7 @@ void register_node_type_sh_clamp(void)
node_type_socket_templates(&ntype, sh_node_clamp_in, sh_node_clamp_out);
node_type_init(&ntype, node_shader_init_clamp);
node_type_gpu(&ntype, gpu_shader_clamp);
- ntype.expand_in_mf_network = sh_node_clamp_expand_in_mf_network;
+ ntype.build_multi_function = sh_node_clamp_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_curves.cc b/source/blender/nodes/shader/nodes/node_shader_curves.cc
index f1d5040a292..df075d6e973 100644
--- a/source/blender/nodes/shader/nodes/node_shader_curves.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_curves.cc
@@ -143,9 +143,10 @@ class CurveVecFunction : public blender::fn::MultiFunction {
}
};
-static void sh_node_curve_vec_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder)
+static void sh_node_curve_vec_build_multi_function(
+ blender::nodes::NodeMultiFunctionBuilder &builder)
{
- bNode &bnode = builder.bnode();
+ bNode &bnode = builder.node();
CurveMapping *cumap = (CurveMapping *)bnode.storage;
BKE_curvemapping_init(cumap);
builder.construct_and_set_matching_fn<CurveVecFunction>(*cumap);
@@ -162,7 +163,7 @@ void register_node_type_sh_curve_vec(void)
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
node_type_exec(&ntype, node_initexec_curves, nullptr, node_shader_exec_curve_vec);
node_type_gpu(&ntype, gpu_shader_curve_vec);
- ntype.expand_in_mf_network = sh_node_curve_vec_expand_in_mf_network;
+ ntype.build_multi_function = sh_node_curve_vec_build_multi_function;
nodeRegisterType(&ntype);
}
@@ -317,9 +318,10 @@ class CurveRGBFunction : public blender::fn::MultiFunction {
}
};
-static void sh_node_curve_rgb_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder)
+static void sh_node_curve_rgb_build_multi_function(
+ blender::nodes::NodeMultiFunctionBuilder &builder)
{
- bNode &bnode = builder.bnode();
+ bNode &bnode = builder.node();
CurveMapping *cumap = (CurveMapping *)bnode.storage;
BKE_curvemapping_init(cumap);
builder.construct_and_set_matching_fn<CurveRGBFunction>(*cumap);
@@ -336,7 +338,7 @@ void register_node_type_sh_curve_rgb(void)
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
node_type_exec(&ntype, node_initexec_curves, nullptr, node_shader_exec_curve_rgb);
node_type_gpu(&ntype, gpu_shader_curve_rgb);
- ntype.expand_in_mf_network = sh_node_curve_rgb_expand_in_mf_network;
+ ntype.build_multi_function = sh_node_curve_rgb_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_map_range.cc b/source/blender/nodes/shader/nodes/node_shader_map_range.cc
index ad7abd9d491..e4739e2864d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_map_range.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_map_range.cc
@@ -261,9 +261,10 @@ class MapRangeSmootherstepFunction : public blender::fn::MultiFunction {
}
};
-static void sh_node_map_range_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder)
+static void sh_node_map_range_build_multi_function(
+ blender::nodes::NodeMultiFunctionBuilder &builder)
{
- bNode &bnode = builder.bnode();
+ bNode &bnode = builder.node();
bool clamp = bnode.custom1 != 0;
int interpolation_type = bnode.custom2;
@@ -301,7 +302,6 @@ static void sh_node_map_range_expand_in_mf_network(blender::nodes::NodeMFNetwork
break;
}
default:
- builder.set_not_implemented();
break;
}
}
@@ -315,7 +315,7 @@ void register_node_type_sh_map_range(void)
node_type_init(&ntype, node_shader_init_map_range);
node_type_update(&ntype, node_shader_update_map_range);
node_type_gpu(&ntype, gpu_shader_map_range);
- ntype.expand_in_mf_network = sh_node_map_range_expand_in_mf_network;
+ ntype.build_multi_function = sh_node_map_range_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_math.cc b/source/blender/nodes/shader/nodes/node_shader_math.cc
index 7a846031456..c30f2948ab1 100644
--- a/source/blender/nodes/shader/nodes/node_shader_math.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_math.cc
@@ -69,11 +69,9 @@ static int gpu_shader_math(GPUMaterial *mat,
return 0;
}
-static const blender::fn::MultiFunction &get_base_multi_function(
- blender::nodes::NodeMFNetworkBuilder &builder)
+static const blender::fn::MultiFunction *get_base_multi_function(bNode &node)
{
- const int mode = builder.bnode().custom1;
-
+ const int mode = node.custom1;
const blender::fn::MultiFunction *base_fn = nullptr;
blender::nodes::try_dispatch_float_math_fl_to_fl(
@@ -82,7 +80,7 @@ static const blender::fn::MultiFunction &get_base_multi_function(
base_fn = &fn;
});
if (base_fn != nullptr) {
- return *base_fn;
+ return base_fn;
}
blender::nodes::try_dispatch_float_math_fl_fl_to_fl(
@@ -92,7 +90,7 @@ static const blender::fn::MultiFunction &get_base_multi_function(
base_fn = &fn;
});
if (base_fn != nullptr) {
- return *base_fn;
+ return base_fn;
}
blender::nodes::try_dispatch_float_math_fl_fl_fl_to_fl(
@@ -102,36 +100,51 @@ static const blender::fn::MultiFunction &get_base_multi_function(
base_fn = &fn;
});
if (base_fn != nullptr) {
- return *base_fn;
+ return base_fn;
}
- return builder.get_not_implemented_fn();
+ return nullptr;
}
-static void sh_node_math_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder)
-{
- const blender::fn::MultiFunction &base_function = get_base_multi_function(builder);
+class ClampWrapperFunction : public blender::fn::MultiFunction {
+ private:
+ const blender::fn::MultiFunction &fn_;
- const blender::nodes::DNode &dnode = builder.dnode();
- blender::fn::MFNetwork &network = builder.network();
- blender::fn::MFFunctionNode &base_node = network.add_function(base_function);
+ public:
+ ClampWrapperFunction(const blender::fn::MultiFunction &fn) : fn_(fn)
+ {
+ this->set_signature(&fn.signature());
+ }
- builder.network_map().add_try_match(*dnode.context(), dnode->inputs(), base_node.inputs());
+ void call(blender::IndexMask mask,
+ blender::fn::MFParams params,
+ blender::fn::MFContext context) const override
+ {
+ fn_.call(mask, params, context);
+
+ /* Assumes the output parameter is the last one. */
+ const int output_param_index = this->param_amount() - 1;
+ /* This has actually been initialized in the call above. */
+ blender::MutableSpan<float> results = params.uninitialized_single_output<float>(
+ output_param_index);
+
+ for (const int i : mask) {
+ float &value = results[i];
+ CLAMP(value, 0.0f, 1.0f);
+ }
+ }
+};
+
+static void sh_node_math_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
+{
+ const blender::fn::MultiFunction *base_function = get_base_multi_function(builder.node());
- const bool clamp_output = builder.bnode().custom2 != 0;
+ const bool clamp_output = builder.node().custom2 != 0;
if (clamp_output) {
- static blender::fn::CustomMF_SI_SO<float, float> clamp_fn{"Clamp", [](float value) {
- CLAMP(value, 0.0f, 1.0f);
- return value;
- }};
- blender::fn::MFFunctionNode &clamp_node = network.add_function(clamp_fn);
- network.add_link(base_node.output(0), clamp_node.input(0));
- builder.network_map().add(blender::nodes::DOutputSocket(dnode.context(), &dnode->output(0)),
- clamp_node.output(0));
+ builder.construct_and_set_matching_fn<ClampWrapperFunction>(*base_function);
}
else {
- builder.network_map().add(blender::nodes::DOutputSocket(dnode.context(), &dnode->output(0)),
- base_node.output(0));
+ builder.set_matching_fn(base_function);
}
}
@@ -144,7 +157,7 @@ void register_node_type_sh_math(void)
node_type_label(&ntype, node_math_label);
node_type_gpu(&ntype, gpu_shader_math);
node_type_update(&ntype, node_math_update);
- ntype.expand_in_mf_network = sh_node_math_expand_in_mf_network;
+ ntype.build_multi_function = sh_node_math_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_mixRgb.cc b/source/blender/nodes/shader/nodes/node_shader_mixRgb.cc
index 47011caeeb6..ade35a40366 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mixRgb.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_mixRgb.cc
@@ -174,9 +174,9 @@ class MixRGBFunction : public blender::fn::MultiFunction {
}
};
-static void sh_node_mix_rgb_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder)
+static void sh_node_mix_rgb_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
{
- bNode &node = builder.bnode();
+ bNode &node = builder.node();
bool clamp = node.custom2 & SHD_MIXRGB_CLAMP;
int mix_type = node.custom1;
builder.construct_and_set_matching_fn<MixRGBFunction>(clamp, mix_type);
@@ -191,7 +191,7 @@ void register_node_type_sh_mix_rgb(void)
node_type_label(&ntype, node_blend_label);
node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_mix_rgb);
node_type_gpu(&ntype, gpu_shader_mix_rgb);
- ntype.expand_in_mf_network = sh_node_mix_rgb_expand_in_mf_network;
+ ntype.build_multi_function = sh_node_mix_rgb_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc b/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc
index a7239154633..2779fc6bf68 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.cc
@@ -96,7 +96,7 @@ class SeparateRGBFunction : public blender::fn::MultiFunction {
}
};
-static void sh_node_seprgb_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder)
+static void sh_node_seprgb_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
{
static SeparateRGBFunction fn;
builder.set_matching_fn(fn);
@@ -110,7 +110,7 @@ void register_node_type_sh_seprgb(void)
node_type_socket_templates(&ntype, sh_node_seprgb_in, sh_node_seprgb_out);
node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_seprgb);
node_type_gpu(&ntype, gpu_shader_seprgb);
- ntype.expand_in_mf_network = sh_node_seprgb_expand_in_mf_network;
+ ntype.build_multi_function = sh_node_seprgb_build_multi_function;
nodeRegisterType(&ntype);
}
@@ -153,7 +153,7 @@ static int gpu_shader_combrgb(GPUMaterial *mat,
return GPU_stack_link(mat, node, "combine_rgb", in, out);
}
-static void sh_node_combrgb_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder)
+static void sh_node_combrgb_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
{
static blender::fn::CustomMF_SI_SI_SI_SO<float, float, float, blender::ColorGeometry4f> fn{
"Combine RGB",
@@ -169,7 +169,7 @@ void register_node_type_sh_combrgb(void)
node_type_socket_templates(&ntype, sh_node_combrgb_in, sh_node_combrgb_out);
node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_combrgb);
node_type_gpu(&ntype, gpu_shader_combrgb);
- ntype.expand_in_mf_network = sh_node_combrgb_expand_in_mf_network;
+ ntype.build_multi_function = sh_node_combrgb_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc b/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc
index efa9581c414..1fd794cdd0a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.cc
@@ -81,7 +81,7 @@ class MF_SeparateXYZ : public blender::fn::MultiFunction {
}
};
-static void sh_node_sepxyz_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder)
+static void sh_node_sepxyz_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
{
static MF_SeparateXYZ separate_fn;
builder.set_matching_fn(separate_fn);
@@ -94,7 +94,7 @@ void register_node_type_sh_sepxyz(void)
sh_fn_node_type_base(&ntype, SH_NODE_SEPXYZ, "Separate XYZ", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_sepxyz_in, sh_node_sepxyz_out);
node_type_gpu(&ntype, gpu_shader_sepxyz);
- ntype.expand_in_mf_network = sh_node_sepxyz_expand_in_mf_network;
+ ntype.build_multi_function = sh_node_sepxyz_build_multi_function;
nodeRegisterType(&ntype);
}
@@ -120,7 +120,7 @@ static int gpu_shader_combxyz(GPUMaterial *mat,
return GPU_stack_link(mat, node, "combine_xyz", in, out);
}
-static void sh_node_combxyz_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder)
+static void sh_node_combxyz_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
{
static blender::fn::CustomMF_SI_SI_SI_SO<float, float, float, blender::float3> fn{
"Combine Vector", [](float x, float y, float z) { return blender::float3(x, y, z); }};
@@ -134,7 +134,7 @@ void register_node_type_sh_combxyz(void)
sh_fn_node_type_base(&ntype, SH_NODE_COMBXYZ, "Combine XYZ", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_combxyz_in, sh_node_combxyz_out);
node_type_gpu(&ntype, gpu_shader_combxyz);
- ntype.expand_in_mf_network = sh_node_combxyz_expand_in_mf_network;
+ ntype.build_multi_function = sh_node_combxyz_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc b/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc
index 5b2eb300aac..1bc42ab0cc6 100644
--- a/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_valToRgb.cc
@@ -163,9 +163,10 @@ class ColorBandFunction : public blender::fn::MultiFunction {
}
};
-static void sh_node_valtorgb_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder)
+static void sh_node_valtorgb_build_multi_function(
+ blender::nodes::NodeMultiFunctionBuilder &builder)
{
- bNode &bnode = builder.bnode();
+ bNode &bnode = builder.node();
const ColorBand *color_band = (const ColorBand *)bnode.storage;
builder.construct_and_set_matching_fn<ColorBandFunction>(*color_band);
}
@@ -181,7 +182,7 @@ void register_node_type_sh_valtorgb(void)
node_type_storage(&ntype, "ColorBand", node_free_standard_storage, node_copy_standard_storage);
node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_valtorgb);
node_type_gpu(&ntype, gpu_shader_valtorgb);
- ntype.expand_in_mf_network = sh_node_valtorgb_expand_in_mf_network;
+ ntype.build_multi_function = sh_node_valtorgb_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_value.cc b/source/blender/nodes/shader/nodes/node_shader_value.cc
index 495c8d12824..602d5a1cf56 100644
--- a/source/blender/nodes/shader/nodes/node_shader_value.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_value.cc
@@ -39,9 +39,9 @@ static int gpu_shader_value(GPUMaterial *mat,
return GPU_stack_link(mat, node, "set_value", in, out, link);
}
-static void sh_node_value_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder)
+static void sh_node_value_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
{
- const bNodeSocket *bsocket = builder.dnode()->output(0).bsocket();
+ const bNodeSocket *bsocket = (bNodeSocket *)builder.node().outputs.first;
const bNodeSocketValueFloat *value = (const bNodeSocketValueFloat *)bsocket->default_value;
builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<float>>(value->value);
}
@@ -53,7 +53,7 @@ void register_node_type_sh_value(void)
sh_fn_node_type_base(&ntype, SH_NODE_VALUE, "Value", NODE_CLASS_INPUT, 0);
node_type_socket_templates(&ntype, nullptr, sh_node_value_out);
node_type_gpu(&ntype, gpu_shader_value);
- ntype.expand_in_mf_network = sh_node_value_expand_in_mf_network;
+ ntype.build_multi_function = sh_node_value_build_multi_function;
nodeRegisterType(&ntype);
}
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 419a11201aa..4424db6aed1 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc
@@ -183,12 +183,11 @@ static void node_shader_update_vector_math(bNodeTree *UNUSED(ntree), bNode *node
}
}
-static const blender::fn::MultiFunction &get_multi_function(
- blender::nodes::NodeMFNetworkBuilder &builder)
+static const blender::fn::MultiFunction *get_multi_function(bNode &node)
{
using blender::float3;
- NodeVectorMathOperation operation = NodeVectorMathOperation(builder.bnode().custom1);
+ NodeVectorMathOperation operation = NodeVectorMathOperation(node.custom1);
const blender::fn::MultiFunction *multi_fn = nullptr;
@@ -199,7 +198,7 @@ static const blender::fn::MultiFunction &get_multi_function(
multi_fn = &fn;
});
if (multi_fn != nullptr) {
- return *multi_fn;
+ return multi_fn;
}
blender::nodes::try_dispatch_float_math_fl3_fl3_fl3_to_fl3(
@@ -209,7 +208,7 @@ static const blender::fn::MultiFunction &get_multi_function(
multi_fn = &fn;
});
if (multi_fn != nullptr) {
- return *multi_fn;
+ return multi_fn;
}
blender::nodes::try_dispatch_float_math_fl3_fl3_fl_to_fl3(
@@ -219,7 +218,7 @@ static const blender::fn::MultiFunction &get_multi_function(
multi_fn = &fn;
});
if (multi_fn != nullptr) {
- return *multi_fn;
+ return multi_fn;
}
blender::nodes::try_dispatch_float_math_fl3_fl3_to_fl(
@@ -229,7 +228,7 @@ static const blender::fn::MultiFunction &get_multi_function(
multi_fn = &fn;
});
if (multi_fn != nullptr) {
- return *multi_fn;
+ return multi_fn;
}
blender::nodes::try_dispatch_float_math_fl3_fl_to_fl3(
@@ -239,7 +238,7 @@ static const blender::fn::MultiFunction &get_multi_function(
multi_fn = &fn;
});
if (multi_fn != nullptr) {
- return *multi_fn;
+ return multi_fn;
}
blender::nodes::try_dispatch_float_math_fl3_to_fl3(
@@ -248,7 +247,7 @@ static const blender::fn::MultiFunction &get_multi_function(
multi_fn = &fn;
});
if (multi_fn != nullptr) {
- return *multi_fn;
+ return multi_fn;
}
blender::nodes::try_dispatch_float_math_fl3_to_fl(
@@ -257,15 +256,16 @@ static const blender::fn::MultiFunction &get_multi_function(
multi_fn = &fn;
});
if (multi_fn != nullptr) {
- return *multi_fn;
+ return multi_fn;
}
- return builder.get_not_implemented_fn();
+ return nullptr;
}
-static void sh_node_vector_math_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder)
+static void sh_node_vector_math_build_multi_function(
+ blender::nodes::NodeMultiFunctionBuilder &builder)
{
- const blender::fn::MultiFunction &fn = get_multi_function(builder);
+ const blender::fn::MultiFunction *fn = get_multi_function(builder.node());
builder.set_matching_fn(fn);
}
@@ -278,7 +278,7 @@ void register_node_type_sh_vect_math(void)
node_type_label(&ntype, node_vector_math_label);
node_type_gpu(&ntype, gpu_shader_vector_math);
node_type_update(&ntype, node_shader_update_vector_math);
- ntype.expand_in_mf_network = sh_node_vector_math_expand_in_mf_network;
+ ntype.build_multi_function = sh_node_vector_math_build_multi_function;
nodeRegisterType(&ntype);
}
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 3b2c2fa5a03..bc51b7e29ea 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
@@ -100,11 +100,10 @@ static float3 sh_node_vector_rotate_euler(const float3 vector,
return result + center;
}
-static const blender::fn::MultiFunction &get_multi_function(
- blender::nodes::NodeMFNetworkBuilder &builder)
+static const blender::fn::MultiFunction *get_multi_function(bNode &node)
{
- bool invert = builder.bnode().custom2;
- const int mode = builder.bnode().custom1;
+ bool invert = node.custom2;
+ const int mode = node.custom1;
switch (mode) {
case NODE_VECTOR_ROTATE_TYPE_AXIS: {
@@ -113,13 +112,13 @@ static const blender::fn::MultiFunction &get_multi_function(
"Rotate Axis", [](float3 in, float3 center, float3 axis, float angle) {
return sh_node_vector_rotate_around_axis(in, center, axis, -angle);
}};
- return fn;
+ return &fn;
}
static blender::fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float3, float, float3> fn{
"Rotate Axis", [](float3 in, float3 center, float3 axis, float angle) {
return sh_node_vector_rotate_around_axis(in, center, axis, angle);
}};
- return fn;
+ return &fn;
}
case NODE_VECTOR_ROTATE_TYPE_AXIS_X: {
float3 axis = float3(1.0f, 0.0f, 0.0f);
@@ -128,13 +127,13 @@ static const blender::fn::MultiFunction &get_multi_function(
"Rotate X-Axis", [=](float3 in, float3 center, float angle) {
return sh_node_vector_rotate_around_axis(in, center, axis, -angle);
}};
- return fn;
+ return &fn;
}
static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
"Rotate X-Axis", [=](float3 in, float3 center, float angle) {
return sh_node_vector_rotate_around_axis(in, center, axis, angle);
}};
- return fn;
+ return &fn;
}
case NODE_VECTOR_ROTATE_TYPE_AXIS_Y: {
float3 axis = float3(0.0f, 1.0f, 0.0f);
@@ -143,13 +142,13 @@ static const blender::fn::MultiFunction &get_multi_function(
"Rotate Y-Axis", [=](float3 in, float3 center, float angle) {
return sh_node_vector_rotate_around_axis(in, center, axis, -angle);
}};
- return fn;
+ return &fn;
}
static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
"Rotate Y-Axis", [=](float3 in, float3 center, float angle) {
return sh_node_vector_rotate_around_axis(in, center, axis, angle);
}};
- return fn;
+ return &fn;
}
case NODE_VECTOR_ROTATE_TYPE_AXIS_Z: {
float3 axis = float3(0.0f, 0.0f, 1.0f);
@@ -158,13 +157,13 @@ static const blender::fn::MultiFunction &get_multi_function(
"Rotate Z-Axis", [=](float3 in, float3 center, float angle) {
return sh_node_vector_rotate_around_axis(in, center, axis, -angle);
}};
- return fn;
+ return &fn;
}
static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
"Rotate Z-Axis", [=](float3 in, float3 center, float angle) {
return sh_node_vector_rotate_around_axis(in, center, axis, angle);
}};
- return fn;
+ return &fn;
}
case NODE_VECTOR_ROTATE_TYPE_EULER_XYZ: {
if (invert) {
@@ -172,24 +171,24 @@ static const blender::fn::MultiFunction &get_multi_function(
"Rotate Euler", [](float3 in, float3 center, float3 rotation) {
return sh_node_vector_rotate_euler(in, center, rotation, true);
}};
- return fn;
+ return &fn;
}
static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{
"Rotate Euler", [](float3 in, float3 center, float3 rotation) {
return sh_node_vector_rotate_euler(in, center, rotation, false);
}};
- return fn;
+ return &fn;
}
default:
BLI_assert_unreachable();
- return builder.get_not_implemented_fn();
+ return nullptr;
}
}
-static void sh_node_vector_rotate_expand_in_mf_network(
- blender::nodes::NodeMFNetworkBuilder &builder)
+static void sh_node_vector_rotate_build_multi_function(
+ blender::nodes::NodeMultiFunctionBuilder &builder)
{
- const blender::fn::MultiFunction &fn = get_multi_function(builder);
+ const blender::fn::MultiFunction *fn = get_multi_function(builder.node());
builder.set_matching_fn(fn);
}
@@ -211,7 +210,7 @@ void register_node_type_sh_vector_rotate(void)
node_type_socket_templates(&ntype, sh_node_vector_rotate_in, sh_node_vector_rotate_out);
node_type_gpu(&ntype, gpu_shader_vector_rotate);
node_type_update(&ntype, node_shader_update_vector_rotate);
- ntype.expand_in_mf_network = sh_node_vector_rotate_expand_in_mf_network;
+ ntype.build_multi_function = sh_node_vector_rotate_build_multi_function;
nodeRegisterType(&ntype);
}