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-11-15 20:24:56 +0300
committerJacques Lucke <jacques@blender.org>2021-11-15 20:24:56 +0300
commit861f65040b582b7d52afee3fa7117f7f0d3f6cdb (patch)
treeee6a88567fa7f483dba1ca9ee6a8e1607dd7ff91
parent677dc13e129cba3b2f1448d491622a18eb1b998b (diff)
progress
-rw-r--r--source/blender/blenkernel/BKE_node.h1
-rw-r--r--source/blender/blenkernel/intern/node.cc523
-rw-r--r--source/blender/blenkernel/intern/node_tree_update.cc569
3 files changed, 569 insertions, 524 deletions
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 645b4410623..59664d42c4c 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -489,6 +489,7 @@ void ntreeUpdateAllUsers(struct Main *main, struct ID *id, int tree_update_flag)
void ntreeGetDependencyList(struct bNodeTree *ntree,
struct bNode ***r_deplist,
int *r_deplist_len);
+void ntreeUpdateNodeLevels(struct bNodeTree *ntree);
/* XXX old trees handle output flags automatically based on special output
* node types and last active selection.
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 4fa2e0c379a..4079b5f2422 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -4454,7 +4454,7 @@ void ntreeGetDependencyList(struct bNodeTree *ntree, struct bNode ***r_deplist,
}
/* only updates node->level for detecting cycles links */
-static void ntree_update_node_level(bNodeTree *ntree)
+void ntreeUpdateNodeLevels(bNodeTree *ntree)
{
/* first clear tag */
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
@@ -4542,519 +4542,6 @@ void ntreeUpdateAllNew(Main *main)
BKE_node_tree_update_main(main, nullptr);
}
-namespace blender::bke::node_field_inferencing {
-
-static bool is_field_socket_type(eNodeSocketDatatype type)
-{
- return ELEM(type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA);
-}
-
-static bool is_field_socket_type(const SocketRef &socket)
-{
- return is_field_socket_type((eNodeSocketDatatype)socket.typeinfo()->type);
-}
-
-static bool update_field_inferencing(bNodeTree &btree);
-
-static InputSocketFieldType get_interface_input_field_type(const NodeRef &node,
- const InputSocketRef &socket)
-{
- if (!is_field_socket_type(socket)) {
- return InputSocketFieldType::None;
- }
- if (node.is_reroute_node()) {
- return InputSocketFieldType::IsSupported;
- }
- if (node.is_group_output_node()) {
- /* Outputs always support fields when the data type is correct. */
- return InputSocketFieldType::IsSupported;
- }
- if (node.is_undefined()) {
- return InputSocketFieldType::None;
- }
-
- const NodeDeclaration *node_decl = node.declaration();
-
- /* Node declarations should be implemented for nodes involved here. */
- BLI_assert(node_decl != nullptr);
-
- /* Get the field type from the declaration. */
- const SocketDeclaration &socket_decl = *node_decl->inputs()[socket.index()];
- const InputSocketFieldType field_type = socket_decl.input_field_type();
- if (field_type == InputSocketFieldType::Implicit) {
- return field_type;
- }
- if (node_decl->is_function_node()) {
- /* In a function node, every socket supports fields. */
- return InputSocketFieldType::IsSupported;
- }
- return field_type;
-}
-
-static OutputFieldDependency get_interface_output_field_dependency(const NodeRef &node,
- const OutputSocketRef &socket)
-{
- if (!is_field_socket_type(socket)) {
- /* Non-field sockets always output data. */
- return OutputFieldDependency::ForDataSource();
- }
- if (node.is_reroute_node()) {
- /* The reroute just forwards what is passed in. */
- return OutputFieldDependency::ForDependentField();
- }
- if (node.is_group_input_node()) {
- /* Input nodes get special treatment in #determine_group_input_states. */
- return OutputFieldDependency::ForDependentField();
- }
- if (node.is_undefined()) {
- return OutputFieldDependency::ForDataSource();
- }
-
- const NodeDeclaration *node_decl = node.declaration();
-
- /* Node declarations should be implemented for nodes involved here. */
- BLI_assert(node_decl != nullptr);
-
- if (node_decl->is_function_node()) {
- /* In a generic function node, all outputs depend on all inputs. */
- return OutputFieldDependency::ForDependentField();
- }
-
- /* Use the socket declaration. */
- const SocketDeclaration &socket_decl = *node_decl->outputs()[socket.index()];
- return socket_decl.output_field_dependency();
-}
-
-static FieldInferencingInterface get_dummy_field_inferencing_interface(const NodeRef &node)
-{
- FieldInferencingInterface inferencing_interface;
- inferencing_interface.inputs.append_n_times(InputSocketFieldType::None, node.inputs().size());
- inferencing_interface.outputs.append_n_times(OutputFieldDependency::ForDataSource(),
- node.outputs().size());
- return inferencing_interface;
-}
-
-/**
- * Retrieves information about how the node interacts with fields.
- * In the future, this information can be stored in the node declaration. This would allow this
- * function to return a reference, making it more efficient.
- */
-static FieldInferencingInterface get_node_field_inferencing_interface(const NodeRef &node)
-{
- /* Node groups already reference all required information, so just return that. */
- if (node.is_group_node()) {
- bNodeTree *group = (bNodeTree *)node.bnode()->id;
- if (group == nullptr) {
- return FieldInferencingInterface();
- }
- if (!ntreeIsRegistered(group)) {
- /* This can happen when there is a linked node group that was not found (see T92799). */
- return get_dummy_field_inferencing_interface(node);
- }
- if (group->field_inferencing_interface == nullptr) {
- /* Update group recursively. */
- update_field_inferencing(*group);
- }
- return *group->field_inferencing_interface;
- }
-
- FieldInferencingInterface inferencing_interface;
- for (const InputSocketRef *input_socket : node.inputs()) {
- inferencing_interface.inputs.append(get_interface_input_field_type(node, *input_socket));
- }
-
- for (const OutputSocketRef *output_socket : node.outputs()) {
- inferencing_interface.outputs.append(
- get_interface_output_field_dependency(node, *output_socket));
- }
- return inferencing_interface;
-}
-
-/**
- * This struct contains information for every socket. The values are propagated through the
- * network.
- */
-struct SocketFieldState {
- /* This socket starts a new field. */
- bool is_field_source = false;
- /* This socket can never become a field, because the node itself does not support it. */
- bool is_always_single = false;
- /* This socket is currently a single value. It could become a field though. */
- bool is_single = true;
- /* This socket is required to be a single value. This can be because the node itself only
- * supports this socket to be a single value, or because a node afterwards requires this to be a
- * single value. */
- bool requires_single = false;
-};
-
-static Vector<const InputSocketRef *> gather_input_socket_dependencies(
- const OutputFieldDependency &field_dependency, const NodeRef &node)
-{
- const OutputSocketFieldType type = field_dependency.field_type();
- Vector<const InputSocketRef *> input_sockets;
- switch (type) {
- case OutputSocketFieldType::FieldSource:
- case OutputSocketFieldType::None: {
- break;
- }
- case OutputSocketFieldType::DependentField: {
- /* This output depends on all inputs. */
- input_sockets.extend(node.inputs());
- break;
- }
- case OutputSocketFieldType::PartiallyDependent: {
- /* This output depends only on a few inputs. */
- for (const int i : field_dependency.linked_input_indices()) {
- input_sockets.append(&node.input(i));
- }
- break;
- }
- }
- return input_sockets;
-}
-
-/**
- * Check what the group output socket depends on. Potentially traverses the node tree
- * to figure out if it is always a field or if it depends on any group inputs.
- */
-static OutputFieldDependency find_group_output_dependencies(
- const InputSocketRef &group_output_socket,
- const Span<SocketFieldState> field_state_by_socket_id)
-{
- if (!is_field_socket_type(group_output_socket)) {
- return OutputFieldDependency::ForDataSource();
- }
-
- /* Use a Set here instead of an array indexed by socket id, because we my only need to look at
- * very few sockets. */
- Set<const InputSocketRef *> handled_sockets;
- Stack<const InputSocketRef *> sockets_to_check;
-
- handled_sockets.add(&group_output_socket);
- sockets_to_check.push(&group_output_socket);
-
- /* Keeps track of group input indices that are (indirectly) connected to the output. */
- Vector<int> linked_input_indices;
-
- while (!sockets_to_check.is_empty()) {
- const InputSocketRef *input_socket = sockets_to_check.pop();
-
- for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) {
- const NodeRef &origin_node = origin_socket->node();
- const SocketFieldState &origin_state = field_state_by_socket_id[origin_socket->id()];
-
- if (origin_state.is_field_source) {
- if (origin_node.is_group_input_node()) {
- /* Found a group input that the group output depends on. */
- linked_input_indices.append_non_duplicates(origin_socket->index());
- }
- else {
- /* Found a field source that is not the group input. So the output is always a field. */
- return OutputFieldDependency::ForFieldSource();
- }
- }
- else if (!origin_state.is_single) {
- const FieldInferencingInterface inferencing_interface =
- get_node_field_inferencing_interface(origin_node);
- const OutputFieldDependency &field_dependency =
- inferencing_interface.outputs[origin_socket->index()];
-
- /* Propagate search further to the left. */
- for (const InputSocketRef *origin_input_socket :
- gather_input_socket_dependencies(field_dependency, origin_node)) {
- if (!origin_input_socket->is_available()) {
- continue;
- }
- if (!field_state_by_socket_id[origin_input_socket->id()].is_single) {
- if (handled_sockets.add(origin_input_socket)) {
- sockets_to_check.push(origin_input_socket);
- }
- }
- }
- }
- }
- }
- return OutputFieldDependency::ForPartiallyDependentField(std::move(linked_input_indices));
-}
-
-static void propagate_data_requirements_from_right_to_left(
- const NodeTreeRef &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id)
-{
- const NodeTreeRef::ToposortResult toposort_result = tree.toposort(
- NodeTreeRef::ToposortDirection::RightToLeft);
-
- for (const NodeRef *node : toposort_result.sorted_nodes) {
- const FieldInferencingInterface inferencing_interface = get_node_field_inferencing_interface(
- *node);
-
- for (const OutputSocketRef *output_socket : node->outputs()) {
- SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
-
- const OutputFieldDependency &field_dependency =
- inferencing_interface.outputs[output_socket->index()];
-
- if (field_dependency.field_type() == OutputSocketFieldType::FieldSource) {
- continue;
- }
- if (field_dependency.field_type() == OutputSocketFieldType::None) {
- state.requires_single = true;
- state.is_always_single = true;
- continue;
- }
-
- /* The output is required to be a single value when it is connected to any input that does
- * not support fields. */
- for (const InputSocketRef *target_socket : output_socket->directly_linked_sockets()) {
- state.requires_single |= field_state_by_socket_id[target_socket->id()].requires_single;
- }
-
- if (state.requires_single) {
- bool any_input_is_field_implicitly = false;
- const Vector<const InputSocketRef *> connected_inputs = gather_input_socket_dependencies(
- field_dependency, *node);
- for (const InputSocketRef *input_socket : connected_inputs) {
- if (!input_socket->is_available()) {
- continue;
- }
- if (inferencing_interface.inputs[input_socket->index()] ==
- InputSocketFieldType::Implicit) {
- if (!input_socket->is_logically_linked()) {
- any_input_is_field_implicitly = true;
- break;
- }
- }
- }
- if (any_input_is_field_implicitly) {
- /* This output isn't a single value actually. */
- state.requires_single = false;
- }
- else {
- /* If the output is required to be a single value, the connected inputs in the same node
- * must not be fields as well. */
- for (const InputSocketRef *input_socket : connected_inputs) {
- field_state_by_socket_id[input_socket->id()].requires_single = true;
- }
- }
- }
- }
-
- /* Some inputs do not require fields independent of what the outputs are connected to. */
- for (const InputSocketRef *input_socket : node->inputs()) {
- SocketFieldState &state = field_state_by_socket_id[input_socket->id()];
- if (inferencing_interface.inputs[input_socket->index()] == InputSocketFieldType::None) {
- state.requires_single = true;
- state.is_always_single = true;
- }
- }
- }
-}
-
-static void determine_group_input_states(
- const NodeTreeRef &tree,
- FieldInferencingInterface &new_inferencing_interface,
- const MutableSpan<SocketFieldState> field_state_by_socket_id)
-{
- {
- /* Non-field inputs never support fields. */
- int index;
- LISTBASE_FOREACH_INDEX (bNodeSocket *, group_input, &tree.btree()->inputs, index) {
- if (!is_field_socket_type((eNodeSocketDatatype)group_input->type)) {
- new_inferencing_interface.inputs[index] = InputSocketFieldType::None;
- }
- }
- }
- /* Check if group inputs are required to be single values, because they are (indirectly)
- * connected to some socket that does not support fields. */
- for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) {
- for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) {
- SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
- if (state.requires_single) {
- new_inferencing_interface.inputs[output_socket->index()] = InputSocketFieldType::None;
- }
- }
- }
- /* If an input does not support fields, this should be reflected in all Group Input nodes. */
- for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) {
- for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) {
- SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
- const bool supports_field = new_inferencing_interface.inputs[output_socket->index()] !=
- InputSocketFieldType::None;
- if (supports_field) {
- state.is_single = false;
- state.is_field_source = true;
- }
- else {
- state.requires_single = true;
- }
- }
- SocketFieldState &dummy_socket_state = field_state_by_socket_id[node->outputs().last()->id()];
- dummy_socket_state.requires_single = true;
- }
-}
-
-static void propagate_field_status_from_left_to_right(
- const NodeTreeRef &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id)
-{
- const NodeTreeRef::ToposortResult toposort_result = tree.toposort(
- NodeTreeRef::ToposortDirection::LeftToRight);
-
- for (const NodeRef *node : toposort_result.sorted_nodes) {
- if (node->is_group_input_node()) {
- continue;
- }
-
- const FieldInferencingInterface inferencing_interface = get_node_field_inferencing_interface(
- *node);
-
- /* Update field state of input sockets, also taking into account linked origin sockets. */
- for (const InputSocketRef *input_socket : node->inputs()) {
- SocketFieldState &state = field_state_by_socket_id[input_socket->id()];
- if (state.is_always_single) {
- state.is_single = true;
- continue;
- }
- state.is_single = true;
- if (input_socket->directly_linked_sockets().is_empty()) {
- if (inferencing_interface.inputs[input_socket->index()] ==
- InputSocketFieldType::Implicit) {
- state.is_single = false;
- }
- }
- else {
- for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) {
- if (!field_state_by_socket_id[origin_socket->id()].is_single) {
- state.is_single = false;
- break;
- }
- }
- }
- }
-
- /* Update field state of output sockets, also taking into account input sockets. */
- for (const OutputSocketRef *output_socket : node->outputs()) {
- SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
- const OutputFieldDependency &field_dependency =
- inferencing_interface.outputs[output_socket->index()];
-
- switch (field_dependency.field_type()) {
- case OutputSocketFieldType::None: {
- state.is_single = true;
- break;
- }
- case OutputSocketFieldType::FieldSource: {
- state.is_single = false;
- state.is_field_source = true;
- break;
- }
- case OutputSocketFieldType::PartiallyDependent:
- case OutputSocketFieldType::DependentField: {
- for (const InputSocketRef *input_socket :
- gather_input_socket_dependencies(field_dependency, *node)) {
- if (!input_socket->is_available()) {
- continue;
- }
- if (!field_state_by_socket_id[input_socket->id()].is_single) {
- state.is_single = false;
- break;
- }
- }
- break;
- }
- }
- }
- }
-}
-
-static void determine_group_output_states(const NodeTreeRef &tree,
- FieldInferencingInterface &new_inferencing_interface,
- const Span<SocketFieldState> field_state_by_socket_id)
-{
- for (const NodeRef *group_output_node : tree.nodes_by_type("NodeGroupOutput")) {
- /* Ignore inactive group output nodes. */
- if (!(group_output_node->bnode()->flag & NODE_DO_OUTPUT)) {
- continue;
- }
- /* Determine dependencies of all group outputs. */
- for (const InputSocketRef *group_output_socket : group_output_node->inputs().drop_back(1)) {
- OutputFieldDependency field_dependency = find_group_output_dependencies(
- *group_output_socket, field_state_by_socket_id);
- new_inferencing_interface.outputs[group_output_socket->index()] = std::move(
- field_dependency);
- }
- break;
- }
-}
-
-static void update_socket_shapes(const NodeTreeRef &tree,
- const Span<SocketFieldState> field_state_by_socket_id)
-{
- const eNodeSocketDisplayShape requires_data_shape = SOCK_DISPLAY_SHAPE_CIRCLE;
- const eNodeSocketDisplayShape data_but_can_be_field_shape = SOCK_DISPLAY_SHAPE_DIAMOND_DOT;
- const eNodeSocketDisplayShape is_field_shape = SOCK_DISPLAY_SHAPE_DIAMOND;
-
- auto get_shape_for_state = [&](const SocketFieldState &state) {
- if (state.is_always_single) {
- return requires_data_shape;
- }
- if (!state.is_single) {
- return is_field_shape;
- }
- if (state.requires_single) {
- return requires_data_shape;
- }
- return data_but_can_be_field_shape;
- };
-
- for (const InputSocketRef *socket : tree.input_sockets()) {
- bNodeSocket *bsocket = socket->bsocket();
- const SocketFieldState &state = field_state_by_socket_id[socket->id()];
- bsocket->display_shape = get_shape_for_state(state);
- }
- for (const OutputSocketRef *socket : tree.output_sockets()) {
- bNodeSocket *bsocket = socket->bsocket();
- const SocketFieldState &state = field_state_by_socket_id[socket->id()];
- bsocket->display_shape = get_shape_for_state(state);
- }
-}
-
-static bool update_field_inferencing(bNodeTree &btree)
-{
- using namespace blender::nodes;
- if (btree.type != NTREE_GEOMETRY) {
- return false;
- }
-
- /* Create new inferencing interface for this node group. */
- FieldInferencingInterface *new_inferencing_interface = new FieldInferencingInterface();
- new_inferencing_interface->inputs.resize(BLI_listbase_count(&btree.inputs),
- InputSocketFieldType::IsSupported);
- new_inferencing_interface->outputs.resize(BLI_listbase_count(&btree.outputs),
- OutputFieldDependency::ForDataSource());
-
- /* Create #NodeTreeRef to accelerate various queries on the node tree (e.g. linked sockets). */
- const NodeTreeRef tree{&btree};
-
- /* Keep track of the state of all sockets. The index into this array is #SocketRef::id(). */
- Array<SocketFieldState> field_state_by_socket_id(tree.sockets().size());
-
- propagate_data_requirements_from_right_to_left(tree, field_state_by_socket_id);
- determine_group_input_states(tree, *new_inferencing_interface, field_state_by_socket_id);
- propagate_field_status_from_left_to_right(tree, field_state_by_socket_id);
- determine_group_output_states(tree, *new_inferencing_interface, field_state_by_socket_id);
- update_socket_shapes(tree, field_state_by_socket_id);
-
- /* Update the previous group interface. */
- const bool group_interface_changed = btree.field_inferencing_interface == nullptr ||
- *btree.field_inferencing_interface !=
- *new_inferencing_interface;
- delete btree.field_inferencing_interface;
- btree.field_inferencing_interface = new_inferencing_interface;
-
- return group_interface_changed;
-}
-
-} // namespace blender::bke::node_field_inferencing
-
/**
* \param tree_update_flag: #eNodeTreeUpdate enum.
*/
@@ -5147,9 +4634,9 @@ void ntreeUpdateTree(Main *bmain, bNodeTree *ntree)
if (ntree->update & NTREE_UPDATE) {
/* If the field interface of this node tree has changed, all node trees using
* this group will need to recalculate their interface as well. */
- if (blender::bke::node_field_inferencing::update_field_inferencing(*ntree)) {
- tree_user_update_flag |= NTREE_UPDATE_FIELD_INFERENCING;
- }
+ // if (blender::bke::node_field_inferencing::update_field_inferencing(*ntree)) {
+ // tree_user_update_flag |= NTREE_UPDATE_FIELD_INFERENCING;
+ // }
}
if (bmain) {
@@ -5161,7 +4648,7 @@ void ntreeUpdateTree(Main *bmain, bNodeTree *ntree)
ntree_update_link_pointers(ntree);
/* update the node level from link dependencies */
- ntree_update_node_level(ntree);
+ ntreeUpdateNodeLevels(ntree);
/* check link validity */
ntree_validate_links(ntree);
diff --git a/source/blender/blenkernel/intern/node_tree_update.cc b/source/blender/blenkernel/intern/node_tree_update.cc
index 82b62b5d37c..11a9d8e07cd 100644
--- a/source/blender/blenkernel/intern/node_tree_update.cc
+++ b/source/blender/blenkernel/intern/node_tree_update.cc
@@ -17,6 +17,7 @@
#include "BLI_map.hh"
#include "BLI_multi_value_map.hh"
#include "BLI_set.hh"
+#include "BLI_stack.hh"
#include "BLI_vector_set.hh"
#include "DNA_modifier_types.h"
@@ -28,8 +29,526 @@
#include "MOD_nodes.h"
+#include "NOD_node_declaration.hh"
+#include "NOD_node_tree_ref.hh"
+
+using namespace blender::nodes;
+
namespace blender::bke {
+namespace node_field_inferencing {
+
+static bool is_field_socket_type(eNodeSocketDatatype type)
+{
+ return ELEM(type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA);
+}
+
+static bool is_field_socket_type(const SocketRef &socket)
+{
+ return is_field_socket_type((eNodeSocketDatatype)socket.typeinfo()->type);
+}
+
+static bool update_field_inferencing(bNodeTree &btree);
+
+static InputSocketFieldType get_interface_input_field_type(const NodeRef &node,
+ const InputSocketRef &socket)
+{
+ if (!is_field_socket_type(socket)) {
+ return InputSocketFieldType::None;
+ }
+ if (node.is_reroute_node()) {
+ return InputSocketFieldType::IsSupported;
+ }
+ if (node.is_group_output_node()) {
+ /* Outputs always support fields when the data type is correct. */
+ return InputSocketFieldType::IsSupported;
+ }
+ if (node.is_undefined()) {
+ return InputSocketFieldType::None;
+ }
+
+ const NodeDeclaration *node_decl = node.declaration();
+
+ /* Node declarations should be implemented for nodes involved here. */
+ BLI_assert(node_decl != nullptr);
+
+ /* Get the field type from the declaration. */
+ const SocketDeclaration &socket_decl = *node_decl->inputs()[socket.index()];
+ const InputSocketFieldType field_type = socket_decl.input_field_type();
+ if (field_type == InputSocketFieldType::Implicit) {
+ return field_type;
+ }
+ if (node_decl->is_function_node()) {
+ /* In a function node, every socket supports fields. */
+ return InputSocketFieldType::IsSupported;
+ }
+ return field_type;
+}
+
+static OutputFieldDependency get_interface_output_field_dependency(const NodeRef &node,
+ const OutputSocketRef &socket)
+{
+ if (!is_field_socket_type(socket)) {
+ /* Non-field sockets always output data. */
+ return OutputFieldDependency::ForDataSource();
+ }
+ if (node.is_reroute_node()) {
+ /* The reroute just forwards what is passed in. */
+ return OutputFieldDependency::ForDependentField();
+ }
+ if (node.is_group_input_node()) {
+ /* Input nodes get special treatment in #determine_group_input_states. */
+ return OutputFieldDependency::ForDependentField();
+ }
+ if (node.is_undefined()) {
+ return OutputFieldDependency::ForDataSource();
+ }
+
+ const NodeDeclaration *node_decl = node.declaration();
+
+ /* Node declarations should be implemented for nodes involved here. */
+ BLI_assert(node_decl != nullptr);
+
+ if (node_decl->is_function_node()) {
+ /* In a generic function node, all outputs depend on all inputs. */
+ return OutputFieldDependency::ForDependentField();
+ }
+
+ /* Use the socket declaration. */
+ const SocketDeclaration &socket_decl = *node_decl->outputs()[socket.index()];
+ return socket_decl.output_field_dependency();
+}
+
+static FieldInferencingInterface get_dummy_field_inferencing_interface(const NodeRef &node)
+{
+ FieldInferencingInterface inferencing_interface;
+ inferencing_interface.inputs.append_n_times(InputSocketFieldType::None, node.inputs().size());
+ inferencing_interface.outputs.append_n_times(OutputFieldDependency::ForDataSource(),
+ node.outputs().size());
+ return inferencing_interface;
+}
+
+/**
+ * Retrieves information about how the node interacts with fields.
+ * In the future, this information can be stored in the node declaration. This would allow this
+ * function to return a reference, making it more efficient.
+ */
+static FieldInferencingInterface get_node_field_inferencing_interface(const NodeRef &node)
+{
+ /* Node groups already reference all required information, so just return that. */
+ if (node.is_group_node()) {
+ bNodeTree *group = (bNodeTree *)node.bnode()->id;
+ if (group == nullptr) {
+ return FieldInferencingInterface();
+ }
+ if (!ntreeIsRegistered(group)) {
+ /* This can happen when there is a linked node group that was not found (see T92799). */
+ return get_dummy_field_inferencing_interface(node);
+ }
+ if (group->field_inferencing_interface == nullptr) {
+ /* Update group recursively. */
+ update_field_inferencing(*group);
+ }
+ return *group->field_inferencing_interface;
+ }
+
+ FieldInferencingInterface inferencing_interface;
+ for (const InputSocketRef *input_socket : node.inputs()) {
+ inferencing_interface.inputs.append(get_interface_input_field_type(node, *input_socket));
+ }
+
+ for (const OutputSocketRef *output_socket : node.outputs()) {
+ inferencing_interface.outputs.append(
+ get_interface_output_field_dependency(node, *output_socket));
+ }
+ return inferencing_interface;
+}
+
+/**
+ * This struct contains information for every socket. The values are propagated through the
+ * network.
+ */
+struct SocketFieldState {
+ /* This socket starts a new field. */
+ bool is_field_source = false;
+ /* This socket can never become a field, because the node itself does not support it. */
+ bool is_always_single = false;
+ /* This socket is currently a single value. It could become a field though. */
+ bool is_single = true;
+ /* This socket is required to be a single value. This can be because the node itself only
+ * supports this socket to be a single value, or because a node afterwards requires this to be a
+ * single value. */
+ bool requires_single = false;
+};
+
+static Vector<const InputSocketRef *> gather_input_socket_dependencies(
+ const OutputFieldDependency &field_dependency, const NodeRef &node)
+{
+ const OutputSocketFieldType type = field_dependency.field_type();
+ Vector<const InputSocketRef *> input_sockets;
+ switch (type) {
+ case OutputSocketFieldType::FieldSource:
+ case OutputSocketFieldType::None: {
+ break;
+ }
+ case OutputSocketFieldType::DependentField: {
+ /* This output depends on all inputs. */
+ input_sockets.extend(node.inputs());
+ break;
+ }
+ case OutputSocketFieldType::PartiallyDependent: {
+ /* This output depends only on a few inputs. */
+ for (const int i : field_dependency.linked_input_indices()) {
+ input_sockets.append(&node.input(i));
+ }
+ break;
+ }
+ }
+ return input_sockets;
+}
+
+/**
+ * Check what the group output socket depends on. Potentially traverses the node tree
+ * to figure out if it is always a field or if it depends on any group inputs.
+ */
+static OutputFieldDependency find_group_output_dependencies(
+ const InputSocketRef &group_output_socket,
+ const Span<SocketFieldState> field_state_by_socket_id)
+{
+ if (!is_field_socket_type(group_output_socket)) {
+ return OutputFieldDependency::ForDataSource();
+ }
+
+ /* Use a Set here instead of an array indexed by socket id, because we my only need to look at
+ * very few sockets. */
+ Set<const InputSocketRef *> handled_sockets;
+ Stack<const InputSocketRef *> sockets_to_check;
+
+ handled_sockets.add(&group_output_socket);
+ sockets_to_check.push(&group_output_socket);
+
+ /* Keeps track of group input indices that are (indirectly) connected to the output. */
+ Vector<int> linked_input_indices;
+
+ while (!sockets_to_check.is_empty()) {
+ const InputSocketRef *input_socket = sockets_to_check.pop();
+
+ for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) {
+ const NodeRef &origin_node = origin_socket->node();
+ const SocketFieldState &origin_state = field_state_by_socket_id[origin_socket->id()];
+
+ if (origin_state.is_field_source) {
+ if (origin_node.is_group_input_node()) {
+ /* Found a group input that the group output depends on. */
+ linked_input_indices.append_non_duplicates(origin_socket->index());
+ }
+ else {
+ /* Found a field source that is not the group input. So the output is always a field. */
+ return OutputFieldDependency::ForFieldSource();
+ }
+ }
+ else if (!origin_state.is_single) {
+ const FieldInferencingInterface inferencing_interface =
+ get_node_field_inferencing_interface(origin_node);
+ const OutputFieldDependency &field_dependency =
+ inferencing_interface.outputs[origin_socket->index()];
+
+ /* Propagate search further to the left. */
+ for (const InputSocketRef *origin_input_socket :
+ gather_input_socket_dependencies(field_dependency, origin_node)) {
+ if (!origin_input_socket->is_available()) {
+ continue;
+ }
+ if (!field_state_by_socket_id[origin_input_socket->id()].is_single) {
+ if (handled_sockets.add(origin_input_socket)) {
+ sockets_to_check.push(origin_input_socket);
+ }
+ }
+ }
+ }
+ }
+ }
+ return OutputFieldDependency::ForPartiallyDependentField(std::move(linked_input_indices));
+}
+
+static void propagate_data_requirements_from_right_to_left(
+ const NodeTreeRef &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id)
+{
+ const NodeTreeRef::ToposortResult toposort_result = tree.toposort(
+ NodeTreeRef::ToposortDirection::RightToLeft);
+
+ for (const NodeRef *node : toposort_result.sorted_nodes) {
+ const FieldInferencingInterface inferencing_interface = get_node_field_inferencing_interface(
+ *node);
+
+ for (const OutputSocketRef *output_socket : node->outputs()) {
+ SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
+
+ const OutputFieldDependency &field_dependency =
+ inferencing_interface.outputs[output_socket->index()];
+
+ if (field_dependency.field_type() == OutputSocketFieldType::FieldSource) {
+ continue;
+ }
+ if (field_dependency.field_type() == OutputSocketFieldType::None) {
+ state.requires_single = true;
+ state.is_always_single = true;
+ continue;
+ }
+
+ /* The output is required to be a single value when it is connected to any input that does
+ * not support fields. */
+ for (const InputSocketRef *target_socket : output_socket->directly_linked_sockets()) {
+ state.requires_single |= field_state_by_socket_id[target_socket->id()].requires_single;
+ }
+
+ if (state.requires_single) {
+ bool any_input_is_field_implicitly = false;
+ const Vector<const InputSocketRef *> connected_inputs = gather_input_socket_dependencies(
+ field_dependency, *node);
+ for (const InputSocketRef *input_socket : connected_inputs) {
+ if (!input_socket->is_available()) {
+ continue;
+ }
+ if (inferencing_interface.inputs[input_socket->index()] ==
+ InputSocketFieldType::Implicit) {
+ if (!input_socket->is_logically_linked()) {
+ any_input_is_field_implicitly = true;
+ break;
+ }
+ }
+ }
+ if (any_input_is_field_implicitly) {
+ /* This output isn't a single value actually. */
+ state.requires_single = false;
+ }
+ else {
+ /* If the output is required to be a single value, the connected inputs in the same node
+ * must not be fields as well. */
+ for (const InputSocketRef *input_socket : connected_inputs) {
+ field_state_by_socket_id[input_socket->id()].requires_single = true;
+ }
+ }
+ }
+ }
+
+ /* Some inputs do not require fields independent of what the outputs are connected to. */
+ for (const InputSocketRef *input_socket : node->inputs()) {
+ SocketFieldState &state = field_state_by_socket_id[input_socket->id()];
+ if (inferencing_interface.inputs[input_socket->index()] == InputSocketFieldType::None) {
+ state.requires_single = true;
+ state.is_always_single = true;
+ }
+ }
+ }
+}
+
+static void determine_group_input_states(
+ const NodeTreeRef &tree,
+ FieldInferencingInterface &new_inferencing_interface,
+ const MutableSpan<SocketFieldState> field_state_by_socket_id)
+{
+ {
+ /* Non-field inputs never support fields. */
+ int index;
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, group_input, &tree.btree()->inputs, index) {
+ if (!is_field_socket_type((eNodeSocketDatatype)group_input->type)) {
+ new_inferencing_interface.inputs[index] = InputSocketFieldType::None;
+ }
+ }
+ }
+ /* Check if group inputs are required to be single values, because they are (indirectly)
+ * connected to some socket that does not support fields. */
+ for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) {
+ for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) {
+ SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
+ if (state.requires_single) {
+ new_inferencing_interface.inputs[output_socket->index()] = InputSocketFieldType::None;
+ }
+ }
+ }
+ /* If an input does not support fields, this should be reflected in all Group Input nodes. */
+ for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) {
+ for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) {
+ SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
+ const bool supports_field = new_inferencing_interface.inputs[output_socket->index()] !=
+ InputSocketFieldType::None;
+ if (supports_field) {
+ state.is_single = false;
+ state.is_field_source = true;
+ }
+ else {
+ state.requires_single = true;
+ }
+ }
+ SocketFieldState &dummy_socket_state = field_state_by_socket_id[node->outputs().last()->id()];
+ dummy_socket_state.requires_single = true;
+ }
+}
+
+static void propagate_field_status_from_left_to_right(
+ const NodeTreeRef &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id)
+{
+ const NodeTreeRef::ToposortResult toposort_result = tree.toposort(
+ NodeTreeRef::ToposortDirection::LeftToRight);
+
+ for (const NodeRef *node : toposort_result.sorted_nodes) {
+ if (node->is_group_input_node()) {
+ continue;
+ }
+
+ const FieldInferencingInterface inferencing_interface = get_node_field_inferencing_interface(
+ *node);
+
+ /* Update field state of input sockets, also taking into account linked origin sockets. */
+ for (const InputSocketRef *input_socket : node->inputs()) {
+ SocketFieldState &state = field_state_by_socket_id[input_socket->id()];
+ if (state.is_always_single) {
+ state.is_single = true;
+ continue;
+ }
+ state.is_single = true;
+ if (input_socket->directly_linked_sockets().is_empty()) {
+ if (inferencing_interface.inputs[input_socket->index()] ==
+ InputSocketFieldType::Implicit) {
+ state.is_single = false;
+ }
+ }
+ else {
+ for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) {
+ if (!field_state_by_socket_id[origin_socket->id()].is_single) {
+ state.is_single = false;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Update field state of output sockets, also taking into account input sockets. */
+ for (const OutputSocketRef *output_socket : node->outputs()) {
+ SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
+ const OutputFieldDependency &field_dependency =
+ inferencing_interface.outputs[output_socket->index()];
+
+ switch (field_dependency.field_type()) {
+ case OutputSocketFieldType::None: {
+ state.is_single = true;
+ break;
+ }
+ case OutputSocketFieldType::FieldSource: {
+ state.is_single = false;
+ state.is_field_source = true;
+ break;
+ }
+ case OutputSocketFieldType::PartiallyDependent:
+ case OutputSocketFieldType::DependentField: {
+ for (const InputSocketRef *input_socket :
+ gather_input_socket_dependencies(field_dependency, *node)) {
+ if (!input_socket->is_available()) {
+ continue;
+ }
+ if (!field_state_by_socket_id[input_socket->id()].is_single) {
+ state.is_single = false;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+}
+
+static void determine_group_output_states(const NodeTreeRef &tree,
+ FieldInferencingInterface &new_inferencing_interface,
+ const Span<SocketFieldState> field_state_by_socket_id)
+{
+ for (const NodeRef *group_output_node : tree.nodes_by_type("NodeGroupOutput")) {
+ /* Ignore inactive group output nodes. */
+ if (!(group_output_node->bnode()->flag & NODE_DO_OUTPUT)) {
+ continue;
+ }
+ /* Determine dependencies of all group outputs. */
+ for (const InputSocketRef *group_output_socket : group_output_node->inputs().drop_back(1)) {
+ OutputFieldDependency field_dependency = find_group_output_dependencies(
+ *group_output_socket, field_state_by_socket_id);
+ new_inferencing_interface.outputs[group_output_socket->index()] = std::move(
+ field_dependency);
+ }
+ break;
+ }
+}
+
+static void update_socket_shapes(const NodeTreeRef &tree,
+ const Span<SocketFieldState> field_state_by_socket_id)
+{
+ const eNodeSocketDisplayShape requires_data_shape = SOCK_DISPLAY_SHAPE_CIRCLE;
+ const eNodeSocketDisplayShape data_but_can_be_field_shape = SOCK_DISPLAY_SHAPE_DIAMOND_DOT;
+ const eNodeSocketDisplayShape is_field_shape = SOCK_DISPLAY_SHAPE_DIAMOND;
+
+ auto get_shape_for_state = [&](const SocketFieldState &state) {
+ if (state.is_always_single) {
+ return requires_data_shape;
+ }
+ if (!state.is_single) {
+ return is_field_shape;
+ }
+ if (state.requires_single) {
+ return requires_data_shape;
+ }
+ return data_but_can_be_field_shape;
+ };
+
+ for (const InputSocketRef *socket : tree.input_sockets()) {
+ bNodeSocket *bsocket = socket->bsocket();
+ const SocketFieldState &state = field_state_by_socket_id[socket->id()];
+ bsocket->display_shape = get_shape_for_state(state);
+ }
+ for (const OutputSocketRef *socket : tree.output_sockets()) {
+ bNodeSocket *bsocket = socket->bsocket();
+ const SocketFieldState &state = field_state_by_socket_id[socket->id()];
+ bsocket->display_shape = get_shape_for_state(state);
+ }
+}
+
+static bool update_field_inferencing(bNodeTree &btree)
+{
+ using namespace blender::nodes;
+ if (btree.type != NTREE_GEOMETRY) {
+ return false;
+ }
+
+ /* Create new inferencing interface for this node group. */
+ FieldInferencingInterface *new_inferencing_interface = new FieldInferencingInterface();
+ new_inferencing_interface->inputs.resize(BLI_listbase_count(&btree.inputs),
+ InputSocketFieldType::IsSupported);
+ new_inferencing_interface->outputs.resize(BLI_listbase_count(&btree.outputs),
+ OutputFieldDependency::ForDataSource());
+
+ /* Create #NodeTreeRef to accelerate various queries on the node tree (e.g. linked sockets). */
+ const NodeTreeRef tree{&btree};
+
+ /* Keep track of the state of all sockets. The index into this array is #SocketRef::id(). */
+ Array<SocketFieldState> field_state_by_socket_id(tree.sockets().size());
+
+ propagate_data_requirements_from_right_to_left(tree, field_state_by_socket_id);
+ determine_group_input_states(tree, *new_inferencing_interface, field_state_by_socket_id);
+ propagate_field_status_from_left_to_right(tree, field_state_by_socket_id);
+ determine_group_output_states(tree, *new_inferencing_interface, field_state_by_socket_id);
+ update_socket_shapes(tree, field_state_by_socket_id);
+
+ /* Update the previous group interface. */
+ const bool group_interface_changed = btree.field_inferencing_interface == nullptr ||
+ *btree.field_inferencing_interface !=
+ *new_inferencing_interface;
+ delete btree.field_inferencing_interface;
+ btree.field_inferencing_interface = new_inferencing_interface;
+
+ return group_interface_changed;
+}
+
+} // namespace node_field_inferencing
+
using IDTreePair = std::pair<ID *, bNodeTree *>;
using TreeNodePair = std::pair<bNodeTree *, bNode *>;
using ObjectModifierPair = std::pair<Object *, ModifierData *>;
@@ -203,7 +722,7 @@ class NodeTreeMainUpdater {
/* TODO: Use owner id of embedded node trees. */
ID *id = &ntree->id;
- ntree->changed_flag = NTREE_CHANGED_NONE;
+ this->reset_changed_flags(*ntree);
if (result.interface_changed) {
if (ntree->type == NTREE_GEOMETRY) {
@@ -317,22 +836,26 @@ class NodeTreeMainUpdater {
result.interface_changed = true;
}
- if (ntree.changed_flag & NTREE_CHANGED_LINK) {
- this->update_input_socket_link_pointers(ntree);
- }
+ this->update_input_socket_link_pointers(ntree);
this->update_individual_nodes(ntree);
if (ntree.typeinfo->update) {
ntree.typeinfo->update(&ntree);
}
- result.interface_changed = true;
- result.output_changed = true;
+ if (node_field_inferencing::update_field_inferencing(ntree)) {
+ result.interface_changed = true;
+ }
+
+ this->update_input_socket_link_pointers(ntree);
+ this->update_node_levels(ntree);
+ this->update_link_validation(ntree);
if (result.interface_changed) {
ntreeInterfaceTypeUpdate(&ntree);
}
+ result.output_changed = true;
return result;
}
@@ -391,6 +914,40 @@ class NodeTreeMainUpdater {
node.typeinfo->update_internal_links(&ntree, &node);
}
}
+
+ void update_node_levels(bNodeTree &ntree)
+ {
+ ntreeUpdateNodeLevels(&ntree);
+ }
+
+ void update_link_validation(bNodeTree &ntree)
+ {
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
+ link->flag |= NODE_LINK_VALID;
+ if (link->fromnode && link->tonode && link->fromnode->level <= link->tonode->level) {
+ link->flag &= ~NODE_LINK_VALID;
+ }
+ else if (ntree.typeinfo->validate_link) {
+ if (!ntree.typeinfo->validate_link(&ntree, link)) {
+ link->flag &= ~NODE_LINK_VALID;
+ }
+ }
+ }
+ }
+
+ void reset_changed_flags(bNodeTree &ntree)
+ {
+ ntree.changed_flag = NTREE_CHANGED_NONE;
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
+ node->changed_flag = NODE_CHANGED_NONE;
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ socket->changed_flag = SOCK_CHANGED_NONE;
+ }
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
+ socket->changed_flag = SOCK_CHANGED_NONE;
+ }
+ }
+ }
};
} // namespace blender::bke