Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Lucke <jacques@blender.org>2021-07-07 12:20:19 +0300
committerJacques Lucke <jacques@blender.org>2021-07-07 12:20:19 +0300
commit0153e99780aef64913dfd4c323984874bf688249 (patch)
tree28d5aa0587149778e227f69c37793cdf4219ea7a /source/blender/nodes
parent77834aff223e49eaa3abed56fb120aeca302a0e0 (diff)
Geometry Nodes: refactor logging during geometry nodes evaluation
Many ui features for geometry nodes need access to information generated during evaluation: * Node warnings. * Attribute search. * Viewer node. * Socket inspection (not in master yet). The way we logged the required information before had some disadvantages: * Viewer node used a completely separate system from node warnings and attribute search. * Most of the context of logged information is lost when e.g. the same node group is used multiple times. * A global lock was needed every time something is logged. This new implementation solves these problems: * All four mentioned ui features use the same underlying logging system. * All context information for logged values is kept intact. * Every thread has its own local logger. The logged informatiton is combined in the end. Differential Revision: https://developer.blender.org/D11785
Diffstat (limited to 'source/blender/nodes')
-rw-r--r--source/blender/nodes/CMakeLists.txt4
-rw-r--r--source/blender/nodes/NOD_geometry_exec.hh8
-rw-r--r--source/blender/nodes/NOD_geometry_nodes_eval_log.hh291
-rw-r--r--source/blender/nodes/intern/geometry_nodes_eval_log.cc330
-rw-r--r--source/blender/nodes/intern/node_geometry_exec.cc17
5 files changed, 633 insertions, 17 deletions
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index a3a52753880..4bfd75c4545 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -165,7 +165,7 @@ set(SRC
geometry/nodes/node_geo_common.cc
geometry/nodes/node_geo_convex_hull.cc
geometry/nodes/node_geo_curve_endpoints.cc
- geometry/nodes/node_geo_curve_length.cc
+ geometry/nodes/node_geo_curve_length.cc
geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
geometry/nodes/node_geo_curve_primitive_circle.cc
geometry/nodes/node_geo_curve_primitive_line.cc
@@ -335,6 +335,7 @@ set(SRC
texture/node_texture_util.c
intern/derived_node_tree.cc
+ intern/geometry_nodes_eval_log.cc
intern/math_functions.cc
intern/node_common.c
intern/node_exec.cc
@@ -358,6 +359,7 @@ set(SRC
NOD_function.h
NOD_geometry.h
NOD_geometry_exec.hh
+ NOD_geometry_nodes_eval_log.hh
NOD_math_functions.hh
NOD_node_tree_multi_function.hh
NOD_node_tree_ref.hh
diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh
index 23474201daa..d6a23051c0b 100644
--- a/source/blender/nodes/NOD_geometry_exec.hh
+++ b/source/blender/nodes/NOD_geometry_exec.hh
@@ -21,11 +21,11 @@
#include "BKE_attribute_access.hh"
#include "BKE_geometry_set.hh"
#include "BKE_geometry_set_instances.hh"
-#include "BKE_node_ui_storage.hh"
#include "DNA_node_types.h"
#include "NOD_derived_node_tree.hh"
+#include "NOD_geometry_nodes_eval_log.hh"
struct Depsgraph;
struct ModifierData;
@@ -52,10 +52,11 @@ using fn::GVMutableArray;
using fn::GVMutableArray_GSpan;
using fn::GVMutableArray_Typed;
using fn::GVMutableArrayPtr;
+using geometry_nodes_eval_log::NodeWarningType;
/**
- * This class exists to separate the memory management details of the geometry nodes evaluator from
- * the node execution functions and related utilities.
+ * This class exists to separate the memory management details of the geometry nodes evaluator
+ * from the node execution functions and related utilities.
*/
class GeoNodeExecParamsProvider {
public:
@@ -63,6 +64,7 @@ class GeoNodeExecParamsProvider {
const Object *self_object = nullptr;
const ModifierData *modifier = nullptr;
Depsgraph *depsgraph = nullptr;
+ geometry_nodes_eval_log::GeoLogger *logger = nullptr;
/**
* Returns true when the node is allowed to get/extract the input value. The identifier is
diff --git a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
new file mode 100644
index 00000000000..a52b182fe7e
--- /dev/null
+++ b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
@@ -0,0 +1,291 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+/**
+ * Many geometry nodes related ui features need access to data produced during evaluation. Not only
+ * is the final output required but also the intermediate results. Those features include
+ * attribute search, node warnings, socket inspection and the viewer node.
+ *
+ * This file provides the framework for logging data during evaluation and accessing the data after
+ * evaluation.
+ *
+ * During logging every thread gets its own local logger to avoid too much locking (logging
+ * generally happens for every socket). After geometry nodes evaluation is done, the threadlocal
+ * logging information is combined and postprocessed to make it easier for the ui to lookup
+ * necessary information.
+ */
+
+#include "BLI_enumerable_thread_specific.hh"
+#include "BLI_linear_allocator.hh"
+#include "BLI_map.hh"
+
+#include "BKE_geometry_set.hh"
+
+#include "FN_generic_pointer.hh"
+
+#include "NOD_derived_node_tree.hh"
+
+struct SpaceNode;
+struct SpaceSpreadsheet;
+
+namespace blender::nodes::geometry_nodes_eval_log {
+
+using fn::GMutablePointer;
+using fn::GPointer;
+
+/** Contains information about a value that has been computed during geometry nodes evaluation. */
+class ValueLog {
+ public:
+ virtual ~ValueLog() = default;
+};
+
+/** Contains an owned copy of a value of a generic type. */
+class GenericValueLog : public ValueLog {
+ private:
+ GMutablePointer data_;
+
+ public:
+ GenericValueLog(GMutablePointer data) : data_(data)
+ {
+ }
+
+ ~GenericValueLog()
+ {
+ data_.destruct();
+ }
+
+ GPointer value() const
+ {
+ return data_;
+ }
+};
+
+struct GeometryAttributeInfo {
+ std::string name;
+ AttributeDomain domain;
+ CustomDataType data_type;
+};
+
+/** Contains information about a geometry set. In most cases this does not store the entire
+ * geometry set as this would require too much memory. */
+class GeometryValueLog : public ValueLog {
+ private:
+ Vector<GeometryAttributeInfo> attributes_;
+ Vector<GeometryComponentType> component_types_;
+ std::unique_ptr<GeometrySet> full_geometry_;
+
+ public:
+ GeometryValueLog(const GeometrySet &geometry_set, bool log_full_geometry);
+
+ Span<GeometryAttributeInfo> attributes() const
+ {
+ return attributes_;
+ }
+
+ Span<GeometryComponentType> component_types() const
+ {
+ return component_types_;
+ }
+
+ const GeometrySet *full_geometry() const
+ {
+ return full_geometry_.get();
+ }
+};
+
+enum class NodeWarningType {
+ Error,
+ Warning,
+ Info,
+};
+
+struct NodeWarning {
+ NodeWarningType type;
+ std::string message;
+};
+
+struct NodeWithWarning {
+ DNode node;
+ NodeWarning warning;
+};
+
+/** The same value can be referenced by multiple sockets when they are linked. */
+struct ValueOfSockets {
+ Span<DSocket> sockets;
+ destruct_ptr<ValueLog> value;
+};
+
+class GeoLogger;
+class ModifierLog;
+
+/** Every thread has its own local logger to avoid having to communicate between threads during
+ * evaluation. After evaluation the individual logs are combined. */
+class LocalGeoLogger {
+ private:
+ /* Back pointer to the owner of this local logger. */
+ GeoLogger *main_logger_;
+ /* Allocator for the many small allocations during logging. This is in a `unique_ptr` so that
+ * ownership can be transferred later on. */
+ std::unique_ptr<LinearAllocator<>> allocator_;
+ Vector<ValueOfSockets> values_;
+ Vector<NodeWithWarning> node_warnings_;
+
+ friend ModifierLog;
+
+ public:
+ LocalGeoLogger(GeoLogger &main_logger) : main_logger_(&main_logger)
+ {
+ this->allocator_ = std::make_unique<LinearAllocator<>>();
+ }
+
+ void log_value_for_sockets(Span<DSocket> sockets, GPointer value);
+ void log_multi_value_socket(DSocket socket, Span<GPointer> values);
+ void log_node_warning(DNode node, NodeWarningType type, std::string message);
+};
+
+/** The root logger class. */
+class GeoLogger {
+ private:
+ /** The entire geometry of sockets in this set should be cached, because e.g. the spreadsheet
+ * displays the data. We don't log the entire geometry at all places, because that would require
+ * way too much memory. */
+ Set<DSocket> log_full_geometry_sockets_;
+ threading::EnumerableThreadSpecific<LocalGeoLogger> threadlocals_;
+
+ friend LocalGeoLogger;
+
+ public:
+ GeoLogger(Set<DSocket> log_full_geometry_sockets)
+ : log_full_geometry_sockets_(std::move(log_full_geometry_sockets)),
+ threadlocals_([this]() { return LocalGeoLogger(*this); })
+ {
+ }
+
+ LocalGeoLogger &local()
+ {
+ return threadlocals_.local();
+ }
+
+ auto begin()
+ {
+ return threadlocals_.begin();
+ }
+
+ auto end()
+ {
+ return threadlocals_.end();
+ }
+};
+
+/** Contains information that has been logged for one specific socket. */
+class SocketLog {
+ private:
+ ValueLog *value_ = nullptr;
+
+ friend ModifierLog;
+
+ public:
+ const ValueLog *value() const
+ {
+ return value_;
+ }
+};
+
+/** Contains information that has been logged for one specific node. */
+class NodeLog {
+ private:
+ Vector<SocketLog> input_logs_;
+ Vector<SocketLog> output_logs_;
+ Vector<NodeWarning, 0> warnings_;
+
+ friend ModifierLog;
+
+ public:
+ const SocketLog *lookup_socket_log(eNodeSocketInOut in_out, int index) const;
+ const SocketLog *lookup_socket_log(const bNode &node, const bNodeSocket &socket) const;
+
+ Span<SocketLog> input_logs() const
+ {
+ return input_logs_;
+ }
+
+ Span<SocketLog> output_logs() const
+ {
+ return output_logs_;
+ }
+
+ Span<NodeWarning> warnings() const
+ {
+ return warnings_;
+ }
+
+ Vector<const GeometryAttributeInfo *> lookup_available_attributes() const;
+};
+
+/** Contains information that has been logged for one specific tree. */
+class TreeLog {
+ private:
+ Map<std::string, destruct_ptr<NodeLog>> node_logs_;
+ Map<std::string, destruct_ptr<TreeLog>> child_logs_;
+
+ friend ModifierLog;
+
+ public:
+ const NodeLog *lookup_node_log(StringRef node_name) const;
+ const NodeLog *lookup_node_log(const bNode &node) const;
+ const TreeLog *lookup_child_log(StringRef node_name) const;
+};
+
+/** Contains information about an entire geometry nodes evaluation. */
+class ModifierLog {
+ private:
+ LinearAllocator<> allocator_;
+ /* Allocators of the individual loggers. */
+ Vector<std::unique_ptr<LinearAllocator<>>> logger_allocators_;
+ destruct_ptr<TreeLog> root_tree_logs_;
+ Vector<destruct_ptr<ValueLog>> logged_values_;
+
+ public:
+ ModifierLog(GeoLogger &logger);
+
+ const TreeLog &root_tree() const
+ {
+ return *root_tree_logs_;
+ }
+
+ /* Utilities to find logged informatiton for a specific context. */
+ static const ModifierLog *find_root_by_node_editor_context(const SpaceNode &snode);
+ static const TreeLog *find_tree_by_node_editor_context(const SpaceNode &snode);
+ static const NodeLog *find_node_by_node_editor_context(const SpaceNode &snode,
+ const bNode &node);
+ static const SocketLog *find_socket_by_node_editor_context(const SpaceNode &snode,
+ const bNode &node,
+ const bNodeSocket &socket);
+ static const NodeLog *find_node_by_spreadsheet_editor_context(
+ const SpaceSpreadsheet &sspreadsheet);
+
+ private:
+ using LogByTreeContext = Map<const DTreeContext *, TreeLog *>;
+
+ TreeLog &lookup_or_add_tree_log(LogByTreeContext &log_by_tree_context,
+ const DTreeContext &tree_context);
+ NodeLog &lookup_or_add_node_log(LogByTreeContext &log_by_tree_context, DNode node);
+ SocketLog &lookup_or_add_socket_log(LogByTreeContext &log_by_tree_context, DSocket socket);
+};
+
+} // namespace blender::nodes::geometry_nodes_eval_log
diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
new file mode 100644
index 00000000000..85182b67c8a
--- /dev/null
+++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
@@ -0,0 +1,330 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "NOD_geometry_nodes_eval_log.hh"
+
+#include "BKE_geometry_set_instances.hh"
+
+#include "DNA_modifier_types.h"
+#include "DNA_space_types.h"
+
+namespace blender::nodes::geometry_nodes_eval_log {
+
+using fn::CPPType;
+
+ModifierLog::ModifierLog(GeoLogger &logger)
+{
+ root_tree_logs_ = allocator_.construct<TreeLog>();
+
+ LogByTreeContext log_by_tree_context;
+
+ /* Combine all the local loggers that have been used by separate threads. */
+ for (LocalGeoLogger &local_logger : logger) {
+ /* Take ownership of the allocator. */
+ logger_allocators_.append(std::move(local_logger.allocator_));
+
+ for (ValueOfSockets &value_of_sockets : local_logger.values_) {
+ ValueLog *value_log = value_of_sockets.value.get();
+
+ /* Take centralized ownership of the logged value. It might be referenced by multiple
+ * sockets. */
+ logged_values_.append(std::move(value_of_sockets.value));
+
+ for (const DSocket &socket : value_of_sockets.sockets) {
+ SocketLog &socket_log = this->lookup_or_add_socket_log(log_by_tree_context, socket);
+ socket_log.value_ = value_log;
+ }
+ }
+
+ for (NodeWithWarning &node_with_warning : local_logger.node_warnings_) {
+ NodeLog &node_log = this->lookup_or_add_node_log(log_by_tree_context,
+ node_with_warning.node);
+ node_log.warnings_.append(node_with_warning.warning);
+ }
+ }
+}
+
+TreeLog &ModifierLog::lookup_or_add_tree_log(LogByTreeContext &log_by_tree_context,
+ const DTreeContext &tree_context)
+{
+ TreeLog *tree_log = log_by_tree_context.lookup_default(&tree_context, nullptr);
+ if (tree_log != nullptr) {
+ return *tree_log;
+ }
+
+ const DTreeContext *parent_context = tree_context.parent_context();
+ if (parent_context == nullptr) {
+ return *root_tree_logs_.get();
+ }
+ TreeLog &parent_log = this->lookup_or_add_tree_log(log_by_tree_context, *parent_context);
+ destruct_ptr<TreeLog> owned_tree_log = allocator_.construct<TreeLog>();
+ tree_log = owned_tree_log.get();
+ log_by_tree_context.add_new(&tree_context, tree_log);
+ parent_log.child_logs_.add_new(tree_context.parent_node()->name(), std::move(owned_tree_log));
+ return *tree_log;
+}
+
+NodeLog &ModifierLog::lookup_or_add_node_log(LogByTreeContext &log_by_tree_context, DNode node)
+{
+ TreeLog &tree_log = this->lookup_or_add_tree_log(log_by_tree_context, *node.context());
+ NodeLog &node_log = *tree_log.node_logs_.lookup_or_add_cb(node->name(), [&]() {
+ destruct_ptr<NodeLog> node_log = allocator_.construct<NodeLog>();
+ node_log->input_logs_.resize(node->inputs().size());
+ node_log->output_logs_.resize(node->outputs().size());
+ return node_log;
+ });
+ return node_log;
+}
+
+SocketLog &ModifierLog::lookup_or_add_socket_log(LogByTreeContext &log_by_tree_context,
+ DSocket socket)
+{
+ NodeLog &node_log = this->lookup_or_add_node_log(log_by_tree_context, socket.node());
+ MutableSpan<SocketLog> socket_logs = socket->is_input() ? node_log.input_logs_ :
+ node_log.output_logs_;
+ SocketLog &socket_log = socket_logs[socket->index()];
+ return socket_log;
+}
+
+const NodeLog *TreeLog::lookup_node_log(StringRef node_name) const
+{
+ const destruct_ptr<NodeLog> *node_log = node_logs_.lookup_ptr_as(node_name);
+ if (node_log == nullptr) {
+ return nullptr;
+ }
+ return node_log->get();
+}
+
+const NodeLog *TreeLog::lookup_node_log(const bNode &node) const
+{
+ return this->lookup_node_log(node.name);
+}
+
+const TreeLog *TreeLog::lookup_child_log(StringRef node_name) const
+{
+ const destruct_ptr<TreeLog> *tree_log = child_logs_.lookup_ptr_as(node_name);
+ if (tree_log == nullptr) {
+ return nullptr;
+ }
+ return tree_log->get();
+}
+
+const SocketLog *NodeLog::lookup_socket_log(eNodeSocketInOut in_out, int index) const
+{
+ BLI_assert(index >= 0);
+ Span<SocketLog> socket_logs = (in_out == SOCK_IN) ? input_logs_ : output_logs_;
+ if (index >= socket_logs.size()) {
+ return nullptr;
+ }
+ return &socket_logs[index];
+}
+
+const SocketLog *NodeLog::lookup_socket_log(const bNode &node, const bNodeSocket &socket) const
+{
+ ListBase sockets = socket.in_out == SOCK_IN ? node.inputs : node.outputs;
+ int index = BLI_findindex(&sockets, &socket);
+ return this->lookup_socket_log((eNodeSocketInOut)socket.in_out, index);
+}
+
+GeometryValueLog::GeometryValueLog(const GeometrySet &geometry_set, bool log_full_geometry)
+{
+ bke::geometry_set_instances_attribute_foreach(
+ geometry_set,
+ [&](StringRefNull attribute_name, const AttributeMetaData &meta_data) {
+ this->attributes_.append({attribute_name, meta_data.domain, meta_data.data_type});
+ return true;
+ },
+ 8);
+ for (const GeometryComponent *component : geometry_set.get_components_for_read()) {
+ component_types_.append(component->type());
+ }
+ if (log_full_geometry) {
+ full_geometry_ = std::make_unique<GeometrySet>(geometry_set);
+ full_geometry_->ensure_owns_direct_data();
+ }
+}
+
+Vector<const GeometryAttributeInfo *> NodeLog::lookup_available_attributes() const
+{
+ Vector<const GeometryAttributeInfo *> attributes;
+ Set<StringRef> names;
+ for (const SocketLog &socket_log : input_logs_) {
+ const ValueLog *value_log = socket_log.value();
+ if (const GeometryValueLog *geo_value_log = dynamic_cast<const GeometryValueLog *>(
+ value_log)) {
+ for (const GeometryAttributeInfo &attribute : geo_value_log->attributes()) {
+ if (names.add(attribute.name)) {
+ attributes.append(&attribute);
+ }
+ }
+ }
+ }
+ return attributes;
+}
+
+const ModifierLog *ModifierLog::find_root_by_node_editor_context(const SpaceNode &snode)
+{
+ if (snode.id == nullptr) {
+ return nullptr;
+ }
+ if (GS(snode.id->name) != ID_OB) {
+ return nullptr;
+ }
+ Object *object = (Object *)snode.id;
+ LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
+ if (md->type == eModifierType_Nodes) {
+ NodesModifierData *nmd = (NodesModifierData *)md;
+ if (nmd->node_group == snode.nodetree) {
+ return (ModifierLog *)nmd->runtime_eval_log;
+ }
+ }
+ }
+ return nullptr;
+}
+
+const TreeLog *ModifierLog::find_tree_by_node_editor_context(const SpaceNode &snode)
+{
+ const ModifierLog *eval_log = ModifierLog::find_root_by_node_editor_context(snode);
+ if (eval_log == nullptr) {
+ return nullptr;
+ }
+ Vector<bNodeTreePath *> tree_path_vec = snode.treepath;
+ if (tree_path_vec.is_empty()) {
+ return nullptr;
+ }
+ TreeLog *current = eval_log->root_tree_logs_.get();
+ for (bNodeTreePath *path : tree_path_vec.as_span().drop_front(1)) {
+ destruct_ptr<TreeLog> *tree_log = current->child_logs_.lookup_ptr_as(path->node_name);
+ if (tree_log == nullptr) {
+ return nullptr;
+ }
+ current = tree_log->get();
+ }
+ return current;
+}
+
+const NodeLog *ModifierLog::find_node_by_node_editor_context(const SpaceNode &snode,
+ const bNode &node)
+{
+ const TreeLog *tree_log = ModifierLog::find_tree_by_node_editor_context(snode);
+ if (tree_log == nullptr) {
+ return nullptr;
+ }
+ return tree_log->lookup_node_log(node);
+}
+
+const SocketLog *ModifierLog::find_socket_by_node_editor_context(const SpaceNode &snode,
+ const bNode &node,
+ const bNodeSocket &socket)
+{
+ const NodeLog *node_log = ModifierLog::find_node_by_node_editor_context(snode, node);
+ if (node_log == nullptr) {
+ return nullptr;
+ }
+ return node_log->lookup_socket_log(node, socket);
+}
+
+const NodeLog *ModifierLog::find_node_by_spreadsheet_editor_context(
+ const SpaceSpreadsheet &sspreadsheet)
+{
+ Vector<SpreadsheetContext *> context_path = sspreadsheet.context_path;
+ if (context_path.size() <= 2) {
+ return nullptr;
+ }
+ if (context_path[0]->type != SPREADSHEET_CONTEXT_OBJECT) {
+ return nullptr;
+ }
+ if (context_path[1]->type != SPREADSHEET_CONTEXT_MODIFIER) {
+ return nullptr;
+ }
+ for (SpreadsheetContext *context : context_path.as_span().drop_front(2)) {
+ if (context->type != SPREADSHEET_CONTEXT_NODE) {
+ return nullptr;
+ }
+ }
+ Span<SpreadsheetContextNode *> node_contexts =
+ context_path.as_span().drop_front(2).cast<SpreadsheetContextNode *>();
+
+ Object *object = ((SpreadsheetContextObject *)context_path[0])->object;
+ StringRefNull modifier_name = ((SpreadsheetContextModifier *)context_path[1])->modifier_name;
+ if (object == nullptr) {
+ return nullptr;
+ }
+
+ const ModifierLog *eval_log = nullptr;
+ LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
+ if (md->type == eModifierType_Nodes) {
+ if (md->name == modifier_name) {
+ NodesModifierData *nmd = (NodesModifierData *)md;
+ eval_log = (const ModifierLog *)nmd->runtime_eval_log;
+ break;
+ }
+ }
+ }
+ if (eval_log == nullptr) {
+ return nullptr;
+ }
+
+ const TreeLog *tree_log = &eval_log->root_tree();
+ for (SpreadsheetContextNode *context : node_contexts.drop_back(1)) {
+ tree_log = tree_log->lookup_child_log(context->node_name);
+ if (tree_log == nullptr) {
+ return nullptr;
+ }
+ }
+ const NodeLog *node_log = tree_log->lookup_node_log(node_contexts.last()->node_name);
+ return node_log;
+}
+
+void LocalGeoLogger::log_value_for_sockets(Span<DSocket> sockets, GPointer value)
+{
+ const CPPType &type = *value.type();
+ Span<DSocket> copied_sockets = allocator_->construct_array_copy(sockets);
+ if (type.is<GeometrySet>()) {
+ bool log_full_geometry = false;
+ for (const DSocket &socket : sockets) {
+ if (main_logger_->log_full_geometry_sockets_.contains(socket)) {
+ log_full_geometry = true;
+ break;
+ }
+ }
+
+ const GeometrySet &geometry_set = *value.get<GeometrySet>();
+ destruct_ptr<GeometryValueLog> value_log = allocator_->construct<GeometryValueLog>(
+ geometry_set, log_full_geometry);
+ values_.append({copied_sockets, std::move(value_log)});
+ }
+ else {
+ void *buffer = allocator_->allocate(type.size(), type.alignment());
+ type.copy_construct(value.get(), buffer);
+ destruct_ptr<GenericValueLog> value_log = allocator_->construct<GenericValueLog>(
+ GMutablePointer{type, buffer});
+ values_.append({copied_sockets, std::move(value_log)});
+ }
+}
+
+void LocalGeoLogger::log_multi_value_socket(DSocket socket, Span<GPointer> values)
+{
+ /* Doesn't have to be logged currently. */
+ UNUSED_VARS(socket, values);
+}
+
+void LocalGeoLogger::log_node_warning(DNode node, NodeWarningType type, std::string message)
+{
+ node_warnings_.append({node, {type, std::move(message)}});
+}
+
+} // namespace blender::nodes::geometry_nodes_eval_log
diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc
index 17a13f2d1b0..5755a14f14d 100644
--- a/source/blender/nodes/intern/node_geometry_exec.cc
+++ b/source/blender/nodes/intern/node_geometry_exec.cc
@@ -16,8 +16,6 @@
#include "DNA_modifier_types.h"
-#include "BKE_node_ui_storage.hh"
-
#include "DEG_depsgraph_query.h"
#include "NOD_geometry_exec.hh"
@@ -26,21 +24,14 @@
#include "node_geometry_util.hh"
+using blender::nodes::geometry_nodes_eval_log::LocalGeoLogger;
+
namespace blender::nodes {
void GeoNodeExecParams::error_message_add(const NodeWarningType type, std::string message) const
{
- bNodeTree *btree_cow = provider_->dnode->btree();
- BLI_assert(btree_cow != nullptr);
- if (btree_cow == nullptr) {
- return;
- }
- bNodeTree *btree_original = (bNodeTree *)DEG_get_original_id((ID *)btree_cow);
-
- const NodeTreeEvaluationContext context(*provider_->self_object, *provider_->modifier);
-
- BKE_nodetree_error_message_add(
- *btree_original, context, *provider_->dnode->bnode(), type, std::move(message));
+ LocalGeoLogger &local_logger = provider_->logger->local();
+ local_logger.log_node_warning(provider_->dnode, type, std::move(message));
}
const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name) const