From 79d9e60076358d2b944b025c49fa6e20da225af5 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 15 Apr 2025 18:03:25 +0200 Subject: [PATCH] Geometry Nodes: initial support for showing logged data in closures This adds initial support for showing logged data in closures. This is more tricky than the other zone types, because the zone content is evaluated elsewhere. The main new thing here is a function that attempts to find where a given closure is evaluated statically. Finding this place statically is also important because we generally decide which compute contexts we want to log before evaluation starts. That's because we don't want to log everything (which is expensive), but just the places that the user is currently looking at. This also changed a bunch of CMakeLists.txt files so that these modules can include NOD_* stuff, which is generally fine everywhere in editors code. Pull Request: https://projects.blender.org/blender/blender/pulls/137403 --- source/blender/editors/curves/CMakeLists.txt | 1 + source/blender/editors/include/ED_node.hh | 13 ++ source/blender/editors/screen/CMakeLists.txt | 1 + .../blender/editors/space_api/CMakeLists.txt | 1 + .../editors/space_buttons/CMakeLists.txt | 1 + .../editors/space_image/CMakeLists.txt | 1 + .../blender/editors/space_node/space_node.cc | 137 +++++++++++++++++- .../editors/space_outliner/CMakeLists.txt | 1 + .../blender/editors/transform/CMakeLists.txt | 1 + source/blender/editors/uvedit/CMakeLists.txt | 1 + source/blender/io/collada/CMakeLists.txt | 1 + 11 files changed, 156 insertions(+), 3 deletions(-) diff --git a/source/blender/editors/curves/CMakeLists.txt b/source/blender/editors/curves/CMakeLists.txt index 36d04971b14..95c2bb7802b 100644 --- a/source/blender/editors/curves/CMakeLists.txt +++ b/source/blender/editors/curves/CMakeLists.txt @@ -43,6 +43,7 @@ set(LIB PRIVATE bf::gpu PRIVATE bf::intern::clog PRIVATE bf::intern::guardedalloc + PRIVATE bf::nodes PRIVATE bf::windowmanager ) diff --git a/source/blender/editors/include/ED_node.hh b/source/blender/editors/include/ED_node.hh index 6c932bb14db..0963263a949 100644 --- a/source/blender/editors/include/ED_node.hh +++ b/source/blender/editors/include/ED_node.hh @@ -12,6 +12,8 @@ #include "BKE_compute_context_cache_fwd.hh" +#include "NOD_geometry_nodes_closure_location.hh" + #include "ED_node_c.hh" struct SpaceNode; @@ -95,6 +97,17 @@ bool node_editor_is_for_geometry_nodes_modifier(const SpaceNode &snode, [[nodiscard]] const ComputeContext *compute_context_for_edittree( const SpaceNode &snode, bke::ComputeContextCache &compute_context_cache); +/** + * Attempts to find a compute context that the closure is evaluated in. If none is found, null is + * returned. If multiple are found, it currently picks the first one it finds which is somewhat + * arbitrary. + */ +[[nodiscard]] const ComputeContext *compute_context_for_closure_evaluation( + const ComputeContext *closure_socket_context, + const bNodeSocket &closure_socket, + bke::ComputeContextCache &compute_context_cache, + const std::optional &source_location); + /** * Creates a compute context for the given zone. It takes e.g. the current inspection index into * account. diff --git a/source/blender/editors/screen/CMakeLists.txt b/source/blender/editors/screen/CMakeLists.txt index 86cda299108..4c23729b9cd 100644 --- a/source/blender/editors/screen/CMakeLists.txt +++ b/source/blender/editors/screen/CMakeLists.txt @@ -6,6 +6,7 @@ set(INC ../asset ../include ../../makesrna + ../../nodes ../../../../extern/fmtlib/include # RNA_prototypes.hh ${CMAKE_BINARY_DIR}/source/blender/makesrna diff --git a/source/blender/editors/space_api/CMakeLists.txt b/source/blender/editors/space_api/CMakeLists.txt index a02675813ba..b563e844bde 100644 --- a/source/blender/editors/space_api/CMakeLists.txt +++ b/source/blender/editors/space_api/CMakeLists.txt @@ -43,6 +43,7 @@ set(LIB bf_editor_space_view3d PRIVATE bf::gpu PRIVATE bf::intern::guardedalloc + PRIVATE bf::nodes PRIVATE bf::windowmanager ) diff --git a/source/blender/editors/space_buttons/CMakeLists.txt b/source/blender/editors/space_buttons/CMakeLists.txt index 66632c909eb..3ac69ab3e85 100644 --- a/source/blender/editors/space_buttons/CMakeLists.txt +++ b/source/blender/editors/space_buttons/CMakeLists.txt @@ -31,6 +31,7 @@ set(LIB PRIVATE bf::dna PRIVATE bf::gpu PRIVATE bf::intern::guardedalloc + PRIVATE bf::nodes PRIVATE bf::windowmanager ) diff --git a/source/blender/editors/space_image/CMakeLists.txt b/source/blender/editors/space_image/CMakeLists.txt index b43ba31881f..b4bc2e1bd89 100644 --- a/source/blender/editors/space_image/CMakeLists.txt +++ b/source/blender/editors/space_image/CMakeLists.txt @@ -42,6 +42,7 @@ set(LIB PRIVATE bf::imbuf::movie PRIVATE bf::intern::clog PRIVATE bf::intern::guardedalloc + PRIVATE bf::nodes PRIVATE bf::render PRIVATE bf::windowmanager ) diff --git a/source/blender/editors/space_node/space_node.cc b/source/blender/editors/space_node/space_node.cc index c3dec6753f0..61250e54940 100644 --- a/source/blender/editors/space_node/space_node.cc +++ b/source/blender/editors/space_node/space_node.cc @@ -10,6 +10,7 @@ #include "BLI_listbase.h" #include "BLI_math_vector.h" +#include "BLI_stack.hh" #include "BLI_string.h" #include "DNA_ID.h" @@ -49,6 +50,7 @@ #include "UI_view2d.hh" #include "DEG_depsgraph.hh" +#include "DEG_depsgraph_query.hh" #include "BLO_read_write.hh" @@ -60,7 +62,8 @@ #include "WM_api.hh" #include "WM_types.hh" -#include "DEG_depsgraph_query.hh" +#include "NOD_node_in_compute_context.hh" +#include "NOD_socket_interface_key.hh" #include "io_utils.hh" @@ -386,8 +389,15 @@ const ComputeContext *compute_context_for_zone(const bke::bNodeTreeZone &zone, parent_compute_context, *zone.output_node, storage.inspection_index); } case GEO_NODE_CLOSURE_OUTPUT: { - /* TODO: Need to find a place where this closure is evaluated. */ - return nullptr; + nodes::ClosureSourceLocation source_location{}; + const bNodeTree &tree = output_node.owner_tree(); + BLI_assert(DEG_is_original_id(&tree.id)); + source_location.orig_node_tree_session_uid = tree.id.session_uid; + source_location.closure_output_node_id = output_node.identifier; + return compute_context_for_closure_evaluation(parent_compute_context, + output_node.output_socket(0), + compute_context_cache, + source_location); } } return nullptr; @@ -444,6 +454,127 @@ static std::optional compute_context_for_tree_path( return current; } +[[nodiscard]] const ComputeContext *compute_context_for_closure_evaluation( + const ComputeContext *closure_socket_context, + const bNodeSocket &closure_socket, + bke::ComputeContextCache &compute_context_cache, + const std::optional &source_location) +{ + using BundlePath = Vector; + + struct SocketToCheck { + nodes::SocketInContext socket; + BundlePath bundle_path; + }; + + Stack sockets_to_check; + Set added_sockets; + + auto add_if_new = [&](const nodes::SocketInContext &socket, BundlePath bundle_path) { + if (added_sockets.add(socket)) { + sockets_to_check.push({socket, std::move(bundle_path)}); + } + }; + + const nodes::SocketInContext start_socket{closure_socket_context, &closure_socket}; + add_if_new(start_socket, {}); + + while (!sockets_to_check.is_empty()) { + const SocketToCheck socket_to_check = sockets_to_check.pop(); + const nodes::SocketInContext socket = socket_to_check.socket; + const BundlePath &bundle_path = socket_to_check.bundle_path; + const nodes::NodeInContext &node = socket.owner_node(); + if (socket->is_input()) { + if (node->is_muted()) { + for (const bNodeLink &link : node->internal_links()) { + if (link.fromsock == socket.socket) { + add_if_new({socket.context, link.tosock}, bundle_path); + } + } + continue; + } + if (node->is_type("GeometryNodeEvaluateClosure")) { + return &compute_context_cache.for_evaluate_closure(socket.context, *node, source_location); + } + if (node->is_group()) { + if (const bNodeTree *group = reinterpret_cast(node->id)) { + group->ensure_topology_cache(); + const ComputeContext &group_compute_context = compute_context_cache.for_group_node( + socket.context, *node, node->owner_tree()); + for (const bNode *input_node : group->group_input_nodes()) { + const bNodeSocket &group_input_socket = input_node->output_socket(socket->index()); + if (group_input_socket.is_directly_linked()) { + add_if_new({&group_compute_context, &group_input_socket}, bundle_path); + } + } + } + continue; + } + if (node->is_group_output()) { + if (const auto *group_context = dynamic_cast( + socket.context)) + { + const bNodeTree *caller_group = group_context->caller_tree(); + const bNode *caller_group_node = group_context->caller_group_node(); + if (caller_group && caller_group_node) { + caller_group->ensure_topology_cache(); + const bNodeSocket &output_socket = caller_group_node->output_socket(socket->index()); + add_if_new({group_context->parent(), &output_socket}, bundle_path); + } + } + continue; + } + if (node->is_type("GeometryNodeCombineBundle")) { + const auto &storage = *static_cast(node->storage); + BundlePath new_bundle_path = bundle_path; + new_bundle_path.append(nodes::SocketInterfaceKey{storage.items[socket->index()].name}); + add_if_new(node.output_socket(0), std::move(new_bundle_path)); + continue; + } + if (node->is_type("GeometryNodeSeparateBundle")) { + if (bundle_path.is_empty()) { + continue; + } + const nodes::SocketInterfaceKey &last_key = bundle_path.last(); + const auto &storage = *static_cast(node->storage); + for (const int output_i : IndexRange(storage.items_num)) { + const nodes::SocketInterfaceKey key{storage.items[output_i].name}; + if (last_key.matches(key)) { + add_if_new(node.output_socket(output_i), bundle_path.as_span().drop_back(1)); + } + } + continue; + } + } + else { + const bke::bNodeTreeZones *zones = node->owner_tree().zones(); + if (!zones) { + continue; + } + const bke::bNodeTreeZone *from_zone = zones->get_zone_by_socket(*socket.socket); + for (const bNodeLink *link : socket->directly_linked_links()) { + if (!link->is_used()) { + continue; + } + bNodeSocket *to_socket = link->tosock; + const bke::bNodeTreeZone *to_zone = zones->get_zone_by_socket(*to_socket); + if (!zones->link_between_zones_is_allowed(from_zone, to_zone)) { + continue; + } + const Vector zones_to_enter = zones->get_zones_to_enter( + from_zone, to_zone); + const ComputeContext *compute_context = compute_context_for_zones( + zones_to_enter, compute_context_cache, socket.context); + if (!compute_context) { + continue; + } + add_if_new({compute_context, to_socket}, bundle_path); + } + } + } + return nullptr; +} + static const ComputeContext *get_node_editor_root_compute_context( const SpaceNode &snode, bke::ComputeContextCache &compute_context_cache) { diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt index 301d8b19679..0b6f62e2924 100644 --- a/source/blender/editors/space_outliner/CMakeLists.txt +++ b/source/blender/editors/space_outliner/CMakeLists.txt @@ -140,6 +140,7 @@ set(LIB PRIVATE bf::imbuf PRIVATE bf::intern::clog PRIVATE bf::intern::guardedalloc + PRIVATE bf::nodes PRIVATE bf::sequencer PRIVATE bf::windowmanager extern_fmtlib diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt index 6626e6e3182..ae8205b394a 100644 --- a/source/blender/editors/transform/CMakeLists.txt +++ b/source/blender/editors/transform/CMakeLists.txt @@ -118,6 +118,7 @@ set(LIB bf_editor_mask PRIVATE bf::gpu PRIVATE bf::intern::guardedalloc + PRIVATE bf::nodes PRIVATE bf::render PRIVATE bf::sequencer PRIVATE bf::windowmanager diff --git a/source/blender/editors/uvedit/CMakeLists.txt b/source/blender/editors/uvedit/CMakeLists.txt index dfa6fd59728..369366b4d7a 100644 --- a/source/blender/editors/uvedit/CMakeLists.txt +++ b/source/blender/editors/uvedit/CMakeLists.txt @@ -41,6 +41,7 @@ set(LIB PRIVATE bf::geometry PRIVATE bf::gpu PRIVATE bf::intern::guardedalloc + PRIVATE bf::nodes PRIVATE bf::windowmanager ) diff --git a/source/blender/io/collada/CMakeLists.txt b/source/blender/io/collada/CMakeLists.txt index b7ccb49df34..32cbb4cb2e6 100644 --- a/source/blender/io/collada/CMakeLists.txt +++ b/source/blender/io/collada/CMakeLists.txt @@ -116,6 +116,7 @@ set(LIB PRIVATE bf::dna PRIVATE bf::imbuf PRIVATE bf::intern::guardedalloc + PRIVATE bf::nodes PRIVATE bf::windowmanager )