Blender V5.0
geometry_nodes_lazy_function.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
22
23#include "NOD_geo_viewer.hh"
24#include "NOD_geometry_exec.hh"
27#include "NOD_multi_function.hh"
29
30#include "BLI_array_utils.hh"
32#include "BLI_bit_span_ops.hh"
33#include "BLI_cpp_types.hh"
34#include "BLI_lazy_threading.hh"
35#include "BLI_map.hh"
36
37#include "DNA_ID.h"
38
42#include "BKE_geometry_set.hh"
43#include "BKE_grease_pencil.hh"
44#include "BKE_library.hh"
46#include "BKE_node_runtime.hh"
51
52#include "ED_node.hh"
53
55
57
59
60#include "list_function_eval.hh"
62
63#include <fmt/format.h>
64#include <iostream>
65#include <sstream>
66
67namespace blender::nodes {
68
69using bke::bNodeTreeZone;
70using bke::bNodeTreeZones;
71using bke::SocketValueVariant;
72using bke::node_tree_reference_lifetimes::ReferenceLifetimesInfo;
73using bke::node_tree_reference_lifetimes::ReferenceSetInfo;
75
81 Vector<lf::Input> &r_inputs,
82 Vector<lf::Output> &r_outputs,
83 MutableSpan<int> r_lf_index_by_bsocket)
84{
85 const bool is_muted = node.is_muted();
86 const lf::ValueUsage input_usage = lf::ValueUsage::Used;
87 for (const bNodeSocket *socket : node.input_sockets()) {
88 if (!socket->is_available()) {
89 continue;
90 }
91 if (!socket->typeinfo->geometry_nodes_default_value) {
92 continue;
93 }
94 const CPPType *type;
95 if (socket->is_multi_input() && !is_muted) {
97 }
98 else {
100 }
101 r_lf_index_by_bsocket[socket->index_in_tree()] = r_inputs.append_and_get_index_as(
102 socket->name, *type, input_usage);
103 }
104 for (const bNodeSocket *socket : node.output_sockets()) {
105 if (!socket->is_available()) {
106 continue;
107 }
108 if (!socket->typeinfo->geometry_nodes_default_value) {
109 continue;
110 }
111 r_lf_index_by_bsocket[socket->index_in_tree()] = r_outputs.append_and_get_index_as(
112 socket->name, CPPType::get<SocketValueVariant>());
113 }
114}
115
120 private:
121 const bNode &node_;
122 const GeometryNodesLazyFunctionGraphInfo &own_lf_graph_info_;
128 Vector<bool> is_attribute_output_bsocket_;
129
130 public:
132 GeometryNodesLazyFunctionGraphInfo &own_lf_graph_info)
133 : node_(node),
134 own_lf_graph_info_(own_lf_graph_info),
135 is_attribute_output_bsocket_(node.output_sockets().size(), false)
136 {
137 BLI_assert(node.typeinfo->geometry_node_execute != nullptr);
138 debug_name_ = node.name;
140 node, inputs_, outputs_, own_lf_graph_info.mapping.lf_index_by_bsocket);
141
142 const NodeDeclaration &node_decl = *node.declaration();
143 const aal::RelationsInNode *relations = node_decl.anonymous_attribute_relations();
144 if (relations == nullptr) {
145 return;
146 }
147 if (!relations->available_relations.is_empty()) {
148 /* Inputs are only used when an output is used that is not just outputting an anonymous
149 * attribute field. */
150 for (lf::Input &input : inputs_) {
152 }
153 for (const aal::AvailableRelation &relation : relations->available_relations) {
154 is_attribute_output_bsocket_[relation.field_output] = true;
155 }
156 }
157 Vector<const bNodeSocket *> handled_field_outputs;
158 for (const aal::AvailableRelation &relation : relations->available_relations) {
159 const bNodeSocket &output_bsocket = node.output_socket(relation.field_output);
160 if (output_bsocket.is_available() && !handled_field_outputs.contains(&output_bsocket)) {
161 handled_field_outputs.append(&output_bsocket);
162 const int lf_index = inputs_.append_and_get_index_as("Output Used", CPPType::get<bool>());
163 own_lf_graph_info.mapping
164 .lf_input_index_for_output_bsocket_usage[output_bsocket.index_in_all_outputs()] =
165 lf_index;
166 }
167 }
168
169 Vector<const bNodeSocket *> handled_geometry_outputs;
170 for (const aal::PropagateRelation &relation : relations->propagate_relations) {
171 const bNodeSocket &output_bsocket = node.output_socket(relation.to_geometry_output);
172 if (output_bsocket.is_available() && !handled_geometry_outputs.contains(&output_bsocket)) {
173 handled_geometry_outputs.append(&output_bsocket);
174 const int lf_index = inputs_.append_and_get_index_as(
175 "Propagate to Output", CPPType::get<GeometryNodesReferenceSet>());
176 own_lf_graph_info.mapping
177 .lf_input_index_for_reference_set_for_output[output_bsocket.index_in_all_outputs()] =
178 lf_index;
179 }
180 }
181 }
182
183 void execute_impl(lf::Params &params, const lf::Context &context) const override
184 {
185 const ScopedNodeTimer node_timer{context, node_};
186
187 GeoNodesUserData *user_data = dynamic_cast<GeoNodesUserData *>(context.user_data);
188 BLI_assert(user_data != nullptr);
189
190 bool used_non_attribute_output_exists = false;
191 for (const int output_bsocket_index : node_.output_sockets().index_range()) {
192 const bNodeSocket &output_bsocket = node_.output_socket(output_bsocket_index);
193 const int lf_index =
194 own_lf_graph_info_.mapping.lf_index_by_bsocket[output_bsocket.index_in_tree()];
195 if (lf_index == -1) {
196 continue;
197 }
198 const lf::ValueUsage output_usage = params.get_output_usage(lf_index);
199 if (output_usage == lf::ValueUsage::Unused) {
200 continue;
201 }
202 if (is_attribute_output_bsocket_[output_bsocket_index]) {
203 if (params.output_was_set(lf_index)) {
204 continue;
205 }
206 this->output_anonymous_attribute_field(params, *user_data, lf_index, output_bsocket);
207 }
208 else {
209 if (output_usage == lf::ValueUsage::Used) {
210 used_non_attribute_output_exists = true;
211 }
212 }
213 }
214
215 if (!used_non_attribute_output_exists) {
216 /* Only attribute outputs are used currently, no need to evaluate the full node and its
217 * inputs. */
218 return;
219 }
220
221 bool missing_input = false;
222 for (const int lf_index : inputs_.index_range()) {
223 if (params.try_get_input_data_ptr_or_request(lf_index) == nullptr) {
224 missing_input = true;
225 }
226 }
227 if (missing_input) {
228 /* Wait until all inputs are available. */
229 return;
230 }
231
232 auto get_anonymous_attribute_name = [&](const int i) {
233 return this->anonymous_attribute_name_for_output(*user_data, i);
234 };
235
236 GeoNodeExecParams geo_params{
237 node_,
238 params,
239 context,
240 own_lf_graph_info_.mapping.lf_input_index_for_output_bsocket_usage,
241 own_lf_graph_info_.mapping.lf_input_index_for_reference_set_for_output,
242 get_anonymous_attribute_name};
243
244 node_.typeinfo->geometry_node_execute(geo_params);
245 }
246
247 std::string input_name(const int index) const override
248 {
249 for (const bNodeSocket *bsocket : node_.output_sockets()) {
250 {
251 const int lf_index =
252 own_lf_graph_info_.mapping
253 .lf_input_index_for_output_bsocket_usage[bsocket->index_in_all_outputs()];
254 if (index == lf_index) {
255 return StringRef("Use Output '") + bsocket->name + "'";
256 }
257 }
258 {
259 const int lf_index =
260 own_lf_graph_info_.mapping
261 .lf_input_index_for_reference_set_for_output[bsocket->index_in_all_outputs()];
262 if (index == lf_index) {
263 return StringRef("Propagate to '") + bsocket->name + "'";
264 }
265 }
266 }
267 return inputs_[index].debug_name;
268 }
269
270 std::string output_name(const int index) const override
271 {
272 return outputs_[index].debug_name;
273 }
274
276 const GeoNodesUserData &user_data,
277 const int lf_index,
278 const bNodeSocket &socket) const
279 {
280 std::string attribute_name = this->anonymous_attribute_name_for_output(user_data,
281 socket.index());
282 std::string socket_inspection_name = make_anonymous_attribute_socket_inspection_string(socket);
283 auto attribute_field = std::make_shared<AttributeFieldInput>(
284 std::move(attribute_name),
285 *socket.typeinfo->base_cpp_type,
286 std::move(socket_inspection_name));
287
288 void *r_value = params.get_output_data_ptr(lf_index);
289 SocketValueVariant::ConstructIn(r_value, GField(std::move(attribute_field)));
290 params.output_set(lf_index);
291 }
292
294 const int output_index) const
295 {
297 user_data.compute_context->hash(),
298 node_.identifier,
299 node_.output_socket(output_index).identifier);
300 }
301};
302
308 public:
310
312 {
313 debug_name_ = "Multi Input";
314 BLI_assert(socket.is_multi_input());
315 for (const bNodeLink *link : socket.directly_linked_links()) {
316 if (link->is_muted() || !link->fromsock->is_available() ||
317 link->fromnode->is_dangling_reroute())
318 {
319 continue;
320 }
321 inputs_.append({"Input", CPPType::get<SocketValueVariant>()});
322 this->links.append(link);
323 }
325 }
326
327 void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
328 {
329 void *output_ptr = params.get_output_data_ptr(0);
330 auto &values = *new (output_ptr) GeoNodesMultiInput<SocketValueVariant>();
331 for (const int i : inputs_.index_range()) {
332 values.values.append(params.extract_input<SocketValueVariant>(i));
333 }
334 params.output_set(0);
335 }
336};
337
342 public:
344 {
345 debug_name_ = "Reroute";
346 inputs_.append({"Input", CPPType::get<SocketValueVariant>()});
347 outputs_.append({"Output", CPPType::get<SocketValueVariant>()});
348 }
349
350 void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
351 {
352 void *input_value = params.try_get_input_data_ptr(0);
353 void *output_value = params.get_output_data_ptr(0);
354 BLI_assert(input_value != nullptr);
355 BLI_assert(output_value != nullptr);
356 const CPPType &type = *inputs_[0].type;
357 type.move_construct(input_value, output_value);
358 params.output_set(0);
359 }
360};
361
368 const bNode &node_;
369
370 public:
371 LazyFunctionForUndefinedNode(const bNode &node, MutableSpan<int> r_lf_index_by_bsocket)
372 : node_(node)
373 {
374 debug_name_ = "Undefined";
375 Vector<lf::Input> dummy_inputs;
376 lazy_function_interface_from_node(node, dummy_inputs, outputs_, r_lf_index_by_bsocket);
377 }
378
379 void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
380 {
382 }
383};
384
390
392 const int lf_index,
393 const bNodeSocket &bsocket)
394{
395 void *output_value = params.get_output_data_ptr(lf_index);
396 construct_socket_default_value(*bsocket.typeinfo, output_value);
397 params.output_set(lf_index);
398}
399
401{
402 const bNodeTree &ntree = node.owner_tree();
403 const Span<int> lf_index_by_bsocket =
404 ntree.runtime->geometry_nodes_lazy_function_graph_info->mapping.lf_index_by_bsocket;
405 for (const bNodeSocket *bsocket : node.output_sockets()) {
406 const int lf_index = lf_index_by_bsocket[bsocket->index_in_tree()];
407 if (lf_index == -1) {
408 continue;
409 }
410 if (params.output_was_set(lf_index)) {
411 continue;
412 }
413 set_default_value_for_output_socket(params, lf_index, *bsocket);
414 }
415}
416
418{
419 return make_anonymous_attribute_socket_inspection_string(socket.owner_node().label_or_name(),
420 socket.name);
421}
423 StringRef socket_name)
424{
425 return fmt::format(fmt::runtime(TIP_("\"{}\" from {}")), socket_name, node_name);
426}
427
429 const MultiFunction &fn,
430 const Span<SocketValueVariant *> input_values,
431 const Span<SocketValueVariant *> output_values,
432 GeoNodesUserData *user_data)
433{
434 /* In this case, the multi-function is evaluated directly. */
435 const IndexMask mask(1);
436 mf::ParamsBuilder params{fn, &mask};
437 mf::ContextBuilder context;
438 context.user_data(user_data);
439
440 for (const int i : input_values.index_range()) {
441 SocketValueVariant &input_variant = *input_values[i];
442 input_variant.convert_to_single();
443 const void *value = input_variant.get_single_ptr_raw();
444 const mf::ParamType param_type = fn.param_type(params.next_param_index());
445 const CPPType &cpp_type = param_type.data_type().single_type();
446 params.add_readonly_single_input(GPointer{cpp_type, value});
447 }
448 for (const int i : output_values.index_range()) {
449 if (output_values[i] == nullptr) {
450 params.add_ignored_single_output("");
451 continue;
452 }
453 SocketValueVariant &output_variant = *output_values[i];
454 const mf::ParamType param_type = fn.param_type(params.next_param_index());
455 const CPPType &cpp_type = param_type.data_type().single_type();
456 const eNodeSocketDatatype socket_type =
458 void *value = output_variant.allocate_single(socket_type);
459 params.add_uninitialized_single_output(GMutableSpan{cpp_type, value, 1});
460 }
461 fn.call(mask, params, context);
462}
463
465 const MultiFunction &fn,
466 const std::shared_ptr<MultiFunction> &owned_fn,
467 const Span<SocketValueVariant *> input_values,
468 const Span<SocketValueVariant *> output_values)
469{
470 /* Convert all inputs into fields, so that they can be used as input in the new field. */
471 Vector<GField> input_fields;
472 for (const int i : input_values.index_range()) {
473 input_fields.append(input_values[i]->extract<GField>());
474 }
475
476 /* Construct the new field node. */
477 std::shared_ptr<fn::FieldOperation> operation;
478 if (owned_fn) {
479 operation = fn::FieldOperation::from(owned_fn, std::move(input_fields));
480 }
481 else {
482 operation = fn::FieldOperation::from(fn, std::move(input_fields));
483 }
484
485 /* Store the new fields in the output. */
486 for (const int i : output_values.index_range()) {
487 if (output_values[i] == nullptr) {
488 continue;
489 }
490 output_values[i]->set(GField{operation, i});
491 }
492}
493
499 const MultiFunction &fn,
500 const std::shared_ptr<MultiFunction> &owned_fn,
501 const Span<SocketValueVariant *> input_values,
502 const Span<SocketValueVariant *> output_values,
503 GeoNodesUserData *user_data,
504 std::string &r_error_message)
505{
506 /* Check input types which determine how the function is evaluated. */
507 bool any_input_is_field = false;
508 bool any_input_is_volume_grid = false;
509 bool any_input_is_list = false;
510 for (const int i : input_values.index_range()) {
511 const SocketValueVariant &value = *input_values[i];
512 if (value.is_context_dependent_field()) {
513 any_input_is_field = true;
514 }
515 else if (value.is_volume_grid()) {
516 any_input_is_volume_grid = true;
517 }
518 else if (value.is_list()) {
519 any_input_is_list = true;
520 }
521 }
522
523 if (any_input_is_volume_grid) {
525 fn, input_values, output_values, r_error_message);
526 }
527 if (any_input_is_list) {
528 execute_multi_function_on_value_variant__list(fn, input_values, output_values, user_data);
529 return true;
530 }
531 if (any_input_is_field) {
532 execute_multi_function_on_value_variant__field(fn, owned_fn, input_values, output_values);
533 return true;
534 }
535 execute_multi_function_on_value_variant__single(fn, input_values, output_values, user_data);
536 return true;
537}
538
539std::optional<SocketValueVariant> implicitly_convert_socket_value(
540 const bke::bNodeSocketType &from_type,
541 const SocketValueVariant &from_value,
543{
544 if (from_type.type == to_type.type) {
545 return from_value;
546 }
548 const CPPType *from_cpp_type = from_type.base_cpp_type;
549 const CPPType *to_cpp_type = to_type.base_cpp_type;
550 if (!from_cpp_type || !to_cpp_type) {
551 return std::nullopt;
552 }
553 if (conversions.is_convertible(*from_cpp_type, *to_cpp_type)) {
554 const MultiFunction &multi_fn = *conversions.get_conversion_multi_function(
555 mf::DataType::ForSingle(*from_cpp_type), mf::DataType::ForSingle(*to_cpp_type));
556 SocketValueVariant input_variant = from_value;
557 SocketValueVariant output_variant;
558 std::string error_message;
560 multi_fn, {&input_variant}, {&output_variant}, nullptr, error_message))
561 {
562 return std::nullopt;
563 }
564 return output_variant;
565 }
566 return std::nullopt;
567}
568
570 private:
571 const MultiFunction &fn_;
572 const bke::bNodeSocketType &dst_type_;
573
574 public:
575 LazyFunctionForImplicitConversion(const MultiFunction &fn, const bke::bNodeSocketType &dst_type)
576 : fn_(fn), dst_type_(dst_type)
577 {
578 debug_name_ = "Convert";
579 inputs_.append_as("From", CPPType::get<SocketValueVariant>());
581 }
582
583 void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
584 {
585 SocketValueVariant *from_value = params.try_get_input_data_ptr<SocketValueVariant>(0);
586 SocketValueVariant *to_value = new (params.get_output_data_ptr(0)) SocketValueVariant();
587 BLI_assert(from_value != nullptr);
588 BLI_assert(to_value != nullptr);
589 std::string error_message;
591 fn_, {from_value}, {to_value}, nullptr, error_message))
592 {
593 std::destroy_at(to_value);
594 construct_socket_default_value(dst_type_, to_value);
595 }
596 params.output_set(0);
597 }
598};
599
602 ResourceScope &scope)
603{
604 if (!from_type.geometry_nodes_default_value || !to_type.geometry_nodes_default_value) {
605 return nullptr;
606 }
607 if (from_type.type == to_type.type) {
608 return &scope.construct<LazyFunctionForRerouteNode>();
609 }
611 const CPPType &from_base_type = *from_type.base_cpp_type;
612 const CPPType &to_base_type = *to_type.base_cpp_type;
613 if (conversions.is_convertible(from_base_type, to_base_type)) {
614 const MultiFunction &multi_fn = *conversions.get_conversion_multi_function(
615 mf::DataType::ForSingle(from_base_type), mf::DataType::ForSingle(to_base_type));
616 return &scope.construct<LazyFunctionForImplicitConversion>(multi_fn, to_type);
617 }
618 return nullptr;
619}
620
628 private:
629 const bNode &node_;
630 Span<int> lf_index_by_bsocket_;
631 Array<const bNodeSocket *> input_by_output_index_;
632
633 public:
634 LazyFunctionForMutedNode(const bNode &node, MutableSpan<int> r_lf_index_by_bsocket)
635 : node_(node), lf_index_by_bsocket_(r_lf_index_by_bsocket)
636 {
637 debug_name_ = "Muted";
638 lazy_function_interface_from_node(node, inputs_, outputs_, r_lf_index_by_bsocket);
639 for (lf::Input &fn_input : inputs_) {
640 fn_input.usage = lf::ValueUsage::Maybe;
641 }
642
643 for (lf::Input &fn_input : inputs_) {
644 fn_input.usage = lf::ValueUsage::Unused;
645 }
646
647 input_by_output_index_.reinitialize(node.output_sockets().size());
648 input_by_output_index_.fill(nullptr);
649 for (const bNodeLink &internal_link : node.internal_links()) {
650 const int input_i = r_lf_index_by_bsocket[internal_link.fromsock->index_in_tree()];
651 const int output_i = r_lf_index_by_bsocket[internal_link.tosock->index_in_tree()];
652 if (ELEM(-1, input_i, output_i)) {
653 continue;
654 }
655 input_by_output_index_[internal_link.tosock->index()] = internal_link.fromsock;
656 inputs_[input_i].usage = lf::ValueUsage::Maybe;
657 }
658 }
659
660 void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
661 {
662 for (const bNodeSocket *output_bsocket : node_.output_sockets()) {
663 const int lf_output_index = lf_index_by_bsocket_[output_bsocket->index_in_tree()];
664 if (lf_output_index == -1) {
665 continue;
666 }
667 if (params.output_was_set(lf_output_index)) {
668 continue;
669 }
670 if (params.get_output_usage(lf_output_index) != lf::ValueUsage::Used) {
671 continue;
672 }
673 const bNodeSocket *input_bsocket = input_by_output_index_[output_bsocket->index()];
674 if (input_bsocket == nullptr) {
675 set_default_value_for_output_socket(params, lf_output_index, *output_bsocket);
676 continue;
677 }
678 const int lf_input_index = lf_index_by_bsocket_[input_bsocket->index_in_tree()];
679 const SocketValueVariant *input_value =
680 params.try_get_input_data_ptr_or_request<SocketValueVariant>(lf_input_index);
681 if (!input_value) {
682 /* Wait for value to be available. */
683 continue;
684 }
685 if (std::optional<SocketValueVariant> converted_value = implicitly_convert_socket_value(
686 *input_bsocket->typeinfo, *input_value, *output_bsocket->typeinfo))
687 {
688 params.set_output(lf_output_index, std::move(*converted_value));
689 continue;
690 }
691 set_default_value_for_output_socket(params, lf_output_index, *output_bsocket);
692 }
693 }
694};
695
700 private:
701 const bNode &node_;
702 const NodeMultiFunctions::Item fn_item_;
703
704 public:
707 MutableSpan<int> r_lf_index_by_bsocket)
708 : node_(node), fn_item_(std::move(fn_item))
709 {
710 BLI_assert(fn_item_.fn != nullptr);
711 debug_name_ = node.name;
712 lazy_function_interface_from_node(node, inputs_, outputs_, r_lf_index_by_bsocket);
713 }
714
715 void execute_impl(lf::Params &params, const lf::Context &context) const override
716 {
717 auto &user_data = *static_cast<GeoNodesUserData *>(context.user_data);
718
719 Vector<SocketValueVariant *> input_values(inputs_.size());
720 Vector<SocketValueVariant *> output_values(outputs_.size());
721 for (const int i : inputs_.index_range()) {
722 input_values[i] = params.try_get_input_data_ptr<SocketValueVariant>(i);
723 }
724 for (const int i : outputs_.index_range()) {
725 if (params.get_output_usage(i) != lf::ValueUsage::Unused) {
726 output_values[i] = new (params.get_output_data_ptr(i)) SocketValueVariant();
727 }
728 else {
729 output_values[i] = nullptr;
730 }
731 }
732
733 bke::NodeComputeContext eval_compute_context{
734 user_data.compute_context, node_.identifier, &node_.owner_tree()};
735 GeoNodesUserData eval_user_data = user_data;
736 eval_user_data.compute_context = &eval_compute_context;
737
738 std::string error_message;
740 fn_item_.owned_fn,
741 input_values,
742 output_values,
743 &eval_user_data,
744 error_message))
745 {
747 if (!error_message.empty()) {
748 const auto &user_data = *static_cast<GeoNodesUserData *>(context.user_data);
749 const auto &local_user_data = *static_cast<GeoNodesLocalUserData *>(
750 context.local_user_data);
751 if (geo_eval_log::GeoTreeLogger *tree_logger = local_user_data.try_get_tree_logger(
752 user_data))
753 {
754 tree_logger->node_warnings.append(
755 *tree_logger->allocator,
756 {node_.identifier, {NodeWarningType::Error, error_message}});
757 }
758 }
759 return;
760 }
761
762 for (const int i : outputs_.index_range()) {
763 if (params.get_output_usage(i) != lf::ValueUsage::Unused) {
764 params.output_set(i);
765 }
766 }
767 }
768};
769
775 private:
779 std::function<void(void *)> init_fn_;
780
781 public:
782 LazyFunctionForImplicitInput(const CPPType &type, std::function<void(void *)> init_fn)
783 : init_fn_(std::move(init_fn))
784 {
785 debug_name_ = "Input";
786 outputs_.append({"Output", type});
787 }
788
789 void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
790 {
791 void *value = params.get_output_data_ptr(0);
792 init_fn_(value);
793 params.output_set(0);
794 }
795};
796
802 private:
803 const bNode &bnode_;
804 Span<int> lf_index_by_bsocket_;
805
806 public:
807 LazyFunctionForViewerNode(const bNode &bnode, MutableSpan<int> r_lf_index_by_bsocket)
808 : bnode_(bnode), lf_index_by_bsocket_(r_lf_index_by_bsocket)
809 {
810 debug_name_ = "Viewer";
811 lazy_function_interface_from_node(bnode, inputs_, outputs_, r_lf_index_by_bsocket);
812 }
813
814 void execute_impl(lf::Params &params, const lf::Context &context) const override
815 {
816 const auto &user_data = *static_cast<GeoNodesUserData *>(context.user_data);
817 const auto &local_user_data = *static_cast<GeoNodesLocalUserData *>(context.local_user_data);
818 geo_eval_log::GeoTreeLogger *tree_logger = local_user_data.try_get_tree_logger(user_data);
819 if (tree_logger == nullptr) {
820 return;
821 }
822
823 LinearAllocator<> &allocator = *tree_logger->allocator;
824
825 const NodeGeometryViewer &storage = *static_cast<const NodeGeometryViewer *>(bnode_.storage);
826
827 Vector<bke::SocketValueVariant *> values(storage.items_num, nullptr);
828
829 for (const int i : IndexRange(storage.items_num)) {
830 const bNodeSocket &bsocket = bnode_.input_socket(i);
831 const int param_index = lf_index_by_bsocket_[bsocket.index_in_tree()];
832 values[i] = params.try_get_input_data_ptr<bke::SocketValueVariant>(param_index);
833 }
834
835 auto log = allocator.construct<geo_eval_log::ViewerNodeLog>();
836 geo_viewer_node_log(bnode_, values, *log);
837 tree_logger->viewer_node_logs.append(allocator, {bnode_.identifier, std::move(log)});
838 }
839};
840
845 private:
846 const lf::FunctionNode &lf_viewer_node_;
847
848 public:
850 : lf_viewer_node_(lf_viewer_node)
851 {
852 debug_name_ = "Viewer Input Usage";
853 outputs_.append_as("Viewer is Used", CPPType::get<bool>());
854 }
855
856 void execute_impl(lf::Params &params, const lf::Context &context) const override
857 {
858 GeoNodesUserData *user_data = dynamic_cast<GeoNodesUserData *>(context.user_data);
859 BLI_assert(user_data != nullptr);
860 if (!user_data->call_data->side_effect_nodes) {
861 params.set_output<bool>(0, false);
862 return;
863 }
864 const ComputeContextHash &context_hash = user_data->compute_context->hash();
865 const Span<const lf::FunctionNode *> nodes_with_side_effects =
866 user_data->call_data->side_effect_nodes->nodes_by_context.lookup(context_hash);
867
868 const bool viewer_is_used = nodes_with_side_effects.contains(&lf_viewer_node_);
869 params.set_output(0, viewer_is_used);
870 }
871};
872
874static bool gizmo_is_used(const GeoNodesUserData &user_data, const lf::FunctionNode &lf_gizmo_node)
875{
876 if (!user_data.call_data->side_effect_nodes) {
877 return false;
878 }
879 const Span<const lf::FunctionNode *> nodes_with_side_effects =
881 user_data.compute_context->hash());
882 const bool is_used = nodes_with_side_effects.contains(&lf_gizmo_node);
883 return is_used;
884}
885
892 private:
893 const bNode &bnode_;
894
895 public:
896 const lf::FunctionNode *self_node = nullptr;
898
899 LazyFunctionForGizmoNode(const bNode &bnode, MutableSpan<int> r_lf_index_by_bsocket)
900 : bnode_(bnode)
901 {
902 debug_name_ = bnode.name;
903 const bNodeSocket &gizmo_socket = bnode.input_socket(0);
904 /* Create inputs for every input of the multi-input socket to make sure that they can be
905 * logged. */
906 for (const bNodeLink *link : gizmo_socket.directly_linked_links()) {
907 if (!link->is_used()) {
908 continue;
909 }
910 if (link->fromnode->is_dangling_reroute()) {
911 continue;
912 }
913 inputs_.append_and_get_index_as(
915 gizmo_links.append(link);
916 }
917 for (const bNodeSocket *socket : bnode.input_sockets().drop_front(1)) {
918 r_lf_index_by_bsocket[socket->index_in_tree()] = inputs_.append_and_get_index_as(
919 socket->identifier, CPPType::get<SocketValueVariant>(), lf::ValueUsage::Maybe);
920 }
921 r_lf_index_by_bsocket[bnode.output_socket(0).index_in_tree()] =
922 outputs_.append_and_get_index_as("Transform", CPPType::get<SocketValueVariant>());
923 }
924
925 void execute_impl(lf::Params &params, const lf::Context &context) const override
926 {
927 const auto &user_data = *static_cast<GeoNodesUserData *>(context.user_data);
928 if (!gizmo_is_used(user_data, *this->self_node)) {
930 return;
931 }
932 if (!params.output_was_set(0)) {
934 GeometryComponentEditData &edit_data =
935 geometry.get_component_for_write<GeometryComponentEditData>();
936 edit_data.gizmo_edit_hints_ = std::make_unique<bke::GizmoEditHints>();
937 edit_data.gizmo_edit_hints_->gizmo_transforms.add(
938 {user_data.compute_context->hash(), bnode_.identifier}, float4x4::identity());
939 params.set_output(0, SocketValueVariant::From(std::move(geometry)));
940 }
941
942 /* Request all inputs so that their values can be logged. */
943 for (const int i : inputs_.index_range()) {
944 params.try_get_input_data_ptr_or_request(i);
945 }
946
947 const auto &local_user_data = *static_cast<GeoNodesLocalUserData *>(context.local_user_data);
948 if (geo_eval_log::GeoTreeLogger *tree_logger = local_user_data.try_get_tree_logger(user_data))
949 {
950 tree_logger->evaluated_gizmo_nodes.append(*tree_logger->allocator, {bnode_.identifier});
951 }
952 }
953};
954
956 private:
957 const lf::FunctionNode *lf_gizmo_node_ = nullptr;
958
959 public:
960 LazyFunctionForGizmoInputsUsage(const bNode &gizmo_node, const lf::FunctionNode &lf_gizmo_node)
961 : lf_gizmo_node_(&lf_gizmo_node)
962 {
963 debug_name_ = gizmo_node.name;
964 outputs_.append_as("Need Inputs", CPPType::get<bool>());
965 }
966
967 void execute_impl(lf::Params &params, const lf::Context &context) const override
968 {
969 const auto &user_data = *static_cast<GeoNodesUserData *>(context.user_data);
970 const bool is_used = gizmo_is_used(user_data, *lf_gizmo_node_);
971 params.set_output(0, is_used);
972 }
973};
974
976 private:
977 const bNode *output_bnode_;
978
979 public:
980 LazyFunctionForSimulationInputsUsage(const bNode &output_bnode) : output_bnode_(&output_bnode)
981 {
982 debug_name_ = "Simulation Inputs Usage";
983 outputs_.append_as("Need Input Inputs", CPPType::get<bool>());
984 outputs_.append_as("Need Output Inputs", CPPType::get<bool>());
985 }
986
987 void execute_impl(lf::Params &params, const lf::Context &context) const override
988 {
989 const GeoNodesUserData &user_data = *static_cast<GeoNodesUserData *>(context.user_data);
990 const GeoNodesCallData &call_data = *user_data.call_data;
991 if (!call_data.simulation_params) {
993 return;
994 }
995 const std::optional<FoundNestedNodeID> found_id = find_nested_node_id(
996 user_data, output_bnode_->identifier);
997 if (!found_id) {
999 return;
1000 }
1001 if (found_id->is_in_loop) {
1003 return;
1004 }
1005 SimulationZoneBehavior *zone_behavior = call_data.simulation_params->get(found_id->id);
1006 if (!zone_behavior) {
1008 return;
1009 }
1010
1011 bool solve_contains_side_effect = false;
1012 if (call_data.side_effect_nodes) {
1013 const Span<const lf::FunctionNode *> side_effect_nodes =
1014 call_data.side_effect_nodes->nodes_by_context.lookup(user_data.compute_context->hash());
1015 solve_contains_side_effect = !side_effect_nodes.is_empty();
1016 }
1017
1018 params.set_output(0, std::holds_alternative<sim_input::PassThrough>(zone_behavior->input));
1019 params.set_output(
1020 1,
1021 solve_contains_side_effect ||
1022 std::holds_alternative<sim_output::StoreNewState>(zone_behavior->output));
1023 }
1024
1026 {
1027 params.set_output(0, false);
1028 params.set_output(1, false);
1029 }
1030};
1031
1033 private:
1034 const bNode *bnode_;
1035
1036 public:
1037 LazyFunctionForBakeInputsUsage(const bNode &bnode) : bnode_(&bnode)
1038 {
1039 debug_name_ = "Bake Inputs Usage";
1040 outputs_.append_as("Used", CPPType::get<bool>());
1041 }
1042
1043 void execute_impl(lf::Params &params, const lf::Context &context) const override
1044 {
1045 const GeoNodesUserData &user_data = *static_cast<GeoNodesUserData *>(context.user_data);
1046 if (!user_data.call_data->bake_params) {
1048 return;
1049 }
1050 const std::optional<FoundNestedNodeID> found_id = find_nested_node_id(user_data,
1051 bnode_->identifier);
1052 if (!found_id) {
1054 return;
1055 }
1056 if (found_id->is_in_loop || found_id->is_in_simulation) {
1058 return;
1059 }
1060 BakeNodeBehavior *behavior = user_data.call_data->bake_params->get(found_id->id);
1061 if (!behavior) {
1063 return;
1064 }
1065 const bool need_inputs = std::holds_alternative<sim_output::PassThrough>(behavior->behavior) ||
1066 std::holds_alternative<sim_output::StoreNewState>(behavior->behavior);
1067 params.set_output(0, need_inputs);
1068 }
1069
1071 {
1072 params.set_output(0, false);
1073 }
1074};
1075
1078{
1079 if (const Set<ComputeContextHash> *contexts = user_data.call_data->socket_log_contexts) {
1080 return contexts->contains(hash);
1081 }
1082 if (user_data.call_data->operator_data) {
1083 return false;
1084 }
1085 return true;
1086}
1087
1093 private:
1094 const bNode &group_node_;
1095 const LazyFunction &group_lazy_function_;
1096 bool has_many_nodes_ = false;
1097
1098 struct Storage {
1099 void *group_storage = nullptr;
1100 };
1101
1102 public:
1104 const GeometryNodesLazyFunctionGraphInfo &group_lf_graph_info,
1105 GeometryNodesLazyFunctionGraphInfo &own_lf_graph_info)
1106 : group_node_(group_node), group_lazy_function_(*group_lf_graph_info.function.function)
1107 {
1108 debug_name_ = group_node.name;
1110
1111 /* This wrapper has the same interface as the actual underlying node group. */
1112 inputs_ = group_lf_graph_info.function.function->inputs();
1113 outputs_ = group_lf_graph_info.function.function->outputs();
1114
1115 has_many_nodes_ = group_lf_graph_info.num_inline_nodes_approximate > 1000;
1116
1117 /* Add a boolean input for every output bsocket that indicates whether that socket is used. */
1118 for (const int i : group_node.output_sockets().index_range()) {
1119 own_lf_graph_info.mapping.lf_input_index_for_output_bsocket_usage
1120 [group_node.output_socket(i).index_in_all_outputs()] =
1121 group_lf_graph_info.function.inputs.output_usages[i];
1122 }
1123
1124 /* Add an reference set input for every output geometry socket that can propagate data
1125 * from inputs. */
1126 for (const int i : group_lf_graph_info.function.inputs.references_to_propagate.geometry_outputs
1127 .index_range())
1128 {
1129 const int lf_index = group_lf_graph_info.function.inputs.references_to_propagate.range[i];
1130 const int output_index =
1131 group_lf_graph_info.function.inputs.references_to_propagate.geometry_outputs[i];
1132 const bNodeSocket &output_bsocket = group_node_.output_socket(output_index);
1133 own_lf_graph_info.mapping
1134 .lf_input_index_for_reference_set_for_output[output_bsocket.index_in_all_outputs()] =
1135 lf_index;
1136 }
1137 }
1138
1139 void execute_impl(lf::Params &params, const lf::Context &context) const override
1140 {
1141 const ScopedNodeTimer node_timer{context, group_node_};
1142 GeoNodesUserData *user_data = dynamic_cast<GeoNodesUserData *>(context.user_data);
1143 BLI_assert(user_data != nullptr);
1144
1145 if (has_many_nodes_) {
1146 /* If the called node group has many nodes, it's likely that executing it takes a while even
1147 * if every individual node is very small. */
1149 }
1150
1151 Storage *storage = static_cast<Storage *>(context.storage);
1152
1153 /* The compute context changes when entering a node group. */
1154 bke::GroupNodeComputeContext compute_context{
1155 user_data->compute_context, group_node_.identifier, &group_node_.owner_tree()};
1156
1157 GeoNodesUserData group_user_data = *user_data;
1158 group_user_data.compute_context = &compute_context;
1160 *user_data, compute_context.hash());
1161
1162 GeoNodesLocalUserData group_local_user_data{group_user_data};
1163 lf::Context group_context{storage->group_storage, &group_user_data, &group_local_user_data};
1164
1165 ScopedComputeContextTimer timer(group_context);
1166 group_lazy_function_.execute(params, group_context);
1167 }
1168
1169 void *init_storage(LinearAllocator<> &allocator) const override
1170 {
1171 Storage *s = allocator.construct<Storage>().release();
1172 s->group_storage = group_lazy_function_.init_storage(allocator);
1173 return s;
1174 }
1175
1176 void destruct_storage(void *storage) const override
1177 {
1178 Storage *s = static_cast<Storage *>(storage);
1179 group_lazy_function_.destruct_storage(s->group_storage);
1180 std::destroy_at(s);
1181 }
1182
1183 std::string name() const override
1184 {
1185 return fmt::format(
1186 fmt::runtime(TIP_("Group '{}' ({})")), group_node_.id->name + 2, group_node_.name);
1187 }
1188
1189 std::string input_name(const int i) const override
1190 {
1191 return group_lazy_function_.input_name(i);
1192 }
1193
1194 std::string output_name(const int i) const override
1195 {
1196 return group_lazy_function_.output_name(i);
1197 }
1198};
1199
1201{
1202 debug_name_ = "Logical Or";
1203 for ([[maybe_unused]] const int i : IndexRange(inputs_num)) {
1204 inputs_.append_as("Input", CPPType::get<bool>(), lf::ValueUsage::Maybe);
1205 }
1206 outputs_.append_as("Output", CPPType::get<bool>());
1207}
1208
1210 const lf::Context & /*context*/) const
1211{
1212 Vector<int, 16> unavailable_inputs;
1213 /* First check all inputs for available values without requesting more inputs. If any of the
1214 * available inputs is true already, the others don't have to be requested anymore. */
1215 for (const int i : inputs_.index_range()) {
1216 if (const bool *value = params.try_get_input_data_ptr<bool>(i)) {
1217 if (*value) {
1218 params.set_output(0, true);
1219 return;
1220 }
1221 }
1222 else {
1223 unavailable_inputs.append(i);
1224 }
1225 }
1226 if (unavailable_inputs.is_empty()) {
1227 params.set_output(0, false);
1228 return;
1229 }
1230 /* Request the next unavailable input. Note that a value might be available now even if it was
1231 * not available before, because it might have been computed in the mean-time. */
1232 for (const int i : unavailable_inputs) {
1233 if (const bool *value = params.try_get_input_data_ptr_or_request<bool>(i)) {
1234 if (*value) {
1235 params.set_output(0, true);
1236 return;
1237 }
1238 }
1239 else {
1240 /* The input has been requested and it's not available yet, so wait until it is ready. */
1241 return;
1242 }
1243 }
1244 /* All inputs were available now and all of them were false, so the final output is false. */
1245 params.set_output(0, false);
1246}
1247
1253 public:
1255 {
1256 debug_name_ = "Switch Socket Usage";
1257 inputs_.append_as("Condition", CPPType::get<SocketValueVariant>());
1258 outputs_.append_as("False", CPPType::get<bool>());
1259 outputs_.append_as("True", CPPType::get<bool>());
1260 }
1261
1262 void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
1263 {
1264 const SocketValueVariant &condition_variant = params.get_input<SocketValueVariant>(0);
1265 if (condition_variant.is_context_dependent_field()) {
1266 params.set_output(0, true);
1267 params.set_output(1, true);
1268 }
1269 else {
1270 const bool value = condition_variant.get<bool>();
1271 params.set_output(0, !value);
1272 params.set_output(1, value);
1273 }
1274 }
1275};
1276
1278 public:
1280 {
1281 debug_name_ = "Enable Output Socket Usage";
1282 inputs_.append_as("Enable", CPPType::get<SocketValueVariant>());
1283 outputs_.append_as("Usage", CPPType::get<bool>());
1284 }
1285
1286 void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
1287 {
1288 const SocketValueVariant &keep_variant = params.get_input<SocketValueVariant>(0);
1289 if (keep_variant.is_single()) {
1290 if (keep_variant.get<bool>() == true) {
1291 params.set_output(0, true);
1292 return;
1293 }
1294 }
1295 params.set_output(0, false);
1296 }
1297};
1298
1304 public:
1306 {
1307 debug_name_ = "Index Switch Socket Usage";
1308 inputs_.append_as("Index", CPPType::get<SocketValueVariant>());
1309 for (const bNodeSocket *socket : bnode.input_sockets().drop_front(1)) {
1310 outputs_.append_as(socket->identifier, CPPType::get<bool>());
1311 }
1312 }
1313
1314 void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
1315 {
1316 const SocketValueVariant &index_variant = params.get_input<SocketValueVariant>(0);
1317 if (index_variant.is_context_dependent_field()) {
1318 for (const int i : outputs_.index_range()) {
1319 params.set_output(i, true);
1320 }
1321 }
1322 else {
1323 const int value = index_variant.get<int>();
1324 for (const int i : outputs_.index_range()) {
1325 params.set_output(i, i == value);
1326 }
1327 }
1328 }
1329};
1330
1335 public:
1337 {
1338 debug_name_ = "Extract References";
1339 inputs_.append_as("Use", CPPType::get<bool>());
1341 outputs_.append_as("References", CPPType::get<GeometryNodesReferenceSet>());
1342 }
1343
1344 void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
1345 {
1346 const bool use = params.get_input<bool>(0);
1347 if (!use) {
1348 params.set_output<GeometryNodesReferenceSet>(0, {});
1349 return;
1350 }
1351 const SocketValueVariant *value_variant =
1352 params.try_get_input_data_ptr_or_request<SocketValueVariant>(1);
1353 if (value_variant == nullptr) {
1354 /* Wait until the field is computed. */
1355 return;
1356 }
1357
1358 GeometryNodesReferenceSet references;
1359 if (value_variant->is_context_dependent_field()) {
1360 const GField &field = value_variant->get<GField>();
1361 field.node().for_each_field_input_recursive([&](const FieldInput &field_input) {
1362 if (const auto *attr_field_input = dynamic_cast<const AttributeFieldInput *>(&field_input))
1363 {
1364 const StringRef name = attr_field_input->attribute_name();
1366 if (!references.names) {
1367 references.names = std::make_shared<Set<std::string>>();
1368 }
1369 references.names->add_as(name);
1370 }
1371 }
1372 });
1373 }
1374 params.set_output(0, std::move(references));
1375 }
1376};
1377
1383 const int amount_;
1384
1385 public:
1386 LazyFunctionForJoinReferenceSets(const int amount) : amount_(amount)
1387 {
1388 debug_name_ = "Join Reference Sets";
1389 for ([[maybe_unused]] const int i : IndexRange(amount)) {
1390 inputs_.append_as("Use", CPPType::get<bool>());
1391 inputs_.append_as(
1393 }
1394 outputs_.append_as("Reference Set", CPPType::get<GeometryNodesReferenceSet>());
1395 }
1396
1397 void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
1398 {
1400 bool set_is_missing = false;
1401 for (const int i : IndexRange(amount_)) {
1402 if (params.get_input<bool>(this->get_use_input(i))) {
1403 if (GeometryNodesReferenceSet *set =
1404 params.try_get_input_data_ptr_or_request<GeometryNodesReferenceSet>(
1405 this->get_reference_set_input(i)))
1406 {
1407 sets.append(set);
1408 }
1409 else {
1410 set_is_missing = true;
1411 }
1412 }
1413 }
1414 if (set_is_missing) {
1415 return;
1416 }
1417 GeometryNodesReferenceSet joined_set;
1418 if (sets.is_empty()) {
1419 /* Nothing to do. */
1420 }
1421 else if (sets.size() == 1) {
1422 joined_set.names = std::move(sets[0]->names);
1423 }
1424 else {
1425 joined_set.names = std::make_shared<Set<std::string>>();
1426 for (const GeometryNodesReferenceSet *set : sets) {
1427 if (set->names) {
1428 for (const std::string &name : *set->names) {
1429 joined_set.names->add(name);
1430 }
1431 }
1432 }
1433 }
1434 params.set_output(0, std::move(joined_set));
1435 }
1436
1437 int get_use_input(const int i) const
1438 {
1439 return 2 * i;
1440 }
1441
1442 int get_reference_set_input(const int i) const
1443 {
1444 return 2 * i + 1;
1445 }
1446
1450 static const LazyFunctionForJoinReferenceSets &get_cached(const int amount, ResourceScope &scope)
1451 {
1452 constexpr int cache_amount = 16;
1453 static std::array<LazyFunctionForJoinReferenceSets, cache_amount> cached_functions = get_cache(
1454 std::make_index_sequence<cache_amount>{});
1455 if (amount < cached_functions.size()) {
1456 return cached_functions[amount];
1457 }
1458
1459 return scope.construct<LazyFunctionForJoinReferenceSets>(amount);
1460 }
1461
1462 private:
1463 template<size_t... I>
1464 static std::array<LazyFunctionForJoinReferenceSets, sizeof...(I)> get_cache(
1465 std::index_sequence<I...> /*indices*/)
1466 {
1468 }
1469};
1470
1472 private:
1473 const bNode &sim_output_bnode_;
1474 const LazyFunction &fn_;
1475
1476 public:
1477 LazyFunctionForSimulationZone(const bNode &sim_output_bnode, const LazyFunction &fn)
1478 : sim_output_bnode_(sim_output_bnode), fn_(fn)
1479 {
1480 debug_name_ = "Simulation Zone";
1481 inputs_ = fn.inputs();
1482 outputs_ = fn.outputs();
1483 }
1484
1485 void execute_impl(lf::Params &params, const lf::Context &context) const override
1486 {
1487 ScopedNodeTimer node_timer{context, sim_output_bnode_};
1488 GeoNodesUserData &user_data = *static_cast<GeoNodesUserData *>(context.user_data);
1489
1490 bke::SimulationZoneComputeContext compute_context{user_data.compute_context,
1491 sim_output_bnode_};
1492
1493 GeoNodesUserData zone_user_data = user_data;
1494 zone_user_data.compute_context = &compute_context;
1496 user_data, compute_context.hash());
1497
1498 GeoNodesLocalUserData zone_local_user_data{zone_user_data};
1499 lf::Context zone_context{context.storage, &zone_user_data, &zone_local_user_data};
1500 fn_.execute(params, zone_context);
1501 }
1502
1503 void *init_storage(LinearAllocator<> &allocator) const override
1504 {
1505 return fn_.init_storage(allocator);
1506 }
1507
1508 void destruct_storage(void *storage) const override
1509 {
1510 fn_.destruct_storage(storage);
1511 }
1512
1513 std::string input_name(const int i) const override
1514 {
1515 return fn_.input_name(i);
1516 }
1517
1518 std::string output_name(const int i) const override
1519 {
1520 return fn_.output_name(i);
1521 }
1522};
1523
1524void report_from_multi_function(const mf::Context &context,
1525 NodeWarningType type,
1526 std::string message)
1527{
1528 const auto *user_data = dynamic_cast<const GeoNodesUserData *>(context.user_data);
1529 if (!user_data) {
1530 return;
1531 }
1532 geo_eval_log::GeoNodesLog *log = user_data->call_data->eval_log;
1533 if (!log) {
1534 return;
1535 }
1536 const bke::NodeComputeContext *node_context = nullptr;
1537 for (const ComputeContext *compute_context = user_data->compute_context; compute_context;
1538 compute_context = compute_context->parent())
1539 {
1540 node_context = dynamic_cast<const bke::NodeComputeContext *>(compute_context);
1541 if (node_context) {
1542 break;
1543 }
1544 }
1545 if (!node_context) {
1546 return;
1547 }
1548 const auto *tree_context = node_context->parent();
1549 if (!tree_context) {
1550 return;
1551 }
1552 geo_eval_log::GeoTreeLogger &logger = log->get_local_tree_logger(*tree_context);
1553 logger.node_warnings.append(*logger.allocator,
1554 {node_context->node_id(), {type, std::move(message)}});
1555}
1556
1558
1596
1597static bool ignore_zone_bsocket(const bNodeSocket &bsocket)
1598{
1599 if (!bsocket.is_available()) {
1600 return true;
1601 }
1602 if (!bsocket.typeinfo->geometry_nodes_default_value) {
1603 /* These are typically extend sockets. */
1604 return true;
1605 }
1606 return false;
1607}
1608
1610 ZoneBuildInfo &zone_info,
1611 const ZoneBodyFunction &body_fn,
1612 const bool expose_all_reference_sets,
1613 Vector<lf::Input> &r_inputs,
1614 Vector<lf::Output> &r_outputs)
1615{
1616 for (const bNodeSocket *socket : zone.input_node()->input_sockets()) {
1617 if (ignore_zone_bsocket(*socket)) {
1618 continue;
1619 }
1622 }
1623
1624 for (const bNodeLink *link : zone.border_links) {
1627 }
1628
1629 for (const bNodeSocket *socket : zone.output_node()->output_sockets()) {
1630 if (ignore_zone_bsocket(*socket)) {
1631 continue;
1632 }
1635 zone_info.indices.outputs.main.append(
1637 }
1638
1639 for ([[maybe_unused]] const bNodeSocket *socket : zone.input_node()->input_sockets()) {
1640 if (ignore_zone_bsocket(*socket)) {
1641 continue;
1642 }
1644 r_outputs.append_and_get_index_as("Usage", CPPType::get<bool>()));
1645 }
1646
1647 for ([[maybe_unused]] const bNodeLink *link : zone.border_links) {
1649 r_outputs.append_and_get_index_as("Border Link Usage", CPPType::get<bool>()));
1650 }
1651
1652 /* Some zone types (e.g. the closure zone) do not expose all reference sets. */
1653 if (expose_all_reference_sets) {
1654 for (const auto item : body_fn.indices.inputs.reference_sets.items()) {
1656 item.key,
1657 r_inputs.append_and_get_index_as(
1659 }
1660 }
1661}
1662
1663std::string zone_wrapper_input_name(const ZoneBuildInfo &zone_info,
1664 const bNodeTreeZone &zone,
1665 const Span<lf::Input> inputs,
1666 const int lf_socket_i)
1667{
1668 if (zone_info.indices.inputs.output_usages.contains(lf_socket_i)) {
1669 const int output_usage_i = lf_socket_i - zone_info.indices.inputs.output_usages.first();
1670 int current_valid_i = 0;
1671 for (const bNodeSocket *bsocket : zone.output_node()->output_sockets()) {
1672 if (ignore_zone_bsocket(*bsocket)) {
1673 continue;
1674 }
1675 if (current_valid_i == output_usage_i) {
1676 return "Usage: " + StringRef(bsocket->name);
1677 }
1678 current_valid_i++;
1679 }
1680 }
1681 return inputs[lf_socket_i].debug_name;
1682}
1683
1684std::string zone_wrapper_output_name(const ZoneBuildInfo &zone_info,
1685 const bNodeTreeZone &zone,
1687 const int lf_socket_i)
1688{
1689 if (zone_info.indices.outputs.input_usages.contains(lf_socket_i)) {
1690 const int input_usage_i = lf_socket_i - zone_info.indices.outputs.input_usages.first();
1691 int current_valid_i = 0;
1692 for (const bNodeSocket *bsocket : zone.input_node()->input_sockets()) {
1693 if (ignore_zone_bsocket(*bsocket)) {
1694 continue;
1695 }
1696 if (current_valid_i == input_usage_i) {
1697 return "Usage: " + StringRef(bsocket->name);
1698 }
1699 current_valid_i++;
1700 }
1701 }
1702 return outputs[lf_socket_i].debug_name;
1703}
1704
1710 private:
1711 const GeometryNodesLazyFunctionGraphInfo &lf_graph_info_;
1712
1713 public:
1715 : lf_graph_info_(lf_graph_info)
1716 {
1717 }
1718
1719 void log_socket_value(const lf::Socket &lf_socket,
1720 const GPointer value,
1721 const lf::Context &context) const override
1722 {
1723 auto &user_data = *static_cast<GeoNodesUserData *>(context.user_data);
1724 if (!user_data.log_socket_values) {
1725 return;
1726 }
1727 auto &local_user_data = *static_cast<GeoNodesLocalUserData *>(context.local_user_data);
1728 geo_eval_log::GeoTreeLogger *tree_logger = local_user_data.try_get_tree_logger(user_data);
1729 if (tree_logger == nullptr) {
1730 return;
1731 }
1732
1733 Span<const bNodeSocket *> bsockets = lf_graph_info_.mapping.bsockets_by_lf_socket_map.lookup(
1734 &lf_socket);
1735 if (bsockets.is_empty()) {
1736 return;
1737 }
1738 if (bsockets[0]->owner_node().is_group_input()) {
1739 /* Only log a group input once instead of for every group input node separately. */
1740 bsockets = bsockets.take_front(1);
1741 }
1742
1743 for (const bNodeSocket *bsocket : bsockets) {
1744 /* Avoid logging to some sockets when the same value will also be logged to a linked socket.
1745 * This reduces the number of logged values without losing information. */
1746 if (bsocket->is_input() && bsocket->is_directly_linked()) {
1747 continue;
1748 }
1749 const bNode &bnode = bsocket->owner_node();
1750 if (bnode.is_reroute()) {
1751 continue;
1752 }
1753 tree_logger->log_value(bsocket->owner_node(), *bsocket, value);
1754 }
1755 }
1756
1758
1760 Span<const lf::OutputSocket *> missing_sockets,
1761 const lf::Context &context) const override
1762 {
1763 std::lock_guard lock{dump_error_context_mutex};
1764
1765 GeoNodesUserData *user_data = dynamic_cast<GeoNodesUserData *>(context.user_data);
1766 BLI_assert(user_data != nullptr);
1767 user_data->compute_context->print_stack(std::cout, node.name());
1768 std::cout << "Missing outputs:\n";
1769 for (const lf::OutputSocket *socket : missing_sockets) {
1770 std::cout << " " << socket->name() << "\n";
1771 }
1772 }
1773
1775 const lf::OutputSocket &from_socket,
1776 const lf::Context &context) const override
1777 {
1778 std::lock_guard lock{dump_error_context_mutex};
1779
1780 std::stringstream ss;
1781 ss << from_socket.node().name() << ":" << from_socket.name() << " -> "
1782 << target_socket.node().name() << ":" << target_socket.name();
1783
1784 GeoNodesUserData *user_data = dynamic_cast<GeoNodesUserData *>(context.user_data);
1785 BLI_assert(user_data != nullptr);
1786 user_data->compute_context->print_stack(std::cout, ss.str());
1787 }
1788
1790 const lf::Params & /*params*/,
1791 const lf::Context &context) const override
1792 {
1793 /* Enable this to see the threads that invoked a node. */
1794 if constexpr (false) {
1795 this->add_thread_id_debug_message(node, context);
1796 }
1797 }
1798
1799 void add_thread_id_debug_message(const lf::FunctionNode &node, const lf::Context &context) const
1800 {
1801 static std::atomic<int> thread_id_source = 0;
1802 static thread_local const int thread_id = thread_id_source.fetch_add(1);
1803 static thread_local const std::string thread_id_str = "Thread: " + std::to_string(thread_id);
1804
1805 const auto &user_data = *static_cast<GeoNodesUserData *>(context.user_data);
1806 const auto &local_user_data = *static_cast<GeoNodesLocalUserData *>(context.local_user_data);
1807 geo_eval_log::GeoTreeLogger *tree_logger = local_user_data.try_get_tree_logger(user_data);
1808 if (tree_logger == nullptr) {
1809 return;
1810 }
1811
1812 /* Find corresponding node based on the socket mapping. */
1813 auto check_sockets = [&](const Span<const lf::Socket *> lf_sockets) {
1814 for (const lf::Socket *lf_socket : lf_sockets) {
1815 const Span<const bNodeSocket *> bsockets =
1816 lf_graph_info_.mapping.bsockets_by_lf_socket_map.lookup(lf_socket);
1817 if (!bsockets.is_empty()) {
1818 const bNodeSocket &bsocket = *bsockets[0];
1819 const bNode &bnode = bsocket.owner_node();
1820 tree_logger->debug_messages.append(*tree_logger->allocator,
1821 {bnode.identifier, thread_id_str});
1822 return true;
1823 }
1824 }
1825 return false;
1826 };
1827
1828 if (check_sockets(node.inputs().cast<const lf::Socket *>())) {
1829 return;
1830 }
1831 check_sockets(node.outputs().cast<const lf::Socket *>());
1832 }
1833};
1834
1841 private:
1842 Span<const lf::FunctionNode *> local_side_effect_nodes_;
1843
1844 public:
1846 Span<const lf::FunctionNode *> local_side_effect_nodes = {})
1847 : local_side_effect_nodes_(local_side_effect_nodes)
1848 {
1849 }
1850
1852 const lf::Context &context) const override
1853 {
1854 GeoNodesUserData *user_data = dynamic_cast<GeoNodesUserData *>(context.user_data);
1855 BLI_assert(user_data != nullptr);
1856 const GeoNodesCallData &call_data = *user_data->call_data;
1857 if (!call_data.side_effect_nodes) {
1858 return {};
1859 }
1860 const ComputeContextHash &context_hash = user_data->compute_context->hash();
1861 Vector<const lf::FunctionNode *> side_effect_nodes =
1862 call_data.side_effect_nodes->nodes_by_context.lookup(context_hash);
1863 side_effect_nodes.extend(local_side_effect_nodes_);
1864 return side_effect_nodes;
1865 }
1866};
1867
1874 private:
1875 const bNodeTree &btree_;
1876 const ReferenceLifetimesInfo &reference_lifetimes_;
1877 ResourceScope &scope_;
1878 NodeMultiFunctions &node_multi_functions_;
1879 GeometryNodesLazyFunctionGraphInfo *lf_graph_info_;
1881 const bke::DataTypeConversions *conversions_;
1882
1886 Map<const bNode *, lf::Node *> simulation_inputs_usage_nodes_;
1887
1888 const bNodeTreeZones *tree_zones_;
1889 MutableSpan<ZoneBuildInfo> zone_build_infos_;
1890
1891 std::optional<BuildGraphParams> root_graph_build_params_;
1892
1897 Vector<lf::GraphInputSocket *> group_input_sockets_;
1902 Vector<lf::GraphOutputSocket *> standard_group_output_sockets_;
1907 Vector<lf::GraphInputSocket *> group_output_used_sockets_;
1912 Vector<lf::GraphOutputSocket *> group_input_usage_sockets_;
1917 Map<int, lf::GraphInputSocket *> reference_set_by_output_;
1918
1920
1921 public:
1924 : btree_(btree),
1925 reference_lifetimes_(*btree.runtime->reference_lifetimes_info),
1926 scope_(lf_graph_info.scope),
1927 node_multi_functions_(lf_graph_info.scope.construct<NodeMultiFunctions>(btree)),
1928 lf_graph_info_(&lf_graph_info)
1929 {
1930 }
1931
1932 void build()
1933 {
1934 btree_.ensure_topology_cache();
1935 btree_.ensure_interface_cache();
1936
1937 mapping_ = &lf_graph_info_->mapping;
1938 conversions_ = &bke::get_implicit_type_conversions();
1939 tree_zones_ = btree_.zones();
1940
1941 this->initialize_mapping_arrays();
1942 this->build_zone_functions();
1943 this->build_root_graph();
1944 this->build_geometry_nodes_group_function();
1945 }
1946
1947 private:
1948 void initialize_mapping_arrays()
1949 {
1951 btree_.all_output_sockets().size());
1954 btree_.all_output_sockets().size());
1956 mapping_->lf_index_by_bsocket.reinitialize(btree_.all_sockets().size());
1957 mapping_->lf_index_by_bsocket.fill(-1);
1958 }
1959
1963 void build_zone_functions()
1964 {
1965 zone_build_infos_ = scope_.construct<Array<ZoneBuildInfo>>(tree_zones_->zones.size());
1966
1967 const Array<int> zone_build_order = this->compute_zone_build_order();
1968
1969 for (const int zone_i : zone_build_order) {
1970 const bNodeTreeZone &zone = *tree_zones_->zones[zone_i];
1971 switch (zone.output_node()->type_legacy) {
1973 this->build_simulation_zone_function(zone);
1974 break;
1975 }
1977 this->build_repeat_zone_function(zone);
1978 break;
1979 }
1981 this->build_foreach_geometry_element_zone_function(zone);
1982 break;
1984 this->build_closure_zone_function(zone);
1985 break;
1986 default: {
1988 break;
1989 }
1990 }
1991 }
1992 }
1993
1994 Array<int> compute_zone_build_order()
1995 {
1996 /* Build nested zones first. */
1997 Array<int> zone_build_order(tree_zones_->zones.size());
1998 array_utils::fill_index_range<int>(zone_build_order);
1999 std::sort(
2000 zone_build_order.begin(), zone_build_order.end(), [&](const int zone_a, const int zone_b) {
2001 return tree_zones_->zones[zone_a]->depth > tree_zones_->zones[zone_b]->depth;
2002 });
2003 return zone_build_order;
2004 }
2005
2010 void build_simulation_zone_function(const bNodeTreeZone &zone)
2011 {
2012 const int zone_i = zone.index;
2013 ZoneBuildInfo &zone_info = zone_build_infos_[zone_i];
2014 lf::Graph &lf_graph = scope_.construct<lf::Graph>();
2015 const auto &sim_output_storage = *static_cast<const NodeGeometrySimulationOutput *>(
2016 zone.output_node()->storage);
2017
2018 Vector<lf::GraphInputSocket *> lf_zone_inputs;
2019 Vector<lf::GraphOutputSocket *> lf_zone_outputs;
2020
2021 if (zone.input_node() != nullptr) {
2022 for (const bNodeSocket *bsocket : zone.input_node()->input_sockets().drop_back(1)) {
2023 zone_info.indices.inputs.main.append(lf_zone_inputs.append_and_get_index(
2024 &lf_graph.add_input(CPPType::get<SocketValueVariant>(), bsocket->name)));
2025 zone_info.indices.outputs.input_usages.append(lf_zone_outputs.append_and_get_index(
2026 &lf_graph.add_output(CPPType::get<bool>(), "Usage: " + StringRef(bsocket->name))));
2027 }
2028 }
2029
2030 this->build_zone_border_links_inputs(
2031 zone, lf_graph, lf_zone_inputs, zone_info.indices.inputs.border_links);
2032 this->build_zone_border_link_input_usages(
2033 zone, lf_graph, lf_zone_outputs, zone_info.indices.outputs.border_link_usages);
2034
2035 for (const bNodeSocket *bsocket : zone.output_node()->output_sockets().drop_back(1)) {
2036 zone_info.indices.outputs.main.append(lf_zone_outputs.append_and_get_index(
2037 &lf_graph.add_output(CPPType::get<SocketValueVariant>(), bsocket->name)));
2038 zone_info.indices.inputs.output_usages.append(lf_zone_inputs.append_and_get_index(
2039 &lf_graph.add_input(CPPType::get<bool>(), "Usage: " + StringRef(bsocket->name))));
2040 }
2041
2042 lf::Node &lf_simulation_usage_node = [&]() -> lf::Node & {
2043 auto &lazy_function = scope_.construct<LazyFunctionForSimulationInputsUsage>(
2044 *zone.output_node());
2045 lf::Node &lf_node = lf_graph.add_function(lazy_function);
2046
2047 for (const int i : zone_info.indices.outputs.input_usages) {
2048 lf_graph.add_link(lf_node.output(0), *lf_zone_outputs[i]);
2049 }
2050
2051 return lf_node;
2052 }();
2053
2054 BuildGraphParams graph_params{lf_graph};
2055
2056 lf::FunctionNode *lf_simulation_input = nullptr;
2057 if (zone.input_node()) {
2058 lf_simulation_input = this->insert_simulation_input_node(
2059 btree_, *zone.input_node(), graph_params);
2060 }
2061 lf::FunctionNode &lf_simulation_output = this->insert_simulation_output_node(
2062 *zone.output_node(), graph_params);
2063
2064 for (const bNodeSocket *bsocket : zone.output_node()->input_sockets().drop_back(1)) {
2065 graph_params.usage_by_bsocket.add(bsocket, &lf_simulation_usage_node.output(1));
2066 }
2067
2068 /* Link simulation input node directly to simulation output node for skip behavior. */
2069 for (const int i : IndexRange(sim_output_storage.items_num)) {
2070 lf::InputSocket &lf_to = lf_simulation_output.input(i + 1);
2071 if (lf_simulation_input) {
2072 lf::OutputSocket &lf_from = lf_simulation_input->output(i + 1);
2073 lf_graph.add_link(lf_from, lf_to);
2074 }
2075 else {
2076 const bNodeSocket &bsocket = zone.output_node()->input_socket(i + 1);
2077 lf_to.set_default_value(bsocket.typeinfo->geometry_nodes_default_value);
2078 }
2079 }
2080
2081 this->insert_nodes_and_zones(zone.child_nodes(), zone.child_zones, graph_params);
2082
2083 if (zone.input_node()) {
2084 this->build_output_socket_usages(*zone.input_node(), graph_params);
2085 }
2086 for (const auto item : graph_params.lf_output_by_bsocket.items()) {
2087 this->insert_links_from_socket(*item.key, *item.value, graph_params);
2088 }
2089
2090 this->link_border_link_inputs_and_usages(zone,
2091 lf_zone_inputs,
2092 zone_info.indices.inputs.border_links,
2093 lf_zone_outputs,
2094 zone_info.indices.outputs.border_link_usages,
2095 graph_params);
2096
2097 for (const int i : zone_info.indices.inputs.main) {
2098 lf_graph.add_link(*lf_zone_inputs[i], lf_simulation_input->input(i));
2099 }
2100
2101 for (const int i : zone_info.indices.outputs.main.index_range()) {
2102 lf_graph.add_link(lf_simulation_output.output(i),
2103 *lf_zone_outputs[zone_info.indices.outputs.main[i]]);
2104 }
2105
2106 this->add_default_inputs(graph_params);
2107
2108 Map<ReferenceSetIndex, lf::OutputSocket *> lf_reference_sets;
2109 this->build_reference_set_for_zone(graph_params, lf_reference_sets);
2110 for (const auto item : lf_reference_sets.items()) {
2111 lf::OutputSocket &lf_attribute_set_socket = *item.value;
2112 if (lf_attribute_set_socket.node().is_interface()) {
2113 zone_info.indices.inputs.reference_sets.add_new(
2114 item.key, lf_zone_inputs.append_and_get_index(&lf_attribute_set_socket));
2115 }
2116 }
2117 this->link_reference_sets(graph_params, lf_reference_sets);
2118 this->fix_link_cycles(lf_graph, graph_params.socket_usage_inputs);
2119
2120 lf_graph.update_node_indices();
2121
2122 auto &logger = scope_.construct<GeometryNodesLazyFunctionLogger>(*lf_graph_info_);
2123 auto &side_effect_provider = scope_.construct<GeometryNodesLazyFunctionSideEffectProvider>();
2124
2125 const auto &lf_graph_fn = scope_.construct<lf::GraphExecutor>(lf_graph,
2126 lf_zone_inputs.as_span(),
2127 lf_zone_outputs.as_span(),
2128 &logger,
2129 &side_effect_provider,
2130 nullptr);
2131 const auto &zone_function = scope_.construct<LazyFunctionForSimulationZone>(
2132 *zone.output_node(), lf_graph_fn);
2133 zone_info.lazy_function = &zone_function;
2134
2135 lf_graph_info_->debug_zone_body_graphs.add(zone.output_node()->identifier, &lf_graph);
2136 // std::cout << "\n\n" << lf_graph.to_dot() << "\n\n";
2137 }
2138
2142 void build_repeat_zone_function(const bNodeTreeZone &zone)
2143 {
2144 ZoneBuildInfo &zone_info = zone_build_infos_[zone.index];
2145 /* Build a function for the loop body. */
2146 ZoneBodyFunction &body_fn = this->build_zone_body_function(
2147 zone, "Repeat Body", &scope_.construct<GeometryNodesLazyFunctionSideEffectProvider>());
2148 /* Wrap the loop body by another function that implements the repeat behavior. */
2149 auto &zone_fn = build_repeat_zone_lazy_function(scope_, btree_, zone, zone_info, body_fn);
2150 zone_info.lazy_function = &zone_fn;
2151 }
2152
2153 void build_foreach_geometry_element_zone_function(const bNodeTreeZone &zone)
2154 {
2155 ZoneBuildInfo &zone_info = zone_build_infos_[zone.index];
2156 /* Build a function for the loop body. */
2157 ZoneBodyFunction &body_fn = this->build_zone_body_function(
2158 zone, "Foreach Body", &scope_.construct<GeometryNodesLazyFunctionSideEffectProvider>());
2159 /* Wrap the loop body in another function that implements the foreach behavior. */
2161 scope_, btree_, zone, zone_info, body_fn);
2162 zone_info.lazy_function = &zone_fn;
2163 }
2164
2165 void build_closure_zone_function(const bNodeTreeZone &zone)
2166 {
2167 ZoneBuildInfo &zone_info = zone_build_infos_[zone.index];
2168 /* Build a function for the closure body. */
2169 ZoneBodyFunction &body_fn = this->build_zone_body_function(
2170 zone, "Closure Body", &scope_.construct<GeometryNodesLazyFunctionSideEffectProvider>());
2171 auto &zone_fn = build_closure_zone_lazy_function(scope_, btree_, zone, zone_info, body_fn);
2172 zone_info.lazy_function = &zone_fn;
2173 }
2174
2178 ZoneBodyFunction &build_zone_body_function(
2179 const bNodeTreeZone &zone,
2180 const StringRef name,
2181 const lf::GraphExecutorSideEffectProvider *side_effect_provider)
2182 {
2183 lf::Graph &lf_body_graph = scope_.construct<lf::Graph>(name);
2184
2185 BuildGraphParams graph_params{lf_body_graph};
2186
2187 Vector<lf::GraphInputSocket *> lf_body_inputs;
2188 Vector<lf::GraphOutputSocket *> lf_body_outputs;
2189 ZoneBodyFunction &body_fn = scope_.construct<ZoneBodyFunction>();
2190
2191 for (const bNodeSocket *bsocket : zone.input_node()->output_sockets()) {
2192 if (ignore_zone_bsocket(*bsocket)) {
2193 continue;
2194 }
2196 bsocket->name);
2197 lf::GraphOutputSocket &lf_input_usage = lf_body_graph.add_output(
2198 CPPType::get<bool>(), "Usage: " + StringRef(bsocket->name));
2199 body_fn.indices.inputs.main.append(lf_body_inputs.append_and_get_index(&lf_input));
2200 body_fn.indices.outputs.input_usages.append(
2201 lf_body_outputs.append_and_get_index(&lf_input_usage));
2202 graph_params.lf_output_by_bsocket.add_new(bsocket, &lf_input);
2203 }
2204
2205 this->build_zone_border_links_inputs(
2206 zone, lf_body_graph, lf_body_inputs, body_fn.indices.inputs.border_links);
2207 this->build_zone_border_link_input_usages(
2208 zone, lf_body_graph, lf_body_outputs, body_fn.indices.outputs.border_link_usages);
2209
2210 for (const bNodeSocket *bsocket : zone.output_node()->input_sockets()) {
2211 if (ignore_zone_bsocket(*bsocket)) {
2212 continue;
2213 }
2214 lf::GraphOutputSocket &lf_output = lf_body_graph.add_output(
2216 lf::GraphInputSocket &lf_output_usage = lf_body_graph.add_input(
2217 CPPType::get<bool>(), "Usage: " + StringRef(bsocket->name));
2218 graph_params.lf_inputs_by_bsocket.add(bsocket, &lf_output);
2219 graph_params.usage_by_bsocket.add(bsocket, &lf_output_usage);
2220 body_fn.indices.outputs.main.append(lf_body_outputs.append_and_get_index(&lf_output));
2221 body_fn.indices.inputs.output_usages.append(
2222 lf_body_inputs.append_and_get_index(&lf_output_usage));
2223 }
2224
2225 this->insert_nodes_and_zones(zone.child_nodes(), zone.child_zones, graph_params);
2226
2227 this->build_output_socket_usages(*zone.input_node(), graph_params);
2228
2229 {
2230 int valid_socket_i = 0;
2231 for (const bNodeSocket *bsocket : zone.input_node()->output_sockets()) {
2232 if (ignore_zone_bsocket(*bsocket)) {
2233 continue;
2234 }
2235 lf::OutputSocket *lf_usage = graph_params.usage_by_bsocket.lookup_default(bsocket,
2236 nullptr);
2237 lf::GraphOutputSocket &lf_usage_output =
2238 *lf_body_outputs[body_fn.indices.outputs.input_usages[valid_socket_i]];
2239 if (lf_usage) {
2240 lf_body_graph.add_link(*lf_usage, lf_usage_output);
2241 }
2242 else {
2243 static const bool static_false = false;
2244 lf_usage_output.set_default_value(&static_false);
2245 }
2246 valid_socket_i++;
2247 }
2248 }
2249
2250 for (const auto item : graph_params.lf_output_by_bsocket.items()) {
2251 this->insert_links_from_socket(*item.key, *item.value, graph_params);
2252 }
2253
2254 this->link_border_link_inputs_and_usages(zone,
2255 lf_body_inputs,
2256 body_fn.indices.inputs.border_links,
2257 lf_body_outputs,
2258 body_fn.indices.outputs.border_link_usages,
2259 graph_params);
2260
2261 this->add_default_inputs(graph_params);
2262
2263 Map<int, lf::OutputSocket *> lf_reference_sets;
2264 this->build_reference_set_for_zone(graph_params, lf_reference_sets);
2265 for (const auto item : lf_reference_sets.items()) {
2266 lf::OutputSocket &lf_attribute_set_socket = *item.value;
2267 if (lf_attribute_set_socket.node().is_interface()) {
2268 body_fn.indices.inputs.reference_sets.add_new(
2269 item.key, lf_body_inputs.append_and_get_index(&lf_attribute_set_socket));
2270 }
2271 }
2272 this->link_reference_sets(graph_params, lf_reference_sets);
2273 this->fix_link_cycles(lf_body_graph, graph_params.socket_usage_inputs);
2274
2275 lf_body_graph.update_node_indices();
2276
2277 auto &logger = scope_.construct<GeometryNodesLazyFunctionLogger>(*lf_graph_info_);
2278
2279 body_fn.function = &scope_.construct<lf::GraphExecutor>(lf_body_graph,
2280 lf_body_inputs.as_span(),
2281 lf_body_outputs.as_span(),
2282 &logger,
2283 side_effect_provider,
2284 nullptr);
2285
2286 lf_graph_info_->debug_zone_body_graphs.add(zone.output_node()->identifier, &lf_body_graph);
2287
2288 // std::cout << "\n\n" << lf_body_graph.to_dot() << "\n\n";
2289
2290 return body_fn;
2291 }
2292
2293 void build_zone_border_links_inputs(const bNodeTreeZone &zone,
2294 lf::Graph &lf_graph,
2295 Vector<lf::GraphInputSocket *> &r_lf_graph_inputs,
2296 Vector<int> &r_indices)
2297 {
2298 for (const bNodeLink *border_link : zone.border_links) {
2299 r_indices.append(r_lf_graph_inputs.append_and_get_index(
2301 StringRef("Link from ") + border_link->fromsock->name)));
2302 }
2303 }
2304
2305 void build_zone_border_link_input_usages(const bNodeTreeZone &zone,
2306 lf::Graph &lf_graph,
2307 Vector<lf::GraphOutputSocket *> &r_lf_graph_outputs,
2308 Vector<int> &r_indices)
2309 {
2310 for (const bNodeLink *border_link : zone.border_links) {
2311 r_indices.append(r_lf_graph_outputs.append_and_get_index(&lf_graph.add_output(
2312 CPPType::get<bool>(), StringRef("Usage: Link from ") + border_link->fromsock->name)));
2313 }
2314 }
2315
2316 void build_reference_set_for_zone(BuildGraphParams &graph_params,
2317 Map<ReferenceSetIndex, lf::OutputSocket *> &lf_reference_sets)
2318 {
2319 const Vector<ReferenceSetIndex> all_required_reference_sets =
2320 this->find_all_required_reference_sets(graph_params.lf_reference_set_input_by_output,
2321 graph_params.lf_reference_set_inputs);
2322
2323 auto add_reference_set_zone_input = [&](const ReferenceSetIndex reference_set_i) {
2324 lf::GraphInputSocket &lf_graph_input = graph_params.lf_graph.add_input(
2325 CPPType::get<GeometryNodesReferenceSet>(), "Reference Set");
2326 lf_reference_sets.add(reference_set_i, &lf_graph_input);
2327 };
2328
2329 VectorSet<ReferenceSetIndex> input_reference_sets;
2330 for (const ReferenceSetIndex reference_set_i : all_required_reference_sets) {
2331 const ReferenceSetInfo &reference_set = reference_lifetimes_.reference_sets[reference_set_i];
2332 switch (reference_set.type) {
2333 case ReferenceSetType::GroupOutputData:
2334 case ReferenceSetType::GroupInputReferenceSet: {
2335 add_reference_set_zone_input(reference_set_i);
2336 break;
2337 }
2338 case ReferenceSetType::LocalReferenceSet:
2339 case ReferenceSetType::ClosureOutputData:
2340 case ReferenceSetType::ClosureInputReferenceSet: {
2341 const bNodeSocket &bsocket = *reference_set.socket;
2342 if (lf::OutputSocket *lf_socket = graph_params.lf_output_by_bsocket.lookup_default(
2343 &bsocket, nullptr))
2344 {
2345 lf::OutputSocket *lf_usage_socket = graph_params.usage_by_bsocket.lookup_default(
2346 &bsocket, nullptr);
2347 lf::OutputSocket &lf_reference_set_socket = this->get_extracted_reference_set(
2348 *lf_socket, lf_usage_socket, graph_params);
2349 lf_reference_sets.add(reference_set_i, &lf_reference_set_socket);
2350 }
2351 else {
2352 /* The reference was not created in the zone, so it needs to come from the input. */
2353 add_reference_set_zone_input(reference_set_i);
2354 }
2355 break;
2356 }
2357 }
2358 }
2359 }
2360
2365 void build_root_graph()
2366 {
2367 lf::Graph &lf_graph = lf_graph_info_->graph;
2368
2369 this->build_main_group_inputs(lf_graph);
2370 if (btree_.group_output_node() == nullptr) {
2371 this->build_fallback_group_outputs(lf_graph);
2372 }
2373
2374 for (const bNodeTreeInterfaceSocket *interface_input : btree_.interface_inputs()) {
2375 lf::GraphOutputSocket &lf_socket = lf_graph.add_output(
2377 StringRef("Usage: ") + (interface_input->name ? interface_input->name : ""));
2378 group_input_usage_sockets_.append(&lf_socket);
2379 }
2380
2381 Vector<lf::GraphInputSocket *> lf_output_usages;
2382 for (const bNodeTreeInterfaceSocket *interface_output : btree_.interface_outputs()) {
2383 lf::GraphInputSocket &lf_socket = lf_graph.add_input(
2385 StringRef("Usage: ") + (interface_output->name ? interface_output->name : ""));
2386 group_output_used_sockets_.append(&lf_socket);
2387 lf_output_usages.append(&lf_socket);
2388 }
2389
2390 BuildGraphParams &graph_params = root_graph_build_params_.emplace(lf_graph);
2391 if (const bNode *group_output_bnode = btree_.group_output_node()) {
2392 for (const bNodeSocket *bsocket : group_output_bnode->input_sockets().drop_back(1)) {
2393 graph_params.usage_by_bsocket.add(bsocket, lf_output_usages[bsocket->index()]);
2394 }
2395 }
2396
2397 this->insert_nodes_and_zones(
2398 tree_zones_->nodes_outside_zones(), tree_zones_->root_zones, graph_params);
2399
2400 for (const auto item : graph_params.lf_output_by_bsocket.items()) {
2401 this->insert_links_from_socket(*item.key, *item.value, graph_params);
2402 }
2403 this->build_group_input_usages(graph_params);
2404 this->add_default_inputs(graph_params);
2405
2406 this->build_root_reference_set_inputs(lf_graph);
2407
2408 Map<ReferenceSetIndex, lf::OutputSocket *> lf_reference_sets;
2409 this->build_reference_sets_outside_of_zones(graph_params, lf_reference_sets);
2410 this->link_reference_sets(graph_params, lf_reference_sets);
2411
2412 this->fix_link_cycles(lf_graph, graph_params.socket_usage_inputs);
2413
2414 // std::cout << "\n\n" << lf_graph.to_dot() << "\n\n";
2415
2416 lf_graph.update_node_indices();
2417 lf_graph_info_->num_inline_nodes_approximate += lf_graph.nodes().size();
2418 }
2419
2424 void build_geometry_nodes_group_function()
2425 {
2426 GeometryNodesGroupFunction &function = lf_graph_info_->function;
2427
2428 Vector<const lf::GraphInputSocket *> lf_graph_inputs;
2429 Vector<const lf::GraphOutputSocket *> lf_graph_outputs;
2430
2431 lf_graph_inputs.extend(group_input_sockets_);
2432 function.inputs.main = lf_graph_inputs.index_range().take_back(group_input_sockets_.size());
2433
2434 lf_graph_inputs.extend(group_output_used_sockets_);
2435 function.inputs.output_usages = lf_graph_inputs.index_range().take_back(
2436 group_output_used_sockets_.size());
2437
2438 for (auto [output_index, lf_socket] : reference_set_by_output_.items()) {
2439 lf_graph_inputs.append(lf_socket);
2440 function.inputs.references_to_propagate.geometry_outputs.append(output_index);
2441 }
2442 function.inputs.references_to_propagate.range = lf_graph_inputs.index_range().take_back(
2443 reference_set_by_output_.size());
2444
2445 lf_graph_outputs.extend(standard_group_output_sockets_);
2446 function.outputs.main = lf_graph_outputs.index_range().take_back(
2447 standard_group_output_sockets_.size());
2448
2449 lf_graph_outputs.extend(group_input_usage_sockets_);
2450 function.outputs.input_usages = lf_graph_outputs.index_range().take_back(
2451 group_input_usage_sockets_.size());
2452
2453 Vector<const lf::FunctionNode *> &local_side_effect_nodes =
2454 scope_.construct<Vector<const lf::FunctionNode *>>();
2455 for (const bNode *bnode : btree_.nodes_by_type("GeometryNodeWarning")) {
2456 if (bnode->output_socket(0).is_directly_linked()) {
2457 /* The warning node is not a side-effect node. Instead, the user explicitly used the output
2458 * socket to specify when the warning node should be used. */
2459 continue;
2460 }
2461 if (tree_zones_->get_zone_by_node(bnode->identifier)) {
2462 /* "Global" warning nodes that are evaluated whenever the node group is evaluated must not
2463 * be in a zone. */
2464 continue;
2465 }
2466 /* Add warning node as side-effect node so that it is always evaluated if the node group is
2467 * evaluated. */
2468 const lf::Socket *lf_socket = root_graph_build_params_->lf_inputs_by_bsocket.lookup(
2469 &bnode->input_socket(0))[0];
2470 const lf::FunctionNode &lf_node = static_cast<const lf::FunctionNode &>(lf_socket->node());
2471 local_side_effect_nodes.append(&lf_node);
2472 }
2473
2474 function.function = &scope_.construct<lf::GraphExecutor>(
2475 lf_graph_info_->graph,
2476 std::move(lf_graph_inputs),
2477 std::move(lf_graph_outputs),
2478 &scope_.construct<GeometryNodesLazyFunctionLogger>(*lf_graph_info_),
2479 &scope_.construct<GeometryNodesLazyFunctionSideEffectProvider>(local_side_effect_nodes),
2480 nullptr);
2481 }
2482
2483 void build_reference_sets_outside_of_zones(
2484 BuildGraphParams &graph_params,
2485 Map<ReferenceSetIndex, lf::OutputSocket *> &lf_reference_sets)
2486 {
2487 const Vector<ReferenceSetIndex> all_required_reference_sets =
2488 this->find_all_required_reference_sets(graph_params.lf_reference_set_input_by_output,
2489 graph_params.lf_reference_set_inputs);
2490 for (const ReferenceSetIndex reference_set_i : all_required_reference_sets) {
2491 const ReferenceSetInfo &reference_set = reference_lifetimes_.reference_sets[reference_set_i];
2492 switch (reference_set.type) {
2493 case ReferenceSetType::LocalReferenceSet: {
2494 const bNodeSocket &bsocket = *reference_set.socket;
2495 lf::OutputSocket &lf_socket = *graph_params.lf_output_by_bsocket.lookup(&bsocket);
2496 lf::OutputSocket *lf_usage_socket = graph_params.usage_by_bsocket.lookup_default(
2497 &bsocket, nullptr);
2498 lf::OutputSocket &lf_reference_set_socket = this->get_extracted_reference_set(
2499 lf_socket, lf_usage_socket, graph_params);
2500 lf_reference_sets.add_new(reference_set_i, &lf_reference_set_socket);
2501 break;
2502 }
2503 case ReferenceSetType::GroupInputReferenceSet: {
2504 const int group_input_i = reference_set.index;
2505 lf::GraphInputSocket &lf_socket = *group_input_sockets_[group_input_i];
2506 lf::OutputSocket *lf_usage_socket = group_input_usage_sockets_[group_input_i]->origin();
2507 lf::OutputSocket &lf_reference_set_socket = this->get_extracted_reference_set(
2508 lf_socket, lf_usage_socket, graph_params);
2509 lf_reference_sets.add_new(reference_set_i, &lf_reference_set_socket);
2510 break;
2511 }
2512 case ReferenceSetType::GroupOutputData: {
2513 const int group_output_i = reference_set.index;
2514 lf::GraphInputSocket *lf_reference_set_socket = reference_set_by_output_.lookup(
2515 group_output_i);
2516 lf_reference_sets.add_new(reference_set_i, lf_reference_set_socket);
2517 break;
2518 }
2519 case ReferenceSetType::ClosureOutputData:
2520 case ReferenceSetType::ClosureInputReferenceSet: {
2521 /* These reference sets are not used outside of zones. */
2523 break;
2524 }
2525 }
2526 }
2527 }
2528
2529 Vector<ReferenceSetIndex> find_all_required_reference_sets(
2530 const Map<const bNodeSocket *, lf::InputSocket *> &lf_reference_set_input_by_output,
2531 const MultiValueMap<ReferenceSetIndex, lf::InputSocket *> &lf_reference_set_inputs)
2532 {
2533 BitVector<> all_required_reference_sets(reference_lifetimes_.reference_sets.size(), false);
2534 for (const bNodeSocket *bsocket : lf_reference_set_input_by_output.keys()) {
2535 all_required_reference_sets |=
2536 reference_lifetimes_.required_data_by_socket[bsocket->index_in_tree()];
2537 }
2538 for (const ReferenceSetIndex reference_set_i : lf_reference_set_inputs.keys()) {
2539 all_required_reference_sets[reference_set_i].set();
2540 }
2541 Vector<ReferenceSetIndex> indices;
2542 bits::foreach_1_index(all_required_reference_sets,
2543 [&](const int index) { indices.append(index); });
2544 return indices;
2545 }
2546
2547 void link_reference_sets(BuildGraphParams &graph_params,
2548 const Map<ReferenceSetIndex, lf::OutputSocket *> &lf_reference_sets)
2549 {
2550 JoinReferenceSetsCache join_reference_sets_cache;
2551 /* Pass reference sets to nodes so that they know which attributes to propagate. */
2552 for (const auto &item : graph_params.lf_reference_set_input_by_output.items()) {
2553 const bNodeSocket &output_bsocket = *item.key;
2554 lf::InputSocket &lf_reference_set_input = *item.value;
2555
2556 Vector<lf::OutputSocket *> lf_reference_sets_to_join;
2557 const BoundedBitSpan required_reference_sets =
2558 reference_lifetimes_.required_data_by_socket[output_bsocket.index_in_tree()];
2559 bits::foreach_1_index(required_reference_sets, [&](const ReferenceSetIndex reference_set_i) {
2560 const ReferenceSetInfo &reference_set =
2561 reference_lifetimes_.reference_sets[reference_set_i];
2562 if (reference_set.type == ReferenceSetType::LocalReferenceSet) {
2563 if (&reference_set.socket->owner_node() == &output_bsocket.owner_node()) {
2564 /* This reference is created in the current node, so it should not be an input. */
2565 return;
2566 }
2567 }
2568 lf_reference_sets_to_join.append(lf_reference_sets.lookup(reference_set_i));
2569 });
2570
2571 if (lf::OutputSocket *lf_joined_reference_set = this->join_reference_sets(
2572 lf_reference_sets_to_join,
2573 join_reference_sets_cache,
2574 graph_params.lf_graph,
2575 graph_params.socket_usage_inputs))
2576 {
2577 graph_params.lf_graph.add_link(*lf_joined_reference_set, lf_reference_set_input);
2578 }
2579 else {
2580 static const GeometryNodesReferenceSet empty_reference_set;
2581 lf_reference_set_input.set_default_value(&empty_reference_set);
2582 }
2583 }
2584
2585 /* Pass reference sets to e.g. sub-zones. */
2586 for (const auto &item : graph_params.lf_reference_set_inputs.items()) {
2587 const ReferenceSetIndex reference_set_i = item.key;
2588 lf::OutputSocket &lf_reference_set = *lf_reference_sets.lookup(reference_set_i);
2589 for (lf::InputSocket *lf_reference_set_input : item.value) {
2590 graph_params.lf_graph.add_link(lf_reference_set, *lf_reference_set_input);
2591 }
2592 }
2593 }
2594
2595 void insert_nodes_and_zones(const Span<const bNode *> bnodes,
2596 const Span<const bNodeTreeZone *> zones,
2597 BuildGraphParams &graph_params)
2598 {
2599 Vector<const bNode *> nodes_to_insert = bnodes;
2600 Map<const bNode *, const bNodeTreeZone *> zone_by_output;
2601 for (const bNodeTreeZone *zone : zones) {
2602 nodes_to_insert.append(zone->output_node());
2603 zone_by_output.add(zone->output_node(), zone);
2604 }
2605 /* Insert nodes from right to left so that usage sockets can be build in the same pass. */
2606 std::sort(nodes_to_insert.begin(), nodes_to_insert.end(), [](const bNode *a, const bNode *b) {
2607 return a->runtime->toposort_right_to_left_index < b->runtime->toposort_right_to_left_index;
2608 });
2609
2610 for (const bNode *bnode : nodes_to_insert) {
2611 this->build_output_socket_usages(*bnode, graph_params);
2612 if (const bNodeTreeZone *zone = zone_by_output.lookup_default(bnode, nullptr)) {
2613 this->insert_child_zone_node(*zone, graph_params);
2614 }
2615 else {
2616 this->insert_node_in_graph(*bnode, graph_params);
2617 }
2618 }
2619 }
2620
2621 void link_border_link_inputs_and_usages(const bNodeTreeZone &zone,
2622 const Span<lf::GraphInputSocket *> lf_inputs,
2623 const Span<int> lf_border_link_input_indices,
2624 const Span<lf::GraphOutputSocket *> lf_usages,
2625 const Span<int> lf_border_link_usage_indices,
2626 BuildGraphParams &graph_params)
2627 {
2628 lf::Graph &lf_graph = graph_params.lf_graph;
2629 for (const int border_link_i : zone.border_links.index_range()) {
2630 const bNodeLink &border_link = *zone.border_links[border_link_i];
2631 lf::GraphInputSocket &lf_from = *lf_inputs[lf_border_link_input_indices[border_link_i]];
2632 const Vector<lf::InputSocket *> lf_link_targets = this->find_link_targets(border_link,
2633 graph_params);
2634 for (lf::InputSocket *lf_to : lf_link_targets) {
2635 lf_graph.add_link(lf_from, *lf_to);
2636 }
2637 lf::GraphOutputSocket &lf_usage_output =
2638 *lf_usages[lf_border_link_usage_indices[border_link_i]];
2639 if (lf::OutputSocket *lf_usage = graph_params.usage_by_bsocket.lookup_default(
2640 border_link.tosock, nullptr))
2641 {
2642 lf_graph.add_link(*lf_usage, lf_usage_output);
2643 }
2644 else {
2645 static const bool static_false = false;
2646 lf_usage_output.set_default_value(&static_false);
2647 }
2648 }
2649 }
2650
2651 lf::OutputSocket &get_extracted_reference_set(lf::OutputSocket &lf_field_socket,
2652 lf::OutputSocket *lf_usage_socket,
2653 BuildGraphParams &graph_params)
2654 {
2655 auto &lazy_function = scope_.construct<LazyFunctionForExtractingReferenceSet>();
2656 lf::Node &lf_node = graph_params.lf_graph.add_function(lazy_function);
2657 lf::InputSocket &lf_use_input = lf_node.input(0);
2658 lf::InputSocket &lf_field_input = lf_node.input(1);
2659 graph_params.socket_usage_inputs.add_new(&lf_use_input);
2660 if (lf_usage_socket) {
2661 graph_params.lf_graph.add_link(*lf_usage_socket, lf_use_input);
2662 }
2663 else {
2664 static const bool static_false = false;
2665 lf_use_input.set_default_value(&static_false);
2666 }
2667 graph_params.lf_graph.add_link(lf_field_socket, lf_field_input);
2668 return lf_node.output(0);
2669 }
2670
2674 lf::OutputSocket *join_reference_sets(const Span<lf::OutputSocket *> lf_reference_set_sockets,
2675 JoinReferenceSetsCache &cache,
2676 lf::Graph &lf_graph,
2677 Set<lf::InputSocket *> &socket_usage_inputs)
2678 {
2679 if (lf_reference_set_sockets.is_empty()) {
2680 return nullptr;
2681 }
2682 if (lf_reference_set_sockets.size() == 1) {
2683 return lf_reference_set_sockets[0];
2684 }
2685
2686 Vector<lf::OutputSocket *, 16> key = lf_reference_set_sockets;
2687 std::sort(key.begin(), key.end());
2688 return cache.lookup_or_add_cb(key, [&]() {
2689 const auto &lazy_function = LazyFunctionForJoinReferenceSets::get_cached(
2690 lf_reference_set_sockets.size(), scope_);
2691 lf::Node &lf_node = lf_graph.add_function(lazy_function);
2692 for (const int i : lf_reference_set_sockets.index_range()) {
2693 lf::OutputSocket &lf_reference_set_socket = *lf_reference_set_sockets[i];
2694 lf::InputSocket &lf_use_input = lf_node.input(lazy_function.get_use_input(i));
2695
2696 /* Some reference sets could potentially be set unused in the future based on more dynamic
2697 * analysis of the node tree. */
2698 static const bool static_true = true;
2699 lf_use_input.set_default_value(&static_true);
2700
2701 socket_usage_inputs.add(&lf_use_input);
2702 lf::InputSocket &lf_reference_set_input = lf_node.input(
2703 lazy_function.get_reference_set_input(i));
2704 lf_graph.add_link(lf_reference_set_socket, lf_reference_set_input);
2705 }
2706 return &lf_node.output(0);
2707 });
2708 }
2709
2710 void insert_child_zone_node(const bNodeTreeZone &child_zone, BuildGraphParams &graph_params)
2711 {
2712 const int child_zone_i = child_zone.index;
2713 ZoneBuildInfo &child_zone_info = zone_build_infos_[child_zone_i];
2714 lf::FunctionNode &child_zone_node = graph_params.lf_graph.add_function(
2715 *child_zone_info.lazy_function);
2716 mapping_->zone_node_map.add_new(&child_zone, &child_zone_node);
2717
2718 {
2719 int valid_socket_i = 0;
2720 for (const bNodeSocket *bsocket : child_zone.input_node()->input_sockets()) {
2721 if (ignore_zone_bsocket(*bsocket)) {
2722 continue;
2723 }
2724 lf::InputSocket &lf_input_socket = child_zone_node.input(
2725 child_zone_info.indices.inputs.main[valid_socket_i]);
2726 lf::OutputSocket &lf_usage_socket = child_zone_node.output(
2727 child_zone_info.indices.outputs.input_usages[valid_socket_i]);
2728 mapping_->bsockets_by_lf_socket_map.add(&lf_input_socket, bsocket);
2729 graph_params.lf_inputs_by_bsocket.add(bsocket, &lf_input_socket);
2730 graph_params.usage_by_bsocket.add(bsocket, &lf_usage_socket);
2731 valid_socket_i++;
2732 }
2733 }
2734 {
2735 int valid_socket_i = 0;
2736 for (const bNodeSocket *bsocket : child_zone.output_node()->output_sockets()) {
2737 if (ignore_zone_bsocket(*bsocket)) {
2738 continue;
2739 }
2740 lf::OutputSocket &lf_output_socket = child_zone_node.output(
2741 child_zone_info.indices.outputs.main[valid_socket_i]);
2742 lf::InputSocket &lf_usage_input = child_zone_node.input(
2743 child_zone_info.indices.inputs.output_usages[valid_socket_i]);
2744 mapping_->bsockets_by_lf_socket_map.add(&lf_output_socket, bsocket);
2745 graph_params.lf_output_by_bsocket.add(bsocket, &lf_output_socket);
2746 graph_params.socket_usage_inputs.add(&lf_usage_input);
2747 if (lf::OutputSocket *lf_usage = graph_params.usage_by_bsocket.lookup_default(bsocket,
2748 nullptr))
2749 {
2750 graph_params.lf_graph.add_link(*lf_usage, lf_usage_input);
2751 }
2752 else {
2753 static const bool static_false = false;
2754 lf_usage_input.set_default_value(&static_false);
2755 }
2756 valid_socket_i++;
2757 }
2758 }
2759
2760 const Span<const bNodeLink *> child_border_links = child_zone.border_links;
2761 for (const int child_border_link_i : child_border_links.index_range()) {
2762 lf::InputSocket &child_border_link_input = child_zone_node.input(
2763 child_zone_info.indices.inputs.border_links[child_border_link_i]);
2764 const bNodeLink &link = *child_border_links[child_border_link_i];
2765 graph_params.lf_input_by_border_link.add(&link, &child_border_link_input);
2766 lf::OutputSocket &lf_usage = child_zone_node.output(
2767 child_zone_info.indices.outputs.border_link_usages[child_border_link_i]);
2768 graph_params.lf_inputs_by_bsocket.add(link.tosock, &child_border_link_input);
2769 graph_params.usage_by_bsocket.add(link.tosock, &lf_usage);
2770 }
2771
2772 for (const auto &item : child_zone_info.indices.inputs.reference_sets.items()) {
2773 const ReferenceSetIndex reference_set_i = item.key;
2774 const int child_zone_input_i = item.value;
2775 lf::InputSocket &lf_reference_set_input = child_zone_node.input(child_zone_input_i);
2776 BLI_assert(lf_reference_set_input.type().is<GeometryNodesReferenceSet>());
2777 graph_params.lf_reference_set_inputs.add(reference_set_i, &lf_reference_set_input);
2778 }
2779 }
2780
2781 void build_main_group_inputs(lf::Graph &lf_graph)
2782 {
2783 const Span<const bNodeTreeInterfaceSocket *> interface_inputs = btree_.interface_inputs();
2784 for (const bNodeTreeInterfaceSocket *interface_input : interface_inputs) {
2785 lf::GraphInputSocket &lf_socket = lf_graph.add_input(
2786 CPPType::get<SocketValueVariant>(), interface_input->name ? interface_input->name : "");
2787 group_input_sockets_.append(&lf_socket);
2788 }
2789 }
2790
2795 void build_fallback_group_outputs(lf::Graph &lf_graph)
2796 {
2797 for (const bNodeTreeInterfaceSocket *interface_output : btree_.interface_outputs()) {
2798 const bke::bNodeSocketType *typeinfo = interface_output->socket_typeinfo();
2799 lf::GraphOutputSocket &lf_socket = lf_graph.add_output(
2801 interface_output->name ? interface_output->name : "");
2802 lf_socket.set_default_value(typeinfo->geometry_nodes_default_value);
2803 standard_group_output_sockets_.append(&lf_socket);
2804 }
2805 }
2806
2807 void insert_node_in_graph(const bNode &bnode, BuildGraphParams &graph_params)
2808 {
2809 const bke::bNodeType *node_type = bnode.typeinfo;
2810 if (node_type == nullptr) {
2811 return;
2812 }
2813 if (bnode.is_muted()) {
2814 this->build_muted_node(bnode, graph_params);
2815 return;
2816 }
2817 if (bnode.is_group()) {
2818 /* Have special handling because `bnode.type_legacy` and `node_type.type_legacy` can be
2819 * different for custom node groups. In other cases they should be identical. */
2820 this->build_group_node(bnode, graph_params);
2821 return;
2822 }
2823 switch (node_type->type_legacy) {
2824 case NODE_FRAME: {
2825 /* Ignored. */
2826 break;
2827 }
2828 case NODE_REROUTE: {
2829 this->build_reroute_node(bnode, graph_params);
2830 break;
2831 }
2832 case NODE_GROUP_INPUT: {
2833 this->handle_group_input_node(bnode, graph_params);
2834 break;
2835 }
2836 case NODE_GROUP_OUTPUT: {
2837 this->build_group_output_node(bnode, graph_params);
2838 break;
2839 }
2840 case GEO_NODE_VIEWER: {
2841 this->build_viewer_node(bnode, graph_params);
2842 break;
2843 }
2844 case GEO_NODE_SWITCH: {
2845 this->build_switch_node(bnode, graph_params);
2846 break;
2847 }
2848 case GEO_NODE_INDEX_SWITCH: {
2849 this->build_index_switch_node(bnode, graph_params);
2850 break;
2851 }
2852 case GEO_NODE_WARNING: {
2853 this->build_warning_node(bnode, graph_params);
2854 break;
2855 }
2859 this->build_gizmo_node(bnode, graph_params);
2860 break;
2861 }
2862 case GEO_NODE_BAKE: {
2863 this->build_bake_node(bnode, graph_params);
2864 break;
2865 }
2866 case GEO_NODE_MENU_SWITCH: {
2867 this->build_menu_switch_node(bnode, graph_params);
2868 break;
2869 }
2870 case NODE_EVALUATE_CLOSURE: {
2871 this->build_evaluate_closure_node(bnode, graph_params);
2872 break;
2873 }
2874 default: {
2875 if (node_type->geometry_node_execute) {
2876 this->build_geometry_node(bnode, graph_params);
2877 break;
2878 }
2879 const NodeMultiFunctions::Item &fn_item = node_multi_functions_.try_get(bnode);
2880 if (fn_item.fn != nullptr) {
2881 this->build_multi_function_node(bnode, fn_item, graph_params);
2882 break;
2883 }
2884 if (bnode.is_type("NodeEnableOutput")) {
2885 this->build_enable_output_node(bnode, graph_params);
2886 break;
2887 }
2888 if (bnode.is_undefined()) {
2889 this->build_undefined_node(bnode, graph_params);
2890 break;
2891 }
2892 /* Nodes that don't match any of the criteria above are just ignored. */
2893 break;
2894 }
2895 }
2896 }
2897
2898 void build_muted_node(const bNode &bnode, BuildGraphParams &graph_params)
2899 {
2900 auto &lazy_function = scope_.construct<LazyFunctionForMutedNode>(
2901 bnode, mapping_->lf_index_by_bsocket);
2902 lf::Node &lf_node = graph_params.lf_graph.add_function(lazy_function);
2903 for (const bNodeSocket *bsocket : bnode.input_sockets()) {
2904 const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()];
2905 if (lf_index == -1) {
2906 continue;
2907 }
2908 lf::InputSocket &lf_socket = lf_node.input(lf_index);
2909 graph_params.lf_inputs_by_bsocket.add(bsocket, &lf_socket);
2910 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket);
2911 }
2912 for (const bNodeSocket *bsocket : bnode.output_sockets()) {
2913 const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()];
2914 if (lf_index == -1) {
2915 continue;
2916 }
2917 lf::OutputSocket &lf_socket = lf_node.output(lf_index);
2918 graph_params.lf_output_by_bsocket.add_new(bsocket, &lf_socket);
2919 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket);
2920 }
2921
2922 this->build_muted_node_usages(bnode, graph_params);
2923 }
2924
2928 void build_muted_node_usages(const bNode &bnode, BuildGraphParams &graph_params)
2929 {
2930 /* Find all outputs that use a specific input. */
2931 MultiValueMap<const bNodeSocket *, const bNodeSocket *> outputs_by_input;
2932 for (const bNodeLink &blink : bnode.internal_links()) {
2933 outputs_by_input.add(blink.fromsock, blink.tosock);
2934 }
2935 for (const auto item : outputs_by_input.items()) {
2936 const bNodeSocket &input_bsocket = *item.key;
2937 const Span<const bNodeSocket *> output_bsockets = item.value;
2938
2939 /* The input is used if any of the internally linked outputs is used. */
2940 Vector<lf::OutputSocket *> lf_socket_usages;
2941 for (const bNodeSocket *output_bsocket : output_bsockets) {
2942 if (lf::OutputSocket *lf_socket = graph_params.usage_by_bsocket.lookup_default(
2943 output_bsocket, nullptr))
2944 {
2945 lf_socket_usages.append(lf_socket);
2946 }
2947 }
2948 graph_params.usage_by_bsocket.add(&input_bsocket,
2949 this->or_socket_usages(lf_socket_usages, graph_params));
2950 }
2951 }
2952
2953 void build_reroute_node(const bNode &bnode, BuildGraphParams &graph_params)
2954 {
2955 const bNodeSocket &input_bsocket = bnode.input_socket(0);
2956 const bNodeSocket &output_bsocket = bnode.output_socket(0);
2957 if (!input_bsocket.typeinfo->geometry_nodes_default_value) {
2958 return;
2959 }
2960
2961 auto &lazy_function = scope_.construct<LazyFunctionForRerouteNode>();
2962 lf::Node &lf_node = graph_params.lf_graph.add_function(lazy_function);
2963
2964 lf::InputSocket &lf_input = lf_node.input(0);
2965 lf::OutputSocket &lf_output = lf_node.output(0);
2966 graph_params.lf_inputs_by_bsocket.add(&input_bsocket, &lf_input);
2967 graph_params.lf_output_by_bsocket.add_new(&output_bsocket, &lf_output);
2968 mapping_->bsockets_by_lf_socket_map.add(&lf_input, &input_bsocket);
2969 mapping_->bsockets_by_lf_socket_map.add(&lf_output, &output_bsocket);
2970
2971 if (lf::OutputSocket *lf_usage = graph_params.usage_by_bsocket.lookup_default(
2972 &bnode.output_socket(0), nullptr))
2973 {
2974 graph_params.usage_by_bsocket.add(&bnode.input_socket(0), lf_usage);
2975 }
2976 }
2977
2978 void handle_group_input_node(const bNode &bnode, BuildGraphParams &graph_params)
2979 {
2980 for (const int i : btree_.interface_inputs().index_range()) {
2981 const bNodeSocket &bsocket = bnode.output_socket(i);
2982 lf::GraphInputSocket &lf_socket = *const_cast<lf::GraphInputSocket *>(
2983 group_input_sockets_[i]);
2984 graph_params.lf_output_by_bsocket.add_new(&bsocket, &lf_socket);
2985 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
2986 }
2987 }
2988
2989 void build_group_output_node(const bNode &bnode, BuildGraphParams &graph_params)
2990 {
2991 Vector<lf::GraphOutputSocket *> lf_graph_outputs;
2992
2993 for (const int i : btree_.interface_outputs().index_range()) {
2994 const bNodeTreeInterfaceSocket &interface_output = *btree_.interface_outputs()[i];
2995 const bNodeSocket &bsocket = bnode.input_socket(i);
2996 lf::GraphOutputSocket &lf_socket = graph_params.lf_graph.add_output(
2997 CPPType::get<SocketValueVariant>(), interface_output.name ? interface_output.name : "");
2998 lf_graph_outputs.append(&lf_socket);
2999 graph_params.lf_inputs_by_bsocket.add(&bsocket, &lf_socket);
3000 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
3001 }
3002
3003 if (&bnode == btree_.group_output_node()) {
3004 standard_group_output_sockets_ = lf_graph_outputs.as_span();
3005 }
3006 }
3007
3008 void build_group_node(const bNode &bnode, BuildGraphParams &graph_params)
3009 {
3010 const bNodeTree *group_btree = reinterpret_cast<bNodeTree *>(bnode.id);
3011 if (group_btree == nullptr) {
3012 return;
3013 }
3014 const GeometryNodesLazyFunctionGraphInfo *group_lf_graph_info =
3016 if (group_lf_graph_info == nullptr) {
3017 return;
3018 }
3019
3020 auto &lazy_function = scope_.construct<LazyFunctionForGroupNode>(
3021 bnode, *group_lf_graph_info, *lf_graph_info_);
3022 lf::FunctionNode &lf_node = graph_params.lf_graph.add_function(lazy_function);
3023
3024 for (const int i : bnode.input_sockets().index_range()) {
3025 const bNodeSocket &bsocket = bnode.input_socket(i);
3026 BLI_assert(!bsocket.is_multi_input());
3027 lf::InputSocket &lf_socket = lf_node.input(group_lf_graph_info->function.inputs.main[i]);
3028 graph_params.lf_inputs_by_bsocket.add(&bsocket, &lf_socket);
3029 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
3030 }
3031 for (const int i : bnode.output_sockets().index_range()) {
3032 const bNodeSocket &bsocket = bnode.output_socket(i);
3033 lf::OutputSocket &lf_socket = lf_node.output(group_lf_graph_info->function.outputs.main[i]);
3034 graph_params.lf_output_by_bsocket.add_new(&bsocket, &lf_socket);
3035 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
3036 }
3037 mapping_->group_node_map.add(&bnode, &lf_node);
3038 lf_graph_info_->num_inline_nodes_approximate +=
3039 group_lf_graph_info->num_inline_nodes_approximate;
3040 static const bool static_false = false;
3041 for (const bNodeSocket *bsocket : bnode.output_sockets()) {
3042 {
3043 const int lf_input_index =
3044 mapping_->lf_input_index_for_output_bsocket_usage[bsocket->index_in_all_outputs()];
3045 if (lf_input_index != -1) {
3046 lf::InputSocket &lf_input = lf_node.input(lf_input_index);
3047 lf_input.set_default_value(&static_false);
3048 graph_params.socket_usage_inputs.add(&lf_input);
3049 }
3050 }
3051 {
3052 /* Keep track of reference set inputs that need to be populated later. */
3053 const int lf_input_index =
3054 mapping_->lf_input_index_for_reference_set_for_output[bsocket->index_in_all_outputs()];
3055 if (lf_input_index != -1) {
3056 lf::InputSocket &lf_input = lf_node.input(lf_input_index);
3057 graph_params.lf_reference_set_input_by_output.add(bsocket, &lf_input);
3058 }
3059 }
3060 }
3061
3062 this->build_group_node_socket_usage(bnode, lf_node, graph_params, *group_lf_graph_info);
3063 }
3064
3065 void build_group_node_socket_usage(const bNode &bnode,
3066 lf::FunctionNode &lf_group_node,
3067 BuildGraphParams &graph_params,
3068 const GeometryNodesLazyFunctionGraphInfo &group_lf_graph_info)
3069 {
3070 for (const bNodeSocket *input_bsocket : bnode.input_sockets()) {
3071 const int input_index = input_bsocket->index();
3072 const InputUsageHint &input_usage_hint =
3073 group_lf_graph_info.mapping.group_input_usage_hints[input_index];
3074 switch (input_usage_hint.type) {
3075 case InputUsageHintType::Never: {
3076 /* Nothing to do. */
3077 break;
3078 }
3079 case InputUsageHintType::DependsOnOutput: {
3080 Vector<lf::OutputSocket *> output_usages;
3081 for (const int i : input_usage_hint.output_dependencies) {
3082 if (lf::OutputSocket *lf_socket = graph_params.usage_by_bsocket.lookup_default(
3083 &bnode.output_socket(i), nullptr))
3084 {
3085 output_usages.append(lf_socket);
3086 }
3087 }
3088 graph_params.usage_by_bsocket.add(input_bsocket,
3089 this->or_socket_usages(output_usages, graph_params));
3090 break;
3091 }
3092 case InputUsageHintType::DynamicSocket: {
3093 graph_params.usage_by_bsocket.add(
3094 input_bsocket,
3095 &lf_group_node.output(
3096 group_lf_graph_info.function.outputs.input_usages[input_index]));
3097 break;
3098 }
3099 }
3100 }
3101
3102 for (const bNodeSocket *output_bsocket : bnode.output_sockets()) {
3103 const int lf_input_index =
3104 mapping_
3105 ->lf_input_index_for_output_bsocket_usage[output_bsocket->index_in_all_outputs()];
3106 BLI_assert(lf_input_index >= 0);
3107 lf::InputSocket &lf_socket = lf_group_node.input(lf_input_index);
3108 if (lf::OutputSocket *lf_output_is_used = graph_params.usage_by_bsocket.lookup_default(
3109 output_bsocket, nullptr))
3110 {
3111 graph_params.lf_graph.add_link(*lf_output_is_used, lf_socket);
3112 }
3113 else {
3114 static const bool static_false = false;
3115 lf_socket.set_default_value(&static_false);
3116 }
3117 }
3118 }
3119
3120 void build_geometry_node(const bNode &bnode, BuildGraphParams &graph_params)
3121 {
3122 auto &lazy_function = scope_.construct<LazyFunctionForGeometryNode>(bnode, *lf_graph_info_);
3123 lf::Node &lf_node = graph_params.lf_graph.add_function(lazy_function);
3124
3125 for (const bNodeSocket *bsocket : bnode.input_sockets()) {
3126 const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()];
3127 if (lf_index == -1) {
3128 continue;
3129 }
3130 lf::InputSocket &lf_socket = lf_node.input(lf_index);
3131
3132 if (bsocket->is_multi_input()) {
3133 auto &multi_input_lazy_function = scope_.construct<LazyFunctionForMultiInput>(*bsocket);
3134 lf::Node &lf_multi_input_node = graph_params.lf_graph.add_function(
3135 multi_input_lazy_function);
3136 graph_params.lf_graph.add_link(lf_multi_input_node.output(0), lf_socket);
3137 for (const int i : multi_input_lazy_function.links.index_range()) {
3138 lf::InputSocket &lf_multi_input_socket = lf_multi_input_node.input(i);
3139 const bNodeLink *link = multi_input_lazy_function.links[i];
3140 graph_params.lf_input_by_multi_input_link.add(link, &lf_multi_input_socket);
3141 mapping_->bsockets_by_lf_socket_map.add(&lf_multi_input_socket, bsocket);
3142 lf_multi_input_socket.set_default_value(bsocket->typeinfo->geometry_nodes_default_value);
3143 }
3144 }
3145 else {
3146 graph_params.lf_inputs_by_bsocket.add(bsocket, &lf_socket);
3147 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket);
3148 }
3149 }
3150 for (const bNodeSocket *bsocket : bnode.output_sockets()) {
3151 const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()];
3152 if (lf_index == -1) {
3153 continue;
3154 }
3155 lf::OutputSocket &lf_socket = lf_node.output(lf_index);
3156 graph_params.lf_output_by_bsocket.add_new(bsocket, &lf_socket);
3157 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket);
3158 }
3159
3160 for (const bNodeSocket *bsocket : bnode.output_sockets()) {
3161 {
3162 const int lf_input_index =
3163 mapping_->lf_input_index_for_output_bsocket_usage[bsocket->index_in_all_outputs()];
3164 if (lf_input_index != -1) {
3165 lf::InputSocket &lf_input_socket = lf_node.input(lf_input_index);
3166 if (lf::OutputSocket *lf_usage = graph_params.usage_by_bsocket.lookup_default(bsocket,
3167 nullptr))
3168 {
3169 graph_params.lf_graph.add_link(*lf_usage, lf_input_socket);
3170 }
3171 else {
3172 static const bool static_false = false;
3173 lf_input_socket.set_default_value(&static_false);
3174 }
3175 graph_params.socket_usage_inputs.add_new(&lf_node.input(lf_input_index));
3176 }
3177 }
3178 {
3179 /* Keep track of reference inputs that need to be populated later. */
3180 const int lf_input_index =
3181 mapping_->lf_input_index_for_reference_set_for_output[bsocket->index_in_all_outputs()];
3182 if (lf_input_index != -1) {
3183 graph_params.lf_reference_set_input_by_output.add(bsocket,
3184 &lf_node.input(lf_input_index));
3185 }
3186 }
3187 }
3188
3189 this->build_standard_node_input_socket_usage(bnode, graph_params);
3190 }
3191
3192 void build_standard_node_input_socket_usage(const bNode &bnode, BuildGraphParams &graph_params)
3193 {
3194 if (bnode.input_sockets().is_empty()) {
3195 return;
3196 }
3197
3198 Vector<lf::OutputSocket *> output_usages;
3199 for (const bNodeSocket *output_socket : bnode.output_sockets()) {
3200 if (!output_socket->is_available()) {
3201 continue;
3202 }
3203 if (lf::OutputSocket *is_used_socket = graph_params.usage_by_bsocket.lookup_default(
3204 output_socket, nullptr))
3205 {
3206 output_usages.append_non_duplicates(is_used_socket);
3207 }
3208 }
3209
3210 /* Assume every input is used when any output is used. */
3211 lf::OutputSocket *lf_usage = this->or_socket_usages(output_usages, graph_params);
3212 if (lf_usage == nullptr) {
3213 return;
3214 }
3215
3216 for (const bNodeSocket *input_socket : bnode.input_sockets()) {
3217 if (input_socket->is_available()) {
3218 graph_params.usage_by_bsocket.add(input_socket, lf_usage);
3219 }
3220 }
3221 }
3222
3223 void build_multi_function_node(const bNode &bnode,
3224 const NodeMultiFunctions::Item &fn_item,
3225 BuildGraphParams &graph_params)
3226 {
3227 auto &lazy_function = scope_.construct<LazyFunctionForMultiFunctionNode>(
3228 bnode, fn_item, mapping_->lf_index_by_bsocket);
3229 lf::FunctionNode &lf_node = graph_params.lf_graph.add_function(lazy_function);
3230
3231 for (const bNodeSocket *bsocket : bnode.input_sockets()) {
3232 const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()];
3233 if (lf_index == -1) {
3234 continue;
3235 }
3236 BLI_assert(!bsocket->is_multi_input());
3237 lf::InputSocket &lf_socket = lf_node.input(lf_index);
3238 graph_params.lf_inputs_by_bsocket.add(bsocket, &lf_socket);
3239 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket);
3240 }
3241 for (const bNodeSocket *bsocket : bnode.output_sockets()) {
3242 const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()];
3243 if (lf_index == -1) {
3244 continue;
3245 }
3246 lf::OutputSocket &lf_socket = lf_node.output(lf_index);
3247 graph_params.lf_output_by_bsocket.add(bsocket, &lf_socket);
3248 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket);
3249 }
3250
3251 this->build_standard_node_input_socket_usage(bnode, graph_params);
3252 }
3253
3254 void build_viewer_node(const bNode &bnode, BuildGraphParams &graph_params)
3255 {
3256 auto &lazy_function = scope_.construct<LazyFunctionForViewerNode>(
3257 bnode, mapping_->lf_index_by_bsocket);
3258 lf::FunctionNode &lf_viewer_node = graph_params.lf_graph.add_function(lazy_function);
3259
3260 for (const bNodeSocket *bsocket : bnode.input_sockets().drop_back(1)) {
3261 const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()];
3262 lf::InputSocket &lf_socket = lf_viewer_node.input(lf_index);
3263 graph_params.lf_inputs_by_bsocket.add(bsocket, &lf_socket);
3264 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket);
3265 }
3266
3267 mapping_->possible_side_effect_node_map.add(&bnode, &lf_viewer_node);
3268
3269 {
3270 auto &usage_lazy_function = scope_.construct<LazyFunctionForViewerInputUsage>(
3271 lf_viewer_node);
3272 lf::FunctionNode &lf_usage_node = graph_params.lf_graph.add_function(usage_lazy_function);
3273
3274 for (const bNodeSocket *bsocket : bnode.input_sockets().drop_back(1)) {
3275 graph_params.usage_by_bsocket.add(bsocket, &lf_usage_node.output(0));
3276 }
3277 }
3278 }
3279
3280 void build_gizmo_node(const bNode &bnode, BuildGraphParams &graph_params)
3281 {
3282 auto &lazy_function = scope_.construct<LazyFunctionForGizmoNode>(
3283 bnode, mapping_->lf_index_by_bsocket);
3284 lf::FunctionNode &lf_gizmo_node = graph_params.lf_graph.add_function(lazy_function);
3285 lazy_function.self_node = &lf_gizmo_node;
3286
3287 for (const int i : lazy_function.gizmo_links.index_range()) {
3288 const bNodeLink &link = *lazy_function.gizmo_links[i];
3289 lf::InputSocket &lf_socket = lf_gizmo_node.input(i);
3290 graph_params.lf_input_by_multi_input_link.add(&link, &lf_socket);
3291 }
3292 for (const int i : bnode.input_sockets().drop_front(1).index_range()) {
3293 lf::InputSocket &lf_socket = lf_gizmo_node.input(i + lazy_function.gizmo_links.size());
3294 const bNodeSocket &bsocket = bnode.input_socket(i + 1);
3295 graph_params.lf_inputs_by_bsocket.add(&bsocket, &lf_socket);
3296 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
3297 }
3298 for (const int i : bnode.output_sockets().index_range()) {
3299 lf::OutputSocket &lf_socket = lf_gizmo_node.output(i);
3300 const bNodeSocket &bsocket = bnode.output_socket(i);
3301 graph_params.lf_output_by_bsocket.add(&bsocket, &lf_socket);
3302 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
3303 }
3304
3305 this->build_gizmo_node_socket_usage(bnode, graph_params, lf_gizmo_node);
3306
3307 mapping_->possible_side_effect_node_map.add(&bnode, &lf_gizmo_node);
3308 }
3309
3310 void build_gizmo_node_socket_usage(const bNode &bnode,
3311 BuildGraphParams &graph_params,
3312 const lf::FunctionNode &lf_gizmo_node)
3313 {
3314 const auto &usage_fn = scope_.construct<LazyFunctionForGizmoInputsUsage>(bnode, lf_gizmo_node);
3315 lf::FunctionNode &lf_usage_node = graph_params.lf_graph.add_function(usage_fn);
3316 for (const bNodeSocket *bsocket : bnode.input_sockets()) {
3317 graph_params.usage_by_bsocket.add(bsocket, &lf_usage_node.output(0));
3318 }
3319 }
3320
3321 lf::FunctionNode *insert_simulation_input_node(const bNodeTree &node_tree,
3322 const bNode &bnode,
3323 BuildGraphParams &graph_params)
3324 {
3325 const NodeGeometrySimulationInput *storage = static_cast<const NodeGeometrySimulationInput *>(
3326 bnode.storage);
3327 if (node_tree.node_by_id(storage->output_node_id) == nullptr) {
3328 return nullptr;
3329 }
3330
3331 std::unique_ptr<LazyFunction> lazy_function = get_simulation_input_lazy_function(
3332 node_tree, bnode, *lf_graph_info_);
3333 lf::FunctionNode &lf_node = graph_params.lf_graph.add_function(*lazy_function);
3334 scope_.add(std::move(lazy_function));
3335
3336 for (const int i : bnode.input_sockets().index_range().drop_back(1)) {
3337 const bNodeSocket &bsocket = bnode.input_socket(i);
3338 lf::InputSocket &lf_socket = lf_node.input(
3339 mapping_->lf_index_by_bsocket[bsocket.index_in_tree()]);
3340 graph_params.lf_inputs_by_bsocket.add(&bsocket, &lf_socket);
3341 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
3342 }
3343 for (const int i : bnode.output_sockets().index_range().drop_back(1)) {
3344 const bNodeSocket &bsocket = bnode.output_socket(i);
3345 lf::OutputSocket &lf_socket = lf_node.output(
3346 mapping_->lf_index_by_bsocket[bsocket.index_in_tree()]);
3347 graph_params.lf_output_by_bsocket.add(&bsocket, &lf_socket);
3348 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
3349 }
3350 return &lf_node;
3351 }
3352
3353 lf::FunctionNode &insert_simulation_output_node(const bNode &bnode,
3354 BuildGraphParams &graph_params)
3355 {
3356 std::unique_ptr<LazyFunction> lazy_function = get_simulation_output_lazy_function(
3357 bnode, *lf_graph_info_);
3358 lf::FunctionNode &lf_node = graph_params.lf_graph.add_function(*lazy_function);
3359 scope_.add(std::move(lazy_function));
3360
3361 for (const int i : bnode.input_sockets().index_range().drop_back(1)) {
3362 const bNodeSocket &bsocket = bnode.input_socket(i);
3363 lf::InputSocket &lf_socket = lf_node.input(
3364 mapping_->lf_index_by_bsocket[bsocket.index_in_tree()]);
3365 graph_params.lf_inputs_by_bsocket.add(&bsocket, &lf_socket);
3366 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
3367 }
3368 for (const int i : bnode.output_sockets().index_range().drop_back(1)) {
3369 const bNodeSocket &bsocket = bnode.output_socket(i);
3370 lf::OutputSocket &lf_socket = lf_node.output(
3371 mapping_->lf_index_by_bsocket[bsocket.index_in_tree()]);
3372 graph_params.lf_output_by_bsocket.add(&bsocket, &lf_socket);
3373 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
3374 }
3375
3376 mapping_->possible_side_effect_node_map.add(&bnode, &lf_node);
3377
3378 return lf_node;
3379 }
3380
3381 void build_bake_node(const bNode &bnode, BuildGraphParams &graph_params)
3382 {
3383 std::unique_ptr<LazyFunction> lazy_function = get_bake_lazy_function(bnode, *lf_graph_info_);
3384 lf::FunctionNode &lf_node = graph_params.lf_graph.add_function(*lazy_function);
3385 scope_.add(std::move(lazy_function));
3386
3387 for (const int i : bnode.input_sockets().index_range().drop_back(1)) {
3388 const bNodeSocket &bsocket = bnode.input_socket(i);
3389 lf::InputSocket &lf_socket = lf_node.input(
3390 mapping_->lf_index_by_bsocket[bsocket.index_in_tree()]);
3391 graph_params.lf_inputs_by_bsocket.add(&bsocket, &lf_socket);
3392 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
3393 }
3394 for (const int i : bnode.output_sockets().index_range().drop_back(1)) {
3395 const bNodeSocket &bsocket = bnode.output_socket(i);
3396 lf::OutputSocket &lf_socket = lf_node.output(
3397 mapping_->lf_index_by_bsocket[bsocket.index_in_tree()]);
3398 graph_params.lf_output_by_bsocket.add(&bsocket, &lf_socket);
3399 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
3400 }
3401
3402 mapping_->possible_side_effect_node_map.add(&bnode, &lf_node);
3403
3404 this->build_bake_node_socket_usage(bnode, graph_params);
3405 }
3406
3407 void build_bake_node_socket_usage(const bNode &bnode, BuildGraphParams &graph_params)
3408 {
3409 const LazyFunction &usage_fn = scope_.construct<LazyFunctionForBakeInputsUsage>(bnode);
3410 lf::FunctionNode &lf_usage_node = graph_params.lf_graph.add_function(usage_fn);
3411 const int items_num = bnode.input_sockets().size() - 1;
3412 for (const int i : IndexRange(items_num)) {
3413 graph_params.usage_by_bsocket.add(&bnode.input_socket(i), &lf_usage_node.output(0));
3414 }
3415 }
3416
3417 void build_switch_node(const bNode &bnode, BuildGraphParams &graph_params)
3418 {
3419 std::unique_ptr<LazyFunction> lazy_function = get_switch_node_lazy_function(bnode);
3420 lf::FunctionNode &lf_node = graph_params.lf_graph.add_function(*lazy_function);
3421 scope_.add(std::move(lazy_function));
3422
3423 for (const int i : bnode.input_sockets().index_range()) {
3424 graph_params.lf_inputs_by_bsocket.add(&bnode.input_socket(i), &lf_node.input(i));
3425 mapping_->bsockets_by_lf_socket_map.add(&lf_node.input(i), &bnode.input_socket(i));
3426 }
3427
3428 graph_params.lf_output_by_bsocket.add(&bnode.output_socket(0), &lf_node.output(0));
3429 mapping_->bsockets_by_lf_socket_map.add(&lf_node.output(0), &bnode.output_socket(0));
3430
3431 this->build_switch_node_socket_usage(bnode, graph_params);
3432 }
3433
3434 void build_switch_node_socket_usage(const bNode &bnode, BuildGraphParams &graph_params)
3435 {
3436 const bNodeSocket &switch_input_bsocket = bnode.input_socket(0);
3437 const bNodeSocket &false_input_bsocket = bnode.input_socket(1);
3438 const bNodeSocket &true_input_bsocket = bnode.input_socket(2);
3439 const bNodeSocket &output_bsocket = bnode.output_socket(0);
3440 lf::OutputSocket *output_is_used_socket = graph_params.usage_by_bsocket.lookup_default(
3441 &output_bsocket, nullptr);
3442 if (output_is_used_socket == nullptr) {
3443 return;
3444 }
3445 graph_params.usage_by_bsocket.add(&switch_input_bsocket, output_is_used_socket);
3446 if (switch_input_bsocket.is_directly_linked()) {
3447 /* The condition input is dynamic, so the usage of the other inputs is as well. */
3448 static const LazyFunctionForSwitchSocketUsage switch_socket_usage_fn;
3449 lf::Node &lf_node = graph_params.lf_graph.add_function(switch_socket_usage_fn);
3450 graph_params.lf_inputs_by_bsocket.add(&switch_input_bsocket, &lf_node.input(0));
3451 graph_params.usage_by_bsocket.add(&false_input_bsocket, &lf_node.output(0));
3452 graph_params.usage_by_bsocket.add(&true_input_bsocket, &lf_node.output(1));
3453 }
3454 else {
3455 if (switch_input_bsocket.default_value_typed<bNodeSocketValueBoolean>()->value) {
3456 graph_params.usage_by_bsocket.add(&true_input_bsocket, output_is_used_socket);
3457 }
3458 else {
3459 graph_params.usage_by_bsocket.add(&false_input_bsocket, output_is_used_socket);
3460 }
3461 }
3462 }
3463
3464 void build_enable_output_node(const bNode &bnode, BuildGraphParams &graph_params)
3465 {
3466 std::unique_ptr<LazyFunction> lazy_function = get_enable_output_node_lazy_function(
3467 bnode, *lf_graph_info_);
3468 lf::FunctionNode &lf_node = graph_params.lf_graph.add_function(*lazy_function);
3469 scope_.add(std::move(lazy_function));
3470
3471 for (const int i : bnode.input_sockets().index_range()) {
3472 graph_params.lf_inputs_by_bsocket.add(&bnode.input_socket(i), &lf_node.input(i));
3473 mapping_->bsockets_by_lf_socket_map.add(&lf_node.input(i), &bnode.input_socket(i));
3474 }
3475 for (const int i : bnode.output_sockets().index_range()) {
3476 graph_params.lf_output_by_bsocket.add(&bnode.output_socket(i), &lf_node.output(i));
3477 mapping_->bsockets_by_lf_socket_map.add(&lf_node.output(i), &bnode.output_socket(i));
3478 }
3479
3480 this->build_enable_output_node_socket_usage(bnode, graph_params);
3481 }
3482
3483 void build_enable_output_node_socket_usage(const bNode &bnode, BuildGraphParams &graph_params)
3484 {
3485 const bNodeSocket &enable_bsocket = *bnode.input_by_identifier("Enable");
3486 const bNodeSocket &value_input_bsocket = *bnode.input_by_identifier("Value");
3487 const bNodeSocket &output_bsocket = bnode.output_socket(0);
3488 lf::OutputSocket *output_is_used_socket = graph_params.usage_by_bsocket.lookup_default(
3489 &output_bsocket, nullptr);
3490 if (!output_is_used_socket) {
3491 return;
3492 }
3493 static LazyFunctionForEnableOutputSocketUsage socket_usage_fn;
3494 lf::Node &lf_node = graph_params.lf_graph.add_function(socket_usage_fn);
3495 graph_params.lf_inputs_by_bsocket.add(&enable_bsocket, &lf_node.input(0));
3496 graph_params.usage_by_bsocket.add(&enable_bsocket, output_is_used_socket);
3497 graph_params.usage_by_bsocket.add(&value_input_bsocket, &lf_node.output(0));
3498 }
3499
3500 void build_index_switch_node(const bNode &bnode, BuildGraphParams &graph_params)
3501 {
3502 std::unique_ptr<LazyFunction> lazy_function = get_index_switch_node_lazy_function(
3503 bnode, *lf_graph_info_);
3504 lf::FunctionNode &lf_node = graph_params.lf_graph.add_function(*lazy_function);
3505 scope_.add(std::move(lazy_function));
3506
3507 for (const int i : bnode.input_sockets().drop_back(1).index_range()) {
3508 graph_params.lf_inputs_by_bsocket.add(&bnode.input_socket(i), &lf_node.input(i));
3509 mapping_->bsockets_by_lf_socket_map.add(&lf_node.input(i), &bnode.input_socket(i));
3510 }
3511
3512 graph_params.lf_output_by_bsocket.add(&bnode.output_socket(0), &lf_node.output(0));
3513 mapping_->bsockets_by_lf_socket_map.add(&lf_node.output(0), &bnode.output_socket(0));
3514
3515 this->build_index_switch_node_socket_usage(bnode, graph_params);
3516 }
3517
3518 void build_index_switch_node_socket_usage(const bNode &bnode, BuildGraphParams &graph_params)
3519 {
3520 const bNodeSocket &index_socket = bnode.input_socket(0);
3521 const int items_num = bnode.input_sockets().size() - 1;
3522
3523 lf::OutputSocket *output_is_used = graph_params.usage_by_bsocket.lookup_default(
3524 &bnode.output_socket(0), nullptr);
3525 if (output_is_used == nullptr) {
3526 return;
3527 }
3528 graph_params.usage_by_bsocket.add(&index_socket, output_is_used);
3529 if (index_socket.is_directly_linked()) {
3530 /* The condition input is dynamic, so the usage of the other inputs is as well. */
3531 auto usage_fn = std::make_unique<LazyFunctionForIndexSwitchSocketUsage>(bnode);
3532 lf::Node &lf_node = graph_params.lf_graph.add_function(*usage_fn);
3533 scope_.add(std::move(usage_fn));
3534
3535 graph_params.lf_inputs_by_bsocket.add(&index_socket, &lf_node.input(0));
3536 for (const int i : IndexRange(items_num)) {
3537 graph_params.usage_by_bsocket.add(&bnode.input_socket(i + 1), &lf_node.output(i));
3538 }
3539 }
3540 else {
3541 const int index = index_socket.default_value_typed<bNodeSocketValueInt>()->value;
3542 if (IndexRange(items_num).contains(index)) {
3543 graph_params.usage_by_bsocket.add(&bnode.input_socket(index + 1), output_is_used);
3544 }
3545 }
3546 }
3547
3548 void build_warning_node(const bNode &bnode, BuildGraphParams &graph_params)
3549 {
3550 auto lazy_function_ptr = get_warning_node_lazy_function(bnode);
3551 LazyFunction &lazy_function = *lazy_function_ptr;
3552 scope_.add(std::move(lazy_function_ptr));
3553
3554 lf::Node &lf_node = graph_params.lf_graph.add_function(lazy_function);
3555
3556 for (const int i : bnode.input_sockets().index_range()) {
3557 const bNodeSocket &bsocket = bnode.input_socket(i);
3558 lf::InputSocket &lf_socket = lf_node.input(i);
3559 graph_params.lf_inputs_by_bsocket.add(&bsocket, &lf_socket);
3560 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
3561 }
3562 for (const int i : bnode.output_sockets().index_range()) {
3563 const bNodeSocket &bsocket = bnode.output_socket(i);
3564 lf::OutputSocket &lf_socket = lf_node.output(i);
3565 graph_params.lf_output_by_bsocket.add(&bsocket, &lf_socket);
3566 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
3567 }
3568
3569 const bNodeSocket &output_bsocket = bnode.output_socket(0);
3570
3571 lf::OutputSocket *lf_usage = nullptr;
3572 if (output_bsocket.is_directly_linked()) {
3573 /* The warning node is only used if the output socket is used. */
3574 lf_usage = graph_params.usage_by_bsocket.lookup_default(&output_bsocket, nullptr);
3575 }
3576 else {
3577 /* The warning node is used if any of the output sockets is used. */
3578 lf_usage = this->or_socket_usages(group_output_used_sockets_, graph_params);
3579 }
3580 if (lf_usage) {
3581 for (const bNodeSocket *socket : bnode.input_sockets()) {
3582 graph_params.usage_by_bsocket.add(socket, lf_usage);
3583 }
3584 }
3585 }
3586
3587 void build_menu_switch_node(const bNode &bnode, BuildGraphParams &graph_params)
3588 {
3589 std::unique_ptr<LazyFunction> lazy_function = get_menu_switch_node_lazy_function(
3590 bnode, *lf_graph_info_);
3591 lf::FunctionNode &lf_node = graph_params.lf_graph.add_function(*lazy_function);
3592 scope_.add(std::move(lazy_function));
3593
3594 int input_index = 0;
3595 for (const bNodeSocket *bsocket : bnode.input_sockets().drop_back(1)) {
3596 if (bsocket->is_available()) {
3597 lf::InputSocket &lf_socket = lf_node.input(input_index);
3598 graph_params.lf_inputs_by_bsocket.add(bsocket, &lf_socket);
3599 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket);
3600 input_index++;
3601 }
3602 }
3603 int output_index = 0;
3604 for (const bNodeSocket *bsocket : bnode.output_sockets()) {
3605 if (bsocket->is_available()) {
3606 lf::OutputSocket &lf_socket = lf_node.output(output_index);
3607 graph_params.lf_output_by_bsocket.add(bsocket, &lf_socket);
3608 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket);
3609 output_index++;
3610 }
3611 }
3612
3613 this->build_menu_switch_node_socket_usage(bnode, graph_params);
3614 }
3615
3616 void build_menu_switch_node_socket_usage(const bNode &bnode, BuildGraphParams &graph_params)
3617 {
3618 const NodeMenuSwitch &storage = *static_cast<NodeMenuSwitch *>(bnode.storage);
3619 const NodeEnumDefinition &enum_def = storage.enum_definition;
3620
3621 const bNodeSocket *switch_input_bsocket = bnode.input_sockets()[0];
3622 Vector<const bNodeSocket *> input_bsockets(enum_def.items_num);
3623 for (const int i : IndexRange(enum_def.items_num)) {
3624 input_bsockets[i] = bnode.input_sockets()[i + 1];
3625 }
3626 const bNodeSocket *output_bsocket = bnode.output_sockets()[0];
3627
3628 lf::OutputSocket *output_is_used_socket = graph_params.usage_by_bsocket.lookup_default(
3629 output_bsocket, nullptr);
3630 if (output_is_used_socket == nullptr) {
3631 return;
3632 }
3633 graph_params.usage_by_bsocket.add(switch_input_bsocket, output_is_used_socket);
3634 if (switch_input_bsocket->is_directly_linked()) {
3635 /* The condition input is dynamic, so the usage of the other inputs is as well. */
3636 std::unique_ptr<LazyFunction> lazy_function =
3638 lf::FunctionNode &lf_node = graph_params.lf_graph.add_function(*lazy_function);
3639 scope_.add(std::move(lazy_function));
3640
3641 graph_params.lf_inputs_by_bsocket.add(switch_input_bsocket, &lf_node.input(0));
3642 for (const int i : IndexRange(enum_def.items_num)) {
3643 graph_params.usage_by_bsocket.add(input_bsockets[i], &lf_node.output(i));
3644 }
3645 }
3646 else {
3647 const int condition =
3648 switch_input_bsocket->default_value_typed<bNodeSocketValueMenu>()->value;
3649 for (const int i : IndexRange(enum_def.items_num)) {
3650 const NodeEnumItem &enum_item = enum_def.items()[i];
3651 if (enum_item.identifier == condition) {
3652 graph_params.usage_by_bsocket.add(input_bsockets[i], output_is_used_socket);
3653 break;
3654 }
3655 }
3656 }
3657 }
3658
3659 void build_evaluate_closure_node(const bNode &bnode, BuildGraphParams &graph_params)
3660 {
3661 const EvaluateClosureFunction function = build_evaluate_closure_node_lazy_function(scope_,
3662 bnode);
3663 lf::FunctionNode &lf_node = graph_params.lf_graph.add_function(*function.lazy_function);
3664 const int inputs_num = bnode.input_sockets().size() - 1;
3665 const int outputs_num = bnode.output_sockets().size() - 1;
3666 BLI_assert(inputs_num == function.indices.inputs.main.size());
3667 BLI_assert(inputs_num == function.indices.outputs.input_usages.size());
3668 BLI_assert(outputs_num == function.indices.outputs.main.size());
3669 BLI_assert(outputs_num == function.indices.inputs.output_usages.size());
3670
3671 mapping_->possible_side_effect_node_map.add(&bnode, &lf_node);
3672
3673 for (const int i : IndexRange(inputs_num)) {
3674 const bNodeSocket &bsocket = bnode.input_socket(i);
3675 lf::InputSocket &lf_socket = lf_node.input(function.indices.inputs.main[i]);
3676 graph_params.lf_inputs_by_bsocket.add(&bsocket, &lf_socket);
3677 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
3678 graph_params.usage_by_bsocket.add(&bsocket,
3679 &lf_node.output(function.indices.outputs.input_usages[i]));
3680 }
3681 for (const int i : IndexRange(outputs_num)) {
3682 const bNodeSocket &bsocket = bnode.output_socket(i);
3683 lf::OutputSocket &lf_socket = lf_node.output(function.indices.outputs.main[i]);
3684 graph_params.lf_output_by_bsocket.add(&bsocket, &lf_socket);
3685 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
3686 lf::InputSocket &lf_usage_socket = lf_node.input(function.indices.inputs.output_usages[i]);
3687 graph_params.socket_usage_inputs.add(&lf_usage_socket);
3688 if (lf::OutputSocket *output_is_used = graph_params.usage_by_bsocket.lookup(&bsocket)) {
3689 graph_params.lf_graph.add_link(*output_is_used, lf_usage_socket);
3690 }
3691 else {
3692 static const bool static_false = false;
3693 lf_usage_socket.set_default_value(&static_false);
3694 }
3695 }
3696 for (const auto item : function.indices.inputs.reference_set_by_output.items()) {
3697 const bNodeSocket &bsocket = bnode.output_socket(item.key);
3698 lf_graph_info_->mapping
3699 .lf_input_index_for_reference_set_for_output[bsocket.index_in_all_outputs()] =
3700 item.value;
3701 graph_params.lf_reference_set_input_by_output.add(&bsocket, &lf_node.input(item.value));
3702 }
3703 }
3704
3705 void build_undefined_node(const bNode &bnode, BuildGraphParams &graph_params)
3706 {
3707 auto &lazy_function = scope_.construct<LazyFunctionForUndefinedNode>(
3708 bnode, mapping_->lf_index_by_bsocket);
3709 lf::FunctionNode &lf_node = graph_params.lf_graph.add_function(lazy_function);
3710
3711 for (const bNodeSocket *bsocket : bnode.output_sockets()) {
3712 const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()];
3713 if (lf_index == -1) {
3714 continue;
3715 }
3716 lf::OutputSocket &lf_socket = lf_node.output(lf_index);
3717 graph_params.lf_output_by_bsocket.add(bsocket, &lf_socket);
3718 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket);
3719 }
3720 }
3721
3722 struct TypeWithLinks {
3723 const bke::bNodeSocketType *typeinfo;
3724 Vector<const bNodeLink *> links;
3725 };
3726
3727 void insert_links_from_socket(const bNodeSocket &from_bsocket,
3728 lf::OutputSocket &from_lf_socket,
3729 BuildGraphParams &graph_params)
3730 {
3731 if (from_bsocket.owner_node().is_dangling_reroute()) {
3732 return;
3733 }
3734
3735 const bke::bNodeSocketType &from_typeinfo = *from_bsocket.typeinfo;
3736
3737 /* Group available target sockets by type so that they can be handled together. */
3738 const Vector<TypeWithLinks> types_with_links = this->group_link_targets_by_type(from_bsocket);
3739
3740 for (const TypeWithLinks &type_with_links : types_with_links) {
3741 if (!type_with_links.typeinfo) {
3742 continue;
3743 }
3744 if (!type_with_links.typeinfo->geometry_nodes_default_value) {
3745 continue;
3746 }
3747 const bke::bNodeSocketType &to_typeinfo = *type_with_links.typeinfo;
3748 const Span<const bNodeLink *> links = type_with_links.links;
3749
3750 lf::OutputSocket *converted_from_lf_socket = this->insert_type_conversion_if_necessary(
3751 from_lf_socket, from_typeinfo, to_typeinfo, graph_params.lf_graph);
3752
3753 for (const bNodeLink *link : links) {
3754 const Vector<lf::InputSocket *> lf_link_targets = this->find_link_targets(*link,
3755 graph_params);
3756 if (converted_from_lf_socket == nullptr) {
3757 for (lf::InputSocket *to_lf_socket : lf_link_targets) {
3758 to_lf_socket->set_default_value(to_typeinfo.geometry_nodes_default_value);
3759 }
3760 }
3761 else {
3762 for (lf::InputSocket *to_lf_socket : lf_link_targets) {
3763 graph_params.lf_graph.add_link(*converted_from_lf_socket, *to_lf_socket);
3764 }
3765 }
3766 }
3767 }
3768 }
3769
3770 Vector<TypeWithLinks> group_link_targets_by_type(const bNodeSocket &from_bsocket)
3771 {
3772 const Span<const bNodeLink *> links_from_bsocket = from_bsocket.directly_linked_links();
3773 Vector<TypeWithLinks> types_with_links;
3774 for (const bNodeLink *link : links_from_bsocket) {
3775 if (link->is_muted()) {
3776 continue;
3777 }
3778 if (!link->is_available()) {
3779 continue;
3780 }
3781 const bNodeSocket &to_bsocket = *link->tosock;
3782 bool inserted = false;
3783 for (TypeWithLinks &types_with_links : types_with_links) {
3784 if (types_with_links.typeinfo == to_bsocket.typeinfo) {
3785 types_with_links.links.append(link);
3786 inserted = true;
3787 break;
3788 }
3789 }
3790 if (inserted) {
3791 continue;
3792 }
3793 types_with_links.append({to_bsocket.typeinfo, {link}});
3794 }
3795 return types_with_links;
3796 }
3797
3798 Vector<lf::InputSocket *> find_link_targets(const bNodeLink &link,
3799 const BuildGraphParams &graph_params)
3800 {
3801 if (lf::InputSocket *lf_input_socket = graph_params.lf_input_by_border_link.lookup_default(
3802 &link, nullptr))
3803 {
3804 return {lf_input_socket};
3805 }
3806
3807 const bNodeSocket &to_bsocket = *link.tosock;
3808 if (to_bsocket.is_multi_input()) {
3809 /* TODO: Cache this index on the link. */
3810 int link_index = 0;
3811 for (const bNodeLink *multi_input_link : to_bsocket.directly_linked_links()) {
3812 if (multi_input_link == &link) {
3813 break;
3814 }
3815 if (multi_input_link->is_muted() || !multi_input_link->fromsock->is_available() ||
3816 multi_input_link->fromnode->is_dangling_reroute())
3817 {
3818 continue;
3819 }
3820 link_index++;
3821 }
3822 if (to_bsocket.owner_node().is_muted()) {
3823 if (link_index == 0) {
3824 return Vector<lf::InputSocket *>(graph_params.lf_inputs_by_bsocket.lookup(&to_bsocket));
3825 }
3826 }
3827 else {
3828 lf::InputSocket *lf_multi_input_socket =
3829 graph_params.lf_input_by_multi_input_link.lookup_default(&link, nullptr);
3830 if (!lf_multi_input_socket) {
3831 return {};
3832 }
3833 return {lf_multi_input_socket};
3834 }
3835 }
3836 else {
3837 return Vector<lf::InputSocket *>(graph_params.lf_inputs_by_bsocket.lookup(&to_bsocket));
3838 }
3839 return {};
3840 }
3841
3842 lf::OutputSocket *insert_type_conversion_if_necessary(lf::OutputSocket &from_socket,
3843 const bke::bNodeSocketType &from_typeinfo,
3844 const bke::bNodeSocketType &to_typeinfo,
3845 lf::Graph &lf_graph)
3846 {
3847 if (from_typeinfo.type == to_typeinfo.type) {
3848 return &from_socket;
3849 }
3850 if (const LazyFunction *conversion_fn = build_implicit_conversion_lazy_function(
3851 from_typeinfo, to_typeinfo, scope_))
3852 {
3853 lf::Node &conversion_node = lf_graph.add_function(*conversion_fn);
3854 lf_graph.add_link(from_socket, conversion_node.input(0));
3855 return &conversion_node.output(0);
3856 }
3857 return nullptr;
3858 }
3859
3860 void add_default_inputs(BuildGraphParams &graph_params)
3861 {
3862 for (auto item : graph_params.lf_inputs_by_bsocket.items()) {
3863 const bNodeSocket &bsocket = *item.key;
3864 const Span<lf::InputSocket *> lf_sockets = item.value;
3865 for (lf::InputSocket *lf_socket : lf_sockets) {
3866 if (lf_socket->origin() != nullptr) {
3867 /* Is linked already. */
3868 continue;
3869 }
3870 this->add_default_input(bsocket, *lf_socket, graph_params);
3871 }
3872 }
3873 }
3874
3875 void add_default_input(const bNodeSocket &input_bsocket,
3876 lf::InputSocket &input_lf_socket,
3877 BuildGraphParams &graph_params)
3878 {
3879 if (this->try_add_implicit_input(input_bsocket, input_lf_socket, graph_params)) {
3880 return;
3881 }
3882 input_lf_socket.set_default_value(&scope_.add_value(
3883 input_bsocket.typeinfo->get_geometry_nodes_cpp_value(input_bsocket.default_value)));
3884 }
3885
3886 bool try_add_implicit_input(const bNodeSocket &input_bsocket,
3887 lf::InputSocket &input_lf_socket,
3888 BuildGraphParams &graph_params)
3889 {
3890 const bNode &bnode = input_bsocket.owner_node();
3891 const SocketDeclaration *socket_decl = input_bsocket.runtime->declaration;
3892 if (socket_decl == nullptr) {
3893 return false;
3894 }
3895 if (socket_decl->input_field_type != InputSocketFieldType::Implicit) {
3896 return false;
3897 }
3898 std::optional<ImplicitInputValueFn> implicit_input_fn = get_implicit_input_value_fn(
3899 socket_decl->default_input_type);
3900 if (!implicit_input_fn.has_value()) {
3901 return false;
3902 }
3903 std::function<void(void *)> init_fn = [&bnode, implicit_input_fn](void *r_value) {
3904 (*implicit_input_fn)(bnode, r_value);
3905 };
3906 const CPPType &type = input_lf_socket.type();
3907 auto &lazy_function = scope_.construct<LazyFunctionForImplicitInput>(type, std::move(init_fn));
3908 lf::Node &lf_node = graph_params.lf_graph.add_function(lazy_function);
3909 graph_params.lf_graph.add_link(lf_node.output(0), input_lf_socket);
3910 return true;
3911 }
3912
3918 void build_root_reference_set_inputs(lf::Graph &lf_graph)
3919 {
3920 const aal::RelationsInNode &tree_relations = reference_lifetimes_.tree_relations;
3921 Vector<int> output_indices;
3922 for (const aal::PropagateRelation &relation : tree_relations.propagate_relations) {
3923 output_indices.append_non_duplicates(relation.to_geometry_output);
3924 }
3925
3926 for (const int i : output_indices.index_range()) {
3927 const int output_index = output_indices[i];
3928 const char *name = btree_.interface_outputs()[output_index]->name;
3929 lf::GraphInputSocket &lf_socket = lf_graph.add_input(
3931 StringRef("Propagate: ") + (name ? name : ""));
3932 reference_set_by_output_.add(output_index, &lf_socket);
3933 }
3934 }
3935
3940 lf::OutputSocket *or_socket_usages(const Span<lf::OutputSocket *> usages,
3941 BuildGraphParams &graph_params)
3942 {
3943 if (usages.is_empty()) {
3944 return nullptr;
3945 }
3946 if (usages.size() == 1) {
3947 return usages[0];
3948 }
3949
3950 /* Sort usages to produce a deterministic key for the same set of sockets. */
3951 Vector<lf::OutputSocket *> usages_sorted(usages);
3952 std::sort(usages_sorted.begin(), usages_sorted.end());
3953 return graph_params.socket_usages_combination_cache.lookup_or_add_cb(
3954 std::move(usages_sorted), [&]() {
3955 auto &logical_or_fn = scope_.construct<LazyFunctionForLogicalOr>(usages.size());
3956 lf::Node &logical_or_node = graph_params.lf_graph.add_function(logical_or_fn);
3957
3958 for (const int i : usages_sorted.index_range()) {
3959 graph_params.lf_graph.add_link(*usages_sorted[i], logical_or_node.input(i));
3960 }
3961 return &logical_or_node.output(0);
3962 });
3963 }
3964
3965 void build_output_socket_usages(const bNode &bnode, BuildGraphParams &graph_params)
3966 {
3967 /* Output sockets are used when any of their linked inputs are used. */
3968 for (const bNodeSocket *socket : bnode.output_sockets()) {
3969 if (!socket->is_available()) {
3970 continue;
3971 }
3972 /* Determine when linked target sockets are used. */
3973 Vector<lf::OutputSocket *> target_usages;
3974 for (const bNodeLink *link : socket->directly_linked_links()) {
3975 if (!link->is_used()) {
3976 continue;
3977 }
3978 const bNodeSocket &target_socket = *link->tosock;
3979 if (lf::OutputSocket *is_used_socket = graph_params.usage_by_bsocket.lookup_default(
3980 &target_socket, nullptr))
3981 {
3982 target_usages.append_non_duplicates(is_used_socket);
3983 }
3984 }
3985 /* Combine target socket usages into the usage of the current socket. */
3986 graph_params.usage_by_bsocket.add(socket,
3987 this->or_socket_usages(target_usages, graph_params));
3988 }
3989 }
3990
3991 void build_group_input_usages(BuildGraphParams &graph_params)
3992 {
3993 const Span<const bNode *> group_input_nodes = btree_.group_input_nodes();
3994 for (const int i : btree_.interface_inputs().index_range()) {
3995 Vector<lf::OutputSocket *> target_usages;
3996 for (const bNode *group_input_node : group_input_nodes) {
3997 if (lf::OutputSocket *lf_socket = graph_params.usage_by_bsocket.lookup_default(
3998 &group_input_node->output_socket(i), nullptr))
3999 {
4000 target_usages.append_non_duplicates(lf_socket);
4001 }
4002 }
4003
4004 lf::OutputSocket *lf_socket = this->or_socket_usages(target_usages, graph_params);
4005 lf::InputSocket *lf_group_output = const_cast<lf::InputSocket *>(
4006 group_input_usage_sockets_[i]);
4007 InputUsageHint input_usage_hint;
4008 if (lf_socket == nullptr) {
4009 static const bool static_false = false;
4010 lf_group_output->set_default_value(&static_false);
4011 input_usage_hint.type = InputUsageHintType::Never;
4012 }
4013 else {
4014 graph_params.lf_graph.add_link(*lf_socket, *lf_group_output);
4015 if (lf_socket->node().is_interface()) {
4016 /* Can support slightly more complex cases where it depends on more than one output in
4017 * the future. */
4018 input_usage_hint.type = InputUsageHintType::DependsOnOutput;
4019 input_usage_hint.output_dependencies = {
4020 group_output_used_sockets_.first_index_of(lf_socket)};
4021 }
4022 else {
4023 input_usage_hint.type = InputUsageHintType::DynamicSocket;
4024 }
4025 }
4026 lf_graph_info_->mapping.group_input_usage_hints.append(std::move(input_usage_hint));
4027 }
4028 }
4029
4041 void fix_link_cycles(lf::Graph &lf_graph, const Set<lf::InputSocket *> &socket_usage_inputs)
4042 {
4043 lf_graph.update_socket_indices();
4044 const int sockets_num = lf_graph.socket_num();
4045
4046 struct SocketState {
4047 bool done = false;
4048 bool in_stack = false;
4049 };
4050
4051 Array<SocketState> socket_states(sockets_num);
4052
4053 Vector<lf::Socket *> lf_sockets_to_check;
4054 for (lf::Node *lf_node : lf_graph.nodes()) {
4055 if (lf_node->is_function()) {
4056 for (lf::OutputSocket *lf_socket : lf_node->outputs()) {
4057 if (lf_socket->targets().is_empty()) {
4058 lf_sockets_to_check.append(lf_socket);
4059 }
4060 }
4061 }
4062 if (lf_node->outputs().is_empty()) {
4063 for (lf::InputSocket *lf_socket : lf_node->inputs()) {
4064 lf_sockets_to_check.append(lf_socket);
4065 }
4066 }
4067 }
4068 Vector<lf::Socket *> lf_socket_stack;
4069 while (!lf_sockets_to_check.is_empty()) {
4070 lf::Socket *lf_inout_socket = lf_sockets_to_check.last();
4071 lf::Node &lf_node = lf_inout_socket->node();
4072 SocketState &state = socket_states[lf_inout_socket->index_in_graph()];
4073
4074 if (!state.in_stack) {
4075 lf_socket_stack.append(lf_inout_socket);
4076 state.in_stack = true;
4077 }
4078
4079 Vector<lf::Socket *, 16> lf_origin_sockets;
4080 if (lf_inout_socket->is_input()) {
4081 lf::InputSocket &lf_input_socket = lf_inout_socket->as_input();
4082 if (lf::OutputSocket *lf_origin_socket = lf_input_socket.origin()) {
4083 lf_origin_sockets.append(lf_origin_socket);
4084 }
4085 }
4086 else {
4087 lf::OutputSocket &lf_output_socket = lf_inout_socket->as_output();
4088 if (lf_node.is_function()) {
4089 lf::FunctionNode &lf_function_node = static_cast<lf::FunctionNode &>(lf_node);
4090 const lf::LazyFunction &fn = lf_function_node.function();
4092 lf_output_socket.index(), [&](const Span<int> input_indices) {
4093 for (const int input_index : input_indices) {
4094 lf_origin_sockets.append(&lf_node.input(input_index));
4095 }
4096 });
4097 }
4098 }
4099
4100 bool pushed_socket = false;
4101 bool detected_cycle = false;
4102 for (lf::Socket *lf_origin_socket : lf_origin_sockets) {
4103 if (socket_states[lf_origin_socket->index_in_graph()].in_stack) {
4104 /* A cycle has been detected. The cycle is broken by removing a link and replacing it
4105 * with a constant "true" input. This can only affect inputs which determine whether a
4106 * specific value is used. Therefore, setting it to a constant true can result in more
4107 * computation later, but does not change correctness.
4108 *
4109 * After the cycle is broken, the cycle-detection is "rolled back" to the socket where
4110 * the first socket of the cycle was found. This is necessary in case another cycle
4111 * goes through this socket. */
4112
4113 detected_cycle = true;
4114 const int index_in_socket_stack = lf_socket_stack.first_index_of(lf_origin_socket);
4115 const int index_in_sockets_to_check = lf_sockets_to_check.first_index_of(
4116 lf_origin_socket);
4117 const Span<lf::Socket *> cycle = lf_socket_stack.as_span().drop_front(
4118 index_in_socket_stack);
4119
4120 bool broke_cycle = false;
4121 for (lf::Socket *lf_cycle_socket : cycle) {
4122 if (lf_cycle_socket->is_input() &&
4123 socket_usage_inputs.contains(&lf_cycle_socket->as_input()))
4124 {
4125 lf::InputSocket &lf_cycle_input_socket = lf_cycle_socket->as_input();
4126 lf_graph.clear_origin(lf_cycle_input_socket);
4127 static const bool static_true = true;
4128 lf_cycle_input_socket.set_default_value(&static_true);
4129 broke_cycle = true;
4130 }
4131 /* This is actually removed from the stack when it is resized below. */
4132 SocketState &lf_cycle_socket_state = socket_states[lf_cycle_socket->index_in_graph()];
4133 lf_cycle_socket_state.in_stack = false;
4134 }
4135 if (!broke_cycle) {
4137 }
4138 /* Roll back algorithm by removing the sockets that corresponded to the cycle from the
4139 * stacks. */
4140 lf_socket_stack.resize(index_in_socket_stack);
4141 /* The +1 is there so that the socket itself is not removed. */
4142 lf_sockets_to_check.resize(index_in_sockets_to_check + 1);
4143 break;
4144 }
4145 if (!socket_states[lf_origin_socket->index_in_graph()].done) {
4146 lf_sockets_to_check.append(lf_origin_socket);
4147 pushed_socket = true;
4148 }
4149 }
4150 if (detected_cycle) {
4151 continue;
4152 }
4153 if (pushed_socket) {
4154 continue;
4155 }
4156
4157 state.done = true;
4158 state.in_stack = false;
4159 lf_sockets_to_check.pop_last();
4160 lf_socket_stack.pop_last();
4161 }
4162 }
4163};
4164
4165static std::unique_ptr<GeometryNodesLazyFunctionGraphInfo>
4167{
4168 btree.ensure_topology_cache();
4169 btree.ensure_interface_cache();
4170
4171 if (btree.has_available_link_cycle()) {
4172 return nullptr;
4173 }
4174 if (btree.type != NTREE_GEOMETRY) {
4175 /* It's possible to get into this situation when localizing a linked node group that is
4176 * missing (#133524). */
4177 return nullptr;
4178 }
4179 const bNodeTreeZones *tree_zones = btree.zones();
4180 if (tree_zones == nullptr) {
4181 return nullptr;
4182 }
4183 for (const bNodeTreeZone *zone : tree_zones->zones) {
4184 if (zone->input_node() == nullptr || zone->output_node() == nullptr) {
4185 /* Simulations and repeats need input and output nodes. */
4186 return nullptr;
4187 }
4188 }
4189 if (const ID *id_orig = DEG_get_original(&btree.id)) {
4190 if (id_orig->tag & ID_TAG_MISSING) {
4191 return nullptr;
4192 }
4193 }
4194 for (const bNodeTreeInterfaceSocket *interface_bsocket : btree.interface_inputs()) {
4195 const bke::bNodeSocketType *typeinfo = interface_bsocket->socket_typeinfo();
4196 if (!typeinfo || !typeinfo->geometry_nodes_default_value) {
4197 return nullptr;
4198 }
4199 }
4200 for (const bNodeTreeInterfaceSocket *interface_bsocket : btree.interface_outputs()) {
4201 const bke::bNodeSocketType *typeinfo = interface_bsocket->socket_typeinfo();
4202 if (!typeinfo || !typeinfo->geometry_nodes_default_value) {
4203 return nullptr;
4204 }
4205 }
4206
4207 auto lf_graph_info = std::make_unique<GeometryNodesLazyFunctionGraphInfo>();
4208 GeometryNodesLazyFunctionBuilder builder{btree, *lf_graph_info};
4209 builder.build();
4210 return lf_graph_info;
4211}
4212
4214 const bNodeTree &btree)
4215{
4216 btree.runtime->geometry_nodes_lazy_function_graph_info_mutex.ensure([&]() {
4217 btree.runtime->geometry_nodes_lazy_function_graph_info =
4219 });
4220 return btree.runtime->geometry_nodes_lazy_function_graph_info.get();
4221}
4222
4227
4228void GeoNodesLocalUserData::ensure_tree_logger(const GeoNodesUserData &user_data) const
4229{
4230 if (geo_eval_log::GeoNodesLog *log = user_data.call_data->eval_log) {
4231 tree_logger_.emplace(&log->get_local_tree_logger(*user_data.compute_context));
4232 return;
4233 }
4234 this->tree_logger_.emplace(nullptr);
4235}
4236
4237std::optional<FoundNestedNodeID> find_nested_node_id(const GeoNodesUserData &user_data,
4238 const int node_id)
4239{
4241 *user_data.call_data->root_ntree, user_data.compute_context, node_id);
4242}
4243
4245{
4246 if (Depsgraph *graph = this->extra) {
4247 DEG_graph_free(graph);
4248 }
4249}
4250
4251static const ID *get_only_evaluated_id(const Depsgraph &depsgraph, const ID &id_orig)
4252{
4253 const ID *id = DEG_get_evaluated(&depsgraph, &id_orig);
4254 if (id == &id_orig) {
4255 return nullptr;
4256 }
4257 return id;
4258}
4259
4261{
4262 if (const Depsgraph *graph = this->active) {
4263 if (const ID *id = get_only_evaluated_id(*graph, id_orig)) {
4264 return id;
4265 }
4266 }
4267 if (const Depsgraph *graph = this->extra) {
4268 if (const ID *id = get_only_evaluated_id(*graph, id_orig)) {
4269 return id;
4270 }
4271 }
4272 return nullptr;
4273}
4274
4276{
4277 if (this->modifier_data) {
4278 return this->modifier_data->self_object;
4279 }
4280 if (this->operator_data) {
4281 return DEG_get_evaluated(this->operator_data->depsgraphs->active,
4282 const_cast<Object *>(this->operator_data->self_object_orig));
4283 }
4284 return nullptr;
4285}
4286
4287} // namespace blender::nodes
Low-level operations for grease pencil.
#define NODE_REROUTE
Definition BKE_node.hh:813
#define NODE_GROUP_OUTPUT
Definition BKE_node.hh:815
#define NODE_FRAME
Definition BKE_node.hh:812
#define NODE_GROUP_INPUT
Definition BKE_node.hh:814
#define NODE_EVALUATE_CLOSURE
#define GEO_NODE_MENU_SWITCH
#define GEO_NODE_GIZMO_LINEAR
#define GEO_NODE_VIEWER
#define GEO_NODE_GIZMO_DIAL
#define GEO_NODE_FOREACH_GEOMETRY_ELEMENT_OUTPUT
#define GEO_NODE_SIMULATION_OUTPUT
#define GEO_NODE_SWITCH
#define NODE_CLOSURE_OUTPUT
#define GEO_NODE_BAKE
#define GEO_NODE_WARNING
#define GEO_NODE_GIZMO_TRANSFORM
#define GEO_NODE_REPEAT_OUTPUT
#define GEO_NODE_INDEX_SWITCH
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define ELEM(...)
#define TIP_(msgid)
void DEG_graph_free(Depsgraph *graph)
Definition depsgraph.cc:306
T * DEG_get_original(T *id)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
ID and Library types, which are fundamental for SDNA.
@ ID_TAG_MISSING
Definition DNA_ID.h:867
struct bNodeTreeInterfaceSocket bNodeTreeInterfaceSocket
struct NodeMenuSwitch NodeMenuSwitch
struct NodeGeometrySimulationInput NodeGeometrySimulationInput
struct bNodeSocketValueMenu bNodeSocketValueMenu
struct bNodeSocketValueInt bNodeSocketValueInt
struct NodeGeometrySimulationOutput NodeGeometrySimulationOutput
struct NodeEnumDefinition NodeEnumDefinition
@ NTREE_GEOMETRY
struct bNodeLink bNodeLink
struct bNode bNode
eNodeSocketDatatype
struct bNodeSocketValueBoolean bNodeSocketValueBoolean
struct bNodeTree bNodeTree
struct NodeEnumItem NodeEnumItem
struct bNodeSocket bNodeSocket
volatile int lock
__forceinline float extract(const int4 &b)
Definition binning.cpp:27
BPy_StructRNA * depsgraph
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
void fill(const T &value) const
Definition BLI_array.hh:272
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:419
static const CPPType & get()
constexpr IndexRange take_back(int64_t n) const
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:295
const Value & lookup(const Key &key) const
Definition BLI_map.hh:545
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
KeyIterator keys() const &
Definition BLI_map.hh:875
ItemIterator items() const &
Definition BLI_map.hh:902
MapType::KeyIterator keys() const
MapType::ItemIterator items() const
void add(const Key &key, const Value &value)
bool contains(const Key &key) const
Definition BLI_set.hh:310
bool add(const Key &key)
Definition BLI_set.hh:248
NodeDefaultInputType default_input_type
InputSocketFieldType input_field_type
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr bool is_empty() const
Definition BLI_span.hh:260
T pop_last()
int64_t append_and_get_index(const T &value)
void append(const T &value)
const T & last(const int64_t n=0) const
bool is_empty() const
IndexRange index_range() const
void resize(const int64_t new_size)
int64_t first_index_of(const T &value) const
void extend(Span< T > array)
void append_non_duplicates(const T &value)
T * end()
Span< T > as_span() const
T * begin()
Vector< const bNode * > child_nodes() const
const bNode * output_node() const
Vector< const bNodeLink * > border_links
Vector< bNodeTreeZone * > child_zones
const bNode * input_node() const
static const CPPType & get()
StringRefNull name() const
bool is() const
void move_construct(void *src, void *dst) const
const ComputeContext * parent() const
void print_stack(std::ostream &stream, StringRef name) const
const ComputeContextHash & hash() const
destruct_ptr< T > construct(Args &&...args)
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:295
const Value & lookup(const Key &key) const
Definition BLI_map.hh:545
Value lookup_default(const Key &key, const Value &default_value) const
Definition BLI_map.hh:570
int64_t size() const
Definition BLI_map.hh:976
ItemIterator items() const &
Definition BLI_map.hh:902
T & construct(Args &&...args)
T * add(std::unique_ptr< T > resource)
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr Span take_front(int64_t n) const
Definition BLI_span.hh:193
constexpr bool is_empty() const
Definition BLI_span.hh:260
constexpr bool contains(const T &value) const
Definition BLI_span.hh:277
int64_t size() const
bool contains(const T &value) const
void append(const T &value)
bool is_empty() const
IndexRange index_range() const
int64_t append_and_get_index_as(ForwardValue &&...value)
int64_t first_index_of(const T &value) const
void extend(Span< T > array)
const T & first() const
bool is_convertible(const CPPType &from_type, const CPPType &to_type) const
const mf::MultiFunction * get_conversion_multi_function(mf::DataType from, mf::DataType to) const
std::unique_ptr< GizmoEditHints > gizmo_edit_hints_
void * allocate_single(eNodeSocketDatatype socket_type)
const bNode * output_node() const
Vector< const bNodeLink * > border_links
const bNode * input_node() const
Vector< const bNode * > nodes_outside_zones() const
Vector< bNodeTreeZone * > root_zones
Vector< bNodeTreeZone * > zones
const bNodeTreeZone * get_zone_by_node(const int32_t node_id) const
virtual void for_each_field_input_recursive(FunctionRef< void(const FieldInput &)> fn) const
Definition field.cc:582
static std::shared_ptr< FieldOperation > from(std::shared_ptr< const mf::MultiFunction > function, Vector< GField > inputs={})
Definition FN_field.hh:242
const FieldNode & node() const
Definition FN_field.hh:135
FunctionNode & add_function(const LazyFunction &fn)
void add_link(OutputSocket &from, InputSocket &to)
GraphOutputSocket & add_output(const CPPType &type, std::string name="")
void clear_origin(InputSocket &socket)
GraphInputSocket & add_input(const CPPType &type, std::string name="")
virtual void possible_output_dependencies(int output_index, FunctionRef< void(Span< int >)> fn) const
Span< const InputSocket * > inputs() const
Span< const OutputSocket * > outputs() const
const InputSocket & input(int index) const
const OutputSocket & output(int index) const
virtual BakeNodeBehavior * get(const int id) const =0
virtual SimulationZoneBehavior * get(const int zone_id) const =0
void dump_when_outputs_are_missing(const lf::FunctionNode &node, Span< const lf::OutputSocket * > missing_sockets, const lf::Context &context) const override
void dump_when_input_is_set_twice(const lf::InputSocket &target_socket, const lf::OutputSocket &from_socket, const lf::Context &context) const override
void add_thread_id_debug_message(const lf::FunctionNode &node, const lf::Context &context) const
void log_socket_value(const lf::Socket &lf_socket, const GPointer value, const lf::Context &context) const override
GeometryNodesLazyFunctionLogger(const GeometryNodesLazyFunctionGraphInfo &lf_graph_info)
void log_before_node_execute(const lf::FunctionNode &node, const lf::Params &, const lf::Context &context) const override
GeometryNodesLazyFunctionSideEffectProvider(Span< const lf::FunctionNode * > local_side_effect_nodes={})
Vector< const lf::FunctionNode * > get_nodes_with_side_effects(const lf::Context &context) const override
void execute_impl(lf::Params &params, const lf::Context &context) const override
void execute_impl(lf::Params &params, const lf::Context &) const override
void execute_impl(lf::Params &params, const lf::Context &) const override
void execute_impl(lf::Params &params, const lf::Context &context) const override
std::string anonymous_attribute_name_for_output(const GeoNodesUserData &user_data, const int output_index) const
void output_anonymous_attribute_field(lf::Params &params, const GeoNodesUserData &user_data, const int lf_index, const bNodeSocket &socket) const
LazyFunctionForGeometryNode(const bNode &node, GeometryNodesLazyFunctionGraphInfo &own_lf_graph_info)
std::string input_name(const int index) const override
std::string output_name(const int index) const override
LazyFunctionForGizmoInputsUsage(const bNode &gizmo_node, const lf::FunctionNode &lf_gizmo_node)
void execute_impl(lf::Params &params, const lf::Context &context) const override
void execute_impl(lf::Params &params, const lf::Context &context) const override
LazyFunctionForGizmoNode(const bNode &bnode, MutableSpan< int > r_lf_index_by_bsocket)
std::string output_name(const int i) const override
LazyFunctionForGroupNode(const bNode &group_node, const GeometryNodesLazyFunctionGraphInfo &group_lf_graph_info, GeometryNodesLazyFunctionGraphInfo &own_lf_graph_info)
void * init_storage(LinearAllocator<> &allocator) const override
std::string input_name(const int i) const override
void execute_impl(lf::Params &params, const lf::Context &context) const override
void execute_impl(lf::Params &params, const lf::Context &) const override
LazyFunctionForImplicitConversion(const MultiFunction &fn, const bke::bNodeSocketType &dst_type)
void execute_impl(lf::Params &params, const lf::Context &) const override
LazyFunctionForImplicitInput(const CPPType &type, std::function< void(void *)> init_fn)
void execute_impl(lf::Params &params, const lf::Context &) const override
void execute_impl(lf::Params &params, const lf::Context &) const override
static const LazyFunctionForJoinReferenceSets & get_cached(const int amount, ResourceScope &scope)
void execute_impl(lf::Params &params, const lf::Context &context) const override
LazyFunctionForMultiFunctionNode(const bNode &node, NodeMultiFunctions::Item fn_item, MutableSpan< int > r_lf_index_by_bsocket)
void execute_impl(lf::Params &params, const lf::Context &context) const override
void execute_impl(lf::Params &params, const lf::Context &) const override
void execute_impl(lf::Params &params, const lf::Context &) const override
LazyFunctionForMutedNode(const bNode &node, MutableSpan< int > r_lf_index_by_bsocket)
void execute_impl(lf::Params &params, const lf::Context &) const override
void execute_impl(lf::Params &params, const lf::Context &context) const override
void * init_storage(LinearAllocator<> &allocator) const override
void execute_impl(lf::Params &params, const lf::Context &context) const override
LazyFunctionForSimulationZone(const bNode &sim_output_bnode, const LazyFunction &fn)
void execute_impl(lf::Params &params, const lf::Context &) const override
LazyFunctionForUndefinedNode(const bNode &node, MutableSpan< int > r_lf_index_by_bsocket)
void execute_impl(lf::Params &params, const lf::Context &) const override
void execute_impl(lf::Params &params, const lf::Context &context) const override
LazyFunctionForViewerInputUsage(const lf::FunctionNode &lf_viewer_node)
LazyFunctionForViewerNode(const bNode &bnode, MutableSpan< int > r_lf_index_by_bsocket)
void execute_impl(lf::Params &params, const lf::Context &context) const override
const aal::RelationsInNode * anonymous_attribute_relations() const
const Item & try_get(const bNode &node) const
static SocketValueVariant & ConstructIn(void *ptr, T &&value)
static SocketValueVariant From(T &&value)
linear_allocator::ChunkedList< ViewerNodeLogWithNode > viewer_node_logs
linear_allocator::ChunkedList< WarningWithNode > node_warnings
linear_allocator::ChunkedList< DebugMessage > debug_messages
void log_value(const bNode &node, const bNodeSocket &socket, GPointer value)
static ushort indices[]
#define input
#define log
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
static ulong state[N]
bool contains(const VArray< bool > &varray, const IndexMask &indices_to_check, bool value)
bool attribute_name_is_anonymous(const StringRef name)
std::optional< eNodeSocketDatatype > geo_nodes_base_cpp_type_to_socket_type(const CPPType &type)
Definition node.cc:5241
const DataTypeConversions & get_implicit_type_conversions()
std::string hash_to_anonymous_attribute_name(Args &&...args)
std::optional< nodes::FoundNestedNodeID > find_nested_node_id_in_root(const SpaceNode &snode, const bNode &node)
static Type to_type(const GPUType type)
void geo_viewer_node_log(const bNode &node, const Span< bke::SocketValueVariant * > input_values, geo_eval_log::ViewerNodeLog &r_log)
static const ID * get_only_evaluated_id(const Depsgraph &depsgraph, const ID &id_orig)
void initialize_zone_wrapper(const bNodeTreeZone &zone, ZoneBuildInfo &zone_info, const ZoneBodyFunction &body_fn, const bool expose_all_reference_sets, Vector< lf::Input > &r_inputs, Vector< lf::Output > &r_outputs)
std::unique_ptr< LazyFunction > get_simulation_output_lazy_function(const bNode &node, GeometryNodesLazyFunctionGraphInfo &own_lf_graph_info)
std::unique_ptr< LazyFunction > get_index_switch_node_lazy_function(const bNode &node, GeometryNodesLazyFunctionGraphInfo &lf_graph_info)
std::unique_ptr< LazyFunction > get_warning_node_lazy_function(const bNode &node)
std::optional< ImplicitInputValueFn > get_implicit_input_value_fn(const NodeDefaultInputType type)
static bool ignore_zone_bsocket(const bNodeSocket &bsocket)
void construct_socket_default_value(const bke::bNodeSocketType &stype, void *r_value)
std::unique_ptr< LazyFunction > get_menu_switch_node_socket_usage_lazy_function(const bNode &node)
std::unique_ptr< LazyFunction > get_simulation_input_lazy_function(const bNodeTree &node_tree, const bNode &node, GeometryNodesLazyFunctionGraphInfo &own_lf_graph_info)
bool should_log_socket_values_for_context(const GeoNodesUserData &user_data, const ComputeContextHash hash)
LazyFunction & build_closure_zone_lazy_function(ResourceScope &scope, const bNodeTree &btree, const bke::bNodeTreeZone &zone, ZoneBuildInfo &zone_info, const ZoneBodyFunction &body_fn)
bool execute_multi_function_on_value_variant(const MultiFunction &fn, const std::shared_ptr< MultiFunction > &owned_fn, const Span< SocketValueVariant * > input_values, const Span< SocketValueVariant * > output_values, GeoNodesUserData *user_data, std::string &r_error_message)
const LazyFunction * build_implicit_conversion_lazy_function(const bke::bNodeSocketType &from_type, const bke::bNodeSocketType &to_type, ResourceScope &scope)
Map< Vector< lf::OutputSocket * >, lf::OutputSocket * > JoinReferenceSetsCache
std::optional< SocketValueVariant > implicitly_convert_socket_value(const bke::bNodeSocketType &from_type, const SocketValueVariant &from_value, const bke::bNodeSocketType &to_type)
LazyFunction & build_repeat_zone_lazy_function(ResourceScope &scope, const bNodeTree &btree, const bke::bNodeTreeZone &zone, ZoneBuildInfo &zone_info, const ZoneBodyFunction &body_fn)
std::unique_ptr< LazyFunction > get_switch_node_lazy_function(const bNode &node)
std::string make_anonymous_attribute_socket_inspection_string(const bNodeSocket &socket)
std::unique_ptr< LazyFunction > get_bake_lazy_function(const bNode &node, GeometryNodesLazyFunctionGraphInfo &lf_graph_info)
const GeometryNodesLazyFunctionGraphInfo * ensure_geometry_nodes_lazy_function_graph(const bNodeTree &btree)
std::optional< FoundNestedNodeID > find_nested_node_id(const GeoNodesUserData &user_data, const int node_id)
void set_default_remaining_node_outputs(lf::Params &params, const bNode &node)
void report_from_multi_function(const mf::Context &context, NodeWarningType type, std::string message)
static bool gizmo_is_used(const GeoNodesUserData &user_data, const lf::FunctionNode &lf_gizmo_node)
void execute_multi_function_on_value_variant__list(const MultiFunction &fn, const Span< SocketValueVariant * > input_values, const Span< SocketValueVariant * > output_values, GeoNodesUserData *user_data)
static void execute_multi_function_on_value_variant__single(const MultiFunction &fn, const Span< SocketValueVariant * > input_values, const Span< SocketValueVariant * > output_values, GeoNodesUserData *user_data)
std::unique_ptr< LazyFunction > get_enable_output_node_lazy_function(const bNode &node, GeometryNodesLazyFunctionGraphInfo &own_lf_graph_info)
void set_default_value_for_output_socket(lf::Params &params, const int lf_index, const bNodeSocket &bsocket)
bool execute_multi_function_on_value_variant__volume_grid(const mf::MultiFunction &, const Span< bke::SocketValueVariant * >, const Span< bke::SocketValueVariant * >, std::string &r_error_message)
std::string zone_wrapper_output_name(const ZoneBuildInfo &zone_info, const bNodeTreeZone &zone, const Span< lf::Output > outputs, const int lf_socket_i)
std::unique_ptr< LazyFunction > get_menu_switch_node_lazy_function(const bNode &node, GeometryNodesLazyFunctionGraphInfo &lf_graph_info)
LazyFunction & build_foreach_geometry_element_zone_lazy_function(ResourceScope &scope, const bNodeTree &btree, const bke::bNodeTreeZone &zone, ZoneBuildInfo &zone_info, const ZoneBodyFunction &body_fn)
static void lazy_function_interface_from_node(const bNode &node, Vector< lf::Input > &r_inputs, Vector< lf::Output > &r_outputs, MutableSpan< int > r_lf_index_by_bsocket)
static void execute_multi_function_on_value_variant__field(const MultiFunction &fn, const std::shared_ptr< MultiFunction > &owned_fn, const Span< SocketValueVariant * > input_values, const Span< SocketValueVariant * > output_values)
std::string zone_wrapper_input_name(const ZoneBuildInfo &zone_info, const bNodeTreeZone &zone, const Span< lf::Input > inputs, const int lf_socket_i)
EvaluateClosureFunction build_evaluate_closure_node_lazy_function(ResourceScope &scope, const bNode &bnode)
static std::unique_ptr< GeometryNodesLazyFunctionGraphInfo > ensure_geometry_nodes_lazy_function_graph_impl(const bNodeTree &btree)
std::unique_ptr< T, DestructValueAtAddress< T > > destruct_ptr
std::mutex Mutex
Definition BLI_mutex.hh:47
static blender::bke::bNodeSocketTemplate outputs[]
static blender::bke::bNodeSocketTemplate inputs[]
#define I
#define hash
Definition noise_c.cc:154
const char * name
Definition DNA_ID.h:414
char name[258]
Definition DNA_ID.h:432
NodeEnumDefinition enum_definition
bNodeSocketRuntimeHandle * runtime
bNodeSocketTypeHandle * typeinfo
void * default_value
char identifier[64]
bNodeTreeRuntimeHandle * runtime
bNodeTypeHandle * typeinfo
struct ID * id
char name[64]
int16_t type_legacy
void * storage
int32_t identifier
Defines a socket type.
Definition BKE_node.hh:158
eNodeSocketDatatype type
Definition BKE_node.hh:193
const SocketValueVariant * geometry_nodes_default_value
Definition BKE_node.hh:211
const blender::CPPType * base_cpp_type
Definition BKE_node.hh:205
MultiValueMap< ReferenceSetIndex, lf::InputSocket * > lf_reference_set_inputs
Map< Vector< lf::OutputSocket * >, lf::OutputSocket * > socket_usages_combination_cache
Map< const bNodeSocket *, lf::OutputSocket * > lf_output_by_bsocket
Map< const bNodeLink *, lf::InputSocket * > lf_input_by_border_link
MultiValueMap< const bNodeSocket *, lf::InputSocket * > lf_inputs_by_bsocket
Map< const bNodeSocket *, lf::OutputSocket * > usage_by_bsocket
Map< const bNodeSocket *, lf::InputSocket * > lf_reference_set_input_by_output
Map< const bNodeLink *, lf::InputSocket * > lf_input_by_multi_input_link
const Set< ComputeContextHash > * socket_log_contexts
const GeoNodesSideEffectNodes * side_effect_nodes
MultiValueMap< ComputeContextHash, const lf::FunctionNode * > nodes_by_context
destruct_ptr< fn::LocalUserData > get_local(LinearAllocator<> &allocator) override
Map< const bke::bNodeTreeZone *, const lf::FunctionNode * > zone_node_map
MultiValueMap< const lf::Socket *, const bNodeSocket * > bsockets_by_lf_socket_map
Map< const bNode *, const lf::FunctionNode * > possible_side_effect_node_map
Map< const bNode *, const lf::FunctionNode * > group_node_map
struct blender::nodes::GeometryNodesGroupFunction::@176034106072117145033162003214300177076220367077 inputs
struct blender::nodes::GeometryNodesGroupFunction::@176034106072117145033162003214300177076220367077::@201205044241144324034052062053171123334141114245 references_to_propagate
GeometryNodesLazyFunctionBuilder(const bNodeTree &btree, GeometryNodesLazyFunctionGraphInfo &lf_graph_info)
struct blender::nodes::ZoneFunctionIndices::@066214264345112070236210367011003021132214177131 outputs
struct blender::nodes::ZoneFunctionIndices::@273312016272125124266321211240073263106341134120 inputs
i
Definition text_draw.cc:230
wmTimer * timer