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
This commit is contained in:
Hans Goudey
2024-04-14 16:47:46 +02:00
committed by Hans Goudey
parent bfd0105213
commit 740d1fbc4b
4 changed files with 129 additions and 24 deletions

View File

@@ -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<ComputeContextHash> &r_socket_log_contexts)
{
wmWindowManager *wm = static_cast<wmWindowManager *>(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<SpaceLink *>(area->spacedata.first);
if (sl->spacetype == SPACE_NODE) {
const SpaceNode &snode = *reinterpret_cast<const SpaceNode *>(sl);
if (snode.edittree == nullptr) {
continue;
}
ComputeContextBuilder compute_context_builder;
compute_context_builder.push<bke::OperatorComputeContext>();
const Map<const bke::bNodeTreeZone *, ComputeContextHash> 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<geo_log::GeoModifierLog>();
Set<ComputeContextHash> socket_log_contexts;
GeoOperatorLog &eval_log = get_static_eval_log();
eval_log.log = std::make_unique<geo_log::GeoModifierLog>();
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) {

View File

@@ -8,6 +8,8 @@
#pragma once
#include <string>
#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<nodes::geo_eval_log::GeoModifierLog> 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();

View File

@@ -340,6 +340,9 @@ class GeoModifierLog {
*/
static Map<const bke::bNodeTreeZone *, ComputeContextHash>
get_context_hash_by_zone_for_node_editor(const SpaceNode &snode, StringRefNull modifier_name);
static Map<const bke::bNodeTreeZone *, ComputeContextHash>
get_context_hash_by_zone_for_node_editor(const SpaceNode &snode,
ComputeContextBuilder &compute_context_builder);
static Map<const bke::bNodeTreeZone *, GeoTreeLog *> get_tree_log_by_zone_for_node_editor(
const SpaceNode &snode);

View File

@@ -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<const bNodeTreeZone *, ComputeContextHash> 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<bke::ModifierComputeContext>(modifier_name);
if (!ed::space_node::push_compute_context_for_tree_path(snode, compute_context_builder)) {
return {};
}
@@ -553,27 +552,58 @@ Map<const bNodeTreeZone *, ComputeContextHash> GeoModifierLog::
return hash_by_zone;
}
Map<const bNodeTreeZone *, ComputeContextHash> GeoModifierLog::
get_context_hash_by_zone_for_node_editor(const SpaceNode &snode, StringRefNull modifier_name)
{
ComputeContextBuilder compute_context_builder;
compute_context_builder.push<bke::ModifierComputeContext>(modifier_name);
return get_context_hash_by_zone_for_node_editor(snode, compute_context_builder);
}
Map<const bNodeTreeZone *, GeoTreeLog *> GeoModifierLog::get_tree_log_by_zone_for_node_editor(
const SpaceNode &snode)
{
std::optional<ed::space_node::ObjectAndModifier> 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<ed::space_node::ObjectAndModifier> 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<const bNodeTreeZone *, ComputeContextHash> hash_by_zone =
GeoModifierLog::get_context_hash_by_zone_for_node_editor(
snode, object_and_modifier->nmd->modifier.name);
Map<const bNodeTreeZone *, GeoTreeLog *> 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<bke::OperatorComputeContext>();
const Map<const bNodeTreeZone *, ComputeContextHash> hash_by_zone =
GeoModifierLog::get_context_hash_by_zone_for_node_editor(snode, compute_context_builder);
Map<const bNodeTreeZone *, GeoTreeLog *> 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<const bNodeTreeZone *, ComputeContextHash> hash_by_zone =
GeoModifierLog::get_context_hash_by_zone_for_node_editor(
snode, object_and_modifier->nmd->modifier.name);
Map<const bNodeTreeZone *, GeoTreeLog *> 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)