Blender V4.3
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
7
9#include "BKE_curves.hh"
11#include "BKE_node_runtime.hh"
14#include "BKE_volume.hh"
15#include "BKE_volume_openvdb.hh"
16
18#include "DNA_modifier_types.h"
19#include "DNA_space_types.h"
20
21#include "ED_geometry.hh"
22#include "ED_node.hh"
23#include "ED_viewer_path.hh"
24
25#include "MOD_nodes.hh"
26
27#include "UI_resources.hh"
28
30
31using bke::bNodeTreeZone;
32using bke::bNodeTreeZones;
33using fn::FieldInput;
34using fn::FieldInputs;
35
37{
38 this->value.destruct();
39}
40
41FieldInfoLog::FieldInfoLog(const GField &field) : type(field.cpp_type())
42{
43 const std::shared_ptr<const fn::FieldInputs> &field_input_nodes = field.node().field_inputs();
44
45 /* Put the deduplicated field inputs into a vector so that they can be sorted below. */
47 if (field_input_nodes) {
48 field_inputs.extend(field_input_nodes->deduplicated_nodes.begin(),
49 field_input_nodes->deduplicated_nodes.end());
50 }
51
52 std::sort(
53 field_inputs.begin(), field_inputs.end(), [](const FieldInput &a, const FieldInput &b) {
54 const int index_a = int(a.category());
55 const int index_b = int(b.category());
56 if (index_a == index_b) {
57 return a.socket_inspection_name().size() < b.socket_inspection_name().size();
58 }
59 return index_a < index_b;
60 });
61
62 for (const FieldInput &field_input : field_inputs) {
63 this->input_tooltips.append(field_input.socket_inspection_name());
64 }
65}
66
67GeometryInfoLog::GeometryInfoLog(const bke::GeometrySet &geometry_set)
68{
69 this->name = geometry_set.name;
70
71 static std::array all_component_types = {bke::GeometryComponent::Type::Curve,
77
78 /* Keep track handled attribute names to make sure that we do not return the same name twice.
79 * Currently #GeometrySet::attribute_foreach does not do that. Note that this will merge
80 * attributes with the same name but different domains or data types on separate components. */
81 Set<StringRef> names;
82
83 geometry_set.attribute_foreach(
84 all_component_types,
85 true,
86 [&](const StringRef attribute_id,
87 const bke::AttributeMetaData &meta_data,
88 const bke::GeometryComponent & /*component*/) {
89 if (!bke::attribute_name_is_anonymous(attribute_id) && names.add(attribute_id)) {
90 this->attributes.append({attribute_id, meta_data.domain, meta_data.data_type});
91 }
92 });
93
94 for (const bke::GeometryComponent *component : geometry_set.get_components()) {
95 this->component_types.append(component->type());
96 switch (component->type()) {
98 const auto &mesh_component = *static_cast<const bke::MeshComponent *>(component);
99 MeshInfo &info = this->mesh_info.emplace();
100 info.verts_num = mesh_component.attribute_domain_size(bke::AttrDomain::Point);
101 info.edges_num = mesh_component.attribute_domain_size(bke::AttrDomain::Edge);
102 info.faces_num = mesh_component.attribute_domain_size(bke::AttrDomain::Face);
103 break;
104 }
106 const auto &curve_component = *static_cast<const bke::CurveComponent *>(component);
107 CurveInfo &info = this->curve_info.emplace();
108 info.points_num = curve_component.attribute_domain_size(bke::AttrDomain::Point);
109 info.splines_num = curve_component.attribute_domain_size(bke::AttrDomain::Curve);
110 break;
111 }
113 const auto &pointcloud_component = *static_cast<const bke::PointCloudComponent *>(
114 component);
115 PointCloudInfo &info = this->pointcloud_info.emplace();
116 info.points_num = pointcloud_component.attribute_domain_size(bke::AttrDomain::Point);
117 break;
118 }
120 const auto &instances_component = *static_cast<const bke::InstancesComponent *>(component);
121 InstancesInfo &info = this->instances_info.emplace();
122 info.instances_num = instances_component.attribute_domain_size(bke::AttrDomain::Instance);
123 break;
124 }
126 const auto &edit_component = *static_cast<const bke::GeometryComponentEditData *>(
127 component);
128 if (!this->edit_data_info) {
129 this->edit_data_info.emplace(EditDataInfo());
130 }
131 EditDataInfo &info = *this->edit_data_info;
132 if (const bke::CurvesEditHints *curve_edit_hints = edit_component.curves_edit_hints_.get())
133 {
134 info.has_deform_matrices = curve_edit_hints->deform_mats.has_value();
135 info.has_deformed_positions = curve_edit_hints->positions().has_value();
136 }
137 if (const bke::GizmoEditHints *gizmo_edit_hints = edit_component.gizmo_edit_hints_.get()) {
138 info.gizmo_transforms_num = gizmo_edit_hints->gizmo_transforms.size();
139 }
140 break;
141 }
143 const auto &volume_component = *static_cast<const bke::VolumeComponent *>(component);
144 if (const Volume *volume = volume_component.get()) {
145 VolumeInfo &info = this->volume_info.emplace();
146 info.grids_num = BKE_volume_num_grids(volume);
147 }
148 break;
149 }
151 const auto &grease_pencil_component = *static_cast<const bke::GreasePencilComponent *>(
152 component);
153 if (const GreasePencil *grease_pencil = grease_pencil_component.get()) {
154 GreasePencilInfo &info = this->grease_pencil_info.emplace(GreasePencilInfo());
155 info.layers_num = grease_pencil->layers().size();
156 }
157 break;
158 }
159 }
160 }
161}
162
163#ifdef WITH_OPENVDB
164struct GridIsEmptyOp {
165 const openvdb::GridBase &base_grid;
166 bool result = false;
167
168 template<typename GridType> bool operator()()
169 {
170 result = static_cast<const GridType &>(base_grid).empty();
171 return true;
172 }
173};
174#endif /* WITH_OPENVDB */
175
176GeometryInfoLog::GeometryInfoLog(const bke::GVolumeGrid &grid)
177{
178 GridInfo &info = this->grid_info.emplace();
179#ifdef WITH_OPENVDB
180 bke::VolumeTreeAccessToken token;
181 const openvdb::GridBase &vdb_grid = grid->grid(token);
182 const VolumeGridType grid_type = bke::volume_grid::get_type(vdb_grid);
183
184 GridIsEmptyOp is_empty_op{vdb_grid};
185 if (BKE_volume_grid_type_operation(grid_type, is_empty_op)) {
186 info.is_empty = is_empty_op.result;
187 }
188 else {
189 info.is_empty = true;
190 }
191#else
192 UNUSED_VARS(grid);
193 info.is_empty = true;
194#endif
195}
196
197/* Avoid generating these in every translation unit. */
198GeoModifierLog::GeoModifierLog() = default;
199GeoModifierLog::~GeoModifierLog() = default;
200
201GeoTreeLogger::GeoTreeLogger() = default;
202GeoTreeLogger::~GeoTreeLogger() = default;
203
204GeoNodeLog::GeoNodeLog() = default;
205GeoNodeLog::~GeoNodeLog() = default;
206
207GeoTreeLog::GeoTreeLog(GeoModifierLog *modifier_log, Vector<GeoTreeLogger *> tree_loggers)
208 : modifier_log_(modifier_log), tree_loggers_(std::move(tree_loggers))
209{
210 for (GeoTreeLogger *tree_logger : tree_loggers_) {
211 for (const ComputeContextHash &hash : tree_logger->children_hashes) {
212 children_hashes_.add(hash);
213 }
214 }
215}
216
217GeoTreeLog::~GeoTreeLog() = default;
218
219void GeoTreeLogger::log_value(const bNode &node, const bNodeSocket &socket, const GPointer value)
220{
221 const CPPType &type = *value.type();
222
223 auto store_logged_value = [&](destruct_ptr<ValueLog> value_log) {
224 auto &socket_values = socket.in_out == SOCK_IN ? this->input_socket_values :
226 socket_values.append(*this->allocator,
227 {node.identifier, socket.index(), std::move(value_log)});
228 };
229
230 auto log_generic_value = [&](const CPPType &type, const void *value) {
231 void *buffer = this->allocator->allocate(type.size(), type.alignment());
232 type.copy_construct(value, buffer);
233 store_logged_value(this->allocator->construct<GenericValueLog>(GMutablePointer{type, buffer}));
234 };
235
236 if (type.is<bke::GeometrySet>()) {
237 const bke::GeometrySet &geometry = *value.get<bke::GeometrySet>();
238 store_logged_value(this->allocator->construct<GeometryInfoLog>(geometry));
239 }
240 else if (type.is<bke::SocketValueVariant>()) {
241 bke::SocketValueVariant value_variant = *value.get<bke::SocketValueVariant>();
242 if (value_variant.is_context_dependent_field()) {
243 const GField field = value_variant.extract<GField>();
244 store_logged_value(this->allocator->construct<FieldInfoLog>(field));
245 }
246#ifdef WITH_OPENVDB
247 else if (value_variant.is_volume_grid()) {
248 const bke::GVolumeGrid grid = value_variant.extract<bke::GVolumeGrid>();
249 store_logged_value(this->allocator->construct<GeometryInfoLog>(grid));
250 }
251#endif
252 else {
253 value_variant.convert_to_single();
254 const GPointer value = value_variant.get_single_ptr();
255 log_generic_value(*value.type(), value.get());
256 }
257 }
258 else {
259 log_generic_value(type, value.get());
260 }
261}
262
263void GeoTreeLogger::log_viewer_node(const bNode &viewer_node, bke::GeometrySet geometry)
264{
266 log->geometry = std::move(geometry);
267 log->geometry.ensure_owns_direct_data();
268 this->viewer_node_logs.append(*this->allocator, {viewer_node.identifier, std::move(log)});
269}
270
271static bool warning_is_propagated(const NodeWarningPropagation propagation,
272 const NodeWarningType warning_type)
273{
274 switch (propagation) {
276 return true;
278 return false;
280 return warning_type == NodeWarningType::Error;
283 }
285 return true;
286}
287
289{
290 if (reduced_node_warnings_) {
291 return;
292 }
293
294 for (GeoTreeLogger *tree_logger : tree_loggers_) {
295 for (const GeoTreeLogger::WarningWithNode &warning : tree_logger->node_warnings) {
297 if (tree) {
298 if (const bNode *node = tree->node_by_id(warning.node_id)) {
299 propagation = NodeWarningPropagation(node->warning_propagation);
300 }
301 }
302 this->nodes.lookup_or_add_default(warning.node_id).warnings.add(warning.warning);
303 if (warning_is_propagated(propagation, warning.warning.type)) {
304 this->all_warnings.add(warning.warning);
305 }
306 }
307 }
308 for (const ComputeContextHash &child_hash : children_hashes_) {
309 GeoTreeLog &child_log = modifier_log_->get_tree_log(child_hash);
310 if (child_log.tree_loggers_.is_empty()) {
311 continue;
312 }
314 const bNodeTree *child_tree = nullptr;
315 const std::optional<int32_t> &parent_node_id = child_log.tree_loggers_[0]->parent_node_id;
316 if (tree && parent_node_id) {
317 if (const bNode *node = tree->node_by_id(*parent_node_id)) {
318 propagation = NodeWarningPropagation(node->warning_propagation);
319 if (node->is_group() && node->id) {
320 child_tree = reinterpret_cast<const bNodeTree *>(node->id);
321 }
322 else if (bke::all_zone_output_node_types().contains(node->type)) {
323 child_tree = tree;
324 }
325 }
326 }
327 child_log.ensure_node_warnings(child_tree);
328 if (parent_node_id.has_value()) {
329 this->nodes.lookup_or_add_default(*parent_node_id)
330 .warnings.add_multiple(child_log.all_warnings);
331 }
332 for (const NodeWarning &warning : child_log.all_warnings) {
333 if (warning_is_propagated(propagation, warning.type)) {
334 this->all_warnings.add(warning);
335 continue;
336 }
337 }
338 }
339 reduced_node_warnings_ = true;
340}
341
343{
344 if (reduced_execution_times_) {
345 return;
346 }
347 for (GeoTreeLogger *tree_logger : tree_loggers_) {
348 for (const GeoTreeLogger::NodeExecutionTime &timings : tree_logger->node_execution_times) {
349 const std::chrono::nanoseconds duration = timings.end - timings.start;
350 this->nodes.lookup_or_add_default_as(timings.node_id).execution_time += duration;
351 }
352 this->execution_time += tree_logger->execution_time;
353 }
354 reduced_execution_times_ = true;
355}
356
358{
359 if (reduced_socket_values_) {
360 return;
361 }
362 for (GeoTreeLogger *tree_logger : tree_loggers_) {
363 for (const GeoTreeLogger::SocketValueLog &value_log_data : tree_logger->input_socket_values) {
364 this->nodes.lookup_or_add_as(value_log_data.node_id)
365 .input_values_.add(value_log_data.socket_index, value_log_data.value.get());
366 }
367 for (const GeoTreeLogger::SocketValueLog &value_log_data : tree_logger->output_socket_values) {
368 this->nodes.lookup_or_add_as(value_log_data.node_id)
369 .output_values_.add(value_log_data.socket_index, value_log_data.value.get());
370 }
371 }
372 reduced_socket_values_ = true;
373}
374
376{
377 if (reduced_viewer_node_logs_) {
378 return;
379 }
380 for (GeoTreeLogger *tree_logger : tree_loggers_) {
381 for (const GeoTreeLogger::ViewerNodeLogWithNode &viewer_log : tree_logger->viewer_node_logs) {
382 this->viewer_node_logs.add(viewer_log.node_id, viewer_log.viewer_log.get());
383 }
384 }
385 reduced_viewer_node_logs_ = true;
386}
387
389{
390 if (reduced_existing_attributes_) {
391 return;
392 }
393 this->ensure_socket_values();
394
395 auto handle_value_log = [&](const ValueLog &value_log) {
396 const GeometryInfoLog *geo_log = dynamic_cast<const GeometryInfoLog *>(&value_log);
397 if (geo_log == nullptr) {
398 return;
399 }
400 for (const GeometryAttributeInfo &attribute : geo_log->attributes) {
401 this->existing_attributes.append(&attribute);
402 }
403 };
404
405 for (const GeoNodeLog &node_log : this->nodes.values()) {
406 for (const ValueLog *value_log : node_log.input_values_.values()) {
407 handle_value_log(*value_log);
408 }
409 for (const ValueLog *value_log : node_log.output_values_.values()) {
410 handle_value_log(*value_log);
411 }
412 }
413 reduced_existing_attributes_ = true;
414}
415
417{
418 if (reduced_used_named_attributes_) {
419 return;
420 }
421
422 auto add_attribute = [&](const int32_t node_id,
423 const StringRefNull attribute_name,
424 const NamedAttributeUsage &usage) {
425 this->nodes.lookup_or_add_default(node_id).used_named_attributes.lookup_or_add(attribute_name,
426 usage) |= usage;
427 this->used_named_attributes.lookup_or_add_as(attribute_name, usage) |= usage;
428 };
429
430 for (GeoTreeLogger *tree_logger : tree_loggers_) {
431 for (const GeoTreeLogger::AttributeUsageWithNode &item : tree_logger->used_named_attributes) {
432 add_attribute(item.node_id, item.attribute_name, item.usage);
433 }
434 }
435 for (const ComputeContextHash &child_hash : children_hashes_) {
436 GeoTreeLog &child_log = modifier_log_->get_tree_log(child_hash);
437 if (child_log.tree_loggers_.is_empty()) {
438 continue;
439 }
441 if (const std::optional<int32_t> &parent_node_id = child_log.tree_loggers_[0]->parent_node_id)
442 {
443 for (const auto item : child_log.used_named_attributes.items()) {
444 add_attribute(*parent_node_id, item.key, item.value);
445 }
446 }
447 }
448 reduced_used_named_attributes_ = true;
449}
450
452{
453 if (reduced_debug_messages_) {
454 return;
455 }
456 for (GeoTreeLogger *tree_logger : tree_loggers_) {
457 for (const GeoTreeLogger::DebugMessage &debug_message : tree_logger->debug_messages) {
458 this->nodes.lookup_or_add_as(debug_message.node_id)
459 .debug_messages.append(debug_message.message);
460 }
461 }
462 reduced_debug_messages_ = true;
463}
464
466{
467 if (reduced_evaluated_gizmo_nodes_) {
468 return;
469 }
470 for (const GeoTreeLogger *tree_logger : tree_loggers_) {
471 for (const GeoTreeLogger::EvaluatedGizmoNode &evaluated_gizmo :
472 tree_logger->evaluated_gizmo_nodes)
473 {
474 this->evaluated_gizmo_nodes.add(evaluated_gizmo.node_id);
475 }
476 }
477}
478
480{
487 BLI_assert(reduced_socket_values_);
488 if (query_socket.is_multi_input()) {
489 /* Not supported currently. */
490 return nullptr;
491 }
492
493 Set<const bNodeSocket *> added_sockets;
494 Stack<const bNodeSocket *> sockets_to_check;
495 sockets_to_check.push(&query_socket);
496 added_sockets.add(&query_socket);
497
498 while (!sockets_to_check.is_empty()) {
499 const bNodeSocket &socket = *sockets_to_check.pop();
500 const bNode &node = socket.owner_node();
501 if (GeoNodeLog *node_log = this->nodes.lookup_ptr(node.identifier)) {
502 ValueLog *value_log = socket.is_input() ?
503 node_log->input_values_.lookup_default(socket.index(), nullptr) :
504 node_log->output_values_.lookup_default(socket.index(), nullptr);
505 if (value_log != nullptr) {
506 return value_log;
507 }
508 }
509
510 if (socket.is_input()) {
511 const Span<const bNodeLink *> links = socket.directly_linked_links();
512 for (const bNodeLink *link : links) {
513 const bNodeSocket &from_socket = *link->fromsock;
514 if (added_sockets.add(&from_socket)) {
515 sockets_to_check.push(&from_socket);
516 }
517 }
518 }
519 else {
520 if (node.is_reroute()) {
521 const bNodeSocket &input_socket = node.input_socket(0);
522 if (added_sockets.add(&input_socket)) {
523 sockets_to_check.push(&input_socket);
524 }
525 const Span<const bNodeLink *> links = input_socket.directly_linked_links();
526 for (const bNodeLink *link : links) {
527 const bNodeSocket &from_socket = *link->fromsock;
528 if (added_sockets.add(&from_socket)) {
529 sockets_to_check.push(&from_socket);
530 }
531 }
532 }
533 else if (node.is_muted()) {
534 if (const bNodeSocket *input_socket = socket.internal_link_input()) {
535 if (added_sockets.add(input_socket)) {
536 sockets_to_check.push(input_socket);
537 }
538 const Span<const bNodeLink *> links = input_socket->directly_linked_links();
539 for (const bNodeLink *link : links) {
540 const bNodeSocket &from_socket = *link->fromsock;
541 if (added_sockets.add(&from_socket)) {
542 sockets_to_check.push(&from_socket);
543 }
544 }
545 }
546 }
547 }
548 }
549
550 return nullptr;
551}
552
554 const CPPType &dst_type,
555 void *dst)
556{
557 const void *src_value = value_log.value.get();
558 if (!src_value) {
559 return false;
560 }
562 const CPPType &src_type = *value_log.value.type();
563 if (!conversions.is_convertible(src_type, dst_type) && src_type != dst_type) {
564 return false;
565 }
566 dst_type.destruct(dst);
567 conversions.convert_to_uninitialized(src_type, dst_type, src_value, dst);
568 return true;
569}
570
572{
573 LocalData &local_data = data_per_thread_.local();
575 local_data.tree_logger_by_context;
576 destruct_ptr<GeoTreeLogger> &tree_logger_ptr = local_tree_loggers.lookup_or_add_default(
577 compute_context.hash());
578 if (tree_logger_ptr) {
579 return *tree_logger_ptr;
580 }
581 tree_logger_ptr = local_data.allocator.construct<GeoTreeLogger>();
582 GeoTreeLogger &tree_logger = *tree_logger_ptr;
583 tree_logger.allocator = &local_data.allocator;
584 const ComputeContext *parent_compute_context = compute_context.parent();
585 if (parent_compute_context != nullptr) {
586 tree_logger.parent_hash = parent_compute_context->hash();
587 GeoTreeLogger &parent_logger = this->get_local_tree_logger(*parent_compute_context);
588 parent_logger.children_hashes.append(compute_context.hash());
589 }
590 if (const bke::GroupNodeComputeContext *typed_compute_context =
591 dynamic_cast<const bke::GroupNodeComputeContext *>(&compute_context))
592 {
593 tree_logger.parent_node_id.emplace(typed_compute_context->node_id());
594 }
595 else if (const bke::RepeatZoneComputeContext *typed_compute_context =
596 dynamic_cast<const bke::RepeatZoneComputeContext *>(&compute_context))
597 {
598 tree_logger.parent_node_id.emplace(typed_compute_context->output_node_id());
599 }
600 else if (const bke::ForeachGeometryElementZoneComputeContext *typed_compute_context =
602 &compute_context))
603 {
604 tree_logger.parent_node_id.emplace(typed_compute_context->output_node_id());
605 }
606 else if (const bke::SimulationZoneComputeContext *typed_compute_context =
607 dynamic_cast<const bke::SimulationZoneComputeContext *>(&compute_context))
608 {
609 tree_logger.parent_node_id.emplace(typed_compute_context->output_node_id());
610 }
611 return tree_logger;
612}
613
615{
616 GeoTreeLog &reduced_tree_log = *tree_logs_.lookup_or_add_cb(compute_context_hash, [&]() {
617 Vector<GeoTreeLogger *> tree_logs;
618 for (LocalData &local_data : data_per_thread_) {
619 destruct_ptr<GeoTreeLogger> *tree_log = local_data.tree_logger_by_context.lookup_ptr(
620 compute_context_hash);
621 if (tree_log != nullptr) {
622 tree_logs.append(tree_log->get());
623 }
624 }
625 return std::make_unique<GeoTreeLog>(this, std::move(tree_logs));
626 });
627 return reduced_tree_log;
628}
629
631 const bNodeTreeZone &zone,
632 ComputeContextBuilder &compute_context_builder,
634{
635 switch (zone.output_node->type) {
637 compute_context_builder.push<bke::SimulationZoneComputeContext>(*zone.output_node);
638 break;
639 }
641 const auto &storage = *static_cast<const NodeGeometryRepeatOutput *>(
642 zone.output_node->storage);
643 compute_context_builder.push<bke::RepeatZoneComputeContext>(*zone.output_node,
644 storage.inspection_index);
645 break;
646 }
648 const auto &storage = *static_cast<const NodeGeometryForeachGeometryElementOutput *>(
649 zone.output_node->storage);
651 *zone.output_node, storage.inspection_index);
652 break;
653 }
654 }
655 r_hash_by_zone.add_new(&zone, compute_context_builder.hash());
656 for (const bNodeTreeZone *child_zone : zone.child_zones) {
657 find_tree_zone_hash_recursive(*child_zone, compute_context_builder, r_hash_by_zone);
658 }
659 compute_context_builder.pop();
660}
661
664 ComputeContextBuilder &compute_context_builder)
665{
666 if (!ed::space_node::push_compute_context_for_tree_path(snode, compute_context_builder)) {
667 return {};
668 }
669
670 const bNodeTreeZones *tree_zones = snode.edittree->zones();
671 if (tree_zones == nullptr) {
672 return {};
673 }
675 hash_by_zone.add_new(nullptr, compute_context_builder.hash());
676 for (const bNodeTreeZone *zone : tree_zones->root_zones) {
677 find_tree_zone_hash_recursive(*zone, compute_context_builder, hash_by_zone);
678 }
679 return hash_by_zone;
680}
681
689
691 const SpaceNode &snode)
692{
695 std::optional<ed::space_node::ObjectAndModifier> object_and_modifier =
697 if (!object_and_modifier) {
698 return {};
699 }
700 GeoModifierLog *modifier_log = object_and_modifier->nmd->runtime->eval_log.get();
701 if (modifier_log == nullptr) {
702 return {};
703 }
706 snode, object_and_modifier->nmd->modifier.name);
708 for (const auto item : hash_by_zone.items()) {
709 GeoTreeLog &tree_log = modifier_log->get_tree_log(item.value);
710 log_by_zone.add(item.key, &tree_log);
711 }
712 return log_by_zone;
713 }
714 case SNODE_GEOMETRY_TOOL: {
717 if (snode.geometry_nodes_tool_tree->id.name + 2 != log.node_group_name) {
718 return {};
719 }
720 ComputeContextBuilder compute_context_builder;
721 compute_context_builder.push<bke::OperatorComputeContext>();
723 GeoModifierLog::get_context_hash_by_zone_for_node_editor(snode, compute_context_builder);
725 for (const auto item : hash_by_zone.items()) {
726 GeoTreeLog &tree_log = log.log->get_tree_log(item.value);
727 log_by_zone.add(item.key, &tree_log);
728 }
729 return log_by_zone;
730 }
731 }
733 return {};
734}
735
737{
738 const std::optional<ed::viewer_path::ViewerPathForGeometryNodesViewer> parsed_path =
740 if (!parsed_path.has_value()) {
741 return nullptr;
742 }
743 const Object *object = parsed_path->object;
744 NodesModifierData *nmd = nullptr;
745 LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
746 if (md->name == parsed_path->modifier_name) {
747 if (md->type == eModifierType_Nodes) {
748 nmd = reinterpret_cast<NodesModifierData *>(md);
749 }
750 }
751 }
752 if (nmd == nullptr) {
753 return nullptr;
754 }
755 if (!nmd->runtime->eval_log) {
756 return nullptr;
757 }
758 nodes::geo_eval_log::GeoModifierLog *modifier_log = nmd->runtime->eval_log.get();
759
760 ComputeContextBuilder compute_context_builder;
761 compute_context_builder.push<bke::ModifierComputeContext>(parsed_path->modifier_name);
762 for (const ViewerPathElem *elem : parsed_path->node_path) {
763 if (!ed::viewer_path::add_compute_context_for_viewer_path_elem(*elem, compute_context_builder))
764 {
765 return nullptr;
766 }
767 }
768 const ComputeContextHash context_hash = compute_context_builder.hash();
769 nodes::geo_eval_log::GeoTreeLog &tree_log = modifier_log->get_tree_log(context_hash);
770 tree_log.ensure_viewer_node_logs();
771
772 const ViewerNodeLog *viewer_log = tree_log.viewer_node_logs.lookup_default(
773 parsed_path->viewer_node_id, nullptr);
774 return viewer_log;
775}
776
778{
779 switch (type) {
781 return ICON_CANCEL;
783 return ICON_ERROR;
785 return ICON_INFO;
786 }
788 return ICON_ERROR;
789}
790
792{
793 switch (type) {
795 return 3;
797 return 2;
799 return 1;
800 }
802 return 0;
803}
804
805} // namespace blender::nodes::geo_eval_log
Low-level operations for curves.
#define GEO_NODE_FOREACH_GEOMETRY_ELEMENT_OUTPUT
Definition BKE_node.hh:1379
#define GEO_NODE_SIMULATION_OUTPUT
Definition BKE_node.hh:1331
#define GEO_NODE_REPEAT_OUTPUT
Definition BKE_node.hh:1338
Volume data-block.
int BKE_volume_num_grids(const Volume *volume)
VolumeGridType
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define LISTBASE_FOREACH(type, var, list)
#define UNUSED_VARS(...)
#define ELEM(...)
@ eModifierType_Nodes
@ SOCK_IN
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
SIMD_FORCE_INLINE btVector3 operator()(const btVector3 &x) const
Return the transform of the vector.
Definition btTransform.h:90
void destruct(void *ptr) const
int64_t size() const
const ComputeContextHash hash() const
const ComputeContext * parent() const
const ComputeContextHash & hash() const
const CPPType * type() const
destruct_ptr< T > construct(Args &&...args)
void * allocate(const int64_t size, const int64_t alignment)
Value & lookup_or_add_default(const Key &key)
Definition BLI_map.hh:601
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:271
void add_new(const Key &key, const Value &value)
Definition BLI_map.hh:241
ItemIterator items() const
Definition BLI_map.hh:864
bool add(const Key &key)
Definition BLI_set.hh:248
constexpr bool contains(const T &value) const
Definition BLI_span.hh:278
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)
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
int attribute_domain_size(AttrDomain domain) const
Vector< bNodeTreeZone * > root_zones
GeoTreeLog & get_tree_log(const ComputeContextHash &compute_context_hash)
GeoTreeLogger & get_local_tree_logger(const ComputeContext &compute_context)
static Map< const bke::bNodeTreeZone *, GeoTreeLog * > get_tree_log_by_zone_for_node_editor(const SpaceNode &snode)
static const ViewerNodeLog * find_viewer_node_log_for_path(const ViewerPath &viewer_path)
static Map< const bke::bNodeTreeZone *, ComputeContextHash > get_context_hash_by_zone_for_node_editor(const SpaceNode &snode, StringRefNull modifier_name)
Vector< const GeometryAttributeInfo * > existing_attributes
void ensure_node_warnings(const bNodeTree *tree)
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
ValueLog * find_socket_value_log(const bNodeSocket &query_socket)
linear_allocator::ChunkedList< ViewerNodeLogWithNode > viewer_node_logs
void log_viewer_node(const bNode &viewer_node, bke::GeometrySet geometry)
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
local_group_size(16, 16) .push_constant(Type b
KDTree_3d * tree
static const char * modifier_name[LS_MODIFIER_NUM]
Definition linestyle.cc:680
ccl_device_inline float3 log(float3 v)
VolumeGridType get_type(const VolumeGridData &grid)
bool attribute_name_is_anonymous(const StringRef name)
const DataTypeConversions & get_implicit_type_conversions()
Span< int > all_zone_output_node_types()
const GeoOperatorLog & node_group_operator_static_eval_log()
bool push_compute_context_for_tree_path(const SpaceNode &snode, ComputeContextBuilder &compute_context_builder)
std::optional< ObjectAndModifier > get_modifier_for_node_editor(const SpaceNode &snode)
bool add_compute_context_for_viewer_path_elem(const ViewerPathElem &elem, ComputeContextBuilder &compute_context_builder)
std::optional< ViewerPathForGeometryNodesViewer > parse_geometry_nodes_viewer(const ViewerPath &viewer_path)
int node_warning_type_icon(const NodeWarningType type)
int node_warning_type_severity(const NodeWarningType type)
static bool warning_is_propagated(const NodeWarningPropagation propagation, const NodeWarningType warning_type)
static void find_tree_zone_hash_recursive(const bNodeTreeZone &zone, ComputeContextBuilder &compute_context_builder, Map< const bNodeTreeZone *, ComputeContextHash > &r_hash_by_zone)
std::unique_ptr< T, DestructValueAtAddress< T > > destruct_ptr
#define hash
Definition noise.c:154
signed int int32_t
Definition stdint.h:77
char name[66]
Definition DNA_ID.h:425
NodesModifierRuntimeHandle * runtime
struct bNodeTree * edittree
struct bNodeTree * geometry_nodes_tool_tree
char geometry_nodes_type
int32_t identifier
void attribute_foreach(Span< GeometryComponent::Type > component_types, bool include_instances, AttributeForeachCallback callback) const