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:
authorJacques Lucke <jacques@blender.org>2021-10-21 16:49:29 +0300
committerJacques Lucke <jacques@blender.org>2021-10-21 16:50:04 +0300
commit090be2775e3d7c0dc3f7956b05c7fb9a72c4bdfc (patch)
treec5783ec4b2ee736e810c0b82339fe9dced785255 /source/blender/modifiers
parent6600ae3aa707d7e1c2728b9af50dc15e81fd7f2b (diff)
Geometry Nodes: fix force-computing multiple non-output sockets
There were some issues when multiple inputs of the same node were forced to be computed (e.g. for the spreadsheet), but none of the node outputs (if existant) were used. Essentially the node was marked as "finished" too early in this case. This fix is necessary for the improved viewer node (T92167).
Diffstat (limited to 'source/blender/modifiers')
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc37
-rw-r--r--source/blender/modifiers/intern/MOD_nodes_evaluator.cc61
2 files changed, 60 insertions, 38 deletions
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index b5ca5f3545f..562589e2610 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -758,32 +758,33 @@ static Vector<SpaceSpreadsheet *> find_spreadsheet_editors(Main *bmain)
return spreadsheets;
}
-static DSocket try_get_socket_to_preview_for_spreadsheet(SpaceSpreadsheet *sspreadsheet,
- NodesModifierData *nmd,
- const ModifierEvalContext *ctx,
- const DerivedNodeTree &tree)
+static void find_sockets_to_preview_for_spreadsheet(SpaceSpreadsheet *sspreadsheet,
+ NodesModifierData *nmd,
+ const ModifierEvalContext *ctx,
+ const DerivedNodeTree &tree,
+ Set<DSocket> &r_sockets_to_preview)
{
Vector<SpreadsheetContext *> context_path = sspreadsheet->context_path;
if (context_path.size() < 3) {
- return {};
+ return;
}
if (context_path[0]->type != SPREADSHEET_CONTEXT_OBJECT) {
- return {};
+ return;
}
if (context_path[1]->type != SPREADSHEET_CONTEXT_MODIFIER) {
- return {};
+ return;
}
SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context_path[0];
if (object_context->object != DEG_get_original_object(ctx->object)) {
- return {};
+ return;
}
SpreadsheetContextModifier *modifier_context = (SpreadsheetContextModifier *)context_path[1];
if (StringRef(modifier_context->modifier_name) != nmd->modifier.name) {
- return {};
+ return;
}
for (SpreadsheetContext *context : context_path.as_span().drop_front(2)) {
if (context->type != SPREADSHEET_CONTEXT_NODE) {
- return {};
+ return;
}
}
@@ -802,11 +803,11 @@ static DSocket try_get_socket_to_preview_for_spreadsheet(SpaceSpreadsheet *sspre
}
}
if (found_node == nullptr) {
- return {};
+ return;
}
context = context->child_context(*found_node);
if (context == nullptr) {
- return {};
+ return;
}
}
@@ -814,10 +815,13 @@ static DSocket try_get_socket_to_preview_for_spreadsheet(SpaceSpreadsheet *sspre
for (const NodeRef *node_ref : tree_ref.nodes_by_type("GeometryNodeViewer")) {
if (node_ref->name() == last_context->node_name) {
const DNode viewer_node{context, node_ref};
- return viewer_node.input(0);
+ for (const InputSocketRef *input_socket : node_ref->inputs()) {
+ if (input_socket->is_available() && input_socket->is_logically_linked()) {
+ r_sockets_to_preview.add(DSocket{context, input_socket});
+ }
+ }
}
}
- return {};
}
static void find_sockets_to_preview(NodesModifierData *nmd,
@@ -831,10 +835,7 @@ static void find_sockets_to_preview(NodesModifierData *nmd,
* intermediate geometries cached for display. */
Vector<SpaceSpreadsheet *> spreadsheets = find_spreadsheet_editors(bmain);
for (SpaceSpreadsheet *sspreadsheet : spreadsheets) {
- const DSocket socket = try_get_socket_to_preview_for_spreadsheet(sspreadsheet, nmd, ctx, tree);
- if (socket) {
- r_sockets_to_preview.add(socket);
- }
+ find_sockets_to_preview_for_spreadsheet(sspreadsheet, nmd, ctx, tree, r_sockets_to_preview);
}
}
diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
index 51dd210c77a..69132f6c177 100644
--- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
+++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
@@ -126,6 +126,12 @@ struct InputState {
* changed by others anymore.
*/
bool was_ready_for_execution = false;
+
+ /**
+ * True when this input has to be computed for logging/debugging purposes, regardless of whether
+ * it is needed for some output.
+ */
+ bool force_compute = false;
};
struct OutputState {
@@ -497,6 +503,14 @@ class GeometryNodesEvaluator {
this->initialize_node_state(item.node, *item.state, allocator);
}
});
+
+ /* Mark input sockets that have to be computed. */
+ for (const DSocket &socket : params_.force_compute_sockets) {
+ NodeState &node_state = *node_states_.lookup_key_as(socket.node()).state;
+ if (socket->is_input()) {
+ node_state.inputs[socket->index()].force_compute = true;
+ }
+ }
}
void initialize_node_state(const DNode node, NodeState &node_state, LinearAllocator<> &allocator)
@@ -743,7 +757,8 @@ class GeometryNodesEvaluator {
return do_execute_node;
}
- /* A node is finished when it has computed all outputs that may be used. */
+ /* A node is finished when it has computed all outputs that may be used have been computed and
+ * when no input is still forced to be computed. */
bool finish_node_if_possible(LockedNode &locked_node)
{
if (locked_node.node_state.node_has_finished) {
@@ -752,35 +767,41 @@ class GeometryNodesEvaluator {
}
/* Check if there is any output that might be used but has not been computed yet. */
- bool has_remaining_output = false;
for (OutputState &output_state : locked_node.node_state.outputs) {
if (output_state.has_been_computed) {
continue;
}
if (output_state.output_usage != ValueUsage::Unused) {
- has_remaining_output = true;
- break;
+ return false;
}
}
- if (!has_remaining_output) {
- /* If there are no remaining outputs, all the inputs can be destructed and/or can become
- * unused. This can also trigger a chain reaction where nodes to the left become finished
- * too. */
- for (const int i : locked_node.node->inputs().index_range()) {
- const DInputSocket socket = locked_node.node.input(i);
- InputState &input_state = locked_node.node_state.inputs[i];
- if (input_state.usage == ValueUsage::Maybe) {
- this->set_input_unused(locked_node, socket);
- }
- else if (input_state.usage == ValueUsage::Required) {
- /* The value was required, so it cannot become unused. However, we can destruct the
- * value. */
- this->destruct_input_value_if_exists(locked_node, socket);
+
+ /* Check if there is an input that still has to be computed. */
+ for (InputState &input_state : locked_node.node_state.inputs) {
+ if (input_state.force_compute) {
+ if (!input_state.was_ready_for_execution) {
+ return false;
}
}
- locked_node.node_state.node_has_finished = true;
}
- return locked_node.node_state.node_has_finished;
+
+ /* If there are no remaining outputs, all the inputs can be destructed and/or can become
+ * unused. This can also trigger a chain reaction where nodes to the left become finished
+ * too. */
+ for (const int i : locked_node.node->inputs().index_range()) {
+ const DInputSocket socket = locked_node.node.input(i);
+ InputState &input_state = locked_node.node_state.inputs[i];
+ if (input_state.usage == ValueUsage::Maybe) {
+ this->set_input_unused(locked_node, socket);
+ }
+ else if (input_state.usage == ValueUsage::Required) {
+ /* The value was required, so it cannot become unused. However, we can destruct the
+ * value. */
+ this->destruct_input_value_if_exists(locked_node, socket);
+ }
+ }
+ locked_node.node_state.node_has_finished = true;
+ return true;
}
bool prepare_node_outputs_for_execution(LockedNode &locked_node)