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:
Diffstat (limited to 'source/blender/modifiers/intern/MOD_nodes_evaluator.cc')
-rw-r--r--source/blender/modifiers/intern/MOD_nodes_evaluator.cc165
1 files changed, 96 insertions, 69 deletions
diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
index 4e808120f4a..6b79c9e0f68 100644
--- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
+++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
@@ -66,31 +66,55 @@ struct SingleInputValue {
void *value = nullptr;
};
-struct MultiInputValueItem {
+struct MultiInputValue {
/**
- * The socket where this value is coming from. This is required to sort the inputs correctly
- * based on the link order later on.
+ * Ordered sockets connected to this multi-input.
*/
- DSocket origin;
+ Vector<DSocket> origins;
/**
- * Should only be null directly after construction. After that it should always point to a value
- * of the correct type.
+ * A value for every origin socket. The order is determined by #origins.
+ * Note, the same origin can occur multiple times. However, it is guaranteed that values coming
+ * from the same origin have the same value (the pointer is different, but they point to values
+ * that would compare equal).
*/
- void *value = nullptr;
-};
-
-struct MultiInputValue {
+ Vector<void *> values;
/**
- * Collection of all the inputs that have been provided already. Note, the same origin can occur
- * multiple times. However, it is guaranteed that if two items have the same origin, they will
- * also have the same value (the pointer is different, but they point to values that would
- * compare equal).
+ * Number of non-null values.
*/
- Vector<MultiInputValueItem> items;
- /**
- * Number of items that need to be added until all inputs have been provided.
- */
- int expected_size = 0;
+ int provided_value_count = 0;
+
+ bool all_values_available() const
+ {
+ return this->missing_values() == 0;
+ }
+
+ int missing_values() const
+ {
+ return this->values.size() - this->provided_value_count;
+ }
+
+ void add_value(const DSocket origin, void *value)
+ {
+ const int index = this->find_available_index(origin);
+ this->values[index] = value;
+ this->provided_value_count++;
+ }
+
+ private:
+ int find_available_index(DSocket origin) const
+ {
+ for (const int i : origins.index_range()) {
+ if (values[i] != nullptr) {
+ continue;
+ }
+ if (origins[i] != origin) {
+ continue;
+ }
+ return i;
+ }
+ BLI_assert_unreachable();
+ return -1;
+ }
};
struct InputState {
@@ -211,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.
@@ -556,13 +581,14 @@ class GeometryNodesEvaluator {
/* Construct the correct struct that can hold the input(s). */
if (socket->is_multi_input_socket()) {
input_state.value.multi = allocator.construct<MultiInputValue>().release();
+ MultiInputValue &multi_value = *input_state.value.multi;
/* Count how many values should be added until the socket is complete. */
- socket.foreach_origin_socket(
- [&](DSocket UNUSED(origin)) { input_state.value.multi->expected_size++; });
+ socket.foreach_origin_socket([&](DSocket origin) { multi_value.origins.append(origin); });
/* If no links are connected, we do read the value from socket itself. */
- if (input_state.value.multi->expected_size == 0) {
- input_state.value.multi->expected_size = 1;
+ if (multi_value.origins.is_empty()) {
+ multi_value.origins.append(socket);
}
+ multi_value.values.resize(multi_value.origins.size(), nullptr);
}
else {
input_state.value.single = allocator.construct<SingleInputValue>().release();
@@ -623,8 +649,10 @@ class GeometryNodesEvaluator {
const InputSocketRef &socket_ref = node->input(i);
if (socket_ref.is_multi_input_socket()) {
MultiInputValue &multi_value = *input_state.value.multi;
- for (MultiInputValueItem &item : multi_value.items) {
- input_state.type->destruct(item.value);
+ for (void *value : multi_value.values) {
+ if (value != nullptr) {
+ input_state.type->destruct(value);
+ }
}
multi_value.~MultiInputValue();
}
@@ -774,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)) {
@@ -853,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));
}
}
@@ -892,7 +930,7 @@ class GeometryNodesEvaluator {
if (socket->is_multi_input_socket()) {
MultiInputValue &multi_value = *input_state.value.multi;
/* Checks if all the linked sockets have been provided already. */
- if (multi_value.items.size() == multi_value.expected_size) {
+ if (multi_value.all_values_available()) {
input_state.was_ready_for_execution = true;
}
else if (is_required) {
@@ -1243,7 +1281,7 @@ class GeometryNodesEvaluator {
int missing_values = 0;
if (input_socket->is_multi_input_socket()) {
MultiInputValue &multi_value = *input_state.value.multi;
- missing_values = multi_value.expected_size - multi_value.items.size();
+ missing_values = multi_value.missing_values();
}
else {
SingleInputValue &single_value = *input_state.value.single;
@@ -1501,10 +1539,10 @@ class GeometryNodesEvaluator {
if (socket->is_multi_input_socket()) {
/* Add a new value to the multi-input. */
MultiInputValue &multi_value = *input_state.value.multi;
- multi_value.items.append({origin, value.get()});
+ multi_value.add_value(origin, value.get());
- if (multi_value.expected_size == multi_value.items.size()) {
- this->log_socket_value({socket}, input_state, multi_value.items);
+ if (multi_value.all_values_available()) {
+ this->log_socket_value({socket}, input_state, multi_value.values);
}
}
else {
@@ -1543,9 +1581,9 @@ class GeometryNodesEvaluator {
GMutablePointer value = this->get_value_from_socket(origin_socket, *input_state.type);
if (input_socket->is_multi_input_socket()) {
MultiInputValue &multi_value = *input_state.value.multi;
- multi_value.items.append({origin_socket, value.get()});
- if (multi_value.expected_size == multi_value.items.size()) {
- this->log_socket_value({input_socket}, input_state, multi_value.items);
+ multi_value.add_value(origin_socket, value.get());
+ if (multi_value.all_values_available()) {
+ this->log_socket_value({input_socket}, input_state, multi_value.values);
}
}
else {
@@ -1568,10 +1606,13 @@ class GeometryNodesEvaluator {
InputState &input_state = locked_node.node_state.inputs[socket->index()];
if (socket->is_multi_input_socket()) {
MultiInputValue &multi_value = *input_state.value.multi;
- for (MultiInputValueItem &item : multi_value.items) {
- input_state.type->destruct(item.value);
+ for (void *&value : multi_value.values) {
+ if (value != nullptr) {
+ input_state.type->destruct(value);
+ value = nullptr;
+ }
}
- multi_value.items.clear();
+ multi_value.provided_value_count = 0;
}
else {
SingleInputValue &single_value = *input_state.value.single;
@@ -1653,7 +1694,7 @@ class GeometryNodesEvaluator {
return *node_states_.lookup_key_as(node).state;
}
- void log_socket_value(DSocket socket, InputState &input_state, Span<MultiInputValueItem> values)
+ void log_socket_value(DSocket socket, InputState &input_state, Span<void *> values)
{
if (params_.geo_logger == nullptr) {
return;
@@ -1662,8 +1703,8 @@ class GeometryNodesEvaluator {
Vector<GPointer, 16> value_pointers;
value_pointers.reserve(values.size());
const CPPType &type = *input_state.type;
- for (const MultiInputValueItem &item : values) {
- value_pointers.append({type, item.value});
+ for (const void *value : values) {
+ value_pointers.append({type, value});
}
params_.geo_logger->local().log_multi_value_socket(socket, value_pointers);
}
@@ -1749,7 +1790,7 @@ bool NodeParamsProvider::can_get_input(StringRef identifier) const
if (socket->is_multi_input_socket()) {
MultiInputValue &multi_value = *input_state.value.multi;
- return multi_value.items.size() == multi_value.expected_size;
+ return multi_value.all_values_available();
}
SingleInputValue &single_value = *input_state.value.single;
return single_value.value != nullptr;
@@ -1789,25 +1830,11 @@ Vector<GMutablePointer> NodeParamsProvider::extract_multi_input(StringRef identi
MultiInputValue &multi_value = *input_state.value.multi;
Vector<GMutablePointer> ret_values;
- socket.foreach_origin_socket([&](DSocket origin) {
- for (MultiInputValueItem &item : multi_value.items) {
- if (item.origin == origin && item.value != nullptr) {
- ret_values.append({*input_state.type, item.value});
- /* Make sure we do not use the same value again if two values have the same origin. */
- item.value = nullptr;
- return;
- }
- }
- BLI_assert_unreachable();
- });
- if (ret_values.is_empty()) {
- /* If the socket is not linked, we just use the value from the socket itself. */
- BLI_assert(multi_value.items.size() == 1);
- MultiInputValueItem &item = multi_value.items[0];
- BLI_assert(item.origin == socket);
- ret_values.append({*input_state.type, item.value});
- }
- multi_value.items.clear();
+ for (void *&value : multi_value.values) {
+ BLI_assert(value != nullptr);
+ ret_values.append({*input_state.type, value});
+ value = nullptr;
+ }
return ret_values;
}