From c37e07bc01a413ffb0ed65ccdf8f10e26795c7c8 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Fri, 16 Dec 2022 12:18:49 +0100 Subject: [PATCH] Geometry Nodes: improve dot graph export of lazy function graph * Dim default input values. * Print default input values instead of type name. * Add node/socket names to group input/output nodes. --- .../functions/FN_field_cpp_type_make.hh | 2 +- .../functions/FN_lazy_function_graph.hh | 16 ++++++- .../functions/intern/lazy_function_graph.cc | 44 ++++++++++++++--- .../nodes/NOD_geometry_nodes_lazy_function.hh | 4 ++ .../intern/geometry_nodes_lazy_function.cc | 48 ++++++++++++++++++- 5 files changed, 103 insertions(+), 11 deletions(-) diff --git a/source/blender/functions/FN_field_cpp_type_make.hh b/source/blender/functions/FN_field_cpp_type_make.hh index 79e46faa9e7..7a4112b432b 100644 --- a/source/blender/functions/FN_field_cpp_type_make.hh +++ b/source/blender/functions/FN_field_cpp_type_make.hh @@ -38,7 +38,7 @@ inline ValueOrFieldCPPType::ValueOrFieldCPPType(TypeTag /*value_type* * Create a new #ValueOrFieldCPPType that can be accessed through `ValueOrFieldCPPType::get()`. */ #define FN_FIELD_CPP_TYPE_MAKE(VALUE_TYPE) \ - BLI_CPP_TYPE_MAKE(blender::fn::ValueOrField, CPPTypeFlags::None) \ + BLI_CPP_TYPE_MAKE(blender::fn::ValueOrField, CPPTypeFlags::Printable) \ template<> \ const blender::fn::ValueOrFieldCPPType & \ blender::fn::ValueOrFieldCPPType::get_impl() \ diff --git a/source/blender/functions/FN_lazy_function_graph.hh b/source/blender/functions/FN_lazy_function_graph.hh index 4ede28c4f26..7352004b7fe 100644 --- a/source/blender/functions/FN_lazy_function_graph.hh +++ b/source/blender/functions/FN_lazy_function_graph.hh @@ -167,15 +167,25 @@ class FunctionNode : public Node { const LazyFunction &function() const; }; +class DummyDebugInfo { + public: + virtual ~DummyDebugInfo() = default; + virtual std::string node_name() const; + virtual std::string input_name(const int i) const; + virtual std::string output_name(const int i) const; +}; + /** * A #Node that does *not* correspond to a #LazyFunction. Instead it can be used to indicate inputs * and outputs of the entire graph. It can have an arbitrary number of inputs and outputs. */ class DummyNode : public Node { private: - std::string name_; + const DummyDebugInfo *debug_info_ = nullptr; friend Node; + friend Socket; + friend Graph; }; /** @@ -208,7 +218,9 @@ class Graph : NonCopyable, NonMovable { /** * Add a new dummy node with the given socket types. */ - DummyNode &add_dummy(Span input_types, Span output_types); + DummyNode &add_dummy(Span input_types, + Span output_types, + const DummyDebugInfo *debug_info = nullptr); /** * Add a link between the two given sockets. diff --git a/source/blender/functions/intern/lazy_function_graph.cc b/source/blender/functions/intern/lazy_function_graph.cc index cc55b70d166..60605a4e64c 100644 --- a/source/blender/functions/intern/lazy_function_graph.cc +++ b/source/blender/functions/intern/lazy_function_graph.cc @@ -48,13 +48,16 @@ FunctionNode &Graph::add_function(const LazyFunction &fn) return node; } -DummyNode &Graph::add_dummy(Span input_types, Span output_types) +DummyNode &Graph::add_dummy(Span input_types, + Span output_types, + const DummyDebugInfo *debug_info) { DummyNode &node = *allocator_.construct().release(); node.fn_ = nullptr; node.inputs_ = allocator_.construct_elements_and_pointer_array(input_types.size()); node.outputs_ = allocator_.construct_elements_and_pointer_array( output_types.size()); + node.debug_info_ = debug_info; for (const int i : input_types.index_range()) { InputSocket &socket = *node.inputs_[i]; @@ -100,6 +103,8 @@ bool Graph::node_indices_are_valid() const return true; } +static const char *fallback_name = "No Name"; + std::string Socket::name() const { if (node_->is_function()) { @@ -110,15 +115,41 @@ std::string Socket::name() const } return fn.output_name(index_in_node_); } - return "Unnamed"; + const DummyNode &dummy_node = *static_cast(node_); + if (dummy_node.debug_info_) { + if (is_input_) { + return dummy_node.debug_info_->input_name(index_in_node_); + } + return dummy_node.debug_info_->output_name(index_in_node_); + } + return fallback_name; } std::string Node::name() const { - if (fn_ == nullptr) { - return static_cast(this)->name_; + if (this->is_function()) { + return fn_->name(); } - return fn_->name(); + const DummyNode &dummy_node = *static_cast(this); + if (dummy_node.debug_info_) { + return dummy_node.debug_info_->node_name(); + } + return fallback_name; +} + +std::string DummyDebugInfo::node_name() const +{ + return fallback_name; +} + +std::string DummyDebugInfo::input_name(const int /*i*/) const +{ + return fallback_name; +} + +std::string DummyDebugInfo::output_name(const int /*i*/) const +{ + return fallback_name; } std::string Graph::to_dot() const @@ -166,10 +197,11 @@ std::string Graph::to_dot() const value_string = type.to_string(default_value); } else { - value_string = "<" + type.name() + ">"; + value_string = type.name(); } dot::Node &default_value_dot_node = digraph.new_node(value_string); default_value_dot_node.set_shape(dot::Attr_shape::Ellipse); + default_value_dot_node.attributes.set("color", "#00000055"); digraph.new_edge(default_value_dot_node, to_dot_port); } } diff --git a/source/blender/nodes/NOD_geometry_nodes_lazy_function.hh b/source/blender/nodes/NOD_geometry_nodes_lazy_function.hh index 240a0115f68..f21100414b3 100644 --- a/source/blender/nodes/NOD_geometry_nodes_lazy_function.hh +++ b/source/blender/nodes/NOD_geometry_nodes_lazy_function.hh @@ -110,6 +110,10 @@ struct GeometryNodesLazyFunctionGraphInfo { * we have to keep track of them separately. */ Vector> functions; + /** + * Debug info that has to be destructed when the graph is not used anymore. + */ + Vector> dummy_debug_infos_; /** * Many sockets have default values. Since those are not owned by the lazy-function graph, we * have to keep track of them separately. This only owns the values, the memory is owned by the diff --git a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc index 9b89d056675..8d11089f253 100644 --- a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc +++ b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc @@ -698,6 +698,36 @@ static GMutablePointer get_socket_default_value(LinearAllocator<> &allocator, return {type, buffer}; } +class GroupInputDebugInfo : public lf::DummyDebugInfo { + public: + Vector socket_names; + + std::string node_name() const override + { + return "Group Input"; + } + + std::string output_name(const int i) const override + { + return this->socket_names[i]; + } +}; + +class GroupOutputDebugInfo : public lf::DummyDebugInfo { + public: + Vector socket_names; + + std::string node_name() const + { + return "Group Output"; + } + + std::string input_name(const int i) const override + { + return this->socket_names[i]; + } +}; + /** * Utility class to build a lazy-function graph based on a geometry nodes tree. * This is mainly a separate class because it makes it easier to have variables that can be @@ -794,15 +824,21 @@ struct GeometryNodesLazyFunctionGraphBuilder { void build_group_input_node() { /* Create a dummy node for the group inputs. */ - group_input_lf_node_ = &lf_graph_->add_dummy({}, group_input_types_); + auto debug_info = std::make_unique(); + group_input_lf_node_ = &lf_graph_->add_dummy({}, group_input_types_, debug_info.get()); + + const bNodeSocket *interface_bsocket = static_cast(btree_.inputs.first); for (const int group_input_index : group_input_indices_) { + BLI_SCOPED_DEFER([&]() { interface_bsocket = interface_bsocket->next; }); if (group_input_index == -1) { mapping_->group_input_sockets.append(nullptr); } else { mapping_->group_input_sockets.append(&group_input_lf_node_->output(group_input_index)); + debug_info->socket_names.append(interface_bsocket->name); } } + lf_graph_info_->dummy_debug_infos_.append(std::move(debug_info)); } void handle_nodes() @@ -925,8 +961,13 @@ struct GeometryNodesLazyFunctionGraphBuilder { void handle_group_output_node(const bNode &bnode) { - lf::DummyNode &group_output_lf_node = lf_graph_->add_dummy(group_output_types_, {}); + auto debug_info = std::make_unique(); + lf::DummyNode &group_output_lf_node = lf_graph_->add_dummy( + group_output_types_, {}, debug_info.get()); + + const bNodeSocket *interface_bsocket = static_cast(btree_.outputs.first); for (const int btree_index : group_output_indices_.index_range()) { + BLI_SCOPED_DEFER([&]() { interface_bsocket = interface_bsocket->next; }); const int lf_index = group_output_indices_[btree_index]; if (lf_index == -1) { continue; @@ -936,7 +977,10 @@ struct GeometryNodesLazyFunctionGraphBuilder { input_socket_map_.add(&bsocket, &lf_socket); mapping_->dummy_socket_map.add(&bsocket, &lf_socket); mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket); + debug_info->socket_names.append(interface_bsocket->name); } + + lf_graph_info_->dummy_debug_infos_.append(std::move(debug_info)); } void handle_group_node(const bNode &bnode)