Geometry Nodes: Log socket values for node tools #120596

Merged
Hans Goudey merged 3 commits from HooglyBoogly/blender:node-tools-log into main 2024-04-14 16:47:56 +02:00
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"
HooglyBoogly marked this conversation as resolved Outdated

.hh

`.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)