[Bf-blender-cvs] [c48e4b7a44b] geometry-nodes: Geometry Nodes: improve node tree evaluation
Jacques Lucke
noreply at git.blender.org
Mon Oct 26 13:27:27 CET 2020
Commit: c48e4b7a44b5771e3bb801d3fa3feae82022720b
Author: Jacques Lucke
Date: Mon Oct 26 13:27:02 2020 +0100
Branches: geometry-nodes
https://developer.blender.org/rBc48e4b7a44b5771e3bb801d3fa3feae82022720b
Geometry Nodes: improve node tree evaluation
This change reduces the number of unnecessary copies of data
and avoids computing the same value more than once.
===================================================================
M source/blender/modifiers/intern/MOD_nodes.cc
M source/blender/nodes/NOD_geometry_exec.hh
===================================================================
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index 38712054f22..6d7fe559eab 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -121,110 +121,98 @@ using namespace blender::bke;
class GeometryNodesEvaluator {
private:
LinearAllocator<> allocator_;
- const DerivedNodeTree &tree_;
- Map<const DOutputSocket *, GMutablePointer> group_input_data_;
+ Map<const DInputSocket *, GMutablePointer> value_by_input_;
Vector<const DInputSocket *> group_outputs_;
MultiFunctionByNode &mf_by_node_;
const DataTypeConversions &conversions_;
public:
- GeometryNodesEvaluator(const DerivedNodeTree &tree,
- Map<const DOutputSocket *, GMutablePointer> group_input_data,
+ GeometryNodesEvaluator(const Map<const DOutputSocket *, GMutablePointer> &group_input_data,
Vector<const DInputSocket *> group_outputs,
MultiFunctionByNode &mf_by_node)
- : tree_(tree),
- group_input_data_(std::move(group_input_data)),
- group_outputs_(std::move(group_outputs)),
+ : group_outputs_(std::move(group_outputs)),
mf_by_node_(mf_by_node),
conversions_(get_implicit_type_conversions())
{
+ for (auto item : group_input_data.items()) {
+ this->forward_to_inputs(*item.key, item.value);
+ }
}
Vector<GMutablePointer> execute()
{
Vector<GMutablePointer> results;
for (const DInputSocket *group_output : group_outputs_) {
- const CPPType &type = *socket_cpp_type_get(*group_output->typeinfo());
- void *result_buffer = allocator_.allocate(type.size(), type.alignment());
- this->compute_input_socket(*group_output, result_buffer);
- results.append(GMutablePointer{type, result_buffer});
+ GMutablePointer result = this->get_input_value(*group_output);
+ results.append(result);
}
- for (GMutablePointer value : group_input_data_.values()) {
- value.type()->destruct(value.get());
+ for (GMutablePointer value : value_by_input_.values()) {
+ value.destruct();
}
return results;
}
private:
- void compute_input_socket(const DInputSocket &socket_to_compute, void *r_value)
+ GMutablePointer get_input_value(const DInputSocket &socket_to_compute)
{
+ std::optional<GMutablePointer> value = value_by_input_.pop_try(&socket_to_compute);
+ if (value.has_value()) {
+ /* This input has been computed before, return it directly. */
+ return *value;
+ }
+
Span<const DOutputSocket *> from_sockets = socket_to_compute.linked_sockets();
Span<const DGroupInput *> from_group_inputs = socket_to_compute.linked_group_inputs();
const int total_inputs = from_sockets.size() + from_group_inputs.size();
BLI_assert(total_inputs <= 1);
+ const CPPType &type = *socket_cpp_type_get(*socket_to_compute.typeinfo());
+
if (total_inputs == 0) {
+ /* The input is not connected, use the value from the socket itself. */
bNodeSocket &bsocket = *socket_to_compute.bsocket();
- socket_cpp_value_get(bsocket, r_value);
- return;
+ void *buffer = allocator_.allocate(type.size(), type.alignment());
+ socket_cpp_value_get(bsocket, buffer);
+ return GMutablePointer{type, buffer};
}
if (from_group_inputs.size() == 1) {
+ /* The input gets its value from the input of a group that is not further connected. */
bNodeSocket &bsocket = *from_group_inputs[0]->bsocket();
- socket_cpp_value_get(bsocket, r_value);
- return;
+ void *buffer = allocator_.allocate(type.size(), type.alignment());
+ socket_cpp_value_get(bsocket, buffer);
+ return GMutablePointer{type, buffer};
}
+ /* Compute the socket now. */
const DOutputSocket &from_socket = *from_sockets[0];
- const CPPType &from_type = *socket_cpp_type_get(*from_socket.typeinfo());
- const CPPType &to_type = *socket_cpp_type_get(*socket_to_compute.typeinfo());
- if (from_type == to_type) {
- this->compute_output_socket(from_socket, r_value);
- }
- else {
- /* The type of both sockets don't match, so a conversion is necessary. */
- if (conversions_.is_convertible(from_type, to_type)) {
- void *from_value = allocator_.allocate(from_type.size(), from_type.alignment());
- this->compute_output_socket(from_socket, from_value);
- conversions_.convert(from_type, to_type, from_value, r_value);
- from_type.destruct(from_value);
- }
- else {
- /* Use a default value when the types cannot be converted. */
- to_type.copy_to_uninitialized(to_type.default_value(), r_value);
- }
- }
+ this->compute_output_and_forward(from_socket);
+ return value_by_input_.pop(&socket_to_compute);
}
- void compute_output_socket(const DOutputSocket &socket_to_compute, void *r_value)
+ void compute_output_and_forward(const DOutputSocket &socket_to_compute)
{
- const GMutablePointer *group_input = group_input_data_.lookup_ptr(&socket_to_compute);
- if (group_input != nullptr) {
- const CPPType &type = *group_input->type();
- type.copy_to_uninitialized(group_input->get(), r_value);
- return;
- }
-
const DNode &node = socket_to_compute.node();
- GValueByName node_inputs{allocator_};
- /* Compute all inputs for the node. */
+ /* Prepare inputs required to execute the node. */
+ GValueByName node_inputs{allocator_};
for (const DInputSocket *input_socket : node.inputs()) {
- const CPPType &type = *socket_cpp_type_get(*input_socket->typeinfo());
- void *buffer = allocator_.allocate(type.size(), type.alignment());
- compute_input_socket(*input_socket, buffer);
- node_inputs.move_in(input_socket->identifier(), GMutablePointer{type, buffer});
- type.destruct(buffer);
+ if (input_socket->is_available()) {
+ GMutablePointer value = this->get_input_value(*input_socket);
+ node_inputs.transfer_ownership_in(input_socket->identifier(), value);
+ }
}
- /* Execute the node itself. */
+ /* Execute the node. */
GValueByName node_outputs{allocator_};
this->execute_node(node, node_inputs, node_outputs);
- /* Pass relevant value to the caller. */
- bNodeSocket *bsocket_to_compute = socket_to_compute.bsocket();
- const CPPType &type_to_compute = *socket_cpp_type_get(*bsocket_to_compute->typeinfo);
- GMutablePointer computed_value = node_outputs.extract(bsocket_to_compute->identifier);
- type_to_compute.relocate_to_uninitialized(computed_value.get(), r_value);
+ /* Forward computed outputs to linked input sockets. */
+ for (const DOutputSocket *output_socket : node.outputs()) {
+ if (output_socket->is_available()) {
+ GMutablePointer value = node_outputs.extract(output_socket->identifier());
+ this->forward_to_inputs(*output_socket, value);
+ }
+ }
}
void execute_node(const DNode &node, GValueByName &node_inputs, GValueByName &node_outputs)
@@ -266,6 +254,55 @@ class GeometryNodesEvaluator {
value.destruct();
}
}
+
+ void forward_to_inputs(const DOutputSocket &from_socket, GMutablePointer value_to_forward)
+ {
+ Span<const DInputSocket *> linked_sockets = from_socket.linked_sockets();
+
+ Vector<const DInputSocket *> to_sockets_with_same_type;
+ Vector<const DInputSocket *> to_sockets_with_different_type;
+ for (const DInputSocket *linked_socket : linked_sockets) {
+ if (from_socket.typeinfo() == linked_socket->typeinfo()) {
+ to_sockets_with_same_type.append(linked_socket);
+ }
+ else {
+ to_sockets_with_different_type.append(linked_socket);
+ }
+ }
+
+ const CPPType &from_type = *value_to_forward.type();
+
+ for (const DInputSocket *to_socket : to_sockets_with_different_type) {
+ const CPPType &to_type = *socket_cpp_type_get(*to_socket->typeinfo());
+ void *buffer = allocator_.allocate(to_type.size(), to_type.alignment());
+ conversions_.convert(from_type, to_type, value_to_forward.get(), buffer);
+ value_by_input_.add_new(to_socket, GMutablePointer{to_type, buffer});
+ }
+
+ if (to_sockets_with_same_type.size() == 0) {
+ /* This value is not further used, so destruct it. */
+ value_to_forward.destruct();
+ }
+ else if (to_sockets_with_same_type.size() == 1) {
+ /* This value is only used on one input socket, no need to copy it. */
+ const DInputSocket *to_socket = to_sockets_with_same_type[0];
+ value_by_input_.add_new(to_socket, value_to_forward);
+ }
+ else {
+ /* Multiple inputs use the value, make a copy for every input except for one. */
+ const DInputSocket *first_to_socket = to_sockets_with_same_type[0];
+ Span<const DInputSocket *> other_to_sockets = to_sockets_with_same_type.as_span().drop_front(
+ 1);
+ const CPPType &type = *value_to_forward.type();
+
+ value_by_input_.add_new(first_to_socket, value_to_forward);
+ for (const DInputSocket *to_socket : other_to_sockets) {
+ void *buffer = allocator_.allocate(type.size(), type.alignment());
+ type.copy_to_uninitialized(value_to_forward.get(), buffer);
+ value_by_input_.add_new(to_socket, GMutablePointer{type, buffer});
+ }
+ }
+ }
};
/**
@@ -292,7 +329,7 @@ static GeometryPtr compute_geometry(const DerivedNodeTree &tree,
Vector<const DInputSocket *> group_outputs;
group_outputs.append(&socket_to_compute);
- GeometryNodesEvaluator evaluator{tree, group_inputs, group_outputs, mf_by_node};
+ GeometryNodesEvaluator evaluator{group_inputs, group_outputs, mf_by_node};
Vector<GMutablePointer> results = evaluator.execute();
BLI_assert(results.size() == 1);
GMutablePointer result = results[0];
diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh
index fe6dc732898..70e2af6c7fb 100644
--- a/source/blender/nodes/NOD_geometry_exec.hh
+++ b/source/blender/nodes/NOD_geometry_exec.hh
@@ -55,7 +55,14 @@ class GValueByName {
}
}
- /* Add a value to the container. */
+ /* Add a v
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list