[Bf-blender-cvs] [3d1244c1342] temp-geometry-nodes-evaluator-refactor: comments
Jacques Lucke
noreply at git.blender.org
Thu Sep 8 17:22:32 CEST 2022
Commit: 3d1244c1342e06a3cbeb26e87229640e579ac8f7
Author: Jacques Lucke
Date: Thu Sep 8 16:07:02 2022 +0200
Branches: temp-geometry-nodes-evaluator-refactor
https://developer.blender.org/rB3d1244c1342e06a3cbeb26e87229640e579ac8f7
comments
===================================================================
M source/blender/functions/FN_lazy_function_graph.hh
M source/blender/functions/intern/lazy_function_graph.cc
M source/blender/functions/intern/lazy_function_graph_executor.cc
===================================================================
diff --git a/source/blender/functions/FN_lazy_function_graph.hh b/source/blender/functions/FN_lazy_function_graph.hh
index 0826bfe7c21..4ede28c4f26 100644
--- a/source/blender/functions/FN_lazy_function_graph.hh
+++ b/source/blender/functions/FN_lazy_function_graph.hh
@@ -4,6 +4,15 @@
/** \file
* \ingroup fn
+ *
+ * This file contains a graph data structure that allows composing multiple lazy-functions into a
+ * combined lazy-function.
+ *
+ * There are two types of nodes in the graph:
+ * - #FunctionNode: Corresponds to a #LazyFunction. The inputs and outputs of the function become
+ * input and output sockets of the node.
+ * - #DummyNode: Is used to indicate inputs and outputs of the entire graph. It can have an
+ * arbitrary number of sockets.
*/
#include "BLI_linear_allocator.hh"
@@ -18,11 +27,27 @@ class OutputSocket;
class Node;
class Graph;
+/**
+ * A #Socket is the interface of a #Node. Every #Socket is either an #InputSocket or #OutputSocket.
+ * Links can be created from output sockets to input sockets.
+ */
class Socket : NonCopyable, NonMovable {
protected:
+ /**
+ * The node the socket belongs to.
+ */
Node *node_;
+ /**
+ * Data type of the socket. Only sockets with the same type can be linked.
+ */
const CPPType *type_;
+ /**
+ * Indicates whether this is an #InputSocket or #OutputSocket.
+ */
bool is_input_;
+ /**
+ * Index of the socket. E.g. 0 for the first input and the first output socket.
+ */
int index_in_node_;
friend Graph;
@@ -31,7 +56,7 @@ class Socket : NonCopyable, NonMovable {
bool is_input() const;
bool is_output() const;
- int index_in_node() const;
+ int index() const;
InputSocket &as_input();
OutputSocket &as_output();
@@ -48,7 +73,20 @@ class Socket : NonCopyable, NonMovable {
class InputSocket : public Socket {
private:
+ /**
+ * An input can have at most one link connected to it. The linked socket is the "origin" because
+ * it's where the data is coming from. The type of the origin must be the same as the type of
+ * this socket.
+ */
OutputSocket *origin_;
+ /**
+ * Can be null or a non-owning pointer to a value of the type of the socket. This value will be
+ * used when the input is used but not linked.
+ *
+ * This is technically not needed, because one could just create a separate node that just
+ * outputs the value, but that would have more overhead. Especially because it's commonly the
+ * case that most inputs are unlinked.
+ */
const void *default_value_ = nullptr;
friend Graph;
@@ -63,6 +101,9 @@ class InputSocket : public Socket {
class OutputSocket : public Socket {
private:
+ /**
+ * An output can be linked to an arbitrary number of inputs of the same type.
+ */
Vector<InputSocket *> targets_;
friend Graph;
@@ -72,11 +113,30 @@ class OutputSocket : public Socket {
Span<const InputSocket *> targets() const;
};
+/**
+ * A #Node has input and output sockets. Every node is either a #FunctionNode or a #DummyNode.
+ */
class Node : NonCopyable, NonMovable {
protected:
+ /**
+ * The function this node corresponds to. If this is null, the node is a #DummyNode.
+ * The function is not owned by this #Node nor by the #Graph.
+ */
const LazyFunction *fn_ = nullptr;
+ /**
+ * Input sockets of the node.
+ */
Span<InputSocket *> inputs_;
+ /**
+ * Output sockets of the node.
+ */
Span<OutputSocket *> outputs_;
+ /**
+ * An index that is set when calling #Graph::update_node_indices. This can be used to create
+ * efficient mappings from nodes to other data using just an array instead of a hash map.
+ *
+ * This is technically not necessary but has better performance than always using hash maps.
+ */
int index_in_graph_ = -1;
friend Graph;
@@ -99,11 +159,18 @@ class Node : NonCopyable, NonMovable {
std::string name() const;
};
+/**
+ * A #Node that corresponds to a specific #LazyFunction.
+ */
class FunctionNode : public Node {
public:
const LazyFunction &function() const;
};
+/**
+ * A #Node that does *not* correspond to a #LazyFunction. Instead it can be used to indicate inputs
+ * and outputs of the entire graph. It can have an arbitrary number of inputs and outputs.
+ */
class DummyNode : public Node {
private:
std::string name_;
@@ -111,24 +178,57 @@ class DummyNode : public Node {
friend Node;
};
+/**
+ * A container for an arbitrary number of nodes and links between their sockets.
+ */
class Graph : NonCopyable, NonMovable {
private:
+ /**
+ * Used to allocate nodes and sockets in the graph.
+ */
LinearAllocator<> allocator_;
+ /**
+ * Contains all nodes in the graph so that it is efficient to iterate over them.
+ */
Vector<Node *> nodes_;
public:
~Graph();
+ /**
+ * Get all nodes in the graph. The index in the span corresponds to #Node::index_in_graph.
+ */
Span<const Node *> nodes() const;
+ /**
+ * Add a new function node with sockets that match the passed in #LazyFunction.
+ */
FunctionNode &add_function(const LazyFunction &fn);
+
+ /**
+ * Add a new dummy node with the given socket types.
+ */
DummyNode &add_dummy(Span<const CPPType *> input_types, Span<const CPPType *> output_types);
+
+ /**
+ * Add a link between the two given sockets.
+ * This has undefined behavior when the input is linked to something else already.
+ */
void add_link(OutputSocket &from, InputSocket &to);
- void remove_link(OutputSocket &from, InputSocket &to);
+ /**
+ * Make sure that #Node::index_in_graph is up to date.
+ */
void update_node_indices();
+
+ /**
+ * Can be used to assert that #update_node_indices has been called.
+ */
bool node_indices_are_valid() const;
+ /**
+ * Utility to generate a dot graph string for the graph. This can be used for debugging.
+ */
std::string to_dot() const;
};
@@ -146,7 +246,7 @@ inline bool Socket::is_output() const
return !is_input_;
}
-inline int Socket::index_in_node() const
+inline int Socket::index() const
{
return index_in_node_;
}
diff --git a/source/blender/functions/intern/lazy_function_graph.cc b/source/blender/functions/intern/lazy_function_graph.cc
index c60431d2c3d..cc55b70d166 100644
--- a/source/blender/functions/intern/lazy_function_graph.cc
+++ b/source/blender/functions/intern/lazy_function_graph.cc
@@ -83,14 +83,6 @@ void Graph::add_link(OutputSocket &from, InputSocket &to)
from.targets_.append(&to);
}
-void Graph::remove_link(OutputSocket &from, InputSocket &to)
-{
- BLI_assert(to.origin_ == &from);
- BLI_assert(from.targets_.contains(&to));
- to.origin_ = nullptr;
- from.targets_.remove_first_occurrence_and_reorder(&to);
-}
-
void Graph::update_node_indices()
{
for (const int i : nodes_.index_range()) {
@@ -161,11 +153,11 @@ std::string Graph::to_dot() const
for (const Node *node : nodes_) {
for (const InputSocket *socket : node->inputs()) {
const dot::NodeWithSocketsRef &to_dot_node = dot_nodes.lookup(&socket->node());
- const dot::NodePort to_dot_port = to_dot_node.input(socket->index_in_node());
+ const dot::NodePort to_dot_port = to_dot_node.input(socket->index());
if (const OutputSocket *origin = socket->origin()) {
dot::NodeWithSocketsRef &from_dot_node = dot_nodes.lookup(&origin->node());
- digraph.new_edge(from_dot_node.output(origin->index_in_node()), to_dot_port);
+ digraph.new_edge(from_dot_node.output(origin->index()), to_dot_port);
}
else if (const void *default_value = socket->default_value()) {
const CPPType &type = socket->type();
diff --git a/source/blender/functions/intern/lazy_function_graph_executor.cc b/source/blender/functions/intern/lazy_function_graph_executor.cc
index 0e17d0a682c..97393b04f8e 100644
--- a/source/blender/functions/intern/lazy_function_graph_executor.cc
+++ b/source/blender/functions/intern/lazy_function_graph_executor.cc
@@ -371,7 +371,7 @@ class Executor {
const OutputSocket &socket = *self_.graph_inputs_[i];
const Node &node = socket.node();
const NodeState &node_state = *node_states_[node.index_in_graph()];
- const OutputState &output_state = node_state.outputs[socket.index_in_node()];
+ const OutputState &output_state = node_state.outputs[socket.index()];
if (output_state.usage == ValueUsage::Unused) {
params_->set_input_unused(i);
}
@@ -428,7 +428,7 @@ class Executor {
void notify_output_required(const OutputSocket &socket, CurrentTask ¤t_task)
{
const Node &node = socket.node();
- const int index_in_node = socket.index_in_node();
+ const int index_in_node = socket.index();
NodeState &node_state = *node_states_[node.index_in_graph()];
OutputState &output_state = node_state.outputs[index_in_node];
@@ -464,7 +464,7 @@ class Executor {
void notify_output_unused(const OutputSocket &socket, CurrentTask ¤t_task)
{
const Node &node = socket.node();
- const int index_in_node = socket.index_in_node();
+ const int index_in_node = socket.index();
NodeState &node_state = *node_states_[node.index_in_graph()];
OutputState &output_state = node_state.outputs[index_in_node];
@@ -759,7 +759,7 @@ class Executor {
void set_input_unused(LockedNode &locked_node, const InputSocket &input_socket)
{
NodeState &node_state = locked_node.node_state;
- const int input_index = input_socket.index_in_node();
+ const int input_index = input_socket.index();
InputState &input_state = node_state.inputs[input_index];
BLI_assert(input_state.usage != ValueUsage::Used);
@@ -795,7 +795,7 @@ class Executor {
{
BLI_assert(&locked_node.node == &input_socket.node());
NodeState &node_state = locked_node.node_state;
- const int input_index = input_socket.index_in_node();
+ const int input_index = input_socket.index();
InputState &input_state = node_state.inputs[input_index];
BLI_assert(input_state.usage != ValueUsage::Unused);
@@ -833,7 +833,7 @@ class Executor {
for (const InputSocket *target_socket : targets) {
const Node &target_node = target_socket->node();
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list