Geometry Nodes: deterministic anonymous attribute lifetimes
Previously, the lifetimes of anonymous attributes were determined by reference counts which were non-deterministic when multiple threads are used. Now the lifetimes of anonymous attributes are handled more explicitly and deterministically. This is a prerequisite for any kind of caching, because caching the output of nodes that do things non-deterministically and have "invisible inputs" (reference counts) doesn't really work. For more details for how deterministic lifetimes are achieved, see D16858. No functional changes are expected. Small performance changes are expected as well (within few percent, anything larger regressions should be reported as bugs). Differential Revision: https://developer.blender.org/D16858
This commit is contained in:
@@ -53,6 +53,10 @@ class Socket : NonCopyable, NonMovable {
|
||||
* Index of the socket. E.g. 0 for the first input and the first output socket.
|
||||
*/
|
||||
int index_in_node_;
|
||||
/**
|
||||
* Index of the socket in the entire graph. Every socket has a different index.
|
||||
*/
|
||||
int index_in_graph_;
|
||||
|
||||
friend Graph;
|
||||
|
||||
@@ -61,6 +65,7 @@ class Socket : NonCopyable, NonMovable {
|
||||
bool is_output() const;
|
||||
|
||||
int index() const;
|
||||
int index_in_graph() const;
|
||||
|
||||
InputSocket &as_input();
|
||||
OutputSocket &as_output();
|
||||
@@ -179,6 +184,20 @@ class DummyDebugInfo {
|
||||
virtual std::string output_name(const int i) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Just stores a string per socket in a dummy node.
|
||||
*/
|
||||
class SimpleDummyDebugInfo : public DummyDebugInfo {
|
||||
public:
|
||||
std::string name;
|
||||
Vector<std::string> input_names;
|
||||
Vector<std::string> output_names;
|
||||
|
||||
std::string node_name() const override;
|
||||
std::string input_name(const int i) const override;
|
||||
std::string output_name(const int i) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@@ -205,6 +224,11 @@ class Graph : NonCopyable, NonMovable {
|
||||
* Contains all nodes in the graph so that it is efficient to iterate over them.
|
||||
*/
|
||||
Vector<Node *> nodes_;
|
||||
/**
|
||||
* Number of sockets in the graph. Can be used as array size when indexing using
|
||||
* `Socket::index_in_graph`.
|
||||
*/
|
||||
int socket_num_ = 0;
|
||||
|
||||
public:
|
||||
~Graph();
|
||||
@@ -213,6 +237,7 @@ class Graph : NonCopyable, NonMovable {
|
||||
* Get all nodes in the graph. The index in the span corresponds to #Node::index_in_graph.
|
||||
*/
|
||||
Span<const Node *> nodes() const;
|
||||
Span<Node *> nodes();
|
||||
|
||||
/**
|
||||
* Add a new function node with sockets that match the passed in #LazyFunction.
|
||||
@@ -232,10 +257,24 @@ class Graph : NonCopyable, NonMovable {
|
||||
*/
|
||||
void add_link(OutputSocket &from, InputSocket &to);
|
||||
|
||||
/**
|
||||
* If the socket is linked, remove the link.
|
||||
*/
|
||||
void clear_origin(InputSocket &socket);
|
||||
|
||||
/**
|
||||
* Make sure that #Node::index_in_graph is up to date.
|
||||
*/
|
||||
void update_node_indices();
|
||||
/**
|
||||
* Make sure that #Socket::index_in_graph is up to date.
|
||||
*/
|
||||
void update_socket_indices();
|
||||
|
||||
/**
|
||||
* Number of sockets in the graph.
|
||||
*/
|
||||
int socket_num() const;
|
||||
|
||||
/**
|
||||
* Can be used to assert that #update_node_indices has been called.
|
||||
@@ -280,6 +319,11 @@ inline int Socket::index() const
|
||||
return index_in_node_;
|
||||
}
|
||||
|
||||
inline int Socket::index_in_graph() const
|
||||
{
|
||||
return index_in_graph_;
|
||||
}
|
||||
|
||||
inline InputSocket &Socket::as_input()
|
||||
{
|
||||
BLI_assert(this->is_input());
|
||||
@@ -445,6 +489,16 @@ inline Span<const Node *> Graph::nodes() const
|
||||
return nodes_;
|
||||
}
|
||||
|
||||
inline Span<Node *> Graph::nodes()
|
||||
{
|
||||
return nodes_;
|
||||
}
|
||||
|
||||
inline int Graph::socket_num() const
|
||||
{
|
||||
return socket_num_;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::fn::lazy_function
|
||||
|
||||
@@ -86,6 +86,14 @@ void Graph::add_link(OutputSocket &from, InputSocket &to)
|
||||
from.targets_.append(&to);
|
||||
}
|
||||
|
||||
void Graph::clear_origin(InputSocket &socket)
|
||||
{
|
||||
if (socket.origin_ != nullptr) {
|
||||
socket.origin_->targets_.remove_first_occurrence_and_reorder(&socket);
|
||||
socket.origin_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Graph::update_node_indices()
|
||||
{
|
||||
for (const int i : nodes_.index_range()) {
|
||||
@@ -93,6 +101,20 @@ void Graph::update_node_indices()
|
||||
}
|
||||
}
|
||||
|
||||
void Graph::update_socket_indices()
|
||||
{
|
||||
int socket_counter = 0;
|
||||
for (const int i : nodes_.index_range()) {
|
||||
for (InputSocket *socket : nodes_[i]->inputs()) {
|
||||
socket->index_in_graph_ = socket_counter++;
|
||||
}
|
||||
for (OutputSocket *socket : nodes_[i]->outputs()) {
|
||||
socket->index_in_graph_ = socket_counter++;
|
||||
}
|
||||
}
|
||||
socket_num_ = socket_counter;
|
||||
}
|
||||
|
||||
bool Graph::node_indices_are_valid() const
|
||||
{
|
||||
for (const int i : nodes_.index_range()) {
|
||||
@@ -152,6 +174,21 @@ std::string DummyDebugInfo::output_name(const int /*i*/) const
|
||||
return fallback_name;
|
||||
}
|
||||
|
||||
std::string SimpleDummyDebugInfo::node_name() const
|
||||
{
|
||||
return this->name;
|
||||
}
|
||||
|
||||
std::string SimpleDummyDebugInfo::input_name(const int i) const
|
||||
{
|
||||
return this->input_names[i];
|
||||
}
|
||||
|
||||
std::string SimpleDummyDebugInfo::output_name(const int i) const
|
||||
{
|
||||
return this->output_names[i];
|
||||
}
|
||||
|
||||
std::string Graph::ToDotOptions::socket_name(const Socket &socket) const
|
||||
{
|
||||
return socket.name();
|
||||
|
||||
Reference in New Issue
Block a user