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
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()) {
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. */
200
203
204GeoNodeLog::GeoNodeLog() = default;
205GeoNodeLog::~GeoNodeLog() = default;
206
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>()) {
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
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{
486
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
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its and value channels Color Retrieve a color attribute
SIMD_FORCE_INLINE btVector3 operator()(const btVector3 &x) const
Return the transform of the vector.
Definition btTransform.h:90
bool is() const
void copy_construct(const void *src, void *dst) const
void destruct(void *ptr) const
int64_t size() const
int64_t alignment() const
const ComputeContextHash hash() 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)
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
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
Vector< bNodeTreeZone * > child_zones
Vector< bNodeTreeZone * > root_zones
const FieldNode & node() const
Definition FN_field.hh:137
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)
GeoTreeLog(GeoModifierLog *modifier_log, Vector< GeoTreeLogger * > tree_loggers)
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
GeometryInfoLog(const bke::GeometrySet &geometry_set)
std::optional< GreasePencilInfo > grease_pencil_info
Vector< bke::GeometryComponent::Type > component_types
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
ListBase modifiers
struct bNodeTree * edittree
struct bNodeTree * geometry_nodes_tool_tree
char geometry_nodes_type
void * storage
int32_t identifier
int16_t type
Vector< const GeometryComponent * > get_components() const
void attribute_foreach(Span< GeometryComponent::Type > component_types, bool include_instances, AttributeForeachCallback callback) const