Blender V5.0
geometry_nodes_log.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BKE_lib_id.hh"
9
10#include "BLI_listbase.h"
11#include "BLI_stack.hh"
12#include "BLI_string_ref.hh"
13#include "BLI_string_utf8.h"
14
18#include "BKE_curves.hh"
20#include "BKE_grease_pencil.hh"
21#include "BKE_lib_query.hh"
23#include "BKE_node_runtime.hh"
25#include "BKE_report.hh"
27#include "BKE_volume.hh"
28#include "BKE_volume_grid.hh"
29#include "BKE_volume_openvdb.hh"
30
32#include "DNA_modifier_types.h"
33#include "DNA_space_types.h"
34
35#include "ED_geometry.hh"
36#include "ED_node.hh"
37#include "ED_viewer_path.hh"
38
39#include "MOD_nodes.hh"
40
41#include "UI_resources.hh"
42
44
46
47using bke::bNodeTreeZone;
48using bke::bNodeTreeZones;
49using fn::FieldInput;
50using fn::FieldInputs;
51
53{
54 this->value.destruct();
55}
56
58{
59 /* Avoid logging the entirety of long strings, to avoid unnecessary memory usage. */
60 if (string.size() <= 100) {
61 this->truncated = false;
62 this->value = allocator.copy_string(string);
63 return;
64 }
65 this->truncated = true;
66 const char *end = BLI_str_find_prev_char_utf8(string.data() + 100, string.data());
67 this->value = allocator.copy_string(StringRef(string.data(), end));
68}
69
70FieldInfoLog::FieldInfoLog(const GField &field) : type(field.cpp_type())
71{
72 const std::shared_ptr<const fn::FieldInputs> &field_input_nodes = field.node().field_inputs();
73
74 /* Put the deduplicated field inputs into a vector so that they can be sorted below. */
76 if (field_input_nodes) {
77 field_inputs.extend(field_input_nodes->deduplicated_nodes.begin(),
78 field_input_nodes->deduplicated_nodes.end());
79 }
80
81 std::sort(
82 field_inputs.begin(), field_inputs.end(), [](const FieldInput &a, const FieldInput &b) {
83 const int index_a = int(a.category());
84 const int index_b = int(b.category());
85 if (index_a == index_b) {
86 return a.socket_inspection_name().size() < b.socket_inspection_name().size();
87 }
88 return index_a < index_b;
89 });
90
91 for (const FieldInput &field_input : field_inputs) {
92 this->input_tooltips.append(field_input.socket_inspection_name());
93 }
94}
95
97{
98 this->name = geometry_set.name;
99
100 static std::array all_component_types = {bke::GeometryComponent::Type::Curve,
106
107 /* Keep track handled attribute names to make sure that we do not return the same name twice.
108 * Currently #GeometrySet::attribute_foreach does not do that. Note that this will merge
109 * attributes with the same name but different domains or data types on separate components. */
110 Set<StringRef> names;
111
112 geometry_set.attribute_foreach(
113 all_component_types,
114 true,
115 [&](const StringRef attribute_id,
116 const bke::AttributeMetaData &meta_data,
117 const bke::GeometryComponent & /*component*/) {
118 if (!bke::attribute_name_is_anonymous(attribute_id) && names.add(attribute_id)) {
119 this->attributes.append({attribute_id, meta_data.domain, meta_data.data_type});
120 }
121 });
122
123 for (const bke::GeometryComponent *component : geometry_set.get_components()) {
124 this->component_types.append(component->type());
125 switch (component->type()) {
127 const auto &mesh_component = *static_cast<const bke::MeshComponent *>(component);
128 MeshInfo &info = this->mesh_info.emplace();
129 info.verts_num = mesh_component.attribute_domain_size(bke::AttrDomain::Point);
130 info.edges_num = mesh_component.attribute_domain_size(bke::AttrDomain::Edge);
131 info.faces_num = mesh_component.attribute_domain_size(bke::AttrDomain::Face);
132 break;
133 }
135 const auto &curve_component = *static_cast<const bke::CurveComponent *>(component);
136 CurveInfo &info = this->curve_info.emplace();
137 info.points_num = curve_component.attribute_domain_size(bke::AttrDomain::Point);
138 info.splines_num = curve_component.attribute_domain_size(bke::AttrDomain::Curve);
139 break;
140 }
142 const auto &pointcloud_component = *static_cast<const bke::PointCloudComponent *>(
143 component);
144 PointCloudInfo &info = this->pointcloud_info.emplace();
145 info.points_num = pointcloud_component.attribute_domain_size(bke::AttrDomain::Point);
146 break;
147 }
149 const auto &instances_component = *static_cast<const bke::InstancesComponent *>(component);
150 InstancesInfo &info = this->instances_info.emplace();
151 info.instances_num = instances_component.attribute_domain_size(bke::AttrDomain::Instance);
152 break;
153 }
155 const auto &edit_component = *static_cast<const bke::GeometryComponentEditData *>(
156 component);
157 if (!this->edit_data_info) {
158 this->edit_data_info.emplace(EditDataInfo());
159 }
160 EditDataInfo &info = *this->edit_data_info;
161 if (const bke::CurvesEditHints *curve_edit_hints = edit_component.curves_edit_hints_.get())
162 {
163 info.has_deform_matrices = curve_edit_hints->deform_mats.has_value();
164 info.has_deformed_positions = curve_edit_hints->positions().has_value();
165 }
166 if (const bke::GizmoEditHints *gizmo_edit_hints = edit_component.gizmo_edit_hints_.get()) {
167 info.gizmo_transforms_num = gizmo_edit_hints->gizmo_transforms.size();
168 }
169 break;
170 }
172#ifdef WITH_OPENVDB
173 const auto &volume_component = *static_cast<const bke::VolumeComponent *>(component);
174 if (const Volume *volume = volume_component.get()) {
175 VolumeInfo &info = this->volume_info.emplace();
176 info.grids.resize(BKE_volume_num_grids(volume));
177 for (const int i : IndexRange(BKE_volume_num_grids(volume))) {
178 const bke::VolumeGridData *grid = BKE_volume_grid_get(volume, i);
179 info.grids[i] = {grid->name(), bke::volume_grid::get_type(*grid)};
180 }
181 }
182#endif /* WITH_OPENVDB */
183 break;
184 }
186 const auto &grease_pencil_component = *static_cast<const bke::GreasePencilComponent *>(
187 component);
188 if (const GreasePencil *grease_pencil = grease_pencil_component.get()) {
190 info.layers_num = grease_pencil->layers().size();
191 Set<StringRef> unique_layer_names;
192 for (const bke::greasepencil::Layer *layer : grease_pencil->layers()) {
193 const StringRefNull layer_name = layer->name();
194 if (unique_layer_names.add(layer_name)) {
195 info.layer_names.append(layer_name);
196 }
197 }
198 }
199 break;
200 }
201 }
202 }
203}
204
205#ifdef WITH_OPENVDB
206struct GridIsEmptyOp {
207 const openvdb::GridBase &base_grid;
208 bool result = false;
209
210 template<typename GridType> bool operator()()
211 {
212 result = static_cast<const GridType &>(base_grid).empty();
213 return true;
214 }
215};
216#endif /* WITH_OPENVDB */
217
218GridInfoLog::GridInfoLog(const bke::GVolumeGrid &grid)
219{
220#ifdef WITH_OPENVDB
221 bke::VolumeTreeAccessToken token;
222 const openvdb::GridBase &vdb_grid = grid->grid(token);
223 const VolumeGridType grid_type = bke::volume_grid::get_type(vdb_grid);
224
225 GridIsEmptyOp is_empty_op{vdb_grid};
226 if (BKE_volume_grid_type_operation(grid_type, is_empty_op)) {
227 this->is_empty = is_empty_op.result;
228 }
229 else {
230 this->is_empty = true;
231 }
232#else
233 UNUSED_VARS(grid);
234 this->is_empty = true;
235#endif
236}
237
239
242 const std::optional<ClosureSourceLocation> &source_location,
243 std::shared_ptr<ClosureEvalLog> eval_log)
244 : inputs(std::move(inputs)), outputs(std::move(outputs)), eval_log(std::move(eval_log))
245{
246 if (source_location) {
247 const bNodeTree *tree_eval = source_location->tree;
248 const bNodeTree *tree_orig = reinterpret_cast<const bNodeTree *>(
249 DEG_get_original_id(&tree_eval->id));
250 this->source = Source{tree_orig->id.session_uid,
251 source_location->closure_output_node_id,
252 source_location->compute_context_hash};
253 }
254}
255
257{
258 if (!list) {
259 this->size = 0;
260 return;
261 }
262 this->size = list->size();
263}
264
266{
267 switch (report.type) {
268 case RPT_ERROR:
270 break;
271 default:
273 break;
274 }
275 this->message = report.message;
276}
277
278/* Avoid generating these in every translation unit. */
279GeoNodesLog::GeoNodesLog() = default;
280GeoNodesLog::~GeoNodesLog() = default;
281
284
285GeoNodeLog::GeoNodeLog() = default;
286GeoNodeLog::~GeoNodeLog() = default;
287
289 : root_log_(root_log), tree_loggers_(std::move(tree_loggers))
290{
291 for (GeoTreeLogger *tree_logger : tree_loggers_) {
292 for (const ComputeContextHash &hash : tree_logger->children_hashes) {
293 children_hashes_.add(hash);
294 }
295 }
296}
297
298GeoTreeLog::~GeoTreeLog() = default;
299
300void GeoTreeLogger::log_value(const bNode &node, const bNodeSocket &socket, const GPointer value)
301{
302 const CPPType &type = *value.type();
303
304 auto store_logged_value = [&](destruct_ptr<ValueLog> value_log) {
305 auto &socket_values = socket.in_out == SOCK_IN ? this->input_socket_values :
307 socket_values.append(*this->allocator,
308 {node.identifier, socket.index(), std::move(value_log)});
309 };
310
311 auto log_generic_value = [&](const CPPType &type, const void *value) {
312 void *buffer = this->allocator->allocate(type);
313 type.copy_construct(value, buffer);
314 store_logged_value(this->allocator->construct<GenericValueLog>(GMutablePointer{type, buffer}));
315 };
316
317 if (type.is<bke::SocketValueVariant>()) {
318 bke::SocketValueVariant value_variant = *value.get<bke::SocketValueVariant>();
319 if (value_variant.valid_for_socket(SOCK_GEOMETRY)) {
320 const bke::GeometrySet &geometry = value_variant.get<bke::GeometrySet>();
321 store_logged_value(this->allocator->construct<GeometryInfoLog>(geometry));
322 }
323 else if (value_variant.is_context_dependent_field()) {
324 const GField field = value_variant.extract<GField>();
325 store_logged_value(this->allocator->construct<FieldInfoLog>(field));
326 }
327#ifdef WITH_OPENVDB
328 else if (value_variant.is_volume_grid()) {
329 const bke::GVolumeGrid grid = value_variant.extract<bke::GVolumeGrid>();
330 store_logged_value(this->allocator->construct<GridInfoLog>(grid));
331 }
332#endif
333 else if (value_variant.is_list()) {
334 const ListPtr list = value_variant.extract<ListPtr>();
335 store_logged_value(this->allocator->construct<ListInfoLog>(list.get()));
336 }
337 else if (value_variant.valid_for_socket(SOCK_BUNDLE)) {
339 if (const BundlePtr bundle = value_variant.extract<BundlePtr>()) {
340 for (const Bundle::StoredItem &item : bundle->items()) {
341 if (const BundleItemSocketValue *socket_value = std::get_if<BundleItemSocketValue>(
342 &item.value.value))
343 {
344 items.append({item.key, {socket_value->type}});
345 }
346 if (const BundleItemInternalValue *internal_value = std::get_if<BundleItemInternalValue>(
347 &item.value.value))
348 {
349 items.append({item.key, {internal_value->value->type_name()}});
350 }
351 }
352 }
353 store_logged_value(this->allocator->construct<BundleValueLog>(std::move(items)));
354 }
355 else if (value_variant.valid_for_socket(SOCK_CLOSURE)) {
358 std::optional<ClosureSourceLocation> source_location;
359 std::shared_ptr<ClosureEvalLog> eval_log;
360 if (const ClosurePtr closure = value_variant.extract<ClosurePtr>()) {
361 const ClosureSignature &signature = closure->signature();
362 for (const ClosureSignature::Item &item : signature.inputs) {
363 inputs.append({item.key, item.type});
364 }
365 for (const ClosureSignature::Item &item : signature.outputs) {
366 outputs.append({item.key, item.type});
367 }
368 source_location = closure->source_location();
369 eval_log = closure->eval_log_ptr();
370 }
371 store_logged_value(this->allocator->construct<ClosureValueLog>(
372 std::move(inputs), std::move(outputs), source_location, eval_log));
373 }
374 else {
375 value_variant.convert_to_single();
376 const GPointer value = value_variant.get_single_ptr();
377 if (value.type()->is<std::string>()) {
378 const std::string &string = *value.get<std::string>();
379 store_logged_value(this->allocator->construct<StringLog>(string, *this->allocator));
380 }
381 else {
382 log_generic_value(*value.type(), value.get());
383 }
384 }
385 }
386 else {
387 log_generic_value(type, value.get());
388 }
389}
390
392{
393 main_geometry_cache_mutex_.ensure([&]() {
394 for (const Item &item : this->items) {
395#ifdef WITH_OPENVDB
396 if (item.value.is_volume_grid()) {
397 const bke::GVolumeGrid grid = item.value.get<bke::GVolumeGrid>();
398 Volume *volume = BKE_id_new_nomain<Volume>(nullptr);
399 grid->add_user();
400 BKE_volume_grid_add(volume, grid.get());
401 main_geometry_cache_ = bke::GeometrySet::from_volume(volume);
402 return;
403 }
404#endif
405 if (item.value.is_single() && item.value.get_single_ptr().is_type<bke::GeometrySet>()) {
406 main_geometry_cache_ = *item.value.get_single_ptr().get<bke::GeometrySet>();
407 return;
408 }
409 }
410 });
411 return main_geometry_cache_ ? &*main_geometry_cache_ : nullptr;
412}
413
414static bool warning_is_propagated(const NodeWarningPropagation propagation,
415 const NodeWarningType warning_type)
416{
417 switch (propagation) {
419 return true;
421 return false;
423 return warning_type == NodeWarningType::Error;
426 }
428 return true;
429}
430
432{
433 if (reduced_node_warnings_) {
434 return;
435 }
436 if (!nmd.node_group) {
437 reduced_node_warnings_ = true;
438 return;
439 }
442 nullptr,
443 &nmd.node_group->id,
444 [&](LibraryIDLinkCallbackData *cb_data) {
445 if (ID *id = *cb_data->id_pointer) {
446 if (GS(id->name) == ID_NT) {
447 const bNodeTree *tree = reinterpret_cast<const bNodeTree *>(id);
448 map.add(id->session_uid, tree);
449 }
450 }
451 return IDWALK_RET_NOP;
452 },
453 nullptr,
455 this->ensure_node_warnings(map);
456}
457
459{
460 if (reduced_node_warnings_) {
461 return;
462 }
464 FOREACH_NODETREE_BEGIN (const_cast<Main *>(&bmain), tree, id) {
465 map.add_new(tree->id.session_uid, tree);
466 }
468 this->ensure_node_warnings(map);
469}
470
472 const Map<uint32_t, const bNodeTree *> &orig_tree_by_session_uid)
473{
474 if (reduced_node_warnings_) {
475 return;
476 }
477 if (tree_loggers_.is_empty()) {
478 return;
479 }
480 const std::optional<uint32_t> tree_uid = tree_loggers_[0]->tree_orig_session_uid;
481 const bNodeTree *tree = tree_uid ? orig_tree_by_session_uid.lookup_default(*tree_uid, nullptr) :
482 nullptr;
483
484 for (GeoTreeLogger *tree_logger : tree_loggers_) {
485 for (const GeoTreeLogger::WarningWithNode &warning : tree_logger->node_warnings) {
487 if (tree) {
488 if (const bNode *node = tree->node_by_id(warning.node_id)) {
489 propagation = NodeWarningPropagation(node->warning_propagation);
490 }
491 }
492 this->nodes.lookup_or_add_default(warning.node_id).warnings.add(warning.warning);
493 if (warning_is_propagated(propagation, warning.warning.type)) {
494 this->all_warnings.add(warning.warning);
495 }
496 }
497 }
498 for (const ComputeContextHash &child_hash : children_hashes_) {
499 GeoTreeLog &child_log = root_log_->get_tree_log(child_hash);
500 if (child_log.tree_loggers_.is_empty()) {
501 continue;
502 }
503 const GeoTreeLogger &first_child_logger = *child_log.tree_loggers_[0];
505 const std::optional<int32_t> &caller_node_id = first_child_logger.parent_node_id;
506 if (tree && caller_node_id) {
507 if (const bNode *caller_node = tree->node_by_id(*caller_node_id)) {
508 propagation = NodeWarningPropagation(caller_node->warning_propagation);
509 }
510 }
511 child_log.ensure_node_warnings(orig_tree_by_session_uid);
512 if (caller_node_id.has_value()) {
513 this->nodes.lookup_or_add_default(*caller_node_id)
514 .warnings.add_multiple(child_log.all_warnings);
515 }
516 for (const NodeWarning &warning : child_log.all_warnings) {
517 if (warning_is_propagated(propagation, warning.type)) {
518 this->all_warnings.add(warning);
519 continue;
520 }
521 }
522 }
523 reduced_node_warnings_ = true;
524}
525
527{
528 if (reduced_execution_times_) {
529 return;
530 }
531 for (GeoTreeLogger *tree_logger : tree_loggers_) {
532 for (const GeoTreeLogger::NodeExecutionTime &timings : tree_logger->node_execution_times) {
533 const std::chrono::nanoseconds duration = timings.end - timings.start;
534 this->nodes.lookup_or_add_default_as(timings.node_id).execution_time += duration;
535 }
536 this->execution_time += tree_logger->execution_time;
537 }
538 reduced_execution_times_ = true;
539}
540
542{
543 if (reduced_socket_values_) {
544 return;
545 }
546 for (GeoTreeLogger *tree_logger : tree_loggers_) {
547 for (const GeoTreeLogger::SocketValueLog &value_log_data : tree_logger->input_socket_values) {
548 this->nodes.lookup_or_add_as(value_log_data.node_id)
549 .input_values_.add(value_log_data.socket_index, value_log_data.value.get());
550 }
551 for (const GeoTreeLogger::SocketValueLog &value_log_data : tree_logger->output_socket_values) {
552 this->nodes.lookup_or_add_as(value_log_data.node_id)
553 .output_values_.add(value_log_data.socket_index, value_log_data.value.get());
554 }
555 }
556 reduced_socket_values_ = true;
557}
558
560{
561 if (reduced_viewer_node_logs_) {
562 return;
563 }
564 for (GeoTreeLogger *tree_logger : tree_loggers_) {
565 for (const GeoTreeLogger::ViewerNodeLogWithNode &viewer_log : tree_logger->viewer_node_logs) {
566 this->viewer_node_logs.add(viewer_log.node_id, viewer_log.viewer_log.get());
567 }
568 }
569 reduced_viewer_node_logs_ = true;
570}
571
573{
574 if (reduced_existing_attributes_) {
575 return;
576 }
577 this->ensure_socket_values();
578
579 auto handle_value_log = [&](const ValueLog &value_log) {
580 const GeometryInfoLog *geo_log = dynamic_cast<const GeometryInfoLog *>(&value_log);
581 if (geo_log == nullptr) {
582 return;
583 }
584 for (const GeometryAttributeInfo &attribute : geo_log->attributes) {
585 this->existing_attributes.append(&attribute);
586 }
587 };
588
589 for (const GeoNodeLog &node_log : this->nodes.values()) {
590 for (const ValueLog *value_log : node_log.input_values_.values()) {
591 handle_value_log(*value_log);
592 }
593 for (const ValueLog *value_log : node_log.output_values_.values()) {
594 handle_value_log(*value_log);
595 }
596 }
597 reduced_existing_attributes_ = true;
598}
599
601{
602 if (reduced_used_named_attributes_) {
603 return;
604 }
605
606 auto add_attribute = [&](const int32_t node_id,
607 const StringRefNull attribute_name,
608 const NamedAttributeUsage &usage) {
609 this->nodes.lookup_or_add_default(node_id).used_named_attributes.lookup_or_add(attribute_name,
610 usage) |= usage;
611 this->used_named_attributes.lookup_or_add_as(attribute_name, usage) |= usage;
612 };
613
614 for (GeoTreeLogger *tree_logger : tree_loggers_) {
615 for (const GeoTreeLogger::AttributeUsageWithNode &item : tree_logger->used_named_attributes) {
616 add_attribute(item.node_id, item.attribute_name, item.usage);
617 }
618 }
619 for (const ComputeContextHash &child_hash : children_hashes_) {
620 GeoTreeLog &child_log = root_log_->get_tree_log(child_hash);
621 if (child_log.tree_loggers_.is_empty()) {
622 continue;
623 }
625 if (const std::optional<int32_t> &parent_node_id = child_log.tree_loggers_[0]->parent_node_id)
626 {
627 for (const auto item : child_log.used_named_attributes.items()) {
628 add_attribute(*parent_node_id, item.key, item.value);
629 }
630 }
631 }
632 reduced_used_named_attributes_ = true;
633}
634
636{
637 if (reduced_debug_messages_) {
638 return;
639 }
640 for (GeoTreeLogger *tree_logger : tree_loggers_) {
641 for (const GeoTreeLogger::DebugMessage &debug_message : tree_logger->debug_messages) {
642 this->nodes.lookup_or_add_as(debug_message.node_id)
643 .debug_messages.append(debug_message.message);
644 }
645 }
646 reduced_debug_messages_ = true;
647}
648
650{
651 if (reduced_evaluated_gizmo_nodes_) {
652 return;
653 }
654 for (const GeoTreeLogger *tree_logger : tree_loggers_) {
655 for (const GeoTreeLogger::EvaluatedGizmoNode &evaluated_gizmo :
656 tree_logger->evaluated_gizmo_nodes)
657 {
658 this->evaluated_gizmo_nodes.add(evaluated_gizmo.node_id);
659 }
660 }
661
662 reduced_evaluated_gizmo_nodes_ = true;
663}
664
666{
667 if (reduced_layer_names_) {
668 return;
669 }
670
671 this->ensure_socket_values();
672
673 auto handle_value_log = [&](const ValueLog &value_log) {
674 const GeometryInfoLog *geo_log = dynamic_cast<const GeometryInfoLog *>(&value_log);
675 if (geo_log == nullptr || !geo_log->grease_pencil_info.has_value()) {
676 return;
677 }
678 for (const std::string &name : geo_log->grease_pencil_info->layer_names) {
679 this->all_layer_names.append(name);
680 }
681 };
682
683 for (const GeoNodeLog &node_log : this->nodes.values()) {
684 for (const ValueLog *value_log : node_log.input_values_.values()) {
685 handle_value_log(*value_log);
686 }
687 for (const ValueLog *value_log : node_log.output_values_.values()) {
688 handle_value_log(*value_log);
689 }
690 }
691
692 reduced_layer_names_ = true;
693}
694
696{
702
703 BLI_assert(reduced_socket_values_);
704 if (query_socket.is_multi_input()) {
705 /* Not supported currently. */
706 return nullptr;
707 }
708
709 Set<const bNodeSocket *> added_sockets;
710 Stack<const bNodeSocket *> sockets_to_check;
711 sockets_to_check.push(&query_socket);
712 added_sockets.add(&query_socket);
713 const bNodeTree &tree = query_socket.owner_tree();
714
715 while (!sockets_to_check.is_empty()) {
716 const bNodeSocket &socket = *sockets_to_check.pop();
717 const bNode &node = socket.owner_node();
718 if (GeoNodeLog *node_log = this->nodes.lookup_ptr(node.identifier)) {
719 ValueLog *value_log = socket.is_input() ?
720 node_log->input_values_.lookup_default(socket.index(), nullptr) :
721 node_log->output_values_.lookup_default(socket.index(), nullptr);
722 if (value_log != nullptr) {
723 return value_log;
724 }
725 }
726
727 if (socket.is_input()) {
728 const Span<const bNodeLink *> links = socket.directly_linked_links();
729 for (const bNodeLink *link : links) {
730 const bNodeSocket &from_socket = *link->fromsock;
731 if (added_sockets.add(&from_socket)) {
732 sockets_to_check.push(&from_socket);
733 }
734 }
735 }
736 else {
737 if (node.is_reroute()) {
738 const bNodeSocket &input_socket = node.input_socket(0);
739 if (added_sockets.add(&input_socket)) {
740 sockets_to_check.push(&input_socket);
741 }
742 const Span<const bNodeLink *> links = input_socket.directly_linked_links();
743 for (const bNodeLink *link : links) {
744 const bNodeSocket &from_socket = *link->fromsock;
745 if (added_sockets.add(&from_socket)) {
746 sockets_to_check.push(&from_socket);
747 }
748 }
749 }
750 else if (node.is_muted()) {
751 if (const bNodeSocket *input_socket = socket.internal_link_input()) {
752 if (added_sockets.add(input_socket)) {
753 sockets_to_check.push(input_socket);
754 }
755 const Span<const bNodeLink *> links = input_socket->directly_linked_links();
756 for (const bNodeLink *link : links) {
757 const bNodeSocket &from_socket = *link->fromsock;
758 if (added_sockets.add(&from_socket)) {
759 sockets_to_check.push(&from_socket);
760 }
761 }
762 }
763 }
764 else if (node.is_group_input()) {
765 const int index = socket.index();
766 /* Check if the value is stored for any other group input node. */
767 for (const bNode *other_group_input : tree.group_input_nodes()) {
768 const bNodeSocket &other_socket = other_group_input->output_socket(index);
769 if (added_sockets.add(&other_socket)) {
770 sockets_to_check.push(&other_socket);
771 }
772 }
773 }
774 }
775 }
776
777 return nullptr;
778}
779
781 const CPPType &dst_type,
782 void *dst)
783{
784 const void *src_value = value_log.value.get();
785 if (!src_value) {
786 return false;
787 }
789 const CPPType &src_type = *value_log.value.type();
790 if (!conversions.is_convertible(src_type, dst_type) && src_type != dst_type) {
791 return false;
792 }
793 dst_type.destruct(dst);
794 conversions.convert_to_uninitialized(src_type, dst_type, src_value, dst);
795 return true;
796}
797
798static std::optional<uint32_t> get_original_session_uid(const ID *id)
799{
800 if (!id) {
801 return {};
802 }
803 if (DEG_is_original(id)) {
804 return id->session_uid;
805 }
806 if (const ID *id_orig = DEG_get_original(id)) {
807 return id_orig->session_uid;
808 }
809 return {};
810}
811
813{
814 LocalData &local_data = data_per_thread_.local();
816 local_data.tree_logger_by_context;
817 destruct_ptr<GeoTreeLogger> &tree_logger_ptr = local_tree_loggers.lookup_or_add_default(
818 compute_context.hash());
819 if (tree_logger_ptr) {
820 return *tree_logger_ptr;
821 }
822 tree_logger_ptr = local_data.allocator.construct<GeoTreeLogger>();
823 GeoTreeLogger &tree_logger = *tree_logger_ptr;
824 tree_logger.allocator = &local_data.allocator;
825 const ComputeContext *parent_compute_context = compute_context.parent();
826 std::optional<uint32_t> parent_tree_session_uid;
827 if (parent_compute_context != nullptr) {
828 tree_logger.parent_hash = parent_compute_context->hash();
829 GeoTreeLogger &parent_logger = this->get_local_tree_logger(*parent_compute_context);
830 parent_logger.children_hashes.append(compute_context.hash());
831 parent_tree_session_uid = parent_logger.tree_orig_session_uid;
832 }
833 if (const auto *context = dynamic_cast<const bke::GroupNodeComputeContext *>(&compute_context)) {
834 tree_logger.parent_node_id.emplace(context->node_id());
835 if (const bNode *caller_node = context->node()) {
836 tree_logger.tree_orig_session_uid = get_original_session_uid(caller_node->id);
837 }
838 }
839 else if (const auto *context = dynamic_cast<const bke::RepeatZoneComputeContext *>(
840 &compute_context))
841 {
842 tree_logger.parent_node_id.emplace(context->output_node_id());
843 tree_logger.tree_orig_session_uid = parent_tree_session_uid;
844 }
845 else if (const auto *context =
847 &compute_context))
848 {
849 tree_logger.parent_node_id.emplace(context->output_node_id());
850 tree_logger.tree_orig_session_uid = parent_tree_session_uid;
851 }
852 else if (const auto *context = dynamic_cast<const bke::SimulationZoneComputeContext *>(
853 &compute_context))
854 {
855 tree_logger.parent_node_id.emplace(context->output_node_id());
856 tree_logger.tree_orig_session_uid = parent_tree_session_uid;
857 }
858 else if (const auto *context = dynamic_cast<const bke::EvaluateClosureComputeContext *>(
859 &compute_context))
860 {
861 tree_logger.parent_node_id.emplace(context->node_id());
862 const std::optional<nodes::ClosureSourceLocation> &location =
863 context->closure_source_location();
864 if (location.has_value()) {
865 BLI_assert(DEG_is_evaluated(location->tree));
866 tree_logger.tree_orig_session_uid = DEG_get_original_id(&location->tree->id)->session_uid;
867 }
868 }
869 else if (const auto *context = dynamic_cast<const bke::ModifierComputeContext *>(
870 &compute_context))
871 {
872 if (const NodesModifierData *nmd = context->nmd()) {
873 tree_logger.tree_orig_session_uid = get_original_session_uid(
874 reinterpret_cast<const ID *>(nmd->node_group));
875 }
876 }
877 else if (const auto *context = dynamic_cast<const bke::OperatorComputeContext *>(
878 &compute_context))
879 {
880 if (const bNodeTree *tree = context->tree()) {
881 tree_logger.tree_orig_session_uid = tree->id.session_uid;
882 }
883 }
884 return tree_logger;
885}
886
888{
889 GeoTreeLog &reduced_tree_log = *tree_logs_.lookup_or_add_cb(compute_context_hash, [&]() {
890 Vector<GeoTreeLogger *> tree_logs;
891 for (LocalData &local_data : data_per_thread_) {
892 destruct_ptr<GeoTreeLogger> *tree_log = local_data.tree_logger_by_context.lookup_ptr(
893 compute_context_hash);
894 if (tree_log != nullptr) {
895 tree_logs.append(tree_log->get());
896 }
897 }
898 return std::make_unique<GeoTreeLog>(this, std::move(tree_logs));
899 });
900 return reduced_tree_log;
901}
902
904 const bNodeTreeZone &zone,
905 bke::ComputeContextCache &compute_context_cache,
906 const ComputeContext *current,
908{
909 current = ed::space_node::compute_context_for_zone(zone, compute_context_cache, current);
910 if (!current) {
911 return;
912 }
913 r_hash_by_zone.add_new(&zone, current->hash());
914 for (const bNodeTreeZone *child_zone : zone.child_zones) {
915 find_tree_zone_hash_recursive(*child_zone, compute_context_cache, current, r_hash_by_zone);
916 }
917}
918
921 bke::ComputeContextCache &compute_context_cache)
922{
924 snode, compute_context_cache);
925 if (!current) {
926 return {};
927 }
928
929 const bNodeTreeZones *tree_zones = snode.edittree->zones();
930 if (tree_zones == nullptr) {
931 return {};
932 }
934 hash_by_zone.add_new(nullptr, current->hash());
935 for (const bNodeTreeZone *zone : tree_zones->root_zones) {
936 find_tree_zone_hash_recursive(*zone, compute_context_cache, current, hash_by_zone);
937 }
938 return hash_by_zone;
939}
940
941static GeoNodesLog *get_root_log(const SpaceNode &snode)
942{
943 if (!ED_node_is_geometry(&snode)) {
944 return nullptr;
945 }
946
949 std::optional<ed::space_node::ObjectAndModifier> object_and_modifier =
951 if (!object_and_modifier) {
952 return {};
953 }
954 return object_and_modifier->nmd->runtime->eval_log.get();
955 }
956 case SNODE_GEOMETRY_TOOL: {
959 if (snode.selected_node_group->id.name + 2 != log.node_group_name) {
960 return {};
961 }
962 return log.log.get();
963 }
964 }
965 return nullptr;
966}
967
969{
970 GeoNodesLog *log = get_root_log(snode);
971 if (!log) {
972 return {};
973 }
974 bke::ComputeContextCache compute_context_cache;
976 GeoNodesLog::get_context_hash_by_zone_for_node_editor(snode, compute_context_cache);
978 for (const auto item : hash_by_zone.items()) {
979 GeoTreeLog &tree_log = log->get_tree_log(item.value);
980 tree_logs_by_zone.add(item.key, &tree_log);
981 }
982 return {tree_logs_by_zone};
983}
984
986{
987 const std::optional<ed::viewer_path::ViewerPathForGeometryNodesViewer> parsed_path =
989 if (!parsed_path.has_value()) {
990 return nullptr;
991 }
992 const Object *object = parsed_path->object;
993 NodesModifierData *nmd = nullptr;
994 LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
995 if (md->persistent_uid == parsed_path->modifier_uid) {
996 if (md->type == eModifierType_Nodes) {
997 nmd = reinterpret_cast<NodesModifierData *>(md);
998 }
999 }
1000 }
1001 if (nmd == nullptr) {
1002 return nullptr;
1003 }
1004 if (!nmd->runtime->eval_log) {
1005 return nullptr;
1006 }
1007 nodes::geo_eval_log::GeoNodesLog *root_log = nmd->runtime->eval_log.get();
1008
1009 bke::ComputeContextCache compute_context_cache;
1010 const ComputeContext *compute_context = &compute_context_cache.for_modifier(nullptr, *nmd);
1011 for (const ViewerPathElem *elem : parsed_path->node_path) {
1013 *elem, compute_context_cache, compute_context);
1014 if (!compute_context) {
1015 return nullptr;
1016 }
1017 }
1018 const ComputeContextHash context_hash = compute_context->hash();
1019 nodes::geo_eval_log::GeoTreeLog &tree_log = root_log->get_tree_log(context_hash);
1020 tree_log.ensure_viewer_node_logs();
1021
1022 const ViewerNodeLog *viewer_log = tree_log.viewer_node_logs.lookup_default(
1023 parsed_path->viewer_node_id, nullptr);
1024 return viewer_log;
1025}
1026
1029 : tree_logs_by_zone_(std::move(tree_logs_by_zone))
1030{
1031}
1032
1034{
1035 return tree_logs_by_zone_.lookup_default(zone, nullptr);
1036}
1037
1039{
1040 const bNodeTree &tree = node.owner_tree();
1041 const bke::bNodeTreeZones *zones = tree.zones();
1042 if (!zones) {
1043 return nullptr;
1044 }
1045 const bke::bNodeTreeZone *zone = zones->get_zone_by_node(node.identifier);
1046 return this->get_main_tree_log(zone);
1047}
1048
1050{
1051 const bNodeTree &tree = socket.owner_tree();
1052 const bke::bNodeTreeZones *zones = tree.zones();
1053 if (!zones) {
1054 return nullptr;
1055 }
1056 const bke::bNodeTreeZone *zone = zones->get_zone_by_socket(socket);
1057 return this->get_main_tree_log(zone);
1058}
1059
1061{
1062 for (GeoTreeLog *tree_log : tree_logs_by_zone_.values()) {
1063 if (tree_log) {
1064 callback(*tree_log);
1065 }
1066 }
1067}
1068
1069} // namespace blender::nodes::geo_eval_log
Low-level operations for curves.
Low-level operations for grease pencil.
void * BKE_id_new_nomain(short type, const char *name)
Definition lib_id.cc:1519
@ IDWALK_RET_NOP
void BKE_library_foreach_ID_link(Main *bmain, ID *id, blender::FunctionRef< LibraryIDLinkCallback > callback, void *user_data, LibraryForeachIDFlag flag)
Definition lib_query.cc:431
@ IDWALK_RECURSE
@ IDWALK_READONLY
#define FOREACH_NODETREE_END
Definition BKE_node.hh:881
#define FOREACH_NODETREE_BEGIN(bmain, _nodetree, _id)
Definition BKE_node.hh:871
@ RPT_ERROR
Definition BKE_report.hh:39
Volume data-block.
void BKE_volume_grid_add(Volume *volume, const blender::bke::VolumeGridData &grid)
int BKE_volume_num_grids(const Volume *volume)
const blender::bke::VolumeGridData * BKE_volume_grid_get(const Volume *volume, int grid_index)
VolumeGridType
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
const char * BLI_str_find_prev_char_utf8(const char *p, const char *str_start) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1
#define UNUSED_VARS(...)
#define ELEM(...)
bool DEG_is_original(const T *id)
bool DEG_is_evaluated(const T *id)
ID * DEG_get_original_id(ID *id)
T * DEG_get_original(T *id)
@ eModifierType_Nodes
@ SOCK_IN
@ SOCK_CLOSURE
@ SOCK_BUNDLE
@ SOCK_GEOMETRY
NodeWarningPropagation
@ NODE_WARNING_PROPAGATION_NONE
@ NODE_WARNING_PROPAGATION_ONLY_ERRORS_AND_WARNINGS
@ NODE_WARNING_PROPAGATION_ONLY_ERRORS
@ NODE_WARNING_PROPAGATION_ALL
SpaceNodeGeometryNodesType
@ SNODE_GEOMETRY_MODIFIER
@ SNODE_GEOMETRY_TOOL
bool ED_node_is_geometry(const SpaceNode *snode)
Definition node_edit.cc:502
BMesh const char void * data
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
SIMD_FORCE_INLINE btVector3 operator()(const btVector3 &x) const
Return the transform of the vector.
Definition btTransform.h:90
GeometryInfoLog(const bke::GeometrySet &geometry_set)
void append(const T &value)
bool is() const
void copy_construct(const void *src, void *dst) const
void destruct(void *ptr) const
const ComputeContext * parent() const
const ComputeContextHash & hash() const
const CPPType * type() const
const CPPType * type() const
const void * get() const
destruct_ptr< T > construct(Args &&...args)
StringRefNull copy_string(StringRef str)
Value & lookup_or_add_default(const Key &key)
Definition BLI_map.hh:639
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:295
Value lookup_default(const Key &key, const Value &default_value) const
Definition BLI_map.hh:570
void add_new(const Key &key, const Value &value)
Definition BLI_map.hh:265
ItemIterator items() const &
Definition BLI_map.hh:902
bool add(const Key &key)
Definition BLI_set.hh:248
bool is_empty() const
Definition BLI_stack.hh:308
void push(const T &value)
Definition BLI_stack.hh:213
void append(const T &value)
void extend(Span< T > array)
const ModifierComputeContext & for_modifier(const ComputeContext *parent, const NodesModifierData &nmd)
void convert_to_uninitialized(const CPPType &from_type, const CPPType &to_type, const void *from_value, void *to_value) const
bool is_convertible(const CPPType &from_type, const CPPType &to_type) const
bool valid_for_socket(eNodeSocketDatatype socket_type) const
Vector< bNodeTreeZone * > child_zones
Vector< bNodeTreeZone * > root_zones
const bNodeTreeZone * get_zone_by_node(const int32_t node_id) const
const bNodeTreeZone * get_zone_by_socket(const bNodeSocket &socket) const
const FieldNode & node() const
Definition FN_field.hh:135
CustomIDVectorSet< Item, ItemKeyGetter > inputs
CustomIDVectorSet< Item, ItemKeyGetter > outputs
ClosureValueLog(Vector< Item > inputs, Vector< Item > outputs, const std::optional< ClosureSourceLocation > &source_location, std::shared_ptr< ClosureEvalLog > eval_log)
GeoTreeLog * get_main_tree_log(const bke::bNodeTreeZone *zone) const
ContextualGeoTreeLogs(Map< const bke::bNodeTreeZone *, GeoTreeLog * > tree_logs_by_zone={})
void foreach_tree_log(FunctionRef< void(GeoTreeLog &)> callback) const
static ContextualGeoTreeLogs get_contextual_tree_logs(const SpaceNode &snode)
static Map< const bke::bNodeTreeZone *, ComputeContextHash > get_context_hash_by_zone_for_node_editor(const SpaceNode &snode, bke::ComputeContextCache &compute_context_cache)
static const ViewerNodeLog * find_viewer_node_log_for_path(const ViewerPath &viewer_path)
GeoTreeLogger & get_local_tree_logger(const ComputeContext &compute_context)
GeoTreeLog & get_tree_log(const ComputeContextHash &compute_context_hash)
Vector< const GeometryAttributeInfo * > existing_attributes
void ensure_node_warnings(const NodesModifierData &nmd)
bool try_convert_primitive_socket_value(const GenericValueLog &value_log, const CPPType &dst_type, void *dst)
Map< int32_t, ViewerNodeLog *, 0 > viewer_node_logs
Map< StringRefNull, NamedAttributeUsage > used_named_attributes
GeoTreeLog(GeoNodesLog *root_log, Vector< GeoTreeLogger * > tree_loggers)
ValueLog * find_socket_value_log(const bNodeSocket &query_socket)
linear_allocator::ChunkedList< SocketValueLog, 16 > input_socket_values
void log_value(const bNode &node, const bNodeSocket &socket, GPointer value)
linear_allocator::ChunkedList< SocketValueLog, 16 > output_socket_values
std::optional< GreasePencilInfo > grease_pencil_info
Vector< bke::GeometryComponent::Type > component_types
const bke::GeometrySet * main_geometry() const
CustomIDVectorSet< Item, ItemIdentifierGetter > items
KDTree_3d * tree
#define log
VolumeGridType get_type(const VolumeGridData &grid)
bool attribute_name_is_anonymous(const StringRef name)
const DataTypeConversions & get_implicit_type_conversions()
const GeoOperatorLog & node_group_operator_static_eval_log()
const ComputeContext * compute_context_for_edittree(const SpaceNode &snode, bke::ComputeContextCache &compute_context_cache)
const ComputeContext * compute_context_for_zone(const bke::bNodeTreeZone &zone, bke::ComputeContextCache &compute_context_cache, const ComputeContext *parent_compute_context)
std::optional< ObjectAndModifier > get_modifier_for_node_editor(const SpaceNode &snode)
std::optional< ViewerPathForGeometryNodesViewer > parse_geometry_nodes_viewer(const ViewerPath &viewer_path)
const ComputeContext * compute_context_for_viewer_path_elem(const ViewerPathElem &elem, bke::ComputeContextCache &compute_context_cache, const ComputeContext *parent_compute_context)
static void find_tree_zone_hash_recursive(const bNodeTreeZone &zone, bke::ComputeContextCache &compute_context_cache, const ComputeContext *current, Map< const bNodeTreeZone *, ComputeContextHash > &r_hash_by_zone)
static std::optional< uint32_t > get_original_session_uid(const ID *id)
static GeoNodesLog * get_root_log(const SpaceNode &snode)
static bool warning_is_propagated(const NodeWarningPropagation propagation, const NodeWarningType warning_type)
ImplicitSharingPtr< Bundle > BundlePtr
ImplicitSharingPtr< List > ListPtr
ImplicitSharingPtr< Closure > ClosurePtr
std::unique_ptr< T, DestructValueAtAddress< T > > destruct_ptr
static blender::bke::bNodeSocketTemplate outputs[]
static blender::bke::bNodeSocketTemplate inputs[]
#define hash
Definition noise_c.cc:154
const char * name
Definition DNA_ID.h:414
char name[258]
Definition DNA_ID.h:432
unsigned int session_uid
Definition DNA_ID.h:462
struct bNodeTree * node_group
NodesModifierRuntimeHandle * runtime
ListBase modifiers
short type
Definition BKE_report.hh:66
const char * message
Definition BKE_report.hh:71
struct bNodeTree * selected_node_group
char node_tree_sub_type
struct bNodeTree * edittree
int32_t identifier
Vector< const GeometryComponent * > get_components() const
static GeometrySet from_volume(Volume *volume, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
void attribute_foreach(Span< GeometryComponent::Type > component_types, bool include_instances, AttributeForeachCallback callback) const
NodeWarning(NodeWarningType type, StringRef message)
StringLog(StringRef string, LinearAllocator<> &allocator)
i
Definition text_draw.cc:230