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
This commit is contained in:
Jacques Lucke
2025-04-15 18:03:25 +02:00
parent dde18802a5
commit 79d9e60076
11 changed files with 156 additions and 3 deletions

View File

@@ -43,6 +43,7 @@ set(LIB
PRIVATE bf::gpu
PRIVATE bf::intern::clog
PRIVATE bf::intern::guardedalloc
PRIVATE bf::nodes
PRIVATE bf::windowmanager
)

View File

@@ -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<nodes::ClosureSourceLocation> &source_location);
/**
* Creates a compute context for the given zone. It takes e.g. the current inspection index into
* account.

View File

@@ -6,6 +6,7 @@ set(INC
../asset
../include
../../makesrna
../../nodes
../../../../extern/fmtlib/include
# RNA_prototypes.hh
${CMAKE_BINARY_DIR}/source/blender/makesrna

View File

@@ -43,6 +43,7 @@ set(LIB
bf_editor_space_view3d
PRIVATE bf::gpu
PRIVATE bf::intern::guardedalloc
PRIVATE bf::nodes
PRIVATE bf::windowmanager
)

View File

@@ -31,6 +31,7 @@ set(LIB
PRIVATE bf::dna
PRIVATE bf::gpu
PRIVATE bf::intern::guardedalloc
PRIVATE bf::nodes
PRIVATE bf::windowmanager
)

View File

@@ -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
)

View File

@@ -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<const ComputeContext *> 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<nodes::ClosureSourceLocation> &source_location)
{
using BundlePath = Vector<nodes::SocketInterfaceKey, 0>;
struct SocketToCheck {
nodes::SocketInContext socket;
BundlePath bundle_path;
};
Stack<SocketToCheck> sockets_to_check;
Set<nodes::SocketInContext> 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<const bNodeTree *>(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<const bke::GroupNodeComputeContext *>(
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<const NodeGeometryCombineBundle *>(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<const NodeGeometrySeparateBundle *>(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<const bke::bNodeTreeZone *> 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)
{

View File

@@ -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

View File

@@ -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

View File

@@ -41,6 +41,7 @@ set(LIB
PRIVATE bf::geometry
PRIVATE bf::gpu
PRIVATE bf::intern::guardedalloc
PRIVATE bf::nodes
PRIVATE bf::windowmanager
)

View File

@@ -116,6 +116,7 @@ set(LIB
PRIVATE bf::dna
PRIVATE bf::imbuf
PRIVATE bf::intern::guardedalloc
PRIVATE bf::nodes
PRIVATE bf::windowmanager
)