From 740d1fbc4b134a3ea11d67ccd2ed5b28ef27767d Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Sun, 14 Apr 2024 16:47:46 +0200 Subject: [PATCH] Geometry Nodes: Log socket values for node tools To ease the process of debugging a node group while creating a node tool, while the group is visible in a node editor, log the socket values from its last execution. The values are only logged for the active object is nothing selected. The Viewer node is still not supported because visualization would probably be very tricky. Pull Request: https://projects.blender.org/blender/blender/pulls/120596 --- .../editors/geometry/node_group_operator.cc | 63 +++++++++++++++- source/blender/editors/include/ED_geometry.hh | 15 ++++ .../blender/nodes/NOD_geometry_nodes_log.hh | 3 + .../nodes/intern/geometry_nodes_log.cc | 72 +++++++++++++------ 4 files changed, 129 insertions(+), 24 deletions(-) diff --git a/source/blender/editors/geometry/node_group_operator.cc b/source/blender/editors/geometry/node_group_operator.cc index a996c6fabad..b1560691447 100644 --- a/source/blender/editors/geometry/node_group_operator.cc +++ b/source/blender/editors/geometry/node_group_operator.cc @@ -36,6 +36,7 @@ #include "BKE_pointcloud.hh" #include "BKE_report.hh" #include "BKE_screen.hh" +#include "BKE_workspace.hh" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -113,6 +114,54 @@ static const bNodeTree *get_node_group(const bContext &C, PointerRNA &ptr, Repor return group; } +GeoOperatorLog::~GeoOperatorLog() {} + +/** + * The socket value log is stored statically so it can be used in the node editor. A fancier + * storage system shouldn't be necessary, since the goal is just to be able to debug intermediate + * values when building a tool. + */ +static GeoOperatorLog &get_static_eval_log() +{ + static GeoOperatorLog log; + return log; +} + +const GeoOperatorLog &node_group_operator_static_eval_log() +{ + return get_static_eval_log(); +} + +/** Find all the visible node editors to log values for. */ +static void find_socket_log_contexts(const Main &bmain, + Set &r_socket_log_contexts) +{ + wmWindowManager *wm = static_cast(bmain.wm.first); + if (wm == nullptr) { + return; + } + LISTBASE_FOREACH (const wmWindow *, window, &wm->windows) { + const bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook); + LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) { + const SpaceLink *sl = static_cast(area->spacedata.first); + if (sl->spacetype == SPACE_NODE) { + const SpaceNode &snode = *reinterpret_cast(sl); + if (snode.edittree == nullptr) { + continue; + } + ComputeContextBuilder compute_context_builder; + compute_context_builder.push(); + const Map hash_by_zone = + geo_log::GeoModifierLog::get_context_hash_by_zone_for_node_editor( + snode, compute_context_builder); + for (const ComputeContextHash &hash : hash_by_zone.values()) { + r_socket_log_contexts.add(hash); + } + } + } + } +} + /** * Geometry nodes currently requires working on "evaluated" data-blocks (rather than "original" * data-blocks that are part of a #Main data-base). This could change in the future, but for now, @@ -385,7 +434,11 @@ static int run_node_group_exec(bContext *C, wmOperator *op) BLI_SCOPED_DEFER([&]() { IDP_FreeProperty_ex(properties, false); }); bke::OperatorComputeContext compute_context; - auto eval_log = std::make_unique(); + Set socket_log_contexts; + GeoOperatorLog &eval_log = get_static_eval_log(); + eval_log.log = std::make_unique(); + eval_log.node_group_name = node_tree->id.name + 2; + find_socket_log_contexts(*bmain, socket_log_contexts); for (Object *object : objects) { nodes::GeoNodesOperatorData operator_eval_data{}; @@ -396,7 +449,11 @@ static int run_node_group_exec(bContext *C, wmOperator *op) nodes::GeoNodesCallData call_data{}; call_data.operator_data = &operator_eval_data; - call_data.eval_log = eval_log.get(); + call_data.eval_log = eval_log.log.get(); + if (object == active_object) { + /* Only log values from the active object. */ + call_data.socket_log_contexts = &socket_log_contexts; + } bke::GeometrySet geometry_orig = get_original_geometry_eval_copy(*object); @@ -409,7 +466,7 @@ static int run_node_group_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_GEOM | ND_DATA, object->data); } - geo_log::GeoTreeLog &tree_log = eval_log->get_tree_log(compute_context.hash()); + geo_log::GeoTreeLog &tree_log = eval_log.log->get_tree_log(compute_context.hash()); tree_log.ensure_node_warnings(); for (const geo_log::NodeWarning &warning : tree_log.all_warnings) { if (warning.type == geo_log::NodeWarningType::Info) { diff --git a/source/blender/editors/include/ED_geometry.hh b/source/blender/editors/include/ED_geometry.hh index a4346df49c0..405e42d66a4 100644 --- a/source/blender/editors/include/ED_geometry.hh +++ b/source/blender/editors/include/ED_geometry.hh @@ -8,6 +8,8 @@ #pragma once +#include + #include "BLI_generic_pointer.hh" #include "BLI_string_ref.hh" @@ -22,6 +24,9 @@ struct PropertyRNA; namespace blender::bke { enum class AttrDomain : int8_t; } +namespace blender::nodes::geo_eval_log { +class GeoModifierLog; +} namespace blender::ed::geometry { @@ -61,6 +66,16 @@ bool ED_geometry_attribute_convert(Mesh *mesh, namespace blender::ed::geometry { +struct GeoOperatorLog { + std::string node_group_name; + std::unique_ptr log; + + GeoOperatorLog() = default; + ~GeoOperatorLog(); +}; + +const GeoOperatorLog &node_group_operator_static_eval_log(); + MenuType node_group_operator_assets_menu(); MenuType node_group_operator_assets_menu_unassigned(); diff --git a/source/blender/nodes/NOD_geometry_nodes_log.hh b/source/blender/nodes/NOD_geometry_nodes_log.hh index 16682e3ccb0..b08e29e72e3 100644 --- a/source/blender/nodes/NOD_geometry_nodes_log.hh +++ b/source/blender/nodes/NOD_geometry_nodes_log.hh @@ -340,6 +340,9 @@ class GeoModifierLog { */ static Map get_context_hash_by_zone_for_node_editor(const SpaceNode &snode, StringRefNull modifier_name); + static Map + get_context_hash_by_zone_for_node_editor(const SpaceNode &snode, + ComputeContextBuilder &compute_context_builder); static Map get_tree_log_by_zone_for_node_editor( const SpaceNode &snode); diff --git a/source/blender/nodes/intern/geometry_nodes_log.cc b/source/blender/nodes/intern/geometry_nodes_log.cc index 8194405201c..659728cffcd 100644 --- a/source/blender/nodes/intern/geometry_nodes_log.cc +++ b/source/blender/nodes/intern/geometry_nodes_log.cc @@ -14,6 +14,7 @@ #include "DNA_modifier_types.h" #include "DNA_space_types.h" +#include "ED_geometry.hh" #include "ED_node.hh" #include "ED_viewer_path.hh" @@ -532,11 +533,9 @@ static void find_tree_zone_hash_recursive( } Map GeoModifierLog:: - get_context_hash_by_zone_for_node_editor(const SpaceNode &snode, StringRefNull modifier_name) + get_context_hash_by_zone_for_node_editor(const SpaceNode &snode, + ComputeContextBuilder &compute_context_builder) { - ComputeContextBuilder compute_context_builder; - compute_context_builder.push(modifier_name); - if (!ed::space_node::push_compute_context_for_tree_path(snode, compute_context_builder)) { return {}; } @@ -553,27 +552,58 @@ Map GeoModifierLog:: return hash_by_zone; } +Map GeoModifierLog:: + get_context_hash_by_zone_for_node_editor(const SpaceNode &snode, StringRefNull modifier_name) +{ + ComputeContextBuilder compute_context_builder; + compute_context_builder.push(modifier_name); + return get_context_hash_by_zone_for_node_editor(snode, compute_context_builder); +} + Map GeoModifierLog::get_tree_log_by_zone_for_node_editor( const SpaceNode &snode) { - std::optional object_and_modifier = - ed::space_node::get_modifier_for_node_editor(snode); - if (!object_and_modifier) { - return {}; + switch (SpaceNodeGeometryNodesType(snode.geometry_nodes_type)) { + case SNODE_GEOMETRY_MODIFIER: { + std::optional object_and_modifier = + ed::space_node::get_modifier_for_node_editor(snode); + if (!object_and_modifier) { + return {}; + } + GeoModifierLog *modifier_log = object_and_modifier->nmd->runtime->eval_log.get(); + if (modifier_log == nullptr) { + return {}; + } + const Map hash_by_zone = + GeoModifierLog::get_context_hash_by_zone_for_node_editor( + snode, object_and_modifier->nmd->modifier.name); + Map log_by_zone; + for (const auto item : hash_by_zone.items()) { + GeoTreeLog &tree_log = modifier_log->get_tree_log(item.value); + log_by_zone.add(item.key, &tree_log); + } + return log_by_zone; + } + case SNODE_GEOMETRY_TOOL: { + const ed::geometry::GeoOperatorLog &log = + ed::geometry::node_group_operator_static_eval_log(); + if (snode.geometry_nodes_tool_tree->id.name + 2 != log.node_group_name) { + return {}; + } + ComputeContextBuilder compute_context_builder; + compute_context_builder.push(); + const Map hash_by_zone = + GeoModifierLog::get_context_hash_by_zone_for_node_editor(snode, compute_context_builder); + Map log_by_zone; + for (const auto item : hash_by_zone.items()) { + GeoTreeLog &tree_log = log.log->get_tree_log(item.value); + log_by_zone.add(item.key, &tree_log); + } + return log_by_zone; + } } - GeoModifierLog *modifier_log = object_and_modifier->nmd->runtime->eval_log.get(); - if (modifier_log == nullptr) { - return {}; - } - const Map hash_by_zone = - GeoModifierLog::get_context_hash_by_zone_for_node_editor( - snode, object_and_modifier->nmd->modifier.name); - Map log_by_zone; - for (const auto item : hash_by_zone.items()) { - GeoTreeLog &tree_log = modifier_log->get_tree_log(item.value); - log_by_zone.add(item.key, &tree_log); - } - return log_by_zone; + BLI_assert_unreachable(); + return {}; } const ViewerNodeLog *GeoModifierLog::find_viewer_node_log_for_path(const ViewerPath &viewer_path)