Geometry Nodes: small refactor towards supporting partially lazy nodes

Currently, a node either supports lazyness during execution (like the Switch
node), or it doesn't. If it does support lazyness, then every input is computed
lazily. However, usually not all inputs actually have to be computed lazily.
E.g. the boolean switch input is always required, while the other inputs
should be computed lazily.

Better support for such sockets  can avoid unnecessary round trips through
the node execution function.
This commit is contained in:
Jacques Lucke 2022-01-01 12:50:48 +01:00
parent 6844304dda
commit 4c46203cb5
1 changed files with 21 additions and 10 deletions

View File

@ -235,9 +235,10 @@ struct NodeState {
MutableSpan<OutputState> outputs;
/**
* Nodes that don't support laziness have some special handling the first time they are executed.
* Most nodes have inputs that are always required. Those have special handling to avoid an extra
* call to the node execution function.
*/
bool non_lazy_node_is_initialized = false;
bool non_lazy_inputs_handled = false;
/**
* Used to check that nodes that don't support laziness do not run more than once.
@ -801,12 +802,12 @@ class GeometryNodesEvaluator {
if (!this->prepare_node_outputs_for_execution(locked_node)) {
return;
}
/* Initialize nodes that don't support laziness. This is done after at least one output is
/* Initialize inputs that don't support laziness. This is done after at least one output is
* required and before we check that all required inputs are provided. This reduces the
* number of "round-trips" through the task pool by one for most nodes. */
if (!node_state.non_lazy_node_is_initialized && !node_supports_laziness(node)) {
this->initialize_non_lazy_node(locked_node);
node_state.non_lazy_node_is_initialized = true;
if (!node_state.non_lazy_inputs_handled) {
this->require_non_lazy_inputs(locked_node);
node_state.non_lazy_inputs_handled = true;
}
/* Prepare inputs and check if all required inputs are provided. */
if (!this->prepare_node_inputs_for_execution(locked_node)) {
@ -880,17 +881,27 @@ class GeometryNodesEvaluator {
return execution_is_necessary;
}
void initialize_non_lazy_node(LockedNode &locked_node)
void require_non_lazy_inputs(LockedNode &locked_node)
{
this->foreach_non_lazy_input(locked_node, [&](const DInputSocket socket) {
this->set_input_required(locked_node, socket);
});
}
void foreach_non_lazy_input(LockedNode &locked_node, FunctionRef<void(DInputSocket socket)> fn)
{
if (node_supports_laziness(locked_node.node)) {
/* In the future only some of the inputs may support lazyness. */
return;
}
/* Nodes that don't support laziness require all inputs. */
for (const int i : locked_node.node->inputs().index_range()) {
InputState &input_state = locked_node.node_state.inputs[i];
if (input_state.type == nullptr) {
/* Ignore unavailable/non-data sockets. */
continue;
}
/* Nodes that don't support laziness require all inputs. */
const DInputSocket input_socket = locked_node.node.input(i);
this->set_input_required(locked_node, input_socket);
fn(locked_node.node.input(i));
}
}