Blender V4.3
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
23#include "NOD_geometry_exec.hh"
25#include "NOD_multi_function.hh"
27
28#include "BLI_array_utils.hh"
30#include "BLI_bit_span_ops.hh"
31#include "BLI_cpp_types.hh"
32#include "BLI_dot_export.hh"
33#include "BLI_hash.h"
34#include "BLI_hash_md5.hh"
35#include "BLI_lazy_threading.hh"
36#include "BLI_map.hh"
37
38#include "DNA_ID.h"
39
42#include "BKE_curves.hh"
44#include "BKE_geometry_set.hh"
45#include "BKE_grease_pencil.hh"
50
53
55
58
59#include <fmt/format.h>
60#include <sstream>
61
62namespace blender::nodes {
63
64namespace aai = bke::anonymous_attribute_inferencing;
65using bke::bNodeTreeZone;
66using bke::bNodeTreeZones;
67using bke::SocketValueVariant;
68
69static const CPPType *get_socket_cpp_type(const bke::bNodeSocketType &typeinfo)
70{
71 const CPPType *type = typeinfo.geometry_nodes_cpp_type;
72 if (type == nullptr) {
73 return nullptr;
74 }
75 BLI_assert(type->has_special_member_functions());
76 return type;
77}
78
79static const CPPType *get_socket_cpp_type(const bNodeSocket &socket)
80{
81 return get_socket_cpp_type(*socket.typeinfo);
82}
83
84static const CPPType *get_vector_type(const CPPType &type)
85{
86 const VectorCPPType *vector_type = VectorCPPType::get_from_value(type);
87 if (vector_type == nullptr) {
88 return nullptr;
89 }
90 return &vector_type->self;
91}
92
98 Vector<lf::Input> &r_inputs,
99 Vector<lf::Output> &r_outputs,
100 MutableSpan<int> r_lf_index_by_bsocket)
101{
102 const bool is_muted = node.is_muted();
103 const lf::ValueUsage input_usage = lf::ValueUsage::Used;
104 for (const bNodeSocket *socket : node.input_sockets()) {
105 if (!socket->is_available()) {
106 continue;
107 }
108 const CPPType *type = get_socket_cpp_type(*socket);
109 if (type == nullptr) {
110 continue;
111 }
112 if (socket->is_multi_input() && !is_muted) {
113 type = get_vector_type(*type);
114 }
115 r_lf_index_by_bsocket[socket->index_in_tree()] = r_inputs.append_and_get_index_as(
116 socket->name, *type, input_usage);
117 }
118 for (const bNodeSocket *socket : node.output_sockets()) {
119 if (!socket->is_available()) {
120 continue;
121 }
122 const CPPType *type = get_socket_cpp_type(*socket);
123 if (type == nullptr) {
124 continue;
125 }
126 r_lf_index_by_bsocket[socket->index_in_tree()] = r_outputs.append_and_get_index_as(
127 socket->name, *type);
128 }
129}
130
135 private:
136 const bNode &node_;
137 const GeometryNodesLazyFunctionGraphInfo &own_lf_graph_info_;
143 Vector<bool> is_attribute_output_bsocket_;
144
145 public:
147 GeometryNodesLazyFunctionGraphInfo &own_lf_graph_info)
148 : node_(node),
149 own_lf_graph_info_(own_lf_graph_info),
150 is_attribute_output_bsocket_(node.output_sockets().size(), false)
151 {
152 BLI_assert(node.typeinfo->geometry_node_execute != nullptr);
153 debug_name_ = node.name;
155 node, inputs_, outputs_, own_lf_graph_info.mapping.lf_index_by_bsocket);
156
157 const NodeDeclaration &node_decl = *node.declaration();
158 const aal::RelationsInNode *relations = node_decl.anonymous_attribute_relations();
159 if (relations == nullptr) {
160 return;
161 }
162 if (!relations->available_relations.is_empty()) {
163 /* Inputs are only used when an output is used that is not just outputting an anonymous
164 * attribute field. */
165 for (lf::Input &input : inputs_) {
166 input.usage = lf::ValueUsage::Maybe;
167 }
168 for (const aal::AvailableRelation &relation : relations->available_relations) {
169 is_attribute_output_bsocket_[relation.field_output] = true;
170 }
171 }
172 Vector<const bNodeSocket *> handled_field_outputs;
173 for (const aal::AvailableRelation &relation : relations->available_relations) {
174 const bNodeSocket &output_bsocket = node.output_socket(relation.field_output);
175 if (output_bsocket.is_available() && !handled_field_outputs.contains(&output_bsocket)) {
176 handled_field_outputs.append(&output_bsocket);
177 const int lf_index = inputs_.append_and_get_index_as("Output Used", CPPType::get<bool>());
178 own_lf_graph_info.mapping
179 .lf_input_index_for_output_bsocket_usage[output_bsocket.index_in_all_outputs()] =
180 lf_index;
181 }
182 }
183
184 Vector<const bNodeSocket *> handled_geometry_outputs;
185 for (const aal::PropagateRelation &relation : relations->propagate_relations) {
186 const bNodeSocket &output_bsocket = node.output_socket(relation.to_geometry_output);
187 if (output_bsocket.is_available() && !handled_geometry_outputs.contains(&output_bsocket)) {
188 handled_geometry_outputs.append(&output_bsocket);
189 const int lf_index = inputs_.append_and_get_index_as(
190 "Propagate to Output", CPPType::get<bke::AnonymousAttributeSet>());
192 [output_bsocket.index_in_all_outputs()] = lf_index;
193 }
194 }
195 }
196
197 void execute_impl(lf::Params &params, const lf::Context &context) const override
198 {
199 const ScopedNodeTimer node_timer{context, node_};
200
201 GeoNodesLFUserData *user_data = dynamic_cast<GeoNodesLFUserData *>(context.user_data);
202 BLI_assert(user_data != nullptr);
203
204 bool used_non_attribute_output_exists = false;
205 for (const int output_bsocket_index : node_.output_sockets().index_range()) {
206 const bNodeSocket &output_bsocket = node_.output_socket(output_bsocket_index);
207 const int lf_index =
208 own_lf_graph_info_.mapping.lf_index_by_bsocket[output_bsocket.index_in_tree()];
209 if (lf_index == -1) {
210 continue;
211 }
212 const lf::ValueUsage output_usage = params.get_output_usage(lf_index);
213 if (output_usage == lf::ValueUsage::Unused) {
214 continue;
215 }
216 if (is_attribute_output_bsocket_[output_bsocket_index]) {
217 if (params.output_was_set(lf_index)) {
218 continue;
219 }
220 this->output_anonymous_attribute_field(params, *user_data, lf_index, output_bsocket);
221 }
222 else {
223 if (output_usage == lf::ValueUsage::Used) {
224 used_non_attribute_output_exists = true;
225 }
226 }
227 }
228
229 if (!used_non_attribute_output_exists) {
230 /* Only attribute outputs are used currently, no need to evaluate the full node and its
231 * inputs. */
232 return;
233 }
234
235 bool missing_input = false;
236 for (const int lf_index : inputs_.index_range()) {
237 if (params.try_get_input_data_ptr_or_request(lf_index) == nullptr) {
238 missing_input = true;
239 }
240 }
241 if (missing_input) {
242 /* Wait until all inputs are available. */
243 return;
244 }
245
246 auto get_anonymous_attribute_name = [&](const int i) {
247 return this->anonymous_attribute_name_for_output(*user_data, i);
248 };
249
250 GeoNodeExecParams geo_params{
251 node_,
252 params,
253 context,
256 get_anonymous_attribute_name};
257
258 node_.typeinfo->geometry_node_execute(geo_params);
259 }
260
261 std::string input_name(const int index) const override
262 {
263 for (const bNodeSocket *bsocket : node_.output_sockets()) {
264 {
265 const int lf_index =
266 own_lf_graph_info_.mapping
267 .lf_input_index_for_output_bsocket_usage[bsocket->index_in_all_outputs()];
268 if (index == lf_index) {
269 return StringRef("Use Output '") + bsocket->name + "'";
270 }
271 }
272 {
273 const int lf_index =
275 [bsocket->index_in_all_outputs()];
276 if (index == lf_index) {
277 return StringRef("Propagate to '") + bsocket->name + "'";
278 }
279 }
280 }
281 return inputs_[index].debug_name;
282 }
283
284 std::string output_name(const int index) const override
285 {
286 return outputs_[index].debug_name;
287 }
288
290 const GeoNodesLFUserData &user_data,
291 const int lf_index,
292 const bNodeSocket &socket) const
293 {
294 std::string attribute_name = this->anonymous_attribute_name_for_output(user_data,
295 socket.index());
296 std::string socket_inspection_name = make_anonymous_attribute_socket_inspection_string(socket);
297 auto attribute_field = std::make_shared<AttributeFieldInput>(
298 std::move(attribute_name),
299 *socket.typeinfo->base_cpp_type,
300 std::move(socket_inspection_name));
301
302 void *r_value = params.get_output_data_ptr(lf_index);
303 new (r_value) SocketValueVariant(GField(std::move(attribute_field)));
304 params.output_set(lf_index);
305 }
306
308 const int output_index) const
309 {
311 user_data.compute_context->hash(),
312 node_.identifier,
313 node_.output_socket(output_index).identifier);
314 }
315};
316
322 private:
323 const CPPType *base_type_;
324
325 public:
327
329 {
330 debug_name_ = "Multi Input";
331 base_type_ = get_socket_cpp_type(socket);
332 BLI_assert(base_type_ != nullptr);
333 BLI_assert(socket.is_multi_input());
334 for (const bNodeLink *link : socket.directly_linked_links()) {
335 if (link->is_muted() || !link->fromsock->is_available() ||
336 link->fromnode->is_dangling_reroute())
337 {
338 continue;
339 }
340 inputs_.append({"Input", *base_type_});
341 this->links.append(link);
342 }
343 const CPPType *vector_type = get_vector_type(*base_type_);
344 BLI_assert(vector_type != nullptr);
345 outputs_.append({"Output", *vector_type});
346 }
347
348 void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
349 {
350 /* Currently we only have multi-inputs for geometry and value sockets. This could be
351 * generalized in the future. */
352 base_type_->to_static_type_tag<GeometrySet, SocketValueVariant>([&](auto type_tag) {
353 using T = typename decltype(type_tag)::type;
354 if constexpr (std::is_void_v<T>) {
355 /* This type is not supported in this node for now. */
357 }
358 else {
359 void *output_ptr = params.get_output_data_ptr(0);
360 Vector<T> &values = *new (output_ptr) Vector<T>();
361 for (const int i : inputs_.index_range()) {
362 values.append(params.extract_input<T>(i));
363 }
364 params.output_set(0);
365 }
366 });
367 }
368};
369
374 public:
376 {
377 debug_name_ = "Reroute";
378 inputs_.append({"Input", type});
379 outputs_.append({"Output", type});
380 }
381
382 void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
383 {
384 void *input_value = params.try_get_input_data_ptr(0);
385 void *output_value = params.get_output_data_ptr(0);
386 BLI_assert(input_value != nullptr);
387 BLI_assert(output_value != nullptr);
388 const CPPType &type = *inputs_[0].type;
389 type.move_construct(input_value, output_value);
390 params.output_set(0);
391 }
392};
393
400 const bNode &node_;
401
402 public:
403 LazyFunctionForUndefinedNode(const bNode &node, MutableSpan<int> r_lf_index_by_bsocket)
404 : node_(node)
405 {
406 debug_name_ = "Undefined";
407 Vector<lf::Input> dummy_inputs;
408 lazy_function_interface_from_node(node, dummy_inputs, outputs_, r_lf_index_by_bsocket);
409 }
410
411 void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
412 {
414 }
415};
416
418 const int lf_index,
419 const bNodeSocket &bsocket)
420{
421 const CPPType &cpp_type = *bsocket.typeinfo->geometry_nodes_cpp_type;
422 void *output_value = params.get_output_data_ptr(lf_index);
423 if (bsocket.typeinfo->geometry_nodes_default_cpp_value) {
424 cpp_type.copy_construct(bsocket.typeinfo->geometry_nodes_default_cpp_value, output_value);
425 }
426 else {
427 cpp_type.value_initialize(output_value);
428 }
429 params.output_set(lf_index);
430}
431
433{
434 const bNodeTree &ntree = node.owner_tree();
435 const Span<int> lf_index_by_bsocket =
436 ntree.runtime->geometry_nodes_lazy_function_graph_info->mapping.lf_index_by_bsocket;
437 for (const bNodeSocket *bsocket : node.output_sockets()) {
438 const int lf_index = lf_index_by_bsocket[bsocket->index_in_tree()];
439 if (lf_index == -1) {
440 continue;
441 }
442 if (params.output_was_set(lf_index)) {
443 continue;
444 }
445 set_default_value_for_output_socket(params, lf_index, *bsocket);
446 }
447}
448
450{
451 return make_anonymous_attribute_socket_inspection_string(socket.owner_node().label_or_name(),
452 socket.name);
453}
455 StringRef socket_name)
456{
457 return fmt::format(TIP_("\"{}\" from {}"), socket_name, node_name);
458}
459
461 const MultiFunction &fn,
462 const Span<SocketValueVariant *> input_values,
463 const Span<SocketValueVariant *> output_values)
464{
465 /* In this case, the multi-function is evaluated directly. */
466 const IndexMask mask(1);
467 mf::ParamsBuilder params{fn, &mask};
468 mf::ContextBuilder context;
469
470 for (const int i : input_values.index_range()) {
471 SocketValueVariant &input_variant = *input_values[i];
472 input_variant.convert_to_single();
473 const void *value = input_variant.get_single_ptr_raw();
474 const mf::ParamType param_type = fn.param_type(params.next_param_index());
475 const CPPType &cpp_type = param_type.data_type().single_type();
476 params.add_readonly_single_input(GPointer{cpp_type, value});
477 }
478 for (const int i : output_values.index_range()) {
479 if (output_values[i] == nullptr) {
480 params.add_ignored_single_output("");
481 continue;
482 }
483 SocketValueVariant &output_variant = *output_values[i];
484 const mf::ParamType param_type = fn.param_type(params.next_param_index());
485 const CPPType &cpp_type = param_type.data_type().single_type();
486 const eNodeSocketDatatype socket_type =
488 void *value = output_variant.allocate_single(socket_type);
489 params.add_uninitialized_single_output(GMutableSpan{cpp_type, value, 1});
490 }
491 fn.call(mask, params, context);
492}
493
495 const MultiFunction &fn,
496 const std::shared_ptr<MultiFunction> &owned_fn,
497 const Span<SocketValueVariant *> input_values,
498 const Span<SocketValueVariant *> output_values)
499{
500 /* Convert all inputs into fields, so that they can be used as input in the new field. */
501 Vector<GField> input_fields;
502 for (const int i : input_values.index_range()) {
503 input_fields.append(input_values[i]->extract<GField>());
504 }
505
506 /* Construct the new field node. */
507 std::shared_ptr<fn::FieldOperation> operation;
508 if (owned_fn) {
509 operation = fn::FieldOperation::Create(owned_fn, std::move(input_fields));
510 }
511 else {
512 operation = fn::FieldOperation::Create(fn, std::move(input_fields));
513 }
514
515 /* Store the new fields in the output. */
516 for (const int i : output_values.index_range()) {
517 if (output_values[i] == nullptr) {
518 continue;
519 }
520 output_values[i]->set(GField{operation, i});
521 }
522}
523
529 const std::shared_ptr<MultiFunction> &owned_fn,
530 const Span<SocketValueVariant *> input_values,
531 const Span<SocketValueVariant *> output_values)
532{
533 /* Check input types which determine how the function is evaluated. */
534 bool any_input_is_field = false;
535 for (const int i : input_values.index_range()) {
536 const SocketValueVariant &value = *input_values[i];
537 if (value.is_context_dependent_field()) {
538 any_input_is_field = true;
539 }
540 }
541
542 if (any_input_is_field) {
543 execute_multi_function_on_value_variant__field(fn, owned_fn, input_values, output_values);
544 }
545 else {
546 execute_multi_function_on_value_variant__single(fn, input_values, output_values);
547 }
548}
549
557 private:
558 const bNode &node_;
559 Span<int> lf_index_by_bsocket_;
560 Array<const bNodeSocket *> input_by_output_index_;
561
562 public:
563 LazyFunctionForMutedNode(const bNode &node, MutableSpan<int> r_lf_index_by_bsocket)
564 : node_(node), lf_index_by_bsocket_(r_lf_index_by_bsocket)
565 {
566 debug_name_ = "Muted";
567 lazy_function_interface_from_node(node, inputs_, outputs_, r_lf_index_by_bsocket);
568 for (lf::Input &fn_input : inputs_) {
569 fn_input.usage = lf::ValueUsage::Maybe;
570 }
571
572 for (lf::Input &fn_input : inputs_) {
573 fn_input.usage = lf::ValueUsage::Unused;
574 }
575
576 input_by_output_index_.reinitialize(node.output_sockets().size());
577 input_by_output_index_.fill(nullptr);
578 for (const bNodeLink &internal_link : node.internal_links()) {
579 const int input_i = r_lf_index_by_bsocket[internal_link.fromsock->index_in_tree()];
580 const int output_i = r_lf_index_by_bsocket[internal_link.tosock->index_in_tree()];
581 if (ELEM(-1, input_i, output_i)) {
582 continue;
583 }
584 input_by_output_index_[internal_link.tosock->index()] = internal_link.fromsock;
585 inputs_[input_i].usage = lf::ValueUsage::Maybe;
586 }
587 }
588
589 void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
590 {
591 for (const bNodeSocket *output_bsocket : node_.output_sockets()) {
592 const int lf_output_index = lf_index_by_bsocket_[output_bsocket->index_in_tree()];
593 if (lf_output_index == -1) {
594 continue;
595 }
596 if (params.output_was_set(lf_output_index)) {
597 continue;
598 }
599 if (params.get_output_usage(lf_output_index) != lf::ValueUsage::Used) {
600 continue;
601 }
602 const bNodeSocket *input_bsocket = input_by_output_index_[output_bsocket->index()];
603 if (input_bsocket == nullptr) {
604 set_default_value_for_output_socket(params, lf_output_index, *output_bsocket);
605 continue;
606 }
607 const int lf_input_index = lf_index_by_bsocket_[input_bsocket->index_in_tree()];
608 const void *input_value = params.try_get_input_data_ptr_or_request(lf_input_index);
609 if (input_value == nullptr) {
610 /* Wait for value to be available. */
611 continue;
612 }
613 void *output_value = params.get_output_data_ptr(lf_output_index);
614 if (input_bsocket->type == output_bsocket->type) {
615 inputs_[lf_input_index].type->copy_construct(input_value, output_value);
616 params.output_set(lf_output_index);
617 continue;
618 }
620 if (conversions.is_convertible(*input_bsocket->typeinfo->base_cpp_type,
621 *output_bsocket->typeinfo->base_cpp_type))
622 {
623 const MultiFunction &multi_fn = *conversions.get_conversion_multi_function(
624 mf::DataType::ForSingle(*input_bsocket->typeinfo->base_cpp_type),
625 mf::DataType::ForSingle(*output_bsocket->typeinfo->base_cpp_type));
626 SocketValueVariant input_variant = *static_cast<const SocketValueVariant *>(input_value);
627 SocketValueVariant *output_variant = new (output_value) SocketValueVariant();
628 execute_multi_function_on_value_variant(multi_fn, {}, {&input_variant}, {output_variant});
629 params.output_set(lf_output_index);
630 continue;
631 }
632 set_default_value_for_output_socket(params, lf_output_index, *output_bsocket);
633 }
634 }
635};
636
642 private:
643 const MultiFunction &fn_;
644
645 public:
647 {
648 debug_name_ = "Convert";
649 inputs_.append_as("From", CPPType::get<SocketValueVariant>());
651 }
652
653 void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
654 {
655 SocketValueVariant *from_value = params.try_get_input_data_ptr<SocketValueVariant>(0);
656 SocketValueVariant *to_value = new (params.get_output_data_ptr(0)) SocketValueVariant();
657 BLI_assert(from_value != nullptr);
658 BLI_assert(to_value != nullptr);
659
660 execute_multi_function_on_value_variant(fn_, {}, {from_value}, {to_value});
661
662 params.output_set(0);
663 }
664};
665
670 private:
671 const NodeMultiFunctions::Item fn_item_;
672
673 public:
676 MutableSpan<int> r_lf_index_by_bsocket)
677 : fn_item_(std::move(fn_item))
678 {
679 BLI_assert(fn_item_.fn != nullptr);
680 debug_name_ = node.name;
681 lazy_function_interface_from_node(node, inputs_, outputs_, r_lf_index_by_bsocket);
682 }
683
684 void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
685 {
686 Vector<SocketValueVariant *> input_values(inputs_.size());
687 Vector<SocketValueVariant *> output_values(outputs_.size());
688 for (const int i : inputs_.index_range()) {
689 input_values[i] = params.try_get_input_data_ptr<SocketValueVariant>(i);
690 }
691 for (const int i : outputs_.index_range()) {
692 if (params.get_output_usage(i) != lf::ValueUsage::Unused) {
693 output_values[i] = new (params.get_output_data_ptr(i)) SocketValueVariant();
694 }
695 else {
696 output_values[i] = nullptr;
697 }
698 }
700 *fn_item_.fn, fn_item_.owned_fn, input_values, output_values);
701 for (const int i : outputs_.index_range()) {
702 if (params.get_output_usage(i) != lf::ValueUsage::Unused) {
703 params.output_set(i);
704 }
705 }
706 }
707};
708
714 private:
718 std::function<void(void *)> init_fn_;
719
720 public:
721 LazyFunctionForImplicitInput(const CPPType &type, std::function<void(void *)> init_fn)
722 : init_fn_(std::move(init_fn))
723 {
724 debug_name_ = "Input";
725 outputs_.append({"Output", type});
726 }
727
728 void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
729 {
730 void *value = params.get_output_data_ptr(0);
731 init_fn_(value);
732 params.output_set(0);
733 }
734};
735
741 private:
742 const bNode &bnode_;
744 bool use_field_input_ = true;
745
746 public:
747 LazyFunctionForViewerNode(const bNode &bnode, MutableSpan<int> r_lf_index_by_bsocket)
748 : bnode_(bnode)
749 {
750 debug_name_ = "Viewer";
751 lazy_function_interface_from_node(bnode, inputs_, outputs_, r_lf_index_by_bsocket);
752
753 /* Remove field input if it is not used. */
754 for (const bNodeSocket *bsocket : bnode.input_sockets().drop_front(1)) {
755 if (!bsocket->is_available()) {
756 continue;
757 }
758 const Span<const bNodeLink *> links = bsocket->directly_linked_links();
759 if (links.is_empty() || links.first()->fromnode->is_dangling_reroute()) {
760 use_field_input_ = false;
761 inputs_.pop_last();
762 r_lf_index_by_bsocket[bsocket->index_in_tree()] = -1;
763 }
764 }
765 }
766
767 void execute_impl(lf::Params &params, const lf::Context &context) const override
768 {
769 const auto &user_data = *static_cast<GeoNodesLFUserData *>(context.user_data);
770 const auto &local_user_data = *static_cast<GeoNodesLFLocalUserData *>(context.local_user_data);
771 geo_eval_log::GeoTreeLogger *tree_logger = local_user_data.try_get_tree_logger(user_data);
772 if (tree_logger == nullptr) {
773 return;
774 }
775
776 GeometrySet geometry = params.extract_input<GeometrySet>(0);
777 const NodeGeometryViewer *storage = static_cast<NodeGeometryViewer *>(bnode_.storage);
778
779 if (use_field_input_) {
780 SocketValueVariant *value_variant = params.try_get_input_data_ptr<SocketValueVariant>(1);
781 BLI_assert(value_variant != nullptr);
782 GField field = value_variant->extract<GField>();
783 const AttrDomain domain = AttrDomain(storage->domain);
784 const StringRefNull viewer_attribute_name = ".viewer";
785 if (domain == AttrDomain::Instance) {
786 if (geometry.has_instances()) {
787 GeometryComponent &component = geometry.get_component_for_write(
790 component, viewer_attribute_name, AttrDomain::Instance, field);
791 }
792 }
793 else {
794 geometry.modify_geometry_sets([&](GeometrySet &geometry) {
795 for (const bke::GeometryComponent::Type type :
800 {
801 if (geometry.has(type)) {
802 GeometryComponent &component = geometry.get_component_for_write(type);
803 AttrDomain used_domain = domain;
804 if (used_domain == AttrDomain::Auto) {
805 if (const std::optional<AttrDomain> detected_domain = bke::try_detect_field_domain(
806 component, field))
807 {
808 used_domain = *detected_domain;
809 }
810 else {
811 used_domain = AttrDomain::Point;
812 }
813 }
815 component, viewer_attribute_name, used_domain, field);
816 }
817 }
818 });
819 }
820 }
821
822 tree_logger->log_viewer_node(bnode_, std::move(geometry));
823 }
824};
825
830 private:
831 const lf::FunctionNode &lf_viewer_node_;
832
833 public:
835 : lf_viewer_node_(lf_viewer_node)
836 {
837 debug_name_ = "Viewer Input Usage";
838 outputs_.append_as("Viewer is Used", CPPType::get<bool>());
839 }
840
841 void execute_impl(lf::Params &params, const lf::Context &context) const override
842 {
843 GeoNodesLFUserData *user_data = dynamic_cast<GeoNodesLFUserData *>(context.user_data);
844 BLI_assert(user_data != nullptr);
845 if (!user_data->call_data->side_effect_nodes) {
846 params.set_output<bool>(0, false);
847 return;
848 }
849 const ComputeContextHash &context_hash = user_data->compute_context->hash();
850 const Span<const lf::FunctionNode *> nodes_with_side_effects =
851 user_data->call_data->side_effect_nodes->nodes_by_context.lookup(context_hash);
852
853 const bool viewer_is_used = nodes_with_side_effects.contains(&lf_viewer_node_);
854 params.set_output(0, viewer_is_used);
855 }
856};
857
859static bool gizmo_is_used(const GeoNodesLFUserData &user_data,
860 const lf::FunctionNode &lf_gizmo_node)
861{
862 if (!user_data.call_data->side_effect_nodes) {
863 return false;
864 }
865 const Span<const lf::FunctionNode *> nodes_with_side_effects =
867 user_data.compute_context->hash());
868 const bool is_used = nodes_with_side_effects.contains(&lf_gizmo_node);
869 return is_used;
870}
871
878 private:
879 const bNode &bnode_;
880
881 public:
882 const lf::FunctionNode *self_node = nullptr;
884
885 LazyFunctionForGizmoNode(const bNode &bnode, MutableSpan<int> r_lf_index_by_bsocket)
886 : bnode_(bnode)
887 {
888 debug_name_ = bnode.name;
889 const bNodeSocket &gizmo_socket = bnode.input_socket(0);
890 /* Create inputs for every input of the multi-input socket to make sure that they can be
891 * logged. */
892 for (const bNodeLink *link : gizmo_socket.directly_linked_links()) {
893 if (!link->is_used()) {
894 continue;
895 }
896 if (link->fromnode->is_dangling_reroute()) {
897 continue;
898 }
899 inputs_.append_and_get_index_as(gizmo_socket.identifier,
900 *gizmo_socket.typeinfo->geometry_nodes_cpp_type,
901 lf::ValueUsage::Maybe);
902 gizmo_links.append(link);
903 }
904 for (const bNodeSocket *socket : bnode.input_sockets().drop_front(1)) {
905 r_lf_index_by_bsocket[socket->index_in_tree()] = inputs_.append_and_get_index_as(
906 socket->identifier, *socket->typeinfo->geometry_nodes_cpp_type, lf::ValueUsage::Maybe);
907 }
908 r_lf_index_by_bsocket[bnode.output_socket(0).index_in_tree()] =
909 outputs_.append_and_get_index_as("Transform", CPPType::get<GeometrySet>());
910 }
911
912 void execute_impl(lf::Params &params, const lf::Context &context) const override
913 {
914 const auto &user_data = *static_cast<GeoNodesLFUserData *>(context.user_data);
915 if (!gizmo_is_used(user_data, *this->self_node)) {
917 return;
918 }
919 if (!params.output_was_set(0)) {
920 GeometrySet geometry;
921 GeometryComponentEditData &edit_data =
922 geometry.get_component_for_write<GeometryComponentEditData>();
923 edit_data.gizmo_edit_hints_ = std::make_unique<bke::GizmoEditHints>();
924 edit_data.gizmo_edit_hints_->gizmo_transforms.add(
925 {user_data.compute_context->hash(), bnode_.identifier}, float4x4::identity());
926 params.set_output(0, std::move(geometry));
927 }
928
929 /* Request all inputs so that their values can be logged. */
930 for (const int i : inputs_.index_range()) {
931 params.try_get_input_data_ptr_or_request(i);
932 }
933
934 const auto &local_user_data = *static_cast<GeoNodesLFLocalUserData *>(context.local_user_data);
935 if (geo_eval_log::GeoTreeLogger *tree_logger = local_user_data.try_get_tree_logger(user_data))
936 {
937 tree_logger->evaluated_gizmo_nodes.append(*tree_logger->allocator, {bnode_.identifier});
938 }
939 }
940};
941
943 private:
944 const lf::FunctionNode *lf_gizmo_node_ = nullptr;
945
946 public:
947 LazyFunctionForGizmoInputsUsage(const bNode &gizmo_node, const lf::FunctionNode &lf_gizmo_node)
948 : lf_gizmo_node_(&lf_gizmo_node)
949 {
950 debug_name_ = gizmo_node.name;
951 outputs_.append_as("Need Inputs", CPPType::get<bool>());
952 }
953
954 void execute_impl(lf::Params &params, const lf::Context &context) const override
955 {
956 const auto &user_data = *static_cast<GeoNodesLFUserData *>(context.user_data);
957 const bool is_used = gizmo_is_used(user_data, *lf_gizmo_node_);
958 params.set_output(0, is_used);
959 }
960};
961
963 private:
964 const bNode *output_bnode_;
965
966 public:
967 LazyFunctionForSimulationInputsUsage(const bNode &output_bnode) : output_bnode_(&output_bnode)
968 {
969 debug_name_ = "Simulation Inputs Usage";
970 outputs_.append_as("Need Input Inputs", CPPType::get<bool>());
971 outputs_.append_as("Need Output Inputs", CPPType::get<bool>());
972 }
973
974 void execute_impl(lf::Params &params, const lf::Context &context) const override
975 {
976 const GeoNodesLFUserData &user_data = *static_cast<GeoNodesLFUserData *>(context.user_data);
977 const GeoNodesCallData &call_data = *user_data.call_data;
978 if (!call_data.simulation_params) {
979 this->set_default_outputs(params);
980 return;
981 }
982 const std::optional<FoundNestedNodeID> found_id = find_nested_node_id(
983 user_data, output_bnode_->identifier);
984 if (!found_id) {
985 this->set_default_outputs(params);
986 return;
987 }
988 if (found_id->is_in_loop) {
989 this->set_default_outputs(params);
990 return;
991 }
992 SimulationZoneBehavior *zone_behavior = call_data.simulation_params->get(found_id->id);
993 if (!zone_behavior) {
994 this->set_default_outputs(params);
995 return;
996 }
997
998 bool solve_contains_side_effect = false;
999 if (call_data.side_effect_nodes) {
1000 const Span<const lf::FunctionNode *> side_effect_nodes =
1001 call_data.side_effect_nodes->nodes_by_context.lookup(user_data.compute_context->hash());
1002 solve_contains_side_effect = !side_effect_nodes.is_empty();
1003 }
1004
1005 params.set_output(0, std::holds_alternative<sim_input::PassThrough>(zone_behavior->input));
1006 params.set_output(
1007 1,
1008 solve_contains_side_effect ||
1009 std::holds_alternative<sim_output::StoreNewState>(zone_behavior->output));
1010 }
1011
1013 {
1014 params.set_output(0, false);
1015 params.set_output(1, false);
1016 }
1017};
1018
1020 private:
1021 const bNode *bnode_;
1022
1023 public:
1024 LazyFunctionForBakeInputsUsage(const bNode &bnode) : bnode_(&bnode)
1025 {
1026 debug_name_ = "Bake Inputs Usage";
1027 outputs_.append_as("Used", CPPType::get<bool>());
1028 }
1029
1030 void execute_impl(lf::Params &params, const lf::Context &context) const override
1031 {
1032 const GeoNodesLFUserData &user_data = *static_cast<GeoNodesLFUserData *>(context.user_data);
1033 if (!user_data.call_data->bake_params) {
1034 this->set_default_outputs(params);
1035 return;
1036 }
1037 const std::optional<FoundNestedNodeID> found_id = find_nested_node_id(user_data,
1038 bnode_->identifier);
1039 if (!found_id) {
1040 this->set_default_outputs(params);
1041 return;
1042 }
1043 if (found_id->is_in_loop || found_id->is_in_simulation) {
1044 this->set_default_outputs(params);
1045 return;
1046 }
1047 BakeNodeBehavior *behavior = user_data.call_data->bake_params->get(found_id->id);
1048 if (!behavior) {
1049 this->set_default_outputs(params);
1050 return;
1051 }
1052 const bool need_inputs = std::holds_alternative<sim_output::PassThrough>(behavior->behavior) ||
1053 std::holds_alternative<sim_output::StoreNewState>(behavior->behavior);
1054 params.set_output(0, need_inputs);
1055 }
1056
1058 {
1059 params.set_output(0, false);
1060 }
1061};
1062
1065{
1066 if (const Set<ComputeContextHash> *contexts = user_data.call_data->socket_log_contexts) {
1067 return contexts->contains(hash);
1068 }
1069 else if (user_data.call_data->operator_data) {
1070 return false;
1071 }
1072 return true;
1073}
1074
1080 private:
1081 const bNode &group_node_;
1082 const LazyFunction &group_lazy_function_;
1083 bool has_many_nodes_ = false;
1084
1085 struct Storage {
1086 void *group_storage = nullptr;
1087 /* To avoid computing the hash more than once. */
1088 std::optional<ComputeContextHash> context_hash_cache;
1089 };
1090
1091 public:
1093 const GeometryNodesLazyFunctionGraphInfo &group_lf_graph_info,
1094 GeometryNodesLazyFunctionGraphInfo &own_lf_graph_info)
1095 : group_node_(group_node), group_lazy_function_(*group_lf_graph_info.function.function)
1096 {
1097 debug_name_ = group_node.name;
1098 allow_missing_requested_inputs_ = true;
1099
1100 /* This wrapper has the same interface as the actual underlying node group. */
1101 inputs_ = group_lf_graph_info.function.function->inputs();
1102 outputs_ = group_lf_graph_info.function.function->outputs();
1103
1104 has_many_nodes_ = group_lf_graph_info.num_inline_nodes_approximate > 1000;
1105
1106 /* Add a boolean input for every output bsocket that indicates whether that socket is used. */
1107 for (const int i : group_node.output_sockets().index_range()) {
1109 [group_node.output_socket(i).index_in_all_outputs()] =
1110 group_lf_graph_info.function.inputs.output_usages[i];
1111 }
1112
1113 /* Add an attribute set input for every output geometry socket that can propagate attributes
1114 * from inputs. */
1115 for (const int i : group_lf_graph_info.function.inputs.attributes_to_propagate.geometry_outputs
1116 .index_range())
1117 {
1118 const int lf_index = group_lf_graph_info.function.inputs.attributes_to_propagate.range[i];
1119 const int output_index =
1121 const bNodeSocket &output_bsocket = group_node_.output_socket(output_index);
1123 [output_bsocket.index_in_all_outputs()] = lf_index;
1124 }
1125 }
1126
1127 void execute_impl(lf::Params &params, const lf::Context &context) const override
1128 {
1129 const ScopedNodeTimer node_timer{context, group_node_};
1130 GeoNodesLFUserData *user_data = dynamic_cast<GeoNodesLFUserData *>(context.user_data);
1131 BLI_assert(user_data != nullptr);
1132
1133 if (has_many_nodes_) {
1134 /* If the called node group has many nodes, it's likely that executing it takes a while even
1135 * if every individual node is very small. */
1136 lazy_threading::send_hint();
1137 }
1138
1139 Storage *storage = static_cast<Storage *>(context.storage);
1140
1141 /* The compute context changes when entering a node group. */
1142 bke::GroupNodeComputeContext compute_context{
1143 user_data->compute_context, group_node_.identifier, storage->context_hash_cache};
1144 storage->context_hash_cache = compute_context.hash();
1145
1146 GeoNodesLFUserData group_user_data = *user_data;
1147 group_user_data.compute_context = &compute_context;
1149 *user_data, compute_context.hash());
1150
1151 GeoNodesLFLocalUserData group_local_user_data{group_user_data};
1152 lf::Context group_context{storage->group_storage, &group_user_data, &group_local_user_data};
1153
1154 ScopedComputeContextTimer timer(group_context);
1155 group_lazy_function_.execute(params, group_context);
1156 }
1157
1158 void *init_storage(LinearAllocator<> &allocator) const override
1159 {
1160 Storage *s = allocator.construct<Storage>().release();
1161 s->group_storage = group_lazy_function_.init_storage(allocator);
1162 return s;
1163 }
1164
1165 void destruct_storage(void *storage) const override
1166 {
1167 Storage *s = static_cast<Storage *>(storage);
1168 group_lazy_function_.destruct_storage(s->group_storage);
1169 std::destroy_at(s);
1170 }
1171
1172 std::string name() const override
1173 {
1174 return fmt::format(TIP_("Group '{}' ({})"), group_node_.id->name + 2, group_node_.name);
1175 }
1176
1177 std::string input_name(const int i) const override
1178 {
1179 return group_lazy_function_.input_name(i);
1180 }
1181
1182 std::string output_name(const int i) const override
1183 {
1184 return group_lazy_function_.output_name(i);
1185 }
1186};
1187
1189 const bNodeSocket &bsocket)
1190{
1191 const bke::bNodeSocketType &typeinfo = *bsocket.typeinfo;
1192 const CPPType *type = get_socket_cpp_type(typeinfo);
1193 if (type == nullptr) {
1194 return {};
1195 }
1196 void *buffer = allocator.allocate(type->size(), type->alignment());
1197 typeinfo.get_geometry_nodes_cpp_value(bsocket.default_value, buffer);
1198 return {type, buffer};
1199}
1200
1206 public:
1207 LazyFunctionForLogicalOr(const int inputs_num)
1208 {
1209 debug_name_ = "Logical Or";
1210 for ([[maybe_unused]] const int i : IndexRange(inputs_num)) {
1211 inputs_.append_as("Input", CPPType::get<bool>(), lf::ValueUsage::Maybe);
1212 }
1213 outputs_.append_as("Output", CPPType::get<bool>());
1214 }
1215
1216 void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
1217 {
1218 Vector<int, 16> unavailable_inputs;
1219 /* First check all inputs for available values without requesting more inputs. If any of the
1220 * available inputs is true already, the others don't have to be requested anymore. */
1221 for (const int i : inputs_.index_range()) {
1222 if (const bool *value = params.try_get_input_data_ptr<bool>(i)) {
1223 if (*value) {
1224 params.set_output(0, true);
1225 return;
1226 }
1227 }
1228 else {
1229 unavailable_inputs.append(i);
1230 }
1231 }
1232 if (unavailable_inputs.is_empty()) {
1233 params.set_output(0, false);
1234 return;
1235 }
1236 /* Request the next unavailable input. Note that a value might be available now even if it was
1237 * not available before, because it might have been computed in the mean-time. */
1238 for (const int i : unavailable_inputs) {
1239 if (const bool *value = params.try_get_input_data_ptr_or_request<bool>(i)) {
1240 if (*value) {
1241 params.set_output(0, true);
1242 return;
1243 }
1244 }
1245 else {
1246 /* The input has been requested and it's not available yet, so wait until it is ready. */
1247 return;
1248 }
1249 }
1250 /* All inputs were available now and all of them were false, so the final output is false. */
1251 params.set_output(0, false);
1252 }
1253};
1254
1260 public:
1262 {
1263 debug_name_ = "Switch Socket Usage";
1264 inputs_.append_as("Condition", CPPType::get<SocketValueVariant>());
1265 outputs_.append_as("False", CPPType::get<bool>());
1266 outputs_.append_as("True", CPPType::get<bool>());
1267 }
1268
1269 void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
1270 {
1271 const SocketValueVariant &condition_variant = params.get_input<SocketValueVariant>(0);
1272 if (condition_variant.is_context_dependent_field()) {
1273 params.set_output(0, true);
1274 params.set_output(1, true);
1275 }
1276 else {
1277 const bool value = condition_variant.get<bool>();
1278 params.set_output(0, !value);
1279 params.set_output(1, value);
1280 }
1281 }
1282};
1283
1289 public:
1291 {
1292 debug_name_ = "Index Switch Socket Usage";
1293 inputs_.append_as("Index", CPPType::get<SocketValueVariant>());
1294 for (const bNodeSocket *socket : bnode.input_sockets().drop_front(1)) {
1295 outputs_.append_as(socket->identifier, CPPType::get<bool>());
1296 }
1297 }
1298
1299 void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
1300 {
1301 const SocketValueVariant &index_variant = params.get_input<SocketValueVariant>(0);
1302 if (index_variant.is_context_dependent_field()) {
1303 for (const int i : outputs_.index_range()) {
1304 params.set_output(i, true);
1305 }
1306 }
1307 else {
1308 const int value = index_variant.get<int>();
1309 for (const int i : outputs_.index_range()) {
1310 params.set_output(i, i == value);
1311 }
1312 }
1313 }
1314};
1315
1320 public:
1322 {
1323 debug_name_ = "Extract Attribute Set";
1324 inputs_.append_as("Use", CPPType::get<bool>());
1325 inputs_.append_as("Field", CPPType::get<SocketValueVariant>(), lf::ValueUsage::Maybe);
1326 outputs_.append_as("Attributes", CPPType::get<bke::AnonymousAttributeSet>());
1327 }
1328
1329 void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
1330 {
1331 const bool use = params.get_input<bool>(0);
1332 if (!use) {
1333 params.set_output<bke::AnonymousAttributeSet>(0, {});
1334 return;
1335 }
1336 const SocketValueVariant *value_variant =
1337 params.try_get_input_data_ptr_or_request<SocketValueVariant>(1);
1338 if (value_variant == nullptr) {
1339 /* Wait until the field is computed. */
1340 return;
1341 }
1342
1343 bke::AnonymousAttributeSet attributes;
1344 if (value_variant->is_context_dependent_field()) {
1345 const GField &field = value_variant->get<GField>();
1346 field.node().for_each_field_input_recursive([&](const FieldInput &field_input) {
1347 if (const auto *attr_field_input = dynamic_cast<const AttributeFieldInput *>(&field_input))
1348 {
1349 const StringRef name = attr_field_input->attribute_name();
1350 if (bke::attribute_name_is_anonymous(name)) {
1351 if (!attributes.names) {
1352 attributes.names = std::make_shared<Set<std::string>>();
1353 }
1354 attributes.names->add_as(name);
1355 }
1356 }
1357 });
1358 }
1359 params.set_output(0, std::move(attributes));
1360 }
1361};
1362
1368 const int amount_;
1369
1370 public:
1371 LazyFunctionForAnonymousAttributeSetJoin(const int amount) : amount_(amount)
1372 {
1373 debug_name_ = "Join Attribute Sets";
1374 for ([[maybe_unused]] const int i : IndexRange(amount)) {
1375 inputs_.append_as("Use", CPPType::get<bool>());
1376 inputs_.append_as(
1377 "Attribute Set", CPPType::get<bke::AnonymousAttributeSet>(), lf::ValueUsage::Maybe);
1378 }
1379 outputs_.append_as("Attribute Set", CPPType::get<bke::AnonymousAttributeSet>());
1380 }
1381
1382 void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
1383 {
1385 bool set_is_missing = false;
1386 for (const int i : IndexRange(amount_)) {
1387 if (params.get_input<bool>(this->get_use_input(i))) {
1389 params.try_get_input_data_ptr_or_request<bke::AnonymousAttributeSet>(
1390 this->get_attribute_set_input(i)))
1391 {
1392 sets.append(set);
1393 }
1394 else {
1395 set_is_missing = true;
1396 }
1397 }
1398 }
1399 if (set_is_missing) {
1400 return;
1401 }
1402 bke::AnonymousAttributeSet joined_set;
1403 if (sets.is_empty()) {
1404 /* Nothing to do. */
1405 }
1406 else if (sets.size() == 1) {
1407 joined_set.names = std::move(sets[0]->names);
1408 }
1409 else {
1410 joined_set.names = std::make_shared<Set<std::string>>();
1411 for (const bke::AnonymousAttributeSet *set : sets) {
1412 if (set->names) {
1413 for (const std::string &name : *set->names) {
1414 joined_set.names->add(name);
1415 }
1416 }
1417 }
1418 }
1419 params.set_output(0, std::move(joined_set));
1420 }
1421
1422 int get_use_input(const int i) const
1423 {
1424 return 2 * i;
1425 }
1426
1427 int get_attribute_set_input(const int i) const
1428 {
1429 return 2 * i + 1;
1430 }
1431
1436 ResourceScope &scope)
1437 {
1438 constexpr int cache_amount = 16;
1439 static std::array<LazyFunctionForAnonymousAttributeSetJoin, cache_amount> cached_functions =
1440 get_cache(std::make_index_sequence<cache_amount>{});
1441 if (amount < cached_functions.size()) {
1442 return cached_functions[amount];
1443 }
1444
1446 }
1447
1448 private:
1449 template<size_t... I>
1450 static std::array<LazyFunctionForAnonymousAttributeSetJoin, sizeof...(I)> get_cache(
1451 std::index_sequence<I...> /*indices*/)
1452 {
1454 }
1455};
1456
1458 private:
1459 const bNode &sim_output_bnode_;
1460 const LazyFunction &fn_;
1461
1462 public:
1463 LazyFunctionForSimulationZone(const bNode &sim_output_bnode, const LazyFunction &fn)
1464 : sim_output_bnode_(sim_output_bnode), fn_(fn)
1465 {
1466 debug_name_ = "Simulation Zone";
1467 inputs_ = fn.inputs();
1468 outputs_ = fn.outputs();
1469 }
1470
1471 void execute_impl(lf::Params &params, const lf::Context &context) const override
1472 {
1473 ScopedNodeTimer node_timer{context, sim_output_bnode_};
1474 GeoNodesLFUserData &user_data = *static_cast<GeoNodesLFUserData *>(context.user_data);
1475
1476 bke::SimulationZoneComputeContext compute_context{user_data.compute_context,
1477 sim_output_bnode_};
1478
1479 GeoNodesLFUserData zone_user_data = user_data;
1480 zone_user_data.compute_context = &compute_context;
1482 user_data, compute_context.hash());
1483
1484 GeoNodesLFLocalUserData zone_local_user_data{zone_user_data};
1485 lf::Context zone_context{context.storage, &zone_user_data, &zone_local_user_data};
1486 fn_.execute(params, zone_context);
1487 }
1488
1489 void *init_storage(LinearAllocator<> &allocator) const override
1490 {
1491 return fn_.init_storage(allocator);
1492 }
1493
1494 void destruct_storage(void *storage) const override
1495 {
1496 fn_.destruct_storage(storage);
1497 }
1498
1499 std::string input_name(const int i) const override
1500 {
1501 return fn_.input_name(i);
1502 }
1503
1504 std::string output_name(const int i) const override
1505 {
1506 return fn_.output_name(i);
1507 }
1508};
1509
1511
1555
1575
1578 const LazyFunction *lazy_function = nullptr;
1579
1582};
1583
1590 const LazyFunction *function = nullptr;
1592};
1593
1594static bool ignore_zone_bsocket(const bNodeSocket &bsocket)
1595{
1596 if (!bsocket.is_available()) {
1597 return true;
1598 }
1599 if (!bsocket.typeinfo->geometry_nodes_cpp_type) {
1600 /* These are typically extend sockets. */
1601 return true;
1602 }
1603 return false;
1604}
1605
1607 ZoneBuildInfo &zone_info,
1608 const ZoneBodyFunction &body_fn,
1609 Vector<lf::Input> &r_inputs,
1610 Vector<lf::Output> &r_outputs)
1611{
1612 for (const bNodeSocket *socket : zone.input_node->input_sockets()) {
1613 if (ignore_zone_bsocket(*socket)) {
1614 continue;
1615 }
1617 socket->name, *socket->typeinfo->geometry_nodes_cpp_type, lf::ValueUsage::Maybe));
1618 }
1619
1620 for (const bNodeLink *link : zone.border_links) {
1622 r_inputs.append_and_get_index_as(link->fromsock->name,
1623 *link->tosock->typeinfo->geometry_nodes_cpp_type,
1624 lf::ValueUsage::Maybe));
1625 }
1626
1627 for (const bNodeSocket *socket : zone.output_node->output_sockets()) {
1628 if (ignore_zone_bsocket(*socket)) {
1629 continue;
1630 }
1631 const CPPType *cpp_type = socket->typeinfo->geometry_nodes_cpp_type;
1633 r_inputs.append_and_get_index_as("Usage", CPPType::get<bool>(), lf::ValueUsage::Maybe));
1634 zone_info.indices.outputs.main.append(
1635 r_outputs.append_and_get_index_as(socket->name, *cpp_type));
1636 }
1637
1638 for ([[maybe_unused]] const bNodeSocket *socket : zone.input_node->input_sockets()) {
1639 if (ignore_zone_bsocket(*socket)) {
1640 continue;
1641 }
1643 r_outputs.append_and_get_index_as("Usage", CPPType::get<bool>()));
1644 }
1645
1646 for ([[maybe_unused]] const bNodeLink *link : zone.border_links) {
1648 r_outputs.append_and_get_index_as("Border Link Usage", CPPType::get<bool>()));
1649 }
1650
1651 for (const auto item : body_fn.indices.inputs.attributes_by_field_source_index.items()) {
1653 item.key,
1654 r_inputs.append_and_get_index_as(
1655 "Attribute Set", CPPType::get<bke::AnonymousAttributeSet>(), lf::ValueUsage::Maybe));
1656 }
1657 for (const auto item : body_fn.indices.inputs.attributes_by_caller_propagation_index.items()) {
1659 item.key,
1660 r_inputs.append_and_get_index_as(
1661 "Attribute Set", CPPType::get<bke::AnonymousAttributeSet>(), lf::ValueUsage::Maybe));
1662 }
1663}
1664
1665static std::string zone_wrapper_input_name(const ZoneBuildInfo &zone_info,
1666 const bNodeTreeZone &zone,
1667 const Span<lf::Input> inputs,
1668 const int lf_socket_i)
1669{
1670 if (zone_info.indices.inputs.output_usages.contains(lf_socket_i)) {
1671 const int output_usage_i = lf_socket_i - zone_info.indices.inputs.output_usages.first();
1672 int current_valid_i = 0;
1673 for (const bNodeSocket *bsocket : zone.output_node->output_sockets()) {
1674 if (ignore_zone_bsocket(*bsocket)) {
1675 continue;
1676 }
1677 if (current_valid_i == output_usage_i) {
1678 return "Usage: " + StringRef(bsocket->name);
1679 }
1680 current_valid_i++;
1681 }
1682 }
1683 return inputs[lf_socket_i].debug_name;
1684}
1685
1686static std::string zone_wrapper_output_name(const ZoneBuildInfo &zone_info,
1687 const bNodeTreeZone &zone,
1688 const Span<lf::Output> outputs,
1689 const int lf_socket_i)
1690{
1691 if (zone_info.indices.outputs.input_usages.contains(lf_socket_i)) {
1692 const int input_usage_i = lf_socket_i - zone_info.indices.outputs.input_usages.first();
1693 int current_valid_i = 0;
1694 for (const bNodeSocket *bsocket : zone.input_node->input_sockets()) {
1695 if (ignore_zone_bsocket(*bsocket)) {
1696 continue;
1697 }
1698 if (current_valid_i == input_usage_i) {
1699 return "Usage: " + StringRef(bsocket->name);
1700 }
1701 current_valid_i++;
1702 }
1703 }
1704 return outputs[lf_socket_i].debug_name;
1705}
1706
1714 public:
1715 const bNode *repeat_output_bnode_ = nullptr;
1716 VectorSet<lf::FunctionNode *> *lf_body_nodes_ = nullptr;
1717
1720 const lf::Context &context) const
1721 {
1722 GeoNodesLFUserData &user_data = *static_cast<GeoNodesLFUserData *>(context.user_data);
1723 const int iteration = lf_body_nodes_->index_of_try(const_cast<lf::FunctionNode *>(&node));
1724 const LazyFunction &fn = node.function();
1725 if (iteration == -1) {
1726 /* The node is not a loop body node, just execute it normally. */
1727 fn.execute(params, context);
1728 return;
1729 }
1730
1731 /* Setup context for the loop body evaluation. */
1732 bke::RepeatZoneComputeContext body_compute_context{
1733 user_data.compute_context, *repeat_output_bnode_, iteration};
1734 GeoNodesLFUserData body_user_data = user_data;
1735 body_user_data.compute_context = &body_compute_context;
1737 user_data, body_compute_context.hash());
1738
1739 GeoNodesLFLocalUserData body_local_user_data{body_user_data};
1740 lf::Context body_context{context.storage, &body_user_data, &body_local_user_data};
1741 fn.execute(params, body_context);
1742 }
1743};
1744
1749 public:
1750 const bNode *repeat_output_bnode_ = nullptr;
1752
1754 const lf::Context &context) const override
1755 {
1756 GeoNodesLFUserData &user_data = *static_cast<GeoNodesLFUserData *>(context.user_data);
1757 const GeoNodesCallData &call_data = *user_data.call_data;
1758 if (!call_data.side_effect_nodes) {
1759 return {};
1760 }
1761 const ComputeContextHash &context_hash = user_data.compute_context->hash();
1762 const Span<int> iterations_with_side_effects =
1764 {context_hash, repeat_output_bnode_->identifier});
1765
1767 for (const int i : iterations_with_side_effects) {
1768 if (i >= 0 && i < lf_body_nodes_.size()) {
1769 lf_nodes.append(lf_body_nodes_[i]);
1770 }
1771 }
1772 return lf_nodes;
1773 }
1774};
1775
1780 std::optional<LazyFunctionForLogicalOr> or_function;
1781 std::optional<RepeatZoneSideEffectProvider> side_effect_provider;
1782 std::optional<RepeatBodyNodeExecuteWrapper> body_execute_wrapper;
1783 std::optional<lf::GraphExecutor> graph_executor;
1785 void *graph_executor_storage = nullptr;
1786 bool multi_threading_enabled = false;
1789};
1790
1792 private:
1793 const bNodeTree &btree_;
1794 const bNodeTreeZone &zone_;
1795 const bNode &repeat_output_bnode_;
1796 const ZoneBuildInfo &zone_info_;
1797 const ZoneBodyFunction &body_fn_;
1798
1799 public:
1801 const bNodeTreeZone &zone,
1802 ZoneBuildInfo &zone_info,
1803 const ZoneBodyFunction &body_fn)
1804 : btree_(btree),
1805 zone_(zone),
1806 repeat_output_bnode_(*zone.output_node),
1807 zone_info_(zone_info),
1808 body_fn_(body_fn)
1809 {
1810 debug_name_ = "Repeat Zone";
1811
1812 initialize_zone_wrapper(zone, zone_info, body_fn, inputs_, outputs_);
1813 /* Iterations input is always used. */
1814 inputs_[zone_info.indices.inputs.main[0]].usage = lf::ValueUsage::Used;
1815 }
1816
1817 void *init_storage(LinearAllocator<> &allocator) const override
1818 {
1819 return allocator.construct<RepeatEvalStorage>().release();
1820 }
1821
1822 void destruct_storage(void *storage) const override
1823 {
1824 RepeatEvalStorage *s = static_cast<RepeatEvalStorage *>(storage);
1825 if (s->graph_executor_storage) {
1826 s->graph_executor->destruct_storage(s->graph_executor_storage);
1827 }
1828 std::destroy_at(s);
1829 }
1830
1831 void execute_impl(lf::Params &params, const lf::Context &context) const override
1832 {
1833 const ScopedNodeTimer node_timer{context, repeat_output_bnode_};
1834
1835 auto &user_data = *static_cast<GeoNodesLFUserData *>(context.user_data);
1836 auto &local_user_data = *static_cast<GeoNodesLFLocalUserData *>(context.local_user_data);
1837
1838 const NodeGeometryRepeatOutput &node_storage = *static_cast<const NodeGeometryRepeatOutput *>(
1839 repeat_output_bnode_.storage);
1840 RepeatEvalStorage &eval_storage = *static_cast<RepeatEvalStorage *>(context.storage);
1841
1842 const int iterations_usage_index = zone_info_.indices.outputs.input_usages[0];
1843 if (!params.output_was_set(iterations_usage_index)) {
1844 /* The iterations input is always used. */
1845 params.set_output(iterations_usage_index, true);
1846 }
1847
1848 if (!eval_storage.graph_executor) {
1849 /* Create the execution graph in the first evaluation. */
1850 this->initialize_execution_graph(
1851 params, eval_storage, node_storage, user_data, local_user_data);
1852 }
1853
1854 /* Execute the graph for the repeat zone. */
1855 lf::RemappedParams eval_graph_params{*eval_storage.graph_executor,
1856 params,
1857 eval_storage.input_index_map,
1858 eval_storage.output_index_map,
1859 eval_storage.multi_threading_enabled};
1860 lf::Context eval_graph_context{
1861 eval_storage.graph_executor_storage, context.user_data, context.local_user_data};
1862 eval_storage.graph_executor->execute(eval_graph_params, eval_graph_context);
1863 }
1864
1874 RepeatEvalStorage &eval_storage,
1875 const NodeGeometryRepeatOutput &node_storage,
1876 GeoNodesLFUserData &user_data,
1877 GeoNodesLFLocalUserData &local_user_data) const
1878 {
1879 const int num_repeat_items = node_storage.items_num;
1880 const int num_border_links = body_fn_.indices.inputs.border_links.size();
1881
1882 /* Number of iterations to evaluate. */
1883 const int iterations = std::max<int>(
1884 0, params.get_input<SocketValueVariant>(zone_info_.indices.inputs.main[0]).get<int>());
1885
1886 /* Show a warning when the inspection index is out of range. */
1887 if (node_storage.inspection_index > 0) {
1888 if (node_storage.inspection_index >= iterations) {
1889 if (geo_eval_log::GeoTreeLogger *tree_logger = local_user_data.try_get_tree_logger(
1890 user_data))
1891 {
1892 tree_logger->node_warnings.append(
1893 *tree_logger->allocator,
1894 {repeat_output_bnode_.identifier,
1895 {NodeWarningType::Info, N_("Inspection index is out of range")}});
1896 }
1897 }
1898 }
1899
1900 /* Take iterations input into account. */
1901 const int main_inputs_offset = 1;
1902 const int body_inputs_offset = 1;
1903
1904 lf::Graph &lf_graph = eval_storage.graph;
1905
1908
1909 for (const int i : inputs_.index_range()) {
1910 const lf::Input &input = inputs_[i];
1911 lf_inputs.append(&lf_graph.add_input(*input.type, this->input_name(i)));
1912 }
1913 for (const int i : outputs_.index_range()) {
1914 const lf::Output &output = outputs_[i];
1915 lf_outputs.append(&lf_graph.add_output(*output.type, this->output_name(i)));
1916 }
1917
1918 /* Create body nodes. */
1919 VectorSet<lf::FunctionNode *> &lf_body_nodes = eval_storage.lf_body_nodes;
1920 for ([[maybe_unused]] const int i : IndexRange(iterations)) {
1921 lf::FunctionNode &lf_node = lf_graph.add_function(*body_fn_.function);
1922 lf_body_nodes.add_new(&lf_node);
1923 }
1924
1925 /* Create nodes for combining border link usages. A border link is used when any of the loop
1926 * bodies uses the border link, so an "or" node is necessary. */
1927 Array<lf::FunctionNode *> lf_border_link_usage_or_nodes(num_border_links);
1928 eval_storage.or_function.emplace(iterations);
1929 for (const int i : IndexRange(num_border_links)) {
1930 lf::FunctionNode &lf_node = lf_graph.add_function(*eval_storage.or_function);
1931 lf_border_link_usage_or_nodes[i] = &lf_node;
1932 }
1933
1934 const bool use_index_values = zone_.input_node->output_socket(0).is_directly_linked();
1935
1936 if (use_index_values) {
1937 eval_storage.index_values.reinitialize(iterations);
1938 threading::parallel_for(IndexRange(iterations), 1024, [&](const IndexRange range) {
1939 for (const int i : range) {
1940 eval_storage.index_values[i].set(i);
1941 }
1942 });
1943 }
1944
1945 /* Handle body nodes one by one. */
1946 static const SocketValueVariant static_unused_index{-1};
1947 for (const int iter_i : lf_body_nodes.index_range()) {
1948 lf::FunctionNode &lf_node = *lf_body_nodes[iter_i];
1949 const SocketValueVariant *index_value = use_index_values ?
1950 &eval_storage.index_values[iter_i] :
1951 &static_unused_index;
1952 lf_node.input(body_fn_.indices.inputs.main[0]).set_default_value(index_value);
1953 for (const int i : IndexRange(num_border_links)) {
1954 lf_graph.add_link(*lf_inputs[zone_info_.indices.inputs.border_links[i]],
1955 lf_node.input(body_fn_.indices.inputs.border_links[i]));
1956 lf_graph.add_link(lf_node.output(body_fn_.indices.outputs.border_link_usages[i]),
1957 lf_border_link_usage_or_nodes[i]->input(iter_i));
1958 }
1959 for (const auto item : body_fn_.indices.inputs.attributes_by_field_source_index.items()) {
1960 lf_graph.add_link(
1962 item.key)],
1963 lf_node.input(item.value));
1964 }
1965 for (const auto item :
1966 body_fn_.indices.inputs.attributes_by_caller_propagation_index.items())
1967 {
1968 lf_graph.add_link(
1970 item.key)],
1971 lf_node.input(item.value));
1972 }
1973 }
1974
1975 static bool static_true = true;
1976
1977 /* Handle body nodes pair-wise. */
1978 for (const int iter_i : lf_body_nodes.index_range().drop_back(1)) {
1979 lf::FunctionNode &lf_node = *lf_body_nodes[iter_i];
1980 lf::FunctionNode &lf_next_node = *lf_body_nodes[iter_i + 1];
1981 for (const int i : IndexRange(num_repeat_items)) {
1982 lf_graph.add_link(
1983 lf_node.output(body_fn_.indices.outputs.main[i]),
1984 lf_next_node.input(body_fn_.indices.inputs.main[i + body_inputs_offset]));
1985 /* TODO: Add back-link after being able to check for cyclic dependencies. */
1986 // lf_graph.add_link(lf_next_node.output(body_fn_.indices.outputs.input_usages[i]),
1987 // lf_node.input(body_fn_.indices.inputs.output_usages[i]));
1988 lf_node.input(body_fn_.indices.inputs.output_usages[i]).set_default_value(&static_true);
1989 }
1990 }
1991
1992 /* Handle border link usage outputs. */
1993 for (const int i : IndexRange(num_border_links)) {
1994 lf_graph.add_link(lf_border_link_usage_or_nodes[i]->output(0),
1995 *lf_outputs[zone_info_.indices.outputs.border_link_usages[i]]);
1996 }
1997
1998 if (iterations > 0) {
1999 {
2000 /* Link first body node to input/output nodes. */
2001 lf::FunctionNode &lf_first_body_node = *lf_body_nodes[0];
2002 for (const int i : IndexRange(num_repeat_items)) {
2003 lf_graph.add_link(
2004 *lf_inputs[zone_info_.indices.inputs.main[i + main_inputs_offset]],
2005 lf_first_body_node.input(body_fn_.indices.inputs.main[i + body_inputs_offset]));
2006 lf_graph.add_link(
2007 lf_first_body_node.output(
2008 body_fn_.indices.outputs.input_usages[i + body_inputs_offset]),
2009 *lf_outputs[zone_info_.indices.outputs.input_usages[i + main_inputs_offset]]);
2010 }
2011 }
2012 {
2013 /* Link last body node to input/output nodes. */
2014 lf::FunctionNode &lf_last_body_node = *lf_body_nodes.as_span().last();
2015 for (const int i : IndexRange(num_repeat_items)) {
2016 lf_graph.add_link(lf_last_body_node.output(body_fn_.indices.outputs.main[i]),
2017 *lf_outputs[zone_info_.indices.outputs.main[i]]);
2018 lf_graph.add_link(*lf_inputs[zone_info_.indices.inputs.output_usages[i]],
2019 lf_last_body_node.input(body_fn_.indices.inputs.output_usages[i]));
2020 }
2021 }
2022 }
2023 else {
2024 /* There are no iterations, just link the input directly to the output. */
2025 for (const int i : IndexRange(num_repeat_items)) {
2026 lf_graph.add_link(*lf_inputs[zone_info_.indices.inputs.main[i + main_inputs_offset]],
2027 *lf_outputs[zone_info_.indices.outputs.main[i]]);
2028 lf_graph.add_link(
2029 *lf_inputs[zone_info_.indices.inputs.output_usages[i]],
2030 *lf_outputs[zone_info_.indices.outputs.input_usages[i + main_inputs_offset]]);
2031 }
2032 for (const int i : IndexRange(num_border_links)) {
2033 static bool static_false = false;
2034 lf_outputs[zone_info_.indices.outputs.border_link_usages[i]]->set_default_value(
2035 &static_false);
2036 }
2037 }
2038
2039 lf_outputs[zone_info_.indices.outputs.input_usages[0]]->set_default_value(&static_true);
2040
2041 /* The graph is ready, update the node indices which are required by the executor. */
2042 lf_graph.update_node_indices();
2043
2044 // std::cout << "\n\n" << lf_graph.to_dot() << "\n\n";
2045
2046 /* Create a mapping from parameter indices inside of this graph to parameters of the repeat
2047 * zone. The main complexity below stems from the fact that the iterations input is handled
2048 * outside of this graph. */
2049 eval_storage.output_index_map.reinitialize(outputs_.size() - 1);
2050 eval_storage.input_index_map.resize(inputs_.size() - 1);
2051 array_utils::fill_index_range<int>(eval_storage.input_index_map, 1);
2052
2053 Vector<const lf::GraphInputSocket *> lf_graph_inputs = lf_inputs.as_span().drop_front(1);
2054
2055 const int iteration_usage_index = zone_info_.indices.outputs.input_usages[0];
2056 array_utils::fill_index_range<int>(
2057 eval_storage.output_index_map.as_mutable_span().take_front(iteration_usage_index));
2058 array_utils::fill_index_range<int>(
2059 eval_storage.output_index_map.as_mutable_span().drop_front(iteration_usage_index),
2060 iteration_usage_index + 1);
2061
2062 Vector<const lf::GraphOutputSocket *> lf_graph_outputs = lf_outputs.as_span().take_front(
2063 iteration_usage_index);
2064 lf_graph_outputs.extend(lf_outputs.as_span().drop_front(iteration_usage_index + 1));
2065
2066 eval_storage.body_execute_wrapper.emplace();
2067 eval_storage.body_execute_wrapper->repeat_output_bnode_ = &repeat_output_bnode_;
2068 eval_storage.body_execute_wrapper->lf_body_nodes_ = &lf_body_nodes;
2069 eval_storage.side_effect_provider.emplace();
2070 eval_storage.side_effect_provider->repeat_output_bnode_ = &repeat_output_bnode_;
2071 eval_storage.side_effect_provider->lf_body_nodes_ = lf_body_nodes;
2072
2073 eval_storage.graph_executor.emplace(lf_graph,
2074 std::move(lf_graph_inputs),
2075 std::move(lf_graph_outputs),
2076 nullptr,
2077 &*eval_storage.side_effect_provider,
2078 &*eval_storage.body_execute_wrapper);
2079 eval_storage.graph_executor_storage = eval_storage.graph_executor->init_storage(
2080 eval_storage.allocator);
2081
2082 /* Log graph for debugging purposes. */
2083 bNodeTree &btree_orig = *reinterpret_cast<bNodeTree *>(
2084 DEG_get_original_id(const_cast<ID *>(&btree_.id)));
2085 if (btree_orig.runtime->logged_zone_graphs) {
2086 std::lock_guard lock{btree_orig.runtime->logged_zone_graphs->mutex};
2087 btree_orig.runtime->logged_zone_graphs->graph_by_zone_id.lookup_or_add_cb(
2088 repeat_output_bnode_.identifier, [&]() { return lf_graph.to_dot(); });
2089 }
2090 }
2091
2092 std::string input_name(const int i) const override
2093 {
2094 return zone_wrapper_input_name(zone_info_, zone_, inputs_, i);
2095 }
2096
2097 std::string output_name(const int i) const override
2098 {
2099 return zone_wrapper_output_name(zone_info_, zone_, outputs_, i);
2100 }
2101};
2102
2103class LazyFunctionForForeachGeometryElementZone;
2104struct ForeachGeometryElementEvalStorage;
2105
2111
2121 std::optional<bke::GeometryFieldContext> field_context;
2122 std::optional<FieldEvaluator> field_evaluator;
2128 std::optional<Array<GeometrySet>> element_geometries;
2132
2134 {
2135 if (this->id.component_type == GeometryComponent::Type::GreasePencil &&
2136 ELEM(this->id.domain, AttrDomain::Point, AttrDomain::Curve))
2137 {
2138 this->field_context.emplace(
2139 *geometry.get_grease_pencil(), this->id.domain, *this->id.layer_index);
2140 }
2141 else {
2142 this->field_context.emplace(*geometry.get_component(this->id.component_type),
2143 this->id.domain);
2144 }
2145 }
2146
2148 {
2149 return *this->field_context->attributes();
2150 }
2151
2153 {
2154 if (this->id.component_type == GeometryComponent::Type::GreasePencil &&
2155 ELEM(this->id.domain, AttrDomain::Point, AttrDomain::Curve))
2156 {
2157 BLI_assert(this->id.layer_index.has_value());
2158 GreasePencil *grease_pencil = geometry.get_grease_pencil_for_write();
2159 const bke::greasepencil::Layer &layer = grease_pencil->layer(*this->id.layer_index);
2160 bke::greasepencil::Drawing *drawing = grease_pencil->get_eval_drawing(layer);
2161 BLI_assert(drawing);
2162 return drawing->strokes_for_write().attributes_for_write();
2163 }
2164 GeometryComponent &component = geometry.get_component_for_write(this->id.component_type);
2165 return *component.attributes_for_write();
2166 }
2167};
2168
2176
2177 public:
2180 ForeachGeometryElementEvalStorage &eval_storage);
2181
2182 void execute_impl(lf::Params &params, const lf::Context &context) const override;
2183
2184 void handle_main_items_and_geometry(lf::Params &params, const lf::Context &context) const;
2185 void handle_generation_items(lf::Params &params, const lf::Context &context) const;
2186 int handle_invalid_generation_items(lf::Params &params) const;
2187 void handle_generation_item_groups(lf::Params &params,
2188 const lf::Context &context,
2189 int first_valid_item_i) const;
2190 void handle_generation_items_group(lf::Params &params,
2191 const lf::Context &context,
2192 int geometry_item_i,
2193 IndexRange generation_items_range) const;
2194 bool handle_generation_items_group_lazyness(lf::Params &params,
2195 const lf::Context &context,
2196 int geometry_item_i,
2197 IndexRange generation_items_range) const;
2198};
2199
2205 public:
2206 const bNode *output_bnode_ = nullptr;
2207 VectorSet<lf::FunctionNode *> *lf_body_nodes_ = nullptr;
2208
2211 const lf::Context &context) const
2212 {
2213 GeoNodesLFUserData &user_data = *static_cast<GeoNodesLFUserData *>(context.user_data);
2214 const int index = lf_body_nodes_->index_of_try(const_cast<lf::FunctionNode *>(&node));
2215 const LazyFunction &fn = node.function();
2216 if (index == -1) {
2217 /* The node is not a loop body node, just execute it normally. */
2218 fn.execute(params, context);
2219 return;
2220 }
2221
2222 /* Setup context for the loop body evaluation. */
2224 user_data.compute_context, *output_bnode_, index};
2225 GeoNodesLFUserData body_user_data = user_data;
2226 body_user_data.compute_context = &body_compute_context;
2228 user_data, body_compute_context.hash());
2229
2230 GeoNodesLFLocalUserData body_local_user_data{body_user_data};
2231 lf::Context body_context{context.storage, &body_user_data, &body_local_user_data};
2232 fn.execute(params, body_context);
2233 }
2234};
2235
2241 public:
2242 const bNode *output_bnode_ = nullptr;
2244
2246 const lf::Context &context) const override
2247 {
2248 GeoNodesLFUserData &user_data = *static_cast<GeoNodesLFUserData *>(context.user_data);
2249 const GeoNodesCallData &call_data = *user_data.call_data;
2250 if (!call_data.side_effect_nodes) {
2251 return {};
2252 }
2253 const ComputeContextHash &context_hash = user_data.compute_context->hash();
2254 const Span<int> iterations_with_side_effects =
2256 {context_hash, output_bnode_->identifier});
2257
2259 for (const int i : iterations_with_side_effects) {
2260 if (i >= 0 && i < lf_body_nodes_.size()) {
2261 lf_nodes.append(lf_body_nodes_[i]);
2262 }
2263 }
2264 return lf_nodes;
2265 }
2266};
2267
2274
2277 std::optional<ForeachGeometryElementZoneSideEffectProvider> side_effect_provider;
2278 std::optional<ForeachGeometryElementNodeExecuteWrapper> body_execute_wrapper;
2279 std::optional<lf::GraphExecutor> graph_executor;
2280 void *graph_executor_storage = nullptr;
2281
2283 std::optional<LazyFunctionForLogicalOr> or_function;
2284 std::optional<LazyFunctionForReduceForeachGeometryElement> reduce_function;
2285
2291
2297 int total_iterations_num = 0;
2298};
2299
2301 private:
2302 const bNodeTree &btree_;
2303 const bNodeTreeZone &zone_;
2304 const bNode &output_bnode_;
2305 const ZoneBuildInfo &zone_info_;
2306 const ZoneBodyFunction &body_fn_;
2307
2308 struct ItemIndices {
2309 /* `outer` refers to sockets on the outside of the zone, and `inner` to the sockets on the
2310 * inside. The `lf` and `bsocket` indices are similar, but the `lf` indices skip unavailable
2311 * and extend sockets. */
2312 IndexRange lf_outer;
2313 IndexRange lf_inner;
2314 IndexRange bsocket_outer;
2315 IndexRange bsocket_inner;
2316 };
2317
2319 struct {
2320 ItemIndices inputs;
2321 ItemIndices main;
2322 ItemIndices generation;
2323 } indices_;
2324
2326
2327 public:
2329 const bNodeTreeZone &zone,
2330 ZoneBuildInfo &zone_info,
2331 const ZoneBodyFunction &body_fn)
2332 : btree_(btree),
2333 zone_(zone),
2334 output_bnode_(*zone.output_node),
2335 zone_info_(zone_info),
2336 body_fn_(body_fn)
2337 {
2338 debug_name_ = "Foreach Geometry Element";
2339
2340 initialize_zone_wrapper(zone, zone_info, body_fn, inputs_, outputs_);
2341 /* All main inputs are always used for now. */
2342 for (const int i : zone_info.indices.inputs.main) {
2343 inputs_[i].usage = lf::ValueUsage::Used;
2344 }
2345
2346 const auto &node_storage = *static_cast<const NodeGeometryForeachGeometryElementOutput *>(
2347 output_bnode_.storage);
2348 const AttrDomain iteration_domain = AttrDomain(node_storage.domain);
2349 BLI_assert(zone_.input_node->output_socket(1).is_available() ==
2350 (iteration_domain != AttrDomain::Corner));
2351
2352 const int input_items_num = node_storage.input_items.items_num;
2353 const int main_items_num = node_storage.main_items.items_num;
2354 const int generation_items_num = node_storage.generation_items.items_num;
2355
2356 indices_.inputs.lf_outer = IndexRange::from_begin_size(2, input_items_num);
2357 indices_.inputs.lf_inner = IndexRange::from_begin_size(
2358 iteration_domain == AttrDomain::Corner ? 1 : 2, input_items_num);
2359 indices_.inputs.bsocket_outer = indices_.inputs.lf_outer;
2360 indices_.inputs.bsocket_inner = indices_.inputs.lf_inner;
2361
2362 indices_.main.lf_outer = IndexRange::from_begin_size(1, main_items_num);
2363 indices_.main.lf_inner = IndexRange::from_begin_size(0, main_items_num);
2364 indices_.main.bsocket_outer = indices_.main.lf_outer;
2365 indices_.main.bsocket_inner = indices_.main.lf_inner;
2366
2367 indices_.generation.lf_outer = IndexRange::from_begin_size(1 + main_items_num,
2368 generation_items_num);
2369 indices_.generation.lf_inner = IndexRange::from_begin_size(main_items_num,
2370 generation_items_num);
2371 indices_.generation.bsocket_outer = IndexRange::from_begin_size(2 + main_items_num,
2372 generation_items_num);
2373 indices_.generation.bsocket_inner = IndexRange::from_begin_size(1 + main_items_num,
2374 generation_items_num);
2375 }
2376
2377 void *init_storage(LinearAllocator<> &allocator) const override
2378 {
2379 return allocator.construct<ForeachGeometryElementEvalStorage>().release();
2380 }
2381
2382 void destruct_storage(void *storage) const override
2383 {
2384 auto *s = static_cast<ForeachGeometryElementEvalStorage *>(storage);
2385 if (s->graph_executor_storage) {
2386 s->graph_executor->destruct_storage(s->graph_executor_storage);
2387 }
2388 std::destroy_at(s);
2389 }
2390
2391 void execute_impl(lf::Params &params, const lf::Context &context) const override
2392 {
2393 const ScopedNodeTimer node_timer{context, output_bnode_};
2394
2395 auto &user_data = *static_cast<GeoNodesLFUserData *>(context.user_data);
2396 auto &local_user_data = *static_cast<GeoNodesLFLocalUserData *>(context.local_user_data);
2397
2398 const auto &node_storage = *static_cast<const NodeGeometryForeachGeometryElementOutput *>(
2399 output_bnode_.storage);
2400 auto &eval_storage = *static_cast<ForeachGeometryElementEvalStorage *>(context.storage);
2401 geo_eval_log::GeoTreeLogger *tree_logger = local_user_data.try_get_tree_logger(user_data);
2402
2403 if (!eval_storage.graph_executor) {
2404 /* Create the execution graph in the first evaluation. */
2405 this->initialize_execution_graph(params, eval_storage, node_storage);
2406
2407 if (tree_logger) {
2408 if (eval_storage.total_iterations_num == 0) {
2409 if (!eval_storage.main_geometry.is_empty()) {
2410 tree_logger->node_warnings.append(
2411 *tree_logger->allocator,
2412 {zone_.input_node->identifier,
2413 {NodeWarningType::Info,
2414 N_("Input geometry has no elements in the iteration domain.")}});
2415 }
2416 }
2417 }
2418 }
2419
2420 lf::Context eval_graph_context{
2421 eval_storage.graph_executor_storage, context.user_data, context.local_user_data};
2422
2423 eval_storage.graph_executor->execute(params, eval_graph_context);
2424 }
2425
2429 const NodeGeometryForeachGeometryElementOutput &node_storage) const
2430 {
2431 eval_storage.main_geometry = params.extract_input<GeometrySet>(
2432 zone_info_.indices.inputs.main[0]);
2433
2434 /* Find all the things we need to iterate over in the input geometry. */
2435 this->prepare_components(params, eval_storage, node_storage);
2436
2437 /* Add interface sockets for the zone graph. Those are the same as for the entire zone, even
2438 * though some of the inputs are not strictly needed anymore. It's easier to avoid another
2439 * level of index remapping though. */
2440 lf::Graph &lf_graph = eval_storage.graph;
2441 Vector<lf::GraphInputSocket *> graph_inputs;
2442 Vector<lf::GraphOutputSocket *> graph_outputs;
2443 for (const int i : inputs_.index_range()) {
2444 const lf::Input &input = inputs_[i];
2445 graph_inputs.append(&lf_graph.add_input(*input.type, this->input_name(i)));
2446 }
2447 for (const int i : outputs_.index_range()) {
2448 const lf::Output &output = outputs_[i];
2449 graph_outputs.append(&lf_graph.add_output(*output.type, this->output_name(i)));
2450 }
2451
2452 /* Add all the nodes and links to the graph. */
2453 this->build_graph_contents(eval_storage, node_storage, graph_inputs, graph_outputs);
2454
2455 eval_storage.side_effect_provider.emplace();
2456 eval_storage.side_effect_provider->output_bnode_ = &output_bnode_;
2457 eval_storage.side_effect_provider->lf_body_nodes_ = eval_storage.lf_body_nodes;
2458
2459 eval_storage.body_execute_wrapper.emplace();
2460 eval_storage.body_execute_wrapper->output_bnode_ = &output_bnode_;
2461 eval_storage.body_execute_wrapper->lf_body_nodes_ = &eval_storage.lf_body_nodes;
2462
2463 lf_graph.update_node_indices();
2464 eval_storage.graph_executor.emplace(lf_graph,
2465 graph_inputs.as_span(),
2466 graph_outputs.as_span(),
2467 nullptr,
2468 &*eval_storage.side_effect_provider,
2469 &*eval_storage.body_execute_wrapper);
2470 eval_storage.graph_executor_storage = eval_storage.graph_executor->init_storage(
2471 eval_storage.allocator);
2472
2473 /* Log graph for debugging purposes. */
2474 bNodeTree &btree_orig = *reinterpret_cast<bNodeTree *>(
2475 DEG_get_original_id(const_cast<ID *>(&btree_.id)));
2476 if (btree_orig.runtime->logged_zone_graphs) {
2477 std::lock_guard lock{btree_orig.runtime->logged_zone_graphs->mutex};
2478 btree_orig.runtime->logged_zone_graphs->graph_by_zone_id.lookup_or_add_cb(
2479 output_bnode_.identifier, [&]() { return lf_graph.to_dot(); });
2480 }
2481 }
2482
2485 const NodeGeometryForeachGeometryElementOutput &node_storage) const
2486 {
2487 const AttrDomain iteration_domain = AttrDomain(node_storage.domain);
2488
2489 /* TODO: Get propagation info from input, but that's not necessary for correctness for now. */
2490 AttributeFilter attribute_filter;
2491
2492 const bNodeSocket &element_geometry_bsocket = zone_.input_node->output_socket(1);
2493 const bool create_element_geometries = element_geometry_bsocket.is_available() &&
2494 element_geometry_bsocket.is_directly_linked();
2495
2496 /* Gather components to process. */
2498 for (const GeometryComponent *src_component : eval_storage.main_geometry.get_components()) {
2499 const GeometryComponent::Type component_type = src_component->type();
2500 if (src_component->type() == GeometryComponent::Type::GreasePencil &&
2501 ELEM(iteration_domain, AttrDomain::Point, AttrDomain::Curve))
2502 {
2503 const GreasePencil &grease_pencil = *eval_storage.main_geometry.get_grease_pencil();
2504 for (const int layer_i : grease_pencil.layers().index_range()) {
2505 const bke::greasepencil::Drawing *drawing = grease_pencil.get_eval_drawing(
2506 grease_pencil.layer(layer_i));
2507 if (drawing == nullptr) {
2508 continue;
2509 }
2510 const bke::CurvesGeometry &curves = drawing->strokes();
2511 if (curves.curves_num() == 0) {
2512 continue;
2513 }
2514 component_ids.append({component_type, iteration_domain, layer_i});
2515 }
2516 }
2517 else {
2518 const int domain_size = src_component->attribute_domain_size(iteration_domain);
2519 if (domain_size > 0) {
2520 component_ids.append({component_type, iteration_domain});
2521 }
2522 }
2523 }
2524
2525 const Field<bool> selection_field = params
2526 .extract_input<SocketValueVariant>(
2527 zone_info_.indices.inputs.main[1])
2528 .extract<Field<bool>>();
2529
2530 /* Evaluate the selection and field inputs for all components. */
2531 int body_nodes_offset = 0;
2532 eval_storage.components.reinitialize(component_ids.size());
2533 for (const int component_i : component_ids.index_range()) {
2534 const ForeachElementComponentID id = component_ids[component_i];
2535 ForeachElementComponent &component_info = eval_storage.components[component_i];
2536 component_info.id = id;
2537 component_info.emplace_field_context(eval_storage.main_geometry);
2538
2539 const int domain_size = component_info.input_attributes().domain_size(id.domain);
2540 BLI_assert(domain_size > 0);
2541
2542 /* Prepare field evaluation for the zone inputs. */
2543 component_info.field_evaluator.emplace(*component_info.field_context, domain_size);
2544 component_info.field_evaluator->set_selection(selection_field);
2545 for (const int item_i : IndexRange(node_storage.input_items.items_num)) {
2546 const GField item_field =
2547 params
2548 .get_input<SocketValueVariant>(
2549 zone_info_.indices.inputs.main[indices_.inputs.lf_outer[item_i]])
2550 .get<GField>();
2551 component_info.field_evaluator->add(item_field);
2552 }
2553
2554 /* Evaluate all fields passed to the zone input. */
2555 component_info.field_evaluator->evaluate();
2556
2557 /* The mask contains all the indices that should be iterated over in the component. */
2558 const IndexMask mask = component_info.field_evaluator->get_evaluated_selection_as_mask();
2559 component_info.body_nodes_range = IndexRange::from_begin_size(body_nodes_offset,
2560 mask.size());
2561 body_nodes_offset += mask.size();
2562
2563 /* Prepare indices that are passed into each iteration. */
2564 component_info.index_values.reinitialize(mask.size());
2565 mask.foreach_index(
2566 [&](const int i, const int pos) { component_info.index_values[pos].set(i); });
2567
2568 if (create_element_geometries) {
2569 component_info.element_geometries = this->try_extract_element_geometries(
2570 eval_storage.main_geometry, id, mask, attribute_filter);
2571 }
2572
2573 /* Prepare remaining inputs that come from the field evaluation.*/
2574 component_info.item_input_values.reinitialize(node_storage.input_items.items_num);
2575 for (const int item_i : IndexRange(node_storage.input_items.items_num)) {
2576 const NodeForeachGeometryElementInputItem &item = node_storage.input_items.items[item_i];
2577 const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
2578 component_info.item_input_values[item_i].reinitialize(mask.size());
2579 const GVArray &values = component_info.field_evaluator->get_evaluated(item_i);
2580 mask.foreach_index(GrainSize(1024), [&](const int i, const int pos) {
2581 SocketValueVariant &value_variant = component_info.item_input_values[item_i][pos];
2582 void *buffer = value_variant.allocate_single(socket_type);
2583 values.get_to_uninitialized(i, buffer);
2584 });
2585 }
2586 }
2587
2588 eval_storage.total_iterations_num = body_nodes_offset;
2589 }
2590
2591 std::optional<Array<GeometrySet>> try_extract_element_geometries(
2592 const GeometrySet &main_geometry,
2593 const ForeachElementComponentID &id,
2594 const IndexMask &mask,
2595 const AttributeFilter &attribute_filter) const
2596 {
2597 switch (id.component_type) {
2598 case GeometryComponent::Type::Mesh: {
2599 const Mesh &main_mesh = *main_geometry.get_mesh();
2600 Array<Mesh *> meshes;
2601 switch (id.domain) {
2602 case AttrDomain::Point: {
2603 meshes = geometry::extract_mesh_vertices(main_mesh, mask, attribute_filter);
2604 break;
2605 }
2606 case AttrDomain::Edge: {
2607 meshes = geometry::extract_mesh_edges(main_mesh, mask, attribute_filter);
2608 break;
2609 }
2610 case AttrDomain::Face: {
2611 meshes = geometry::extract_mesh_faces(main_mesh, mask, attribute_filter);
2612 break;
2613 }
2614 default: {
2615 return std::nullopt;
2616 }
2617 }
2618 Array<GeometrySet> element_geometries(meshes.size());
2619 for (const int i : meshes.index_range()) {
2620 element_geometries[i].replace_mesh(meshes[i]);
2621 }
2622 return element_geometries;
2623 }
2624 case GeometryComponent::Type::PointCloud: {
2625 if (id.domain != AttrDomain::Point) {
2626 return std::nullopt;
2627 }
2628 const PointCloud &main_pointcloud = *main_geometry.get_pointcloud();
2629 Array<PointCloud *> pointclouds = geometry::extract_pointcloud_points(
2630 main_pointcloud, mask, attribute_filter);
2631 Array<GeometrySet> element_geometries(pointclouds.size());
2632 for (const int i : pointclouds.index_range()) {
2633 element_geometries[i].replace_pointcloud(pointclouds[i]);
2634 }
2635 return element_geometries;
2636 }
2637 case GeometryComponent::Type::Curve: {
2638 const Curves &main_curves = *main_geometry.get_curves();
2639 Array<Curves *> element_curves;
2640 switch (id.domain) {
2641 case AttrDomain::Point: {
2642 element_curves = geometry::extract_curves_points(main_curves, mask, attribute_filter);
2643 break;
2644 }
2645 case AttrDomain::Curve: {
2646 element_curves = geometry::extract_curves(main_curves, mask, attribute_filter);
2647 break;
2648 }
2649 default:
2650 return std::nullopt;
2651 }
2652 Array<GeometrySet> element_geometries(element_curves.size());
2653 for (const int i : element_curves.index_range()) {
2654 element_geometries[i].replace_curves(element_curves[i]);
2655 }
2656 return element_geometries;
2657 }
2658 case GeometryComponent::Type::Instance: {
2659 if (id.domain != AttrDomain::Instance) {
2660 return std::nullopt;
2661 }
2662 const bke::Instances &main_instances = *main_geometry.get_instances();
2663 Array<bke::Instances *> element_instances = geometry::extract_instances(
2664 main_instances, mask, attribute_filter);
2665 Array<GeometrySet> element_geometries(element_instances.size());
2666 for (const int i : element_instances.index_range()) {
2667 element_geometries[i].replace_instances(element_instances[i]);
2668 }
2669 return element_geometries;
2670 }
2671 case GeometryComponent::Type::GreasePencil: {
2672 const GreasePencil &main_grease_pencil = *main_geometry.get_grease_pencil();
2673 Array<GreasePencil *> element_grease_pencils;
2674 switch (id.domain) {
2675 case AttrDomain::Layer: {
2676 element_grease_pencils = geometry::extract_greasepencil_layers(
2677 main_grease_pencil, mask, attribute_filter);
2678 break;
2679 }
2680 case AttrDomain::Point: {
2681 element_grease_pencils = geometry::extract_greasepencil_layer_points(
2682 main_grease_pencil, *id.layer_index, mask, attribute_filter);
2683 break;
2684 }
2685 case AttrDomain::Curve: {
2686 element_grease_pencils = geometry::extract_greasepencil_layer_curves(
2687 main_grease_pencil, *id.layer_index, mask, attribute_filter);
2688 break;
2689 }
2690 default:
2691 return std::nullopt;
2692 }
2693 Array<GeometrySet> element_geometries(element_grease_pencils.size());
2694 for (const int i : element_geometries.index_range()) {
2695 element_geometries[i].replace_grease_pencil(element_grease_pencils[i]);
2696 }
2697 return element_geometries;
2698 }
2699 default:
2700 break;
2701 }
2702 return std::nullopt;
2703 }
2704
2706 const NodeGeometryForeachGeometryElementOutput &node_storage,
2707 Span<lf::GraphInputSocket *> graph_inputs,
2708 Span<lf::GraphOutputSocket *> graph_outputs) const
2709 {
2710 lf::Graph &lf_graph = eval_storage.graph;
2711
2712 /* Create body nodes. */
2713 VectorSet<lf::FunctionNode *> &lf_body_nodes = eval_storage.lf_body_nodes;
2714 for ([[maybe_unused]] const int i : IndexRange(eval_storage.total_iterations_num)) {
2715 lf::FunctionNode &lf_node = lf_graph.add_function(*body_fn_.function);
2716 lf_body_nodes.add_new(&lf_node);
2717 }
2718
2719 /* Link up output usages to body nodes. */
2720 for (const int zone_output_i : body_fn_.indices.inputs.output_usages.index_range()) {
2721 /* +1 because of geometry output. */
2722 lf::GraphInputSocket &lf_graph_input =
2723 *graph_inputs[zone_info_.indices.inputs.output_usages[1 + zone_output_i]];
2724 for (const int i : lf_body_nodes.index_range()) {
2725 lf::FunctionNode &lf_node = *lf_body_nodes[i];
2726 lf_graph.add_link(lf_graph_input,
2727 lf_node.input(body_fn_.indices.inputs.output_usages[zone_output_i]));
2728 }
2729 }
2730
2731 const bNodeSocket &element_geometry_bsocket = zone_.input_node->output_socket(1);
2732
2733 static const GeometrySet empty_geometry;
2734 for (const ForeachElementComponent &component_info : eval_storage.components) {
2735 for (const int i : component_info.body_nodes_range.index_range()) {
2736 const int body_i = component_info.body_nodes_range[i];
2737 lf::FunctionNode &lf_body_node = *lf_body_nodes[body_i];
2738 /* Set index input for loop body. */
2739 lf_body_node.input(body_fn_.indices.inputs.main[0])
2740 .set_default_value(&component_info.index_values[i]);
2741 /* Set geometry element input for loop body. */
2742 if (element_geometry_bsocket.is_available()) {
2743 const GeometrySet *element_geometry = component_info.element_geometries.has_value() ?
2744 &(*component_info.element_geometries)[i] :
2745 &empty_geometry;
2746 lf_body_node.input(body_fn_.indices.inputs.main[1]).set_default_value(element_geometry);
2747 }
2748 /* Set main input values for loop body. */
2749 for (const int item_i : IndexRange(node_storage.input_items.items_num)) {
2750 lf_body_node.input(body_fn_.indices.inputs.main[indices_.inputs.lf_inner[item_i]])
2751 .set_default_value(&component_info.item_input_values[item_i][i]);
2752 }
2753 /* Link up border-link inputs to the loop body. */
2754 for (const int border_link_i : zone_info_.indices.inputs.border_links.index_range()) {
2755 lf_graph.add_link(
2756 *graph_inputs[zone_info_.indices.inputs.border_links[border_link_i]],
2757 lf_body_node.input(body_fn_.indices.inputs.border_links[border_link_i]));
2758 }
2759 /* Link up attribute propagation information. */
2760 for (const auto item : body_fn_.indices.inputs.attributes_by_field_source_index.items()) {
2761 lf_graph.add_link(
2762 *graph_inputs[zone_info_.indices.inputs.attributes_by_field_source_index.lookup(
2763 item.key)],
2764 lf_body_node.input(item.value));
2765 }
2766 for (const auto item :
2768 {
2769 lf_graph.add_link(
2771 .lookup(item.key)],
2772 lf_body_node.input(item.value));
2773 }
2774 }
2775 }
2776
2777 /* Add the reduce function that has all outputs from the zone bodies as input. */
2778 eval_storage.reduce_function.emplace(*this, eval_storage);
2779 lf::FunctionNode &lf_reduce = lf_graph.add_function(*eval_storage.reduce_function);
2780
2781 /* Link up body outputs to reduce function. */
2782 const int body_main_outputs_num = node_storage.main_items.items_num +
2783 node_storage.generation_items.items_num;
2784 BLI_assert(body_main_outputs_num == body_fn_.indices.outputs.main.size());
2785 for (const int i : IndexRange(eval_storage.total_iterations_num)) {
2786 lf::FunctionNode &lf_body_node = *lf_body_nodes[i];
2787 for (const int item_i : IndexRange(node_storage.main_items.items_num)) {
2788 lf_graph.add_link(lf_body_node.output(body_fn_.indices.outputs.main[item_i]),
2789 lf_reduce.input(i * body_main_outputs_num + item_i));
2790 }
2791 for (const int item_i : IndexRange(node_storage.generation_items.items_num)) {
2792 const int body_output_i = item_i + node_storage.main_items.items_num;
2793 lf_graph.add_link(lf_body_node.output(body_fn_.indices.outputs.main[body_output_i]),
2794 lf_reduce.input(i * body_main_outputs_num + body_output_i));
2795 }
2796 }
2797
2798 /* Link up reduce function outputs to final zone outputs. */
2799 lf_graph.add_link(lf_reduce.output(0), *graph_outputs[zone_info_.indices.outputs.main[0]]);
2800 for (const int item_i : IndexRange(node_storage.main_items.items_num)) {
2801 const int output_i = indices_.main.lf_outer[item_i];
2802 lf_graph.add_link(lf_reduce.output(output_i),
2803 *graph_outputs[zone_info_.indices.outputs.main[output_i]]);
2804 }
2805 for (const int item_i : IndexRange(node_storage.generation_items.items_num)) {
2806 const int output_i = indices_.generation.lf_outer[item_i];
2807 lf_graph.add_link(lf_reduce.output(output_i),
2808 *graph_outputs[zone_info_.indices.outputs.main[output_i]]);
2809 }
2810
2811 /* All zone inputs are used for now. */
2812 static bool static_true{true};
2813 for (const int i : zone_info_.indices.outputs.input_usages) {
2814 graph_outputs[i]->set_default_value(&static_true);
2815 }
2816
2817 /* Handle usage outputs for border-links. A border-link is used if it's used by any of the
2818 * iterations. */
2819 eval_storage.or_function.emplace(eval_storage.total_iterations_num);
2820 for (const int border_link_i : zone_.border_links.index_range()) {
2821 lf::FunctionNode &lf_or = lf_graph.add_function(*eval_storage.or_function);
2822 for (const int i : lf_body_nodes.index_range()) {
2823 lf::FunctionNode &lf_body_node = *lf_body_nodes[i];
2824 lf_graph.add_link(
2825 lf_body_node.output(body_fn_.indices.outputs.border_link_usages[border_link_i]),
2826 lf_or.input(i));
2827 }
2828 lf_graph.add_link(
2829 lf_or.output(0),
2830 *graph_outputs[zone_info_.indices.outputs.border_link_usages[border_link_i]]);
2831 }
2832 }
2833
2834 std::string input_name(const int i) const override
2835 {
2836 return zone_wrapper_input_name(zone_info_, zone_, inputs_, i);
2837 }
2838
2839 std::string output_name(const int i) const override
2840 {
2841 return zone_wrapper_output_name(zone_info_, zone_, outputs_, i);
2842 }
2843};
2844
2845LazyFunctionForReduceForeachGeometryElement::LazyFunctionForReduceForeachGeometryElement(
2848 : parent_(parent), eval_storage_(eval_storage)
2849{
2850 debug_name_ = "Reduce";
2851
2852 const auto &node_storage = *static_cast<NodeGeometryForeachGeometryElementOutput *>(
2853 parent.output_bnode_.storage);
2854
2855 inputs_.reserve(eval_storage.total_iterations_num *
2856 (node_storage.main_items.items_num + node_storage.generation_items.items_num));
2857
2858 for ([[maybe_unused]] const int i : eval_storage.lf_body_nodes.index_range()) {
2859 /* Add parameters for main items. */
2860 for (const int item_i : IndexRange(node_storage.main_items.items_num)) {
2861 const NodeForeachGeometryElementMainItem &item = node_storage.main_items.items[item_i];
2862 const bNodeSocket &socket = parent.output_bnode_.input_socket(
2863 parent_.indices_.main.bsocket_inner[item_i]);
2864 inputs_.append_as(
2865 item.name, *socket.typeinfo->geometry_nodes_cpp_type, lf::ValueUsage::Used);
2866 }
2867 /* Add parameters for generation items. */
2868 for (const int item_i : IndexRange(node_storage.generation_items.items_num)) {
2870 node_storage.generation_items.items[item_i];
2871 const bNodeSocket &socket = parent.output_bnode_.input_socket(
2872 parent_.indices_.generation.bsocket_inner[item_i]);
2873 inputs_.append_as(
2874 item.name, *socket.typeinfo->geometry_nodes_cpp_type, lf::ValueUsage::Maybe);
2875 }
2876 }
2877
2878 /* Add output for main geometry. */
2879 outputs_.append_as("Geometry", CPPType::get<GeometrySet>());
2880 /* Add outputs for main items. */
2881 for (const int item_i : IndexRange(node_storage.main_items.items_num)) {
2882 const NodeForeachGeometryElementMainItem &item = node_storage.main_items.items[item_i];
2883 const bNodeSocket &socket = parent.output_bnode_.output_socket(
2884 parent_.indices_.main.bsocket_outer[item_i]);
2885 outputs_.append_as(item.name, *socket.typeinfo->geometry_nodes_cpp_type);
2886 }
2887 /* Add outputs for generation items. */
2888 for (const int item_i : IndexRange(node_storage.generation_items.items_num)) {
2890 node_storage.generation_items.items[item_i];
2891 const bNodeSocket &socket = parent.output_bnode_.output_socket(
2892 parent_.indices_.generation.bsocket_outer[item_i]);
2893 outputs_.append_as(item.name, *socket.typeinfo->geometry_nodes_cpp_type);
2894 }
2895}
2896
2899 const GeometryComponent::Type component_type)
2900{
2901 switch (component_type) {
2904 return AttrDomain::Point;
2906 return AttrDomain::Curve;
2908 return AttrDomain::Instance;
2910 return AttrDomain::Layer;
2911 default:
2912 break;
2913 }
2914 return std::nullopt;
2915}
2916
2918 const lf::Context &context) const
2919{
2920 const auto &node_storage = *static_cast<NodeGeometryForeachGeometryElementOutput *>(
2921 parent_.output_bnode_.storage);
2922
2923 this->handle_main_items_and_geometry(params, context);
2924 if (node_storage.generation_items.items_num == 0) {
2925 return;
2926 }
2927 this->handle_generation_items(params, context);
2928}
2929
2931 lf::Params &params, const lf::Context &context) const
2932{
2933 auto &user_data = *static_cast<GeoNodesLFUserData *>(context.user_data);
2934 const auto &node_storage = *static_cast<NodeGeometryForeachGeometryElementOutput *>(
2935 parent_.output_bnode_.storage);
2936 const int body_main_outputs_num = node_storage.main_items.items_num +
2937 node_storage.generation_items.items_num;
2938
2939 const int main_geometry_output = 0;
2940 if (params.output_was_set(main_geometry_output)) {
2941 /* Done already. */
2942 return;
2943 }
2944
2945 GeometrySet output_geometry = eval_storage_.main_geometry;
2946
2947 for (const int item_i : IndexRange(node_storage.main_items.items_num)) {
2948 const NodeForeachGeometryElementMainItem &item = node_storage.main_items.items[item_i];
2949 const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
2950 const CPPType *base_cpp_type = bke::socket_type_to_geo_nodes_base_cpp_type(socket_type);
2951 if (!base_cpp_type) {
2952 continue;
2953 }
2954 const eCustomDataType cd_type = bke::cpp_type_to_custom_data_type(*base_cpp_type);
2955
2956 /* Compute output attribute name for this item. */
2957 const std::string attribute_name = bke::hash_to_anonymous_attribute_name(
2958 user_data.call_data->self_object()->id.name,
2959 user_data.compute_context->hash(),
2960 parent_.output_bnode_.identifier,
2961 item.identifier);
2962
2963 /* Create a new output attribute for the current item on each iteration component. */
2964 for (const ForeachElementComponent &component_info : eval_storage_.components) {
2965 MutableAttributeAccessor attributes = component_info.attributes_for_write(output_geometry);
2966 const int domain_size = attributes.domain_size(component_info.id.domain);
2967 const IndexMask mask = component_info.field_evaluator->get_evaluated_selection_as_mask();
2968
2969 /* Actually create the attribute. */
2970 GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_only_span(
2971 attribute_name, component_info.id.domain, cd_type);
2972
2973 /* Fill the elements of the attribute that we didn't iterate over because they were not
2974 * selected. */
2975 IndexMaskMemory memory;
2976 const IndexMask inverted_mask = mask.complement(IndexRange(domain_size), memory);
2977 base_cpp_type->value_initialize_indices(attribute.span.data(), inverted_mask);
2978
2979 /* Copy the values from each iteration into the attribute. */
2980 mask.foreach_index([&](const int i, const int pos) {
2981 const int lf_param_index = pos * body_main_outputs_num + item_i;
2982 SocketValueVariant &value_variant = params.get_input<SocketValueVariant>(lf_param_index);
2983 value_variant.convert_to_single();
2984 const void *value = value_variant.get_single_ptr_raw();
2985 base_cpp_type->copy_construct(value, attribute.span[i]);
2986 });
2987
2988 attribute.finish();
2989 }
2990
2991 /* Output the field for the anonymous attribute. */
2992 auto attribute_field = std::make_shared<AttributeFieldInput>(
2993 attribute_name,
2994 *base_cpp_type,
2996 parent_.output_bnode_.output_socket(parent_.indices_.main.bsocket_outer[item_i])));
2997 SocketValueVariant attribute_value_variant{GField(std::move(attribute_field))};
2998 params.set_output(1 + item_i, std::move(attribute_value_variant));
2999 }
3000
3001 /* Output the original geometry with potentially additional attributes. */
3002 params.set_output(main_geometry_output, std::move(output_geometry));
3003}
3004
3006 lf::Params &params, const lf::Context &context) const
3007{
3008 const auto &node_storage = *static_cast<NodeGeometryForeachGeometryElementOutput *>(
3009 parent_.output_bnode_.storage);
3010
3011 const int first_valid_item_i = this->handle_invalid_generation_items(params);
3012 if (first_valid_item_i == node_storage.generation_items.items_num) {
3013 return;
3014 }
3015 this->handle_generation_item_groups(params, context, first_valid_item_i);
3016}
3017
3019 lf::Params &params) const
3020{
3021 const auto &node_storage = *static_cast<NodeGeometryForeachGeometryElementOutput *>(
3022 parent_.output_bnode_.storage);
3023
3024 int item_i = 0;
3025 /* Handle invalid generation items that come before a geometry. */
3026 for (; item_i < node_storage.generation_items.items_num; item_i++) {
3028 node_storage.generation_items.items[item_i];
3029 const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
3030 if (socket_type == SOCK_GEOMETRY) {
3031 break;
3032 }
3033 const int lf_socket_i = parent_.indices_.generation.lf_outer[item_i];
3034 if (!params.output_was_set(lf_socket_i)) {
3035 const int bsocket_i = parent_.indices_.generation.bsocket_outer[item_i];
3037 params, lf_socket_i, parent_.zone_.output_node->output_socket(bsocket_i));
3038 }
3039 }
3040 return item_i;
3041}
3042
3044 lf::Params &params, const lf::Context &context, const int first_valid_item_i) const
3045{
3046 const auto &node_storage = *static_cast<NodeGeometryForeachGeometryElementOutput *>(
3047 parent_.output_bnode_.storage);
3048 int previous_geometry_item_i = first_valid_item_i;
3049 /* Iterate over all groups. A group starts with a geometry socket followed by an arbitrary number
3050 * of non-geometry sockets. */
3051 for (const int item_i :
3052 IndexRange::from_begin_end(first_valid_item_i + 1, node_storage.generation_items.items_num))
3053 {
3055 node_storage.generation_items.items[item_i];
3056 const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
3057 if (socket_type == SOCK_GEOMETRY) {
3059 params,
3060 context,
3061 previous_geometry_item_i,
3062 IndexRange::from_begin_end(previous_geometry_item_i + 1, item_i));
3063 previous_geometry_item_i = item_i;
3064 }
3065 }
3067 params,
3068 context,
3069 previous_geometry_item_i,
3070 IndexRange::from_begin_end(previous_geometry_item_i + 1,
3071 node_storage.generation_items.items_num));
3072}
3073
3076 const lf::Context &context,
3077 const int geometry_item_i,
3078 const IndexRange generation_items_range) const
3079{
3080 auto &user_data = *static_cast<GeoNodesLFUserData *>(context.user_data);
3081 const auto &node_storage = *static_cast<NodeGeometryForeachGeometryElementOutput *>(
3082 parent_.output_bnode_.storage);
3083 const int body_main_outputs_num = node_storage.main_items.items_num +
3084 node_storage.generation_items.items_num;
3085
3086 /* Handle the case when the output is not needed or the inputs have not been computed yet. */
3088 params, context, geometry_item_i, generation_items_range))
3089 {
3090 return;
3091 }
3092
3093 /* TODO: Get propagation info from input, but that's not necessary for correctness for now. */
3094 AttributeFilter attribute_filter;
3095
3096 const int bodies_num = eval_storage_.lf_body_nodes.size();
3097 Array<GeometrySet> geometries(bodies_num + 1);
3098
3099 /* Create attribute names for the outputs. */
3100 Array<std::string> attribute_names(generation_items_range.size());
3101 for (const int i : generation_items_range.index_range()) {
3102 const int item_i = generation_items_range[i];
3104 node_storage.generation_items.items[item_i];
3105 attribute_names[i] = bke::hash_to_anonymous_attribute_name(
3106 user_data.call_data->self_object()->id.name,
3107 user_data.compute_context->hash(),
3108 parent_.output_bnode_.identifier,
3109 item.identifier);
3110 }
3111
3112 for (const ForeachElementComponent &component_info : eval_storage_.components) {
3113 const AttributeAccessor src_attributes = component_info.input_attributes();
3114
3115 /* These are the attributes we need to propagate from the original input geometry. */
3116 struct NameWithType {
3117 StringRef name;
3118 eCustomDataType type;
3119 };
3120 Vector<NameWithType> attributes_to_propagate;
3121 src_attributes.foreach_attribute([&](const bke::AttributeIter &iter) {
3122 if (iter.data_type == CD_PROP_STRING) {
3123 return;
3124 }
3125 if (attribute_filter.allow_skip(iter.name)) {
3126 return;
3127 }
3128 attributes_to_propagate.append({iter.name, iter.data_type});
3129 });
3130 Map<StringRef, GVArray> cached_adapted_src_attributes;
3131
3132 const IndexMask mask = component_info.field_evaluator->get_evaluated_selection_as_mask();
3133
3134 /* Add attributes for each field on the geometry created by each iteration. */
3135 mask.foreach_index([&](const int element_i, const int local_body_i) {
3136 const int body_i = component_info.body_nodes_range[local_body_i];
3137 const int geometry_param_i = body_i * body_main_outputs_num +
3138 parent_.indices_.generation.lf_inner[geometry_item_i];
3139 GeometrySet &geometry = geometries[body_i];
3140 geometry = params.extract_input<GeometrySet>(geometry_param_i);
3141
3142 for (const GeometryComponent::Type dst_component_type :
3148 {
3149 if (!geometry.has(dst_component_type)) {
3150 continue;
3151 }
3152 GeometryComponent &dst_component = geometry.get_component_for_write(dst_component_type);
3153 MutableAttributeAccessor dst_attributes = *dst_component.attributes_for_write();
3154
3155 /* Determine the domain that we propagate the input attribute to. Technically, this is only
3156 * a single value for the entire geometry, but we can't optimize for that yet. */
3157 const std::optional<AttrDomain> propagation_domain =
3159 if (!propagation_domain) {
3160 continue;
3161 }
3162
3163 /* Propagate attributes from the input geometry. */
3164 for (const NameWithType &name_with_type : attributes_to_propagate) {
3165 const StringRef name = name_with_type.name;
3166 const eCustomDataType cd_type = name_with_type.type;
3167 if (src_attributes.is_builtin(name) && !dst_attributes.is_builtin(name)) {
3168 continue;
3169 }
3170 if (dst_attributes.contains(name)) {
3171 /* Attributes created in the zone shouldn't be overridden. */
3172 continue;
3173 }
3174 /* Get the source attribute adapted to the iteration domain. */
3175 const GVArray &src_attribute = cached_adapted_src_attributes.lookup_or_add_cb(
3176 name, [&]() {
3177 GAttributeReader attribute = src_attributes.lookup(name);
3178 return src_attributes.adapt_domain(
3179 *attribute, attribute.domain, component_info.id.domain);
3180 });
3181 if (!src_attribute) {
3182 continue;
3183 }
3184 const CPPType &type = src_attribute.type();
3185 BUFFER_FOR_CPP_TYPE_VALUE(type, element_value);
3186 src_attribute.get_to_uninitialized(element_i, element_value);
3187
3188 /* Actually create the attribute. */
3189 GSpanAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write_only_span(
3190 name, *propagation_domain, cd_type);
3191 type.fill_assign_n(element_value, dst_attribute.span.data(), dst_attribute.span.size());
3192 dst_attribute.finish();
3193
3194 type.destruct(element_value);
3195 }
3196 }
3197
3198 /* Create an attribute for each field that corresponds to the current geometry. */
3199 for (const int local_item_i : generation_items_range.index_range()) {
3200 const int item_i = generation_items_range[local_item_i];
3202 node_storage.generation_items.items[item_i];
3203 const AttrDomain capture_domain = AttrDomain(item.domain);
3204 const int field_param_i = body_i * body_main_outputs_num +
3205 parent_.indices_.generation.lf_inner[item_i];
3206 GField field = params.get_input<SocketValueVariant>(field_param_i).get<GField>();
3207
3208 if (capture_domain == AttrDomain::Instance) {
3209 if (geometry.has_instances()) {
3211 geometry.get_component_for_write(GeometryComponent::Type::Instance),
3212 attribute_names[local_item_i],
3213 capture_domain,
3214 field);
3215 }
3216 }
3217 else {
3218 geometry.modify_geometry_sets([&](GeometrySet &sub_geometry) {
3219 for (const GeometryComponent::Type component_type :
3224 {
3225 if (sub_geometry.has(component_type)) {
3227 sub_geometry.get_component_for_write(component_type),
3228 attribute_names[local_item_i],
3229 capture_domain,
3230 field);
3231 }
3232 }
3233 });
3234 }
3235 }
3236 });
3237 }
3238
3239 /* The last geometry contains the edit data from the main geometry. */
3240 GeometrySet &edit_data_geometry = geometries.last();
3241 edit_data_geometry = eval_storage_.main_geometry;
3242 edit_data_geometry.keep_only({GeometryComponent::Type::Edit});
3243
3244 /* Join the geometries from all iterations into a single one. */
3245 GeometrySet joined_geometry = geometry::join_geometries(geometries, attribute_filter);
3246
3247 /* Output the joined geometry. */
3248 params.set_output(parent_.indices_.generation.lf_outer[geometry_item_i],
3249 std::move(joined_geometry));
3250
3251 /* Output the anonymous attribute fields. */
3252 for (const int local_item_i : generation_items_range.index_range()) {
3253 const int item_i = generation_items_range[local_item_i];
3255 node_storage.generation_items.items[item_i];
3256 const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
3257 const CPPType &base_cpp_type = *bke::socket_type_to_geo_nodes_base_cpp_type(socket_type);
3258 const StringRef attribute_name = attribute_names[local_item_i];
3259 auto attribute_field = std::make_shared<AttributeFieldInput>(
3260 attribute_name,
3261 base_cpp_type,
3263 parent_.output_bnode_.output_socket(2 + node_storage.main_items.items_num + item_i)));
3264 SocketValueVariant attribute_value_variant{GField(std::move(attribute_field))};
3265 params.set_output(parent_.indices_.generation.lf_outer[item_i],
3266 std::move(attribute_value_variant));
3267 }
3268}
3269
3272 const lf::Context & /*context*/,
3273 const int geometry_item_i,
3274 const IndexRange generation_items_range) const
3275{
3276 const auto &node_storage = *static_cast<NodeGeometryForeachGeometryElementOutput *>(
3277 parent_.output_bnode_.storage);
3278 const int body_main_outputs_num = node_storage.main_items.items_num +
3279 node_storage.generation_items.items_num;
3280
3281 const int geometry_output_param = parent_.indices_.generation.lf_outer[geometry_item_i];
3282
3283 if (params.output_was_set(geometry_output_param)) {
3284 /* Done already. */
3285 return false;
3286 }
3287 const lf::ValueUsage geometry_output_usage = params.get_output_usage(geometry_output_param);
3288 if (geometry_output_usage == lf::ValueUsage::Unused) {
3289 /* Output dummy values. */
3290 const int start_bsocket_i = parent_.indices_.generation.bsocket_outer[geometry_item_i];
3291 for (const int i : IndexRange(1 + generation_items_range.size())) {
3292 const bNodeSocket &bsocket = parent_.output_bnode_.output_socket(start_bsocket_i + i);
3293 set_default_value_for_output_socket(params, geometry_output_param + i, bsocket);
3294 }
3295 return false;
3296 }
3297 bool any_output_used = false;
3298 for (const int i : IndexRange(1 + generation_items_range.size())) {
3299 const lf::ValueUsage usage = params.get_output_usage(geometry_output_param + i);
3300 if (usage == lf::ValueUsage::Used) {
3301 any_output_used = true;
3302 break;
3303 }
3304 }
3305 if (!any_output_used) {
3306 /* Only execute below if we are sure that the output is actually needed. */
3307 return false;
3308 }
3309 const int bodies_num = eval_storage_.lf_body_nodes.size();
3310
3311 /* Check if all inputs are available, and request them if not. */
3312 bool has_missing_input = false;
3313 for (const int body_i : IndexRange(bodies_num)) {
3314 const int offset = body_i * body_main_outputs_num +
3315 parent_.indices_.generation.lf_inner[geometry_item_i];
3316 for (const int i : IndexRange(1 + generation_items_range.size())) {
3317 const bool is_available = params.try_get_input_data_ptr_or_request(offset + i) != nullptr;
3318 if (!is_available) {
3319 has_missing_input = true;
3320 }
3321 }
3322 }
3323 if (has_missing_input) {
3324 /* Come back when all inputs are available. */
3325 return false;
3326 }
3327 return true;
3328}
3329
3334class GeometryNodesLazyFunctionLogger : public lf::GraphExecutor::Logger {
3335 private:
3336 const GeometryNodesLazyFunctionGraphInfo &lf_graph_info_;
3337
3338 public:
3340 : lf_graph_info_(lf_graph_info)
3341 {
3342 }
3343
3344 void log_socket_value(const lf::Socket &lf_socket,
3345 const GPointer value,
3346 const lf::Context &context) const override
3347 {
3348 auto &user_data = *static_cast<GeoNodesLFUserData *>(context.user_data);
3349 if (!user_data.log_socket_values) {
3350 return;
3351 }
3352 auto &local_user_data = *static_cast<GeoNodesLFLocalUserData *>(context.local_user_data);
3353 geo_eval_log::GeoTreeLogger *tree_logger = local_user_data.try_get_tree_logger(user_data);
3354 if (tree_logger == nullptr) {
3355 return;
3356 }
3357
3358 const Span<const bNodeSocket *> bsockets =
3359 lf_graph_info_.mapping.bsockets_by_lf_socket_map.lookup(&lf_socket);
3360 if (bsockets.is_empty()) {
3361 return;
3362 }
3363
3364 for (const bNodeSocket *bsocket : bsockets) {
3365 /* Avoid logging to some sockets when the same value will also be logged to a linked socket.
3366 * This reduces the number of logged values without losing information. */
3367 if (bsocket->is_input() && bsocket->is_directly_linked()) {
3368 continue;
3369 }
3370 const bNode &bnode = bsocket->owner_node();
3371 if (bnode.is_reroute()) {
3372 continue;
3373 }
3374 tree_logger->log_value(bsocket->owner_node(), *bsocket, value);
3375 }
3376 }
3377
3378 static inline std::mutex dump_error_context_mutex;
3379
3381 Span<const lf::OutputSocket *> missing_sockets,
3382 const lf::Context &context) const override
3383 {
3384 std::lock_guard lock{dump_error_context_mutex};
3385
3386 GeoNodesLFUserData *user_data = dynamic_cast<GeoNodesLFUserData *>(context.user_data);
3387 BLI_assert(user_data != nullptr);
3388 user_data->compute_context->print_stack(std::cout, node.name());
3389 std::cout << "Missing outputs:\n";
3390 for (const lf::OutputSocket *socket : missing_sockets) {
3391 std::cout << " " << socket->name() << "\n";
3392 }
3393 }
3394
3396 const lf::OutputSocket &from_socket,
3397 const lf::Context &context) const override
3398 {
3399 std::lock_guard lock{dump_error_context_mutex};
3400
3401 std::stringstream ss;
3402 ss << from_socket.node().name() << ":" << from_socket.name() << " -> "
3403 << target_socket.node().name() << ":" << target_socket.name();
3404
3405 GeoNodesLFUserData *user_data = dynamic_cast<GeoNodesLFUserData *>(context.user_data);
3406 BLI_assert(user_data != nullptr);
3407 user_data->compute_context->print_stack(std::cout, ss.str());
3408 }
3409
3411 const lf::Params & /*params*/,
3412 const lf::Context &context) const override
3413 {
3414 /* Enable this to see the threads that invoked a node. */
3415 if constexpr (false) {
3416 this->add_thread_id_debug_message(node, context);
3417 }
3418 }
3419
3420 void add_thread_id_debug_message(const lf::FunctionNode &node, const lf::Context &context) const
3421 {
3422 static std::atomic<int> thread_id_source = 0;
3423 static thread_local const int thread_id = thread_id_source.fetch_add(1);
3424 static thread_local const std::string thread_id_str = "Thread: " + std::to_string(thread_id);
3425
3426 const auto &user_data = *static_cast<GeoNodesLFUserData *>(context.user_data);
3427 const auto &local_user_data = *static_cast<GeoNodesLFLocalUserData *>(context.local_user_data);
3428 geo_eval_log::GeoTreeLogger *tree_logger = local_user_data.try_get_tree_logger(user_data);
3429 if (tree_logger == nullptr) {
3430 return;
3431 }
3432
3433 /* Find corresponding node based on the socket mapping. */
3434 auto check_sockets = [&](const Span<const lf::Socket *> lf_sockets) {
3435 for (const lf::Socket *lf_socket : lf_sockets) {
3436 const Span<const bNodeSocket *> bsockets =
3437 lf_graph_info_.mapping.bsockets_by_lf_socket_map.lookup(lf_socket);
3438 if (!bsockets.is_empty()) {
3439 const bNodeSocket &bsocket = *bsockets[0];
3440 const bNode &bnode = bsocket.owner_node();
3441 tree_logger->debug_messages.append(*tree_logger->allocator,
3442 {bnode.identifier, thread_id_str});
3443 return true;
3444 }
3445 }
3446 return false;
3447 };
3448
3449 if (check_sockets(node.inputs().cast<const lf::Socket *>())) {
3450 return;
3451 }
3452 check_sockets(node.outputs().cast<const lf::Socket *>());
3453 }
3454};
3455
3461class GeometryNodesLazyFunctionSideEffectProvider : public lf::GraphExecutor::SideEffectProvider {
3462 private:
3463 Span<const lf::FunctionNode *> local_side_effect_nodes_;
3464
3465 public:
3467 Span<const lf::FunctionNode *> local_side_effect_nodes = {})
3468 : local_side_effect_nodes_(local_side_effect_nodes)
3469 {
3470 }
3471
3473 const lf::Context &context) const override
3474 {
3475 GeoNodesLFUserData *user_data = dynamic_cast<GeoNodesLFUserData *>(context.user_data);
3476 BLI_assert(user_data != nullptr);
3477 const GeoNodesCallData &call_data = *user_data->call_data;
3478 if (!call_data.side_effect_nodes) {
3479 return {};
3480 }
3481 const ComputeContextHash &context_hash = user_data->compute_context->hash();
3482 Vector<const lf::FunctionNode *> side_effect_nodes =
3483 call_data.side_effect_nodes->nodes_by_context.lookup(context_hash);
3484 side_effect_nodes.extend(local_side_effect_nodes_);
3485 return side_effect_nodes;
3486 }
3487};
3488
3495 private:
3496 const bNodeTree &btree_;
3497 const aai::AnonymousAttributeInferencingResult &attribute_inferencing_;
3498 ResourceScope &scope_;
3499 NodeMultiFunctions &node_multi_functions_;
3500 GeometryNodesLazyFunctionGraphInfo *lf_graph_info_;
3502 const bke::DataTypeConversions *conversions_;
3503
3507 Map<const bNode *, lf::Node *> simulation_inputs_usage_nodes_;
3508
3509 const bNodeTreeZones *tree_zones_;
3510 MutableSpan<ZoneBuildInfo> zone_build_infos_;
3511
3512 std::optional<BuildGraphParams> root_graph_build_params_;
3513
3518 Vector<const lf::GraphInputSocket *> group_input_sockets_;
3523 Vector<const lf::GraphOutputSocket *> standard_group_output_sockets_;
3528 Vector<lf::GraphInputSocket *> group_output_used_sockets_;
3533 Vector<const lf::GraphOutputSocket *> group_input_usage_sockets_;
3538 Map<int, const lf::GraphInputSocket *> attribute_set_by_geometry_output_;
3539
3541
3542 public:
3545 : btree_(btree),
3546 attribute_inferencing_(*btree.runtime->anonymous_attribute_inferencing),
3547 scope_(lf_graph_info.scope),
3548 node_multi_functions_(lf_graph_info.scope.construct<NodeMultiFunctions>(btree)),
3549 lf_graph_info_(&lf_graph_info)
3550 {
3551 }
3552
3553 void build()
3554 {
3555 btree_.ensure_topology_cache();
3556 btree_.ensure_interface_cache();
3557
3558 mapping_ = &lf_graph_info_->mapping;
3559 conversions_ = &bke::get_implicit_type_conversions();
3560 tree_zones_ = btree_.zones();
3561
3562 this->initialize_mapping_arrays();
3563 this->build_zone_functions();
3564 this->build_root_graph();
3565 this->build_geometry_nodes_group_function();
3566 }
3567
3568 private:
3569 void initialize_mapping_arrays()
3570 {
3572 btree_.all_output_sockets().size());
3575 btree_.all_output_sockets().size());
3577 mapping_->lf_index_by_bsocket.reinitialize(btree_.all_sockets().size());
3578 mapping_->lf_index_by_bsocket.fill(-1);
3579 }
3580
3584 void build_zone_functions()
3585 {
3586 zone_build_infos_ = scope_.construct<Array<ZoneBuildInfo>>(tree_zones_->zones.size());
3587
3588 const Array<int> zone_build_order = this->compute_zone_build_order();
3589
3590 for (const int zone_i : zone_build_order) {
3591 const bNodeTreeZone &zone = *tree_zones_->zones[zone_i];
3592 switch (zone.output_node->type) {
3594 this->build_simulation_zone_function(zone);
3595 break;
3596 }
3598 this->build_repeat_zone_function(zone);
3599 break;
3600 }
3602 this->build_foreach_geometry_element_zone_function(zone);
3603 break;
3604 default: {
3606 break;
3607 }
3608 }
3609 }
3610 }
3611
3612 Array<int> compute_zone_build_order()
3613 {
3614 /* Build nested zones first. */
3615 Array<int> zone_build_order(tree_zones_->zones.size());
3616 array_utils::fill_index_range<int>(zone_build_order);
3617 std::sort(
3618 zone_build_order.begin(), zone_build_order.end(), [&](const int zone_a, const int zone_b) {
3619 return tree_zones_->zones[zone_a]->depth > tree_zones_->zones[zone_b]->depth;
3620 });
3621 return zone_build_order;
3622 }
3623
3628 void build_simulation_zone_function(const bNodeTreeZone &zone)
3629 {
3630 const int zone_i = zone.index;
3631 ZoneBuildInfo &zone_info = zone_build_infos_[zone_i];
3632 lf::Graph &lf_graph = scope_.construct<lf::Graph>();
3633 const auto &sim_output_storage = *static_cast<const NodeGeometrySimulationOutput *>(
3634 zone.output_node->storage);
3635
3636 Vector<lf::GraphInputSocket *> lf_zone_inputs;
3637 Vector<lf::GraphOutputSocket *> lf_zone_outputs;
3638
3639 if (zone.input_node != nullptr) {
3640 for (const bNodeSocket *bsocket : zone.input_node->input_sockets().drop_back(1)) {
3641 zone_info.indices.inputs.main.append(lf_zone_inputs.append_and_get_index(
3642 &lf_graph.add_input(*bsocket->typeinfo->geometry_nodes_cpp_type, bsocket->name)));
3643 zone_info.indices.outputs.input_usages.append(lf_zone_outputs.append_and_get_index(
3644 &lf_graph.add_output(CPPType::get<bool>(), "Usage: " + StringRef(bsocket->name))));
3645 }
3646 }
3647
3648 this->build_zone_border_links_inputs(
3649 zone, lf_graph, lf_zone_inputs, zone_info.indices.inputs.border_links);
3650 this->build_zone_border_link_input_usages(
3651 zone, lf_graph, lf_zone_outputs, zone_info.indices.outputs.border_link_usages);
3652
3653 for (const bNodeSocket *bsocket : zone.output_node->output_sockets().drop_back(1)) {
3654 zone_info.indices.outputs.main.append(lf_zone_outputs.append_and_get_index(
3655 &lf_graph.add_output(*bsocket->typeinfo->geometry_nodes_cpp_type, bsocket->name)));
3656 zone_info.indices.inputs.output_usages.append(lf_zone_inputs.append_and_get_index(
3657 &lf_graph.add_input(CPPType::get<bool>(), "Usage: " + StringRef(bsocket->name))));
3658 }
3659
3660 lf::Node &lf_simulation_usage_node = [&]() -> lf::Node & {
3661 auto &lazy_function = scope_.construct<LazyFunctionForSimulationInputsUsage>(
3662 *zone.output_node);
3663 lf::Node &lf_node = lf_graph.add_function(lazy_function);
3664
3665 for (const int i : zone_info.indices.outputs.input_usages) {
3666 lf_graph.add_link(lf_node.output(0), *lf_zone_outputs[i]);
3667 }
3668
3669 return lf_node;
3670 }();
3671
3672 BuildGraphParams graph_params{lf_graph};
3673
3674 lf::FunctionNode *lf_simulation_input = nullptr;
3675 if (zone.input_node) {
3676 lf_simulation_input = this->insert_simulation_input_node(
3677 btree_, *zone.input_node, graph_params);
3678 }
3679 lf::FunctionNode &lf_simulation_output = this->insert_simulation_output_node(*zone.output_node,
3680 graph_params);
3681
3682 for (const bNodeSocket *bsocket : zone.output_node->input_sockets().drop_back(1)) {
3683 graph_params.usage_by_bsocket.add(bsocket, &lf_simulation_usage_node.output(1));
3684 }
3685
3686 /* Link simulation input node directly to simulation output node for skip behavior. */
3687 for (const int i : IndexRange(sim_output_storage.items_num)) {
3688 lf::InputSocket &lf_to = lf_simulation_output.input(i + 1);
3689 if (lf_simulation_input) {
3690 lf::OutputSocket &lf_from = lf_simulation_input->output(i + 1);
3691 lf_graph.add_link(lf_from, lf_to);
3692 }
3693 else {
3694 lf_to.set_default_value(lf_to.type().default_value());
3695 }
3696 }
3697
3698 this->insert_nodes_and_zones(zone.child_nodes, zone.child_zones, graph_params);
3699
3700 if (zone.input_node) {
3701 this->build_output_socket_usages(*zone.input_node, graph_params);
3702 }
3703 for (const auto item : graph_params.lf_output_by_bsocket.items()) {
3704 this->insert_links_from_socket(*item.key, *item.value, graph_params);
3705 }
3706
3707 this->link_border_link_inputs_and_usages(zone,
3708 lf_zone_inputs,
3709 zone_info.indices.inputs.border_links,
3710 lf_zone_outputs,
3711 zone_info.indices.outputs.border_link_usages,
3712 graph_params);
3713
3714 for (const int i : zone_info.indices.inputs.main) {
3715 lf_graph.add_link(*lf_zone_inputs[i], lf_simulation_input->input(i));
3716 }
3717
3718 for (const int i : zone_info.indices.outputs.main.index_range()) {
3719 lf_graph.add_link(lf_simulation_output.output(i),
3720 *lf_zone_outputs[zone_info.indices.outputs.main[i]]);
3721 }
3722
3723 this->add_default_inputs(graph_params);
3724
3725 Map<int, lf::OutputSocket *> lf_attribute_set_by_field_source_index;
3726 Map<int, lf::OutputSocket *> lf_attribute_set_by_caller_propagation_index;
3727 this->build_attribute_set_inputs_for_zone(graph_params,
3728 lf_attribute_set_by_field_source_index,
3729 lf_attribute_set_by_caller_propagation_index);
3730 for (const auto item : lf_attribute_set_by_field_source_index.items()) {
3731 lf::OutputSocket &lf_attribute_set_socket = *item.value;
3732 if (lf_attribute_set_socket.node().is_interface()) {
3733 zone_info.indices.inputs.attributes_by_field_source_index.add_new(
3734 item.key, lf_zone_inputs.append_and_get_index(&lf_attribute_set_socket));
3735 }
3736 }
3737 for (const auto item : lf_attribute_set_by_caller_propagation_index.items()) {
3738 lf::OutputSocket &lf_attribute_set_socket = *item.value;
3739 if (lf_attribute_set_socket.node().is_interface()) {
3740 zone_info.indices.inputs.attributes_by_caller_propagation_index.add_new(
3741 item.key, lf_zone_inputs.append_and_get_index(&lf_attribute_set_socket));
3742 }
3743 }
3744 this->link_attribute_set_inputs(lf_graph,
3745 graph_params,
3746 lf_attribute_set_by_field_source_index,
3747 lf_attribute_set_by_caller_propagation_index);
3748 this->fix_link_cycles(lf_graph, graph_params.socket_usage_inputs);
3749
3750 lf_graph.update_node_indices();
3751
3752 auto &logger = scope_.construct<GeometryNodesLazyFunctionLogger>(*lf_graph_info_);
3753 auto &side_effect_provider = scope_.construct<GeometryNodesLazyFunctionSideEffectProvider>();
3754
3755 const auto &lf_graph_fn = scope_.construct<lf::GraphExecutor>(lf_graph,
3756 lf_zone_inputs.as_span(),
3757 lf_zone_outputs.as_span(),
3758 &logger,
3759 &side_effect_provider,
3760 nullptr);
3761 const auto &zone_function = scope_.construct<LazyFunctionForSimulationZone>(*zone.output_node,
3762 lf_graph_fn);
3763 zone_info.lazy_function = &zone_function;
3764
3765 lf_graph_info_->debug_zone_body_graphs.add(zone.output_node->identifier, &lf_graph);
3766 // std::cout << "\n\n" << lf_graph.to_dot() << "\n\n";
3767 }
3768
3772 void build_repeat_zone_function(const bNodeTreeZone &zone)
3773 {
3774 ZoneBuildInfo &zone_info = zone_build_infos_[zone.index];
3775 /* Build a function for the loop body. */
3776 ZoneBodyFunction &body_fn = this->build_zone_body_function(zone, "Repeat Body");
3777 /* Wrap the loop body by another function that implements the repeat behavior. */
3778 auto &zone_fn = scope_.construct<LazyFunctionForRepeatZone>(btree_, zone, zone_info, body_fn);
3779 zone_info.lazy_function = &zone_fn;
3780 }
3781
3782 void build_foreach_geometry_element_zone_function(const bNodeTreeZone &zone)
3783 {
3784 ZoneBuildInfo &zone_info = zone_build_infos_[zone.index];
3785 /* Build a function for the loop body. */
3786 ZoneBodyFunction &body_fn = this->build_zone_body_function(zone, "Foreach Body");
3787 /* Wrap the loop body in another function that implements the foreach behavior. */
3788 auto &zone_fn = scope_.construct<LazyFunctionForForeachGeometryElementZone>(
3789 btree_, zone, zone_info, body_fn);
3790 zone_info.lazy_function = &zone_fn;
3791 }
3792
3796 ZoneBodyFunction &build_zone_body_function(const bNodeTreeZone &zone, const StringRef name)
3797 {
3798 lf::Graph &lf_body_graph = scope_.construct<lf::Graph>(name);
3799
3800 BuildGraphParams graph_params{lf_body_graph};
3801
3802 Vector<lf::GraphInputSocket *> lf_body_inputs;
3803 Vector<lf::GraphOutputSocket *> lf_body_outputs;
3804 ZoneBodyFunction &body_fn = scope_.construct<ZoneBodyFunction>();
3805
3806 for (const bNodeSocket *bsocket : zone.input_node->output_sockets()) {
3807 if (ignore_zone_bsocket(*bsocket)) {
3808 continue;
3809 }
3810 lf::GraphInputSocket &lf_input = lf_body_graph.add_input(
3811 *bsocket->typeinfo->geometry_nodes_cpp_type, bsocket->name);
3812 lf::GraphOutputSocket &lf_input_usage = lf_body_graph.add_output(
3813 CPPType::get<bool>(), "Usage: " + StringRef(bsocket->name));
3814 body_fn.indices.inputs.main.append(lf_body_inputs.append_and_get_index(&lf_input));
3815 body_fn.indices.outputs.input_usages.append(
3816 lf_body_outputs.append_and_get_index(&lf_input_usage));
3817 graph_params.lf_output_by_bsocket.add_new(bsocket, &lf_input);
3818 }
3819
3820 this->build_zone_border_links_inputs(
3821 zone, lf_body_graph, lf_body_inputs, body_fn.indices.inputs.border_links);
3822 this->build_zone_border_link_input_usages(
3823 zone, lf_body_graph, lf_body_outputs, body_fn.indices.outputs.border_link_usages);
3824
3825 for (const bNodeSocket *bsocket : zone.output_node->input_sockets()) {
3826 if (ignore_zone_bsocket(*bsocket)) {
3827 continue;
3828 }
3829 lf::GraphOutputSocket &lf_output = lf_body_graph.add_output(
3830 *bsocket->typeinfo->geometry_nodes_cpp_type, bsocket->name);
3831 lf::GraphInputSocket &lf_output_usage = lf_body_graph.add_input(
3832 CPPType::get<bool>(), "Usage: " + StringRef(bsocket->name));
3833 graph_params.lf_inputs_by_bsocket.add(bsocket, &lf_output);
3834 graph_params.usage_by_bsocket.add(bsocket, &lf_output_usage);
3835 body_fn.indices.outputs.main.append(lf_body_outputs.append_and_get_index(&lf_output));
3836 body_fn.indices.inputs.output_usages.append(
3837 lf_body_inputs.append_and_get_index(&lf_output_usage));
3838 }
3839
3840 this->insert_nodes_and_zones(zone.child_nodes, zone.child_zones, graph_params);
3841
3842 this->build_output_socket_usages(*zone.input_node, graph_params);
3843
3844 {
3845 int valid_socket_i = 0;
3846 for (const bNodeSocket *bsocket : zone.input_node->output_sockets()) {
3847 if (ignore_zone_bsocket(*bsocket)) {
3848 continue;
3849 }
3850 lf::OutputSocket *lf_usage = graph_params.usage_by_bsocket.lookup_default(bsocket,
3851 nullptr);
3852 lf::GraphOutputSocket &lf_usage_output =
3853 *lf_body_outputs[body_fn.indices.outputs.input_usages[valid_socket_i]];
3854 if (lf_usage) {
3855 lf_body_graph.add_link(*lf_usage, lf_usage_output);
3856 }
3857 else {
3858 static const bool static_false = false;
3859 lf_usage_output.set_default_value(&static_false);
3860 }
3861 valid_socket_i++;
3862 }
3863 }
3864
3865 for (const auto item : graph_params.lf_output_by_bsocket.items()) {
3866 this->insert_links_from_socket(*item.key, *item.value, graph_params);
3867 }
3868
3869 this->link_border_link_inputs_and_usages(zone,
3870 lf_body_inputs,
3871 body_fn.indices.inputs.border_links,
3872 lf_body_outputs,
3873 body_fn.indices.outputs.border_link_usages,
3874 graph_params);
3875
3876 this->add_default_inputs(graph_params);
3877
3878 Map<int, lf::OutputSocket *> lf_attribute_set_by_field_source_index;
3879 Map<int, lf::OutputSocket *> lf_attribute_set_by_caller_propagation_index;
3880
3881 this->build_attribute_set_inputs_for_zone(graph_params,
3882 lf_attribute_set_by_field_source_index,
3883 lf_attribute_set_by_caller_propagation_index);
3884 for (const auto item : lf_attribute_set_by_field_source_index.items()) {
3885 lf::OutputSocket &lf_attribute_set_socket = *item.value;
3886 if (lf_attribute_set_socket.node().is_interface()) {
3887 body_fn.indices.inputs.attributes_by_field_source_index.add_new(
3888 item.key, lf_body_inputs.append_and_get_index(&lf_attribute_set_socket));
3889 }
3890 }
3891 for (const auto item : lf_attribute_set_by_caller_propagation_index.items()) {
3892 lf::OutputSocket &lf_attribute_set_socket = *item.value;
3893 if (lf_attribute_set_socket.node().is_interface()) {
3894 body_fn.indices.inputs.attributes_by_caller_propagation_index.add_new(
3895 item.key, lf_body_inputs.append_and_get_index(&lf_attribute_set_socket));
3896 }
3897 }
3898 this->link_attribute_set_inputs(lf_body_graph,
3899 graph_params,
3900 lf_attribute_set_by_field_source_index,
3901 lf_attribute_set_by_caller_propagation_index);
3902 this->fix_link_cycles(lf_body_graph, graph_params.socket_usage_inputs);
3903
3904 lf_body_graph.update_node_indices();
3905
3906 auto &logger = scope_.construct<GeometryNodesLazyFunctionLogger>(*lf_graph_info_);
3907 auto &side_effect_provider = scope_.construct<GeometryNodesLazyFunctionSideEffectProvider>();
3908
3909 body_fn.function = &scope_.construct<lf::GraphExecutor>(lf_body_graph,
3910 lf_body_inputs.as_span(),
3911 lf_body_outputs.as_span(),
3912 &logger,
3913 &side_effect_provider,
3914 nullptr);
3915
3916 lf_graph_info_->debug_zone_body_graphs.add(zone.output_node->identifier, &lf_body_graph);
3917
3918 // std::cout << "\n\n" << lf_body_graph.to_dot() << "\n\n";
3919
3920 return body_fn;
3921 }
3922
3923 void build_zone_border_links_inputs(const bNodeTreeZone &zone,
3924 lf::Graph &lf_graph,
3925 Vector<lf::GraphInputSocket *> &r_lf_graph_inputs,
3926 Vector<int> &r_indices)
3927 {
3928 for (const bNodeLink *border_link : zone.border_links) {
3929 r_indices.append(r_lf_graph_inputs.append_and_get_index(
3930 &lf_graph.add_input(*border_link->tosock->typeinfo->geometry_nodes_cpp_type,
3931 StringRef("Link from ") + border_link->fromsock->name)));
3932 }
3933 }
3934
3935 void build_zone_border_link_input_usages(const bNodeTreeZone &zone,
3936 lf::Graph &lf_graph,
3937 Vector<lf::GraphOutputSocket *> &r_lf_graph_outputs,
3938 Vector<int> &r_indices)
3939 {
3940 for (const bNodeLink *border_link : zone.border_links) {
3941 r_indices.append(r_lf_graph_outputs.append_and_get_index(&lf_graph.add_output(
3942 CPPType::get<bool>(), StringRef("Usage: Link from ") + border_link->fromsock->name)));
3943 }
3944 }
3945
3946 void build_attribute_set_inputs_for_zone(
3947 BuildGraphParams &graph_params,
3948 Map<int, lf::OutputSocket *> &lf_attribute_set_by_field_source_index,
3949 Map<int, lf::OutputSocket *> &lf_attribute_set_by_caller_propagation_index)
3950 {
3951 const Vector<int> all_required_field_sources = this->find_all_required_field_source_indices(
3952 graph_params.lf_attribute_set_input_by_output_geometry_bsocket,
3953 graph_params.lf_attribute_set_input_by_field_source_index);
3954 const Vector<int> all_required_caller_propagation_indices =
3955 this->find_all_required_caller_propagation_indices(
3956 graph_params.lf_attribute_set_input_by_output_geometry_bsocket,
3957 graph_params.lf_attribute_set_input_by_caller_propagation_index);
3958
3959 Map<int, int> input_by_field_source_index;
3960
3961 for (const int field_source_index : all_required_field_sources) {
3962 const aai::FieldSource &field_source =
3963 attribute_inferencing_.all_field_sources[field_source_index];
3964 if ([[maybe_unused]] const auto *input_field_source = std::get_if<aai::InputFieldSource>(
3965 &field_source.data))
3966 {
3967 input_by_field_source_index.add_new(field_source_index,
3968 input_by_field_source_index.size());
3969 }
3970 else {
3971 const auto &socket_field_source = std::get<aai::SocketFieldSource>(field_source.data);
3972 const bNodeSocket &bsocket = *socket_field_source.socket;
3973 if (lf::OutputSocket *lf_field_socket = graph_params.lf_output_by_bsocket.lookup_default(
3974 &bsocket, nullptr))
3975 {
3976 lf::OutputSocket *lf_usage_socket = graph_params.usage_by_bsocket.lookup_default(
3977 &bsocket, nullptr);
3978 lf::OutputSocket &lf_attribute_set_socket = this->get_extracted_attributes(
3979 *lf_field_socket,
3980 lf_usage_socket,
3981 graph_params.lf_graph,
3982 graph_params.socket_usage_inputs);
3983 lf_attribute_set_by_field_source_index.add(field_source_index, &lf_attribute_set_socket);
3984 }
3985 else {
3986 input_by_field_source_index.add_new(field_source_index,
3987 input_by_field_source_index.size());
3988 }
3989 }
3990 }
3991
3992 {
3993 Vector<lf::GraphInputSocket *> attribute_set_inputs;
3994 const int num = input_by_field_source_index.size() +
3995 all_required_caller_propagation_indices.size();
3996 for ([[maybe_unused]] const int i : IndexRange(num)) {
3997 attribute_set_inputs.append(&graph_params.lf_graph.add_input(
3998 CPPType::get<bke::AnonymousAttributeSet>(), "Attribute Set"));
3999 }
4000
4001 for (const auto item : input_by_field_source_index.items()) {
4002 const int field_source_index = item.key;
4003 const int attribute_set_index = item.value;
4004 lf::GraphInputSocket &lf_attribute_set_socket = *attribute_set_inputs[attribute_set_index];
4005 lf_attribute_set_by_field_source_index.add(field_source_index, &lf_attribute_set_socket);
4006 }
4007 for (const int i : all_required_caller_propagation_indices.index_range()) {
4008 const int caller_propagation_index = all_required_caller_propagation_indices[i];
4009 lf::GraphInputSocket &lf_attribute_set_socket =
4010 *attribute_set_inputs[input_by_field_source_index.size() + i];
4011 lf_attribute_set_by_caller_propagation_index.add_new(caller_propagation_index,
4012 &lf_attribute_set_socket);
4013 }
4014 }
4015 }
4016
4021 void build_root_graph()
4022 {
4023 lf::Graph &lf_graph = lf_graph_info_->graph;
4024
4025 this->build_main_group_inputs(lf_graph);
4026 if (btree_.group_output_node() == nullptr) {
4027 this->build_fallback_group_outputs(lf_graph);
4028 }
4029
4030 for (const bNodeTreeInterfaceSocket *interface_input : btree_.interface_inputs()) {
4031 lf::GraphOutputSocket &lf_socket = lf_graph.add_output(
4033 StringRef("Usage: ") + (interface_input->name ? interface_input->name : ""));
4034 group_input_usage_sockets_.append(&lf_socket);
4035 }
4036
4037 Vector<lf::GraphInputSocket *> lf_output_usages;
4038 for (const bNodeTreeInterfaceSocket *interface_output : btree_.interface_outputs()) {
4039 lf::GraphInputSocket &lf_socket = lf_graph.add_input(
4041 StringRef("Usage: ") + (interface_output->name ? interface_output->name : ""));
4042 group_output_used_sockets_.append(&lf_socket);
4043 lf_output_usages.append(&lf_socket);
4044 }
4045
4046 BuildGraphParams &graph_params = root_graph_build_params_.emplace(lf_graph);
4047 if (const bNode *group_output_bnode = btree_.group_output_node()) {
4048 for (const bNodeSocket *bsocket : group_output_bnode->input_sockets().drop_back(1)) {
4049 graph_params.usage_by_bsocket.add(bsocket, lf_output_usages[bsocket->index()]);
4050 }
4051 }
4052
4053 this->insert_nodes_and_zones(
4054 tree_zones_->nodes_outside_zones, tree_zones_->root_zones, graph_params);
4055
4056 for (const auto item : graph_params.lf_output_by_bsocket.items()) {
4057 this->insert_links_from_socket(*item.key, *item.value, graph_params);
4058 }
4059 this->build_group_input_usages(graph_params);
4060 this->add_default_inputs(graph_params);
4061
4062 this->build_attribute_propagation_input_node(lf_graph);
4063
4064 Map<int, lf::OutputSocket *> lf_attribute_set_by_field_source_index;
4065 Map<int, lf::OutputSocket *> lf_attribute_set_by_caller_propagation_index;
4066 this->build_attribute_set_inputs_outside_of_zones(
4067 graph_params,
4068 lf_attribute_set_by_field_source_index,
4069 lf_attribute_set_by_caller_propagation_index);
4070 this->link_attribute_set_inputs(lf_graph,
4071 graph_params,
4072 lf_attribute_set_by_field_source_index,
4073 lf_attribute_set_by_caller_propagation_index);
4074
4075 this->fix_link_cycles(lf_graph, graph_params.socket_usage_inputs);
4076
4077 // std::cout << "\n\n" << lf_graph.to_dot() << "\n\n";
4078
4079 lf_graph.update_node_indices();
4080 lf_graph_info_->num_inline_nodes_approximate += lf_graph.nodes().size();
4081 }
4082
4087 void build_geometry_nodes_group_function()
4088 {
4089 GeometryNodesGroupFunction &function = lf_graph_info_->function;
4090
4091 Vector<const lf::GraphInputSocket *> lf_graph_inputs;
4092 Vector<const lf::GraphOutputSocket *> lf_graph_outputs;
4093
4094 lf_graph_inputs.extend(group_input_sockets_);
4095 function.inputs.main = lf_graph_inputs.index_range().take_back(group_input_sockets_.size());
4096
4097 lf_graph_inputs.extend(group_output_used_sockets_);
4098 function.inputs.output_usages = lf_graph_inputs.index_range().take_back(
4099 group_output_used_sockets_.size());
4100
4101 for (auto [output_index, lf_socket] : attribute_set_by_geometry_output_.items()) {
4102 lf_graph_inputs.append(lf_socket);
4103 function.inputs.attributes_to_propagate.geometry_outputs.append(output_index);
4104 }
4105 function.inputs.attributes_to_propagate.range = lf_graph_inputs.index_range().take_back(
4106 attribute_set_by_geometry_output_.size());
4107
4108 lf_graph_outputs.extend(standard_group_output_sockets_);
4109 function.outputs.main = lf_graph_outputs.index_range().take_back(
4110 standard_group_output_sockets_.size());
4111
4112 lf_graph_outputs.extend(group_input_usage_sockets_);
4113 function.outputs.input_usages = lf_graph_outputs.index_range().take_back(
4114 group_input_usage_sockets_.size());
4115
4116 Vector<const lf::FunctionNode *> &local_side_effect_nodes =
4117 scope_.construct<Vector<const lf::FunctionNode *>>();
4118 for (const bNode *bnode : btree_.nodes_by_type("GeometryNodeWarning")) {
4119 if (bnode->output_socket(0).is_directly_linked()) {
4120 /* The warning node is not a side-effect node. Instead, the user explicitly used the output
4121 * socket to specify when the warning node should be used. */
4122 continue;
4123 }
4124 if (tree_zones_->get_zone_by_node(bnode->identifier)) {
4125 /* "Global" warning nodes that are evaluated whenever the node group is evaluated must not
4126 * be in a zone. */
4127 continue;
4128 }
4129 /* Add warning node as side-effect node so that it is always evaluated if the node group is
4130 * evaluated. */
4131 const lf::Socket *lf_socket = root_graph_build_params_->lf_inputs_by_bsocket.lookup(
4132 &bnode->input_socket(0))[0];
4133 const lf::FunctionNode &lf_node = static_cast<const lf::FunctionNode &>(lf_socket->node());
4134 local_side_effect_nodes.append(&lf_node);
4135 }
4136
4137 function.function = &scope_.construct<lf::GraphExecutor>(
4138 lf_graph_info_->graph,
4139 std::move(lf_graph_inputs),
4140 std::move(lf_graph_outputs),
4141 &scope_.construct<GeometryNodesLazyFunctionLogger>(*lf_graph_info_),
4142 &scope_.construct<GeometryNodesLazyFunctionSideEffectProvider>(local_side_effect_nodes),
4143 nullptr);
4144 }
4145
4146 void build_attribute_set_inputs_outside_of_zones(
4147 BuildGraphParams &graph_params,
4148 Map<int, lf::OutputSocket *> &lf_attribute_set_by_field_source_index,
4149 Map<int, lf::OutputSocket *> &lf_attribute_set_by_caller_propagation_index)
4150 {
4151 const Vector<int> all_required_field_sources = this->find_all_required_field_source_indices(
4152 graph_params.lf_attribute_set_input_by_output_geometry_bsocket,
4153 graph_params.lf_attribute_set_input_by_field_source_index);
4154
4155 for (const int field_source_index : all_required_field_sources) {
4156 const aai::FieldSource &field_source =
4157 attribute_inferencing_.all_field_sources[field_source_index];
4158 lf::OutputSocket *lf_attribute_set_socket;
4159 if (const auto *input_field_source = std::get_if<aai::InputFieldSource>(&field_source.data))
4160 {
4161 const int input_index = input_field_source->input_index;
4162 lf::OutputSocket &lf_field_socket = const_cast<lf::OutputSocket &>(
4163 *group_input_sockets_[input_index]);
4164 lf::OutputSocket *lf_usage_socket = const_cast<lf::OutputSocket *>(
4165 group_input_usage_sockets_[input_index]->origin());
4166 lf_attribute_set_socket = &this->get_extracted_attributes(
4167 lf_field_socket,
4168 lf_usage_socket,
4169 graph_params.lf_graph,
4170 graph_params.socket_usage_inputs);
4171 }
4172 else {
4173 const auto &socket_field_source = std::get<aai::SocketFieldSource>(field_source.data);
4174 const bNodeSocket &bsocket = *socket_field_source.socket;
4175 lf::OutputSocket &lf_field_socket = *graph_params.lf_output_by_bsocket.lookup(&bsocket);
4176 lf::OutputSocket *lf_usage_socket = graph_params.usage_by_bsocket.lookup_default(&bsocket,
4177 nullptr);
4178 lf_attribute_set_socket = &this->get_extracted_attributes(
4179 lf_field_socket,
4180 lf_usage_socket,
4181 graph_params.lf_graph,
4182 graph_params.socket_usage_inputs);
4183 }
4184 lf_attribute_set_by_field_source_index.add_new(field_source_index, lf_attribute_set_socket);
4185 }
4186
4187 for (const int caller_propagation_index :
4188 attribute_inferencing_.propagated_output_geometry_indices.index_range())
4189 {
4190 const int group_output_index =
4191 attribute_inferencing_.propagated_output_geometry_indices[caller_propagation_index];
4192 lf::OutputSocket &lf_attribute_set_socket = const_cast<lf::OutputSocket &>(
4193 *attribute_set_by_geometry_output_.lookup(group_output_index));
4194 lf_attribute_set_by_caller_propagation_index.add(caller_propagation_index,
4195 &lf_attribute_set_socket);
4196 }
4197 }
4198
4199 Vector<int> find_all_required_field_source_indices(
4200 const Map<const bNodeSocket *, lf::InputSocket *>
4201 &lf_attribute_set_input_by_output_geometry_bsocket,
4202 const MultiValueMap<int, lf::InputSocket *> &lf_attribute_set_input_by_field_source_index)
4203 {
4204 BitVector<> all_required_field_sources(attribute_inferencing_.all_field_sources.size(), false);
4205 for (const bNodeSocket *geometry_output_bsocket :
4206 lf_attribute_set_input_by_output_geometry_bsocket.keys())
4207 {
4208 all_required_field_sources |=
4209 attribute_inferencing_
4210 .required_fields_by_geometry_socket[geometry_output_bsocket->index_in_tree()];
4211 }
4212 for (const int field_source_index : lf_attribute_set_input_by_field_source_index.keys()) {
4213 all_required_field_sources[field_source_index].set();
4214 }
4215
4216 Vector<int> indices;
4217 bits::foreach_1_index(all_required_field_sources, [&](const int i) { indices.append(i); });
4218 return indices;
4219 }
4220
4221 Vector<int> find_all_required_caller_propagation_indices(
4222 const Map<const bNodeSocket *, lf::InputSocket *>
4223 &lf_attribute_set_input_by_output_geometry_bsocket,
4224 const MultiValueMap<int, lf::InputSocket *>
4225 &lf_attribute_set_input_by_caller_propagation_index)
4226 {
4227 BitVector<> all_required_caller_propagation_indices(
4228 attribute_inferencing_.propagated_output_geometry_indices.size(), false);
4229 for (const bNodeSocket *geometry_output_bs :
4230 lf_attribute_set_input_by_output_geometry_bsocket.keys())
4231 {
4232 all_required_caller_propagation_indices |=
4233 attribute_inferencing_
4234 .propagate_to_output_by_geometry_socket[geometry_output_bs->index_in_tree()];
4235 }
4236 for (const int caller_propagation_index :
4237 lf_attribute_set_input_by_caller_propagation_index.keys())
4238 {
4239 all_required_caller_propagation_indices[caller_propagation_index].set();
4240 }
4241
4242 Vector<int> indices;
4243 bits::foreach_1_index(all_required_caller_propagation_indices,
4244 [&](const int i) { indices.append(i); });
4245 return indices;
4246 }
4247
4248 void link_attribute_set_inputs(
4249 lf::Graph &lf_graph,
4250 BuildGraphParams &graph_params,
4251 const Map<int, lf::OutputSocket *> &lf_attribute_set_by_field_source_index,
4252 const Map<int, lf::OutputSocket *> &lf_attribute_set_by_caller_propagation_index)
4253 {
4254 JoinAttributeSetsCache join_attribute_sets_cache;
4255
4256 for (const MapItem<const bNodeSocket *, lf::InputSocket *> item :
4257 graph_params.lf_attribute_set_input_by_output_geometry_bsocket.items())
4258 {
4259 const bNodeSocket &geometry_output_bsocket = *item.key;
4260 lf::InputSocket &lf_attribute_set_input = *item.value;
4261
4262 Vector<lf::OutputSocket *> lf_attribute_set_sockets;
4263
4264 const BoundedBitSpan required_fields =
4265 attribute_inferencing_
4266 .required_fields_by_geometry_socket[geometry_output_bsocket.index_in_tree()];
4267 bits::foreach_1_index(required_fields, [&](const int field_source_index) {
4268 const auto &field_source = attribute_inferencing_.all_field_sources[field_source_index];
4269 if (const auto *socket_field_source = std::get_if<aai::SocketFieldSource>(
4270 &field_source.data))
4271 {
4272 if (&socket_field_source->socket->owner_node() == &geometry_output_bsocket.owner_node())
4273 {
4274 return;
4275 }
4276 }
4277 lf_attribute_set_sockets.append(
4278 lf_attribute_set_by_field_source_index.lookup(field_source_index));
4279 });
4280
4281 const BoundedBitSpan required_caller_propagations =
4282 attribute_inferencing_
4283 .propagate_to_output_by_geometry_socket[geometry_output_bsocket.index_in_tree()];
4284 bits::foreach_1_index(required_caller_propagations, [&](const int caller_propagation_index) {
4285 lf_attribute_set_sockets.append(
4286 lf_attribute_set_by_caller_propagation_index.lookup(caller_propagation_index));
4287 });
4288
4289 if (lf::OutputSocket *lf_attribute_set = this->join_attribute_sets(
4290 lf_attribute_set_sockets,
4291 join_attribute_sets_cache,
4292 lf_graph,
4293 graph_params.socket_usage_inputs))
4294 {
4295 lf_graph.add_link(*lf_attribute_set, lf_attribute_set_input);
4296 }
4297 else {
4298 static const bke::AnonymousAttributeSet empty_set;
4299 lf_attribute_set_input.set_default_value(&empty_set);
4300 }
4301 }
4302
4303 for (const auto item : graph_params.lf_attribute_set_input_by_field_source_index.items()) {
4304 const int field_source_index = item.key;
4305 lf::OutputSocket &lf_attribute_set_socket = *lf_attribute_set_by_field_source_index.lookup(
4306 field_source_index);
4307 for (lf::InputSocket *lf_attribute_set_input : item.value) {
4308 lf_graph.add_link(lf_attribute_set_socket, *lf_attribute_set_input);
4309 }
4310 }
4311 for (const auto item : graph_params.lf_attribute_set_input_by_caller_propagation_index.items())
4312 {
4313 const int caller_propagation_index = item.key;
4314 lf::OutputSocket &lf_attribute_set_socket =
4315 *lf_attribute_set_by_caller_propagation_index.lookup(caller_propagation_index);
4316 for (lf::InputSocket *lf_attribute_set_input : item.value) {
4317 lf_graph.add_link(lf_attribute_set_socket, *lf_attribute_set_input);
4318 }
4319 }
4320 }
4321
4322 void insert_nodes_and_zones(const Span<const bNode *> bnodes,
4323 const Span<const bNodeTreeZone *> zones,
4324 BuildGraphParams &graph_params)
4325 {
4326 Vector<const bNode *> nodes_to_insert = bnodes;
4327 Map<const bNode *, const bNodeTreeZone *> zone_by_output;
4328 for (const bNodeTreeZone *zone : zones) {
4329 nodes_to_insert.append(zone->output_node);
4330 zone_by_output.add(zone->output_node, zone);
4331 }
4332 /* Insert nodes from right to left so that usage sockets can be build in the same pass. */
4333 std::sort(nodes_to_insert.begin(), nodes_to_insert.end(), [](const bNode *a, const bNode *b) {
4334 return a->runtime->toposort_right_to_left_index < b->runtime->toposort_right_to_left_index;
4335 });
4336
4337 for (const bNode *bnode : nodes_to_insert) {
4338 this->build_output_socket_usages(*bnode, graph_params);
4339 if (const bNodeTreeZone *zone = zone_by_output.lookup_default(bnode, nullptr)) {
4340 this->insert_child_zone_node(*zone, graph_params);
4341 }
4342 else {
4343 this->insert_node_in_graph(*bnode, graph_params);
4344 }
4345 }
4346 }
4347
4348 void link_border_link_inputs_and_usages(const bNodeTreeZone &zone,
4349 const Span<lf::GraphInputSocket *> lf_inputs,
4350 const Span<int> lf_border_link_input_indices,
4351 const Span<lf::GraphOutputSocket *> lf_usages,
4352 const Span<int> lf_border_link_usage_indices,
4353 BuildGraphParams &graph_params)
4354 {
4355 lf::Graph &lf_graph = graph_params.lf_graph;
4356 for (const int border_link_i : zone.border_links.index_range()) {
4357 const bNodeLink &border_link = *zone.border_links[border_link_i];
4358 lf::GraphInputSocket &lf_from = *lf_inputs[lf_border_link_input_indices[border_link_i]];
4359 const Vector<lf::InputSocket *> lf_link_targets = this->find_link_targets(border_link,
4360 graph_params);
4361 for (lf::InputSocket *lf_to : lf_link_targets) {
4362 lf_graph.add_link(lf_from, *lf_to);
4363 }
4364 lf::GraphOutputSocket &lf_usage_output =
4365 *lf_usages[lf_border_link_usage_indices[border_link_i]];
4366 if (lf::OutputSocket *lf_usage = graph_params.usage_by_bsocket.lookup_default(
4367 border_link.tosock, nullptr))
4368 {
4369 lf_graph.add_link(*lf_usage, lf_usage_output);
4370 }
4371 else {
4372 static const bool static_false = false;
4373 lf_usage_output.set_default_value(&static_false);
4374 }
4375 }
4376 }
4377
4378 lf::OutputSocket &get_extracted_attributes(lf::OutputSocket &lf_field_socket,
4379 lf::OutputSocket *lf_usage_socket,
4380 lf::Graph &lf_graph,
4381 Set<lf::InputSocket *> &socket_usage_inputs)
4382 {
4383 auto &lazy_function = scope_.construct<LazyFunctionForAnonymousAttributeSetExtract>();
4384 lf::Node &lf_node = lf_graph.add_function(lazy_function);
4385 lf::InputSocket &lf_use_input = lf_node.input(0);
4386 lf::InputSocket &lf_field_input = lf_node.input(1);
4387 socket_usage_inputs.add_new(&lf_use_input);
4388 if (lf_usage_socket) {
4389 lf_graph.add_link(*lf_usage_socket, lf_use_input);
4390 }
4391 else {
4392 static const bool static_false = false;
4393 lf_use_input.set_default_value(&static_false);
4394 }
4395 lf_graph.add_link(lf_field_socket, lf_field_input);
4396 return lf_node.output(0);
4397 }
4398
4402 lf::OutputSocket *join_attribute_sets(const Span<lf::OutputSocket *> lf_attribute_set_sockets,
4404 lf::Graph &lf_graph,
4405 Set<lf::InputSocket *> &socket_usage_inputs)
4406 {
4407 if (lf_attribute_set_sockets.is_empty()) {
4408 return nullptr;
4409 }
4410 if (lf_attribute_set_sockets.size() == 1) {
4411 return lf_attribute_set_sockets[0];
4412 }
4413
4414 Vector<lf::OutputSocket *, 16> key = lf_attribute_set_sockets;
4415 std::sort(key.begin(), key.end());
4416 return cache.lookup_or_add_cb(key, [&]() {
4417 const auto &lazy_function = LazyFunctionForAnonymousAttributeSetJoin::get_cached(
4418 lf_attribute_set_sockets.size(), scope_);
4419 lf::Node &lf_node = lf_graph.add_function(lazy_function);
4420 for (const int i : lf_attribute_set_sockets.index_range()) {
4421 lf::OutputSocket &lf_attribute_set_socket = *lf_attribute_set_sockets[i];
4422 lf::InputSocket &lf_use_input = lf_node.input(lazy_function.get_use_input(i));
4423
4424 /* Some attribute sets could potentially be set unused in the future based on more dynamic
4425 * analysis of the node tree. */
4426 static const bool static_true = true;
4427 lf_use_input.set_default_value(&static_true);
4428
4429 socket_usage_inputs.add(&lf_use_input);
4430 lf::InputSocket &lf_attribute_set_input = lf_node.input(
4431 lazy_function.get_attribute_set_input(i));
4432 lf_graph.add_link(lf_attribute_set_socket, lf_attribute_set_input);
4433 }
4434 return &lf_node.output(0);
4435 });
4436 }
4437
4438 void insert_child_zone_node(const bNodeTreeZone &child_zone, BuildGraphParams &graph_params)
4439 {
4440 const int child_zone_i = child_zone.index;
4441 ZoneBuildInfo &child_zone_info = zone_build_infos_[child_zone_i];
4442 lf::FunctionNode &child_zone_node = graph_params.lf_graph.add_function(
4443 *child_zone_info.lazy_function);
4444 mapping_->zone_node_map.add_new(&child_zone, &child_zone_node);
4445
4446 {
4447 int valid_socket_i = 0;
4448 for (const bNodeSocket *bsocket : child_zone.input_node->input_sockets()) {
4449 if (ignore_zone_bsocket(*bsocket)) {
4450 continue;
4451 }
4452 lf::InputSocket &lf_input_socket = child_zone_node.input(
4453 child_zone_info.indices.inputs.main[valid_socket_i]);
4454 lf::OutputSocket &lf_usage_socket = child_zone_node.output(
4455 child_zone_info.indices.outputs.input_usages[valid_socket_i]);
4456 mapping_->bsockets_by_lf_socket_map.add(&lf_input_socket, bsocket);
4457 graph_params.lf_inputs_by_bsocket.add(bsocket, &lf_input_socket);
4458 graph_params.usage_by_bsocket.add(bsocket, &lf_usage_socket);
4459 valid_socket_i++;
4460 }
4461 }
4462 {
4463 int valid_socket_i = 0;
4464 for (const bNodeSocket *bsocket : child_zone.output_node->output_sockets()) {
4465 if (ignore_zone_bsocket(*bsocket)) {
4466 continue;
4467 }
4468 lf::OutputSocket &lf_output_socket = child_zone_node.output(
4469 child_zone_info.indices.outputs.main[valid_socket_i]);
4470 lf::InputSocket &lf_usage_input = child_zone_node.input(
4471 child_zone_info.indices.inputs.output_usages[valid_socket_i]);
4472 mapping_->bsockets_by_lf_socket_map.add(&lf_output_socket, bsocket);
4473 graph_params.lf_output_by_bsocket.add(bsocket, &lf_output_socket);
4474 graph_params.socket_usage_inputs.add(&lf_usage_input);
4475 if (lf::OutputSocket *lf_usage = graph_params.usage_by_bsocket.lookup_default(bsocket,
4476 nullptr))
4477 {
4478 graph_params.lf_graph.add_link(*lf_usage, lf_usage_input);
4479 }
4480 else {
4481 static const bool static_false = false;
4482 lf_usage_input.set_default_value(&static_false);
4483 }
4484 valid_socket_i++;
4485 }
4486 }
4487
4488 const Span<const bNodeLink *> child_border_links = child_zone.border_links;
4489 for (const int child_border_link_i : child_border_links.index_range()) {
4490 lf::InputSocket &child_border_link_input = child_zone_node.input(
4491 child_zone_info.indices.inputs.border_links[child_border_link_i]);
4492 const bNodeLink &link = *child_border_links[child_border_link_i];
4493 graph_params.lf_input_by_border_link.add(&link, &child_border_link_input);
4494 lf::OutputSocket &lf_usage = child_zone_node.output(
4495 child_zone_info.indices.outputs.border_link_usages[child_border_link_i]);
4496 graph_params.lf_inputs_by_bsocket.add(link.tosock, &child_border_link_input);
4497 graph_params.usage_by_bsocket.add(link.tosock, &lf_usage);
4498 }
4499
4500 for (const auto item : child_zone_info.indices.inputs.attributes_by_field_source_index.items())
4501 {
4502 const int field_source_index = item.key;
4503 const int child_zone_input_index = item.value;
4504 lf::InputSocket &lf_attribute_set_input = child_zone_node.input(child_zone_input_index);
4505 graph_params.lf_attribute_set_input_by_field_source_index.add(field_source_index,
4506 &lf_attribute_set_input);
4507 }
4508 for (const auto item :
4509 child_zone_info.indices.inputs.attributes_by_caller_propagation_index.items())
4510 {
4511 const int caller_propagation_index = item.key;
4512 const int child_zone_input_index = item.value;
4513 lf::InputSocket &lf_attribute_set_input = child_zone_node.input(child_zone_input_index);
4514 BLI_assert(lf_attribute_set_input.type().is<bke::AnonymousAttributeSet>());
4515 graph_params.lf_attribute_set_input_by_caller_propagation_index.add(caller_propagation_index,
4516 &lf_attribute_set_input);
4517 }
4518 }
4519
4520 void build_main_group_inputs(lf::Graph &lf_graph)
4521 {
4522 const Span<const bNodeTreeInterfaceSocket *> interface_inputs = btree_.interface_inputs();
4523 for (const bNodeTreeInterfaceSocket *interface_input : interface_inputs) {
4524 const bke::bNodeSocketType *typeinfo = interface_input->socket_typeinfo();
4525 lf::GraphInputSocket &lf_socket = lf_graph.add_input(
4526 *typeinfo->geometry_nodes_cpp_type, interface_input->name ? interface_input->name : "");
4527 group_input_sockets_.append(&lf_socket);
4528 }
4529 }
4530
4535 void build_fallback_group_outputs(lf::Graph &lf_graph)
4536 {
4537 for (const bNodeTreeInterfaceSocket *interface_output : btree_.interface_outputs()) {
4538 const bke::bNodeSocketType *typeinfo = interface_output->socket_typeinfo();
4539 const CPPType &type = *typeinfo->geometry_nodes_cpp_type;
4540 lf::GraphOutputSocket &lf_socket = lf_graph.add_output(
4541 type, interface_output->name ? interface_output->name : "");
4542 const void *default_value = typeinfo->geometry_nodes_default_cpp_value;
4543 if (default_value == nullptr) {
4544 default_value = type.default_value();
4545 }
4546 lf_socket.set_default_value(default_value);
4547 standard_group_output_sockets_.append(&lf_socket);
4548 }
4549 }
4550
4551 void insert_node_in_graph(const bNode &bnode, BuildGraphParams &graph_params)
4552 {
4553 const bke::bNodeType *node_type = bnode.typeinfo;
4554 if (node_type == nullptr) {
4555 return;
4556 }
4557 if (bnode.is_muted()) {
4558 this->build_muted_node(bnode, graph_params);
4559 return;
4560 }
4561 switch (node_type->type) {
4562 case NODE_FRAME: {
4563 /* Ignored. */
4564 break;
4565 }
4566 case NODE_REROUTE: {
4567 this->build_reroute_node(bnode, graph_params);
4568 break;
4569 }
4570 case NODE_GROUP_INPUT: {
4571 this->handle_group_input_node(bnode, graph_params);
4572 break;
4573 }
4574 case NODE_GROUP_OUTPUT: {
4575 this->build_group_output_node(bnode, graph_params);
4576 break;
4577 }
4578 case NODE_CUSTOM_GROUP:
4579 case NODE_GROUP: {
4580 this->build_group_node(bnode, graph_params);
4581 break;
4582 }
4583 case GEO_NODE_VIEWER: {
4584 this->build_viewer_node(bnode, graph_params);
4585 break;
4586 }
4587 case GEO_NODE_SWITCH: {
4588 this->build_switch_node(bnode, graph_params);
4589 break;
4590 }
4591 case GEO_NODE_INDEX_SWITCH: {
4592 this->build_index_switch_node(bnode, graph_params);
4593 break;
4594 }
4595 case GEO_NODE_WARNING: {
4596 this->build_warning_node(bnode, graph_params);
4597 break;
4598 }
4602 this->build_gizmo_node(bnode, graph_params);
4603 break;
4604 }
4605 case GEO_NODE_BAKE: {
4606 this->build_bake_node(bnode, graph_params);
4607 break;
4608 }
4609 case GEO_NODE_MENU_SWITCH: {
4610 this->build_menu_switch_node(bnode, graph_params);
4611 break;
4612 }
4613 default: {
4614 if (node_type->geometry_node_execute) {
4615 this->build_geometry_node(bnode, graph_params);
4616 break;
4617 }
4618 const NodeMultiFunctions::Item &fn_item = node_multi_functions_.try_get(bnode);
4619 if (fn_item.fn != nullptr) {
4620 this->build_multi_function_node(bnode, fn_item, graph_params);
4621 break;
4622 }
4623 if (node_type == &bke::NodeTypeUndefined) {
4624 this->build_undefined_node(bnode, graph_params);
4625 break;
4626 }
4627 /* Nodes that don't match any of the criteria above are just ignored. */
4628 break;
4629 }
4630 }
4631 }
4632
4633 void build_muted_node(const bNode &bnode, BuildGraphParams &graph_params)
4634 {
4635 auto &lazy_function = scope_.construct<LazyFunctionForMutedNode>(
4636 bnode, mapping_->lf_index_by_bsocket);
4637 lf::Node &lf_node = graph_params.lf_graph.add_function(lazy_function);
4638 for (const bNodeSocket *bsocket : bnode.input_sockets()) {
4639 const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()];
4640 if (lf_index == -1) {
4641 continue;
4642 }
4643 lf::InputSocket &lf_socket = lf_node.input(lf_index);
4644 graph_params.lf_inputs_by_bsocket.add(bsocket, &lf_socket);
4645 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket);
4646 }
4647 for (const bNodeSocket *bsocket : bnode.output_sockets()) {
4648 const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()];
4649 if (lf_index == -1) {
4650 continue;
4651 }
4652 lf::OutputSocket &lf_socket = lf_node.output(lf_index);
4653 graph_params.lf_output_by_bsocket.add_new(bsocket, &lf_socket);
4654 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket);
4655 }
4656
4657 this->build_muted_node_usages(bnode, graph_params);
4658 }
4659
4663 void build_muted_node_usages(const bNode &bnode, BuildGraphParams &graph_params)
4664 {
4665 /* Find all outputs that use a specific input. */
4666 MultiValueMap<const bNodeSocket *, const bNodeSocket *> outputs_by_input;
4667 for (const bNodeLink &blink : bnode.internal_links()) {
4668 outputs_by_input.add(blink.fromsock, blink.tosock);
4669 }
4670 for (const auto item : outputs_by_input.items()) {
4671 const bNodeSocket &input_bsocket = *item.key;
4672 const Span<const bNodeSocket *> output_bsockets = item.value;
4673
4674 /* The input is used if any of the internally linked outputs is used. */
4675 Vector<lf::OutputSocket *> lf_socket_usages;
4676 for (const bNodeSocket *output_bsocket : output_bsockets) {
4677 if (lf::OutputSocket *lf_socket = graph_params.usage_by_bsocket.lookup_default(
4678 output_bsocket, nullptr))
4679 {
4680 lf_socket_usages.append(lf_socket);
4681 }
4682 }
4683 graph_params.usage_by_bsocket.add(&input_bsocket,
4684 this->or_socket_usages(lf_socket_usages, graph_params));
4685 }
4686 }
4687
4688 void build_reroute_node(const bNode &bnode, BuildGraphParams &graph_params)
4689 {
4690 const bNodeSocket &input_bsocket = bnode.input_socket(0);
4691 const bNodeSocket &output_bsocket = bnode.output_socket(0);
4692 const CPPType *type = get_socket_cpp_type(input_bsocket);
4693 if (type == nullptr) {
4694 return;
4695 }
4696
4697 auto &lazy_function = scope_.construct<LazyFunctionForRerouteNode>(*type);
4698 lf::Node &lf_node = graph_params.lf_graph.add_function(lazy_function);
4699
4700 lf::InputSocket &lf_input = lf_node.input(0);
4701 lf::OutputSocket &lf_output = lf_node.output(0);
4702 graph_params.lf_inputs_by_bsocket.add(&input_bsocket, &lf_input);
4703 graph_params.lf_output_by_bsocket.add_new(&output_bsocket, &lf_output);
4704 mapping_->bsockets_by_lf_socket_map.add(&lf_input, &input_bsocket);
4705 mapping_->bsockets_by_lf_socket_map.add(&lf_output, &output_bsocket);
4706
4707 if (lf::OutputSocket *lf_usage = graph_params.usage_by_bsocket.lookup_default(
4708 &bnode.output_socket(0), nullptr))
4709 {
4710 graph_params.usage_by_bsocket.add(&bnode.input_socket(0), lf_usage);
4711 }
4712 }
4713
4714 void handle_group_input_node(const bNode &bnode, BuildGraphParams &graph_params)
4715 {
4716 for (const int i : btree_.interface_inputs().index_range()) {
4717 const bNodeSocket &bsocket = bnode.output_socket(i);
4718 lf::GraphInputSocket &lf_socket = *const_cast<lf::GraphInputSocket *>(
4719 group_input_sockets_[i]);
4720 graph_params.lf_output_by_bsocket.add_new(&bsocket, &lf_socket);
4721 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
4722 }
4723 }
4724
4725 void build_group_output_node(const bNode &bnode, BuildGraphParams &graph_params)
4726 {
4727 Vector<lf::GraphOutputSocket *> lf_graph_outputs;
4728
4729 for (const int i : btree_.interface_outputs().index_range()) {
4730 const bNodeTreeInterfaceSocket &interface_output = *btree_.interface_outputs()[i];
4731 const bNodeSocket &bsocket = bnode.input_socket(i);
4732 const bke::bNodeSocketType *typeinfo = interface_output.socket_typeinfo();
4733 const CPPType &type = *typeinfo->geometry_nodes_cpp_type;
4734 lf::GraphOutputSocket &lf_socket = graph_params.lf_graph.add_output(
4735 type, interface_output.name ? interface_output.name : "");
4736 lf_graph_outputs.append(&lf_socket);
4737 graph_params.lf_inputs_by_bsocket.add(&bsocket, &lf_socket);
4738 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
4739 }
4740
4741 if (&bnode == btree_.group_output_node()) {
4742 standard_group_output_sockets_ = lf_graph_outputs.as_span();
4743 }
4744 }
4745
4746 void build_group_node(const bNode &bnode, BuildGraphParams &graph_params)
4747 {
4748 const bNodeTree *group_btree = reinterpret_cast<bNodeTree *>(bnode.id);
4749 if (group_btree == nullptr) {
4750 return;
4751 }
4752 const GeometryNodesLazyFunctionGraphInfo *group_lf_graph_info =
4754 if (group_lf_graph_info == nullptr) {
4755 return;
4756 }
4757
4758 auto &lazy_function = scope_.construct<LazyFunctionForGroupNode>(
4759 bnode, *group_lf_graph_info, *lf_graph_info_);
4760 lf::FunctionNode &lf_node = graph_params.lf_graph.add_function(lazy_function);
4761
4762 for (const int i : bnode.input_sockets().index_range()) {
4763 const bNodeSocket &bsocket = bnode.input_socket(i);
4764 BLI_assert(!bsocket.is_multi_input());
4765 lf::InputSocket &lf_socket = lf_node.input(group_lf_graph_info->function.inputs.main[i]);
4766 graph_params.lf_inputs_by_bsocket.add(&bsocket, &lf_socket);
4767 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
4768 }
4769 for (const int i : bnode.output_sockets().index_range()) {
4770 const bNodeSocket &bsocket = bnode.output_socket(i);
4771 lf::OutputSocket &lf_socket = lf_node.output(group_lf_graph_info->function.outputs.main[i]);
4772 graph_params.lf_output_by_bsocket.add_new(&bsocket, &lf_socket);
4773 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
4774 }
4775 mapping_->group_node_map.add(&bnode, &lf_node);
4776 lf_graph_info_->num_inline_nodes_approximate +=
4777 group_lf_graph_info->num_inline_nodes_approximate;
4778 static const bool static_false = false;
4779 for (const bNodeSocket *bsocket : bnode.output_sockets()) {
4780 {
4781 const int lf_input_index =
4782 mapping_->lf_input_index_for_output_bsocket_usage[bsocket->index_in_all_outputs()];
4783 if (lf_input_index != -1) {
4784 lf::InputSocket &lf_input = lf_node.input(lf_input_index);
4785 lf_input.set_default_value(&static_false);
4786 graph_params.socket_usage_inputs.add(&lf_input);
4787 }
4788 }
4789 {
4790 /* Keep track of attribute set inputs that need to be populated later. */
4791 const int lf_input_index = mapping_->lf_input_index_for_attribute_propagation_to_output
4792 [bsocket->index_in_all_outputs()];
4793 if (lf_input_index != -1) {
4794 lf::InputSocket &lf_input = lf_node.input(lf_input_index);
4795 graph_params.lf_attribute_set_input_by_output_geometry_bsocket.add(bsocket, &lf_input);
4796 }
4797 }
4798 }
4799
4800 this->build_group_node_socket_usage(bnode, lf_node, graph_params, *group_lf_graph_info);
4801 }
4802
4803 void build_group_node_socket_usage(const bNode &bnode,
4804 lf::FunctionNode &lf_group_node,
4805 BuildGraphParams &graph_params,
4806 const GeometryNodesLazyFunctionGraphInfo &group_lf_graph_info)
4807 {
4808 for (const bNodeSocket *input_bsocket : bnode.input_sockets()) {
4809 const int input_index = input_bsocket->index();
4810 const InputUsageHint &input_usage_hint =
4811 group_lf_graph_info.mapping.group_input_usage_hints[input_index];
4812 switch (input_usage_hint.type) {
4814 /* Nothing to do. */
4815 break;
4816 }
4818 Vector<lf::OutputSocket *> output_usages;
4819 for (const int i : input_usage_hint.output_dependencies) {
4820 if (lf::OutputSocket *lf_socket = graph_params.usage_by_bsocket.lookup_default(
4821 &bnode.output_socket(i), nullptr))
4822 {
4823 output_usages.append(lf_socket);
4824 }
4825 }
4826 graph_params.usage_by_bsocket.add(input_bsocket,
4827 this->or_socket_usages(output_usages, graph_params));
4828 break;
4829 }
4831 graph_params.usage_by_bsocket.add(
4832 input_bsocket,
4833 &lf_group_node.output(
4834 group_lf_graph_info.function.outputs.input_usages[input_index]));
4835 break;
4836 }
4837 }
4838 }
4839
4840 for (const bNodeSocket *output_bsocket : bnode.output_sockets()) {
4841 const int lf_input_index =
4842 mapping_
4843 ->lf_input_index_for_output_bsocket_usage[output_bsocket->index_in_all_outputs()];
4844 BLI_assert(lf_input_index >= 0);
4845 lf::InputSocket &lf_socket = lf_group_node.input(lf_input_index);
4846 if (lf::OutputSocket *lf_output_is_used = graph_params.usage_by_bsocket.lookup_default(
4847 output_bsocket, nullptr))
4848 {
4849 graph_params.lf_graph.add_link(*lf_output_is_used, lf_socket);
4850 }
4851 else {
4852 static const bool static_false = false;
4853 lf_socket.set_default_value(&static_false);
4854 }
4855 }
4856 }
4857
4858 void build_geometry_node(const bNode &bnode, BuildGraphParams &graph_params)
4859 {
4860 auto &lazy_function = scope_.construct<LazyFunctionForGeometryNode>(bnode, *lf_graph_info_);
4861 lf::Node &lf_node = graph_params.lf_graph.add_function(lazy_function);
4862
4863 for (const bNodeSocket *bsocket : bnode.input_sockets()) {
4864 const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()];
4865 if (lf_index == -1) {
4866 continue;
4867 }
4868 lf::InputSocket &lf_socket = lf_node.input(lf_index);
4869
4870 if (bsocket->is_multi_input()) {
4871 auto &multi_input_lazy_function = scope_.construct<LazyFunctionForMultiInput>(*bsocket);
4872 lf::Node &lf_multi_input_node = graph_params.lf_graph.add_function(
4873 multi_input_lazy_function);
4874 graph_params.lf_graph.add_link(lf_multi_input_node.output(0), lf_socket);
4875 for (const int i : multi_input_lazy_function.links.index_range()) {
4876 lf::InputSocket &lf_multi_input_socket = lf_multi_input_node.input(i);
4877 const bNodeLink *link = multi_input_lazy_function.links[i];
4878 graph_params.lf_input_by_multi_input_link.add(link, &lf_multi_input_socket);
4879 mapping_->bsockets_by_lf_socket_map.add(&lf_multi_input_socket, bsocket);
4880 const void *default_value = lf_multi_input_socket.type().default_value();
4881 lf_multi_input_socket.set_default_value(default_value);
4882 }
4883 }
4884 else {
4885 graph_params.lf_inputs_by_bsocket.add(bsocket, &lf_socket);
4886 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket);
4887 }
4888 }
4889 for (const bNodeSocket *bsocket : bnode.output_sockets()) {
4890 const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()];
4891 if (lf_index == -1) {
4892 continue;
4893 }
4894 lf::OutputSocket &lf_socket = lf_node.output(lf_index);
4895 graph_params.lf_output_by_bsocket.add_new(bsocket, &lf_socket);
4896 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket);
4897 }
4898
4899 for (const bNodeSocket *bsocket : bnode.output_sockets()) {
4900 {
4901 const int lf_input_index =
4902 mapping_->lf_input_index_for_output_bsocket_usage[bsocket->index_in_all_outputs()];
4903 if (lf_input_index != -1) {
4904 lf::InputSocket &lf_input_socket = lf_node.input(lf_input_index);
4905 if (lf::OutputSocket *lf_usage = graph_params.usage_by_bsocket.lookup_default(bsocket,
4906 nullptr))
4907 {
4908 graph_params.lf_graph.add_link(*lf_usage, lf_input_socket);
4909 }
4910 else {
4911 static const bool static_false = false;
4912 lf_input_socket.set_default_value(&static_false);
4913 }
4914 graph_params.socket_usage_inputs.add_new(&lf_node.input(lf_input_index));
4915 }
4916 }
4917 {
4918 /* Keep track of attribute set inputs that need to be populated later. */
4919 const int lf_input_index = mapping_->lf_input_index_for_attribute_propagation_to_output
4920 [bsocket->index_in_all_outputs()];
4921 if (lf_input_index != -1) {
4922 graph_params.lf_attribute_set_input_by_output_geometry_bsocket.add(
4923 bsocket, &lf_node.input(lf_input_index));
4924 }
4925 }
4926 }
4927
4928 this->build_standard_node_input_socket_usage(bnode, graph_params);
4929 }
4930
4931 void build_standard_node_input_socket_usage(const bNode &bnode, BuildGraphParams &graph_params)
4932 {
4933 if (bnode.input_sockets().is_empty()) {
4934 return;
4935 }
4936
4937 Vector<lf::OutputSocket *> output_usages;
4938 for (const bNodeSocket *output_socket : bnode.output_sockets()) {
4939 if (!output_socket->is_available()) {
4940 continue;
4941 }
4942 if (lf::OutputSocket *is_used_socket = graph_params.usage_by_bsocket.lookup_default(
4943 output_socket, nullptr))
4944 {
4945 output_usages.append_non_duplicates(is_used_socket);
4946 }
4947 }
4948
4949 /* Assume every input is used when any output is used. */
4950 lf::OutputSocket *lf_usage = this->or_socket_usages(output_usages, graph_params);
4951 if (lf_usage == nullptr) {
4952 return;
4953 }
4954
4955 for (const bNodeSocket *input_socket : bnode.input_sockets()) {
4956 if (input_socket->is_available()) {
4957 graph_params.usage_by_bsocket.add(input_socket, lf_usage);
4958 }
4959 }
4960 }
4961
4962 void build_multi_function_node(const bNode &bnode,
4963 const NodeMultiFunctions::Item &fn_item,
4964 BuildGraphParams &graph_params)
4965 {
4966 auto &lazy_function = scope_.construct<LazyFunctionForMultiFunctionNode>(
4967 bnode, fn_item, mapping_->lf_index_by_bsocket);
4968 lf::FunctionNode &lf_node = graph_params.lf_graph.add_function(lazy_function);
4969
4970 for (const bNodeSocket *bsocket : bnode.input_sockets()) {
4971 const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()];
4972 if (lf_index == -1) {
4973 continue;
4974 }
4975 BLI_assert(!bsocket->is_multi_input());
4976 lf::InputSocket &lf_socket = lf_node.input(lf_index);
4977 graph_params.lf_inputs_by_bsocket.add(bsocket, &lf_socket);
4978 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket);
4979 }
4980 for (const bNodeSocket *bsocket : bnode.output_sockets()) {
4981 const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()];
4982 if (lf_index == -1) {
4983 continue;
4984 }
4985 lf::OutputSocket &lf_socket = lf_node.output(lf_index);
4986 graph_params.lf_output_by_bsocket.add(bsocket, &lf_socket);
4987 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket);
4988 }
4989
4990 this->build_standard_node_input_socket_usage(bnode, graph_params);
4991 }
4992
4993 void build_viewer_node(const bNode &bnode, BuildGraphParams &graph_params)
4994 {
4995 auto &lazy_function = scope_.construct<LazyFunctionForViewerNode>(
4996 bnode, mapping_->lf_index_by_bsocket);
4997 lf::FunctionNode &lf_viewer_node = graph_params.lf_graph.add_function(lazy_function);
4998
4999 for (const bNodeSocket *bsocket : bnode.input_sockets()) {
5000 const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()];
5001 if (lf_index == -1) {
5002 continue;
5003 }
5004 lf::InputSocket &lf_socket = lf_viewer_node.input(lf_index);
5005 graph_params.lf_inputs_by_bsocket.add(bsocket, &lf_socket);
5006 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket);
5007 }
5008
5009 mapping_->possible_side_effect_node_map.add(&bnode, &lf_viewer_node);
5010
5011 {
5012 auto &usage_lazy_function = scope_.construct<LazyFunctionForViewerInputUsage>(
5013 lf_viewer_node);
5014 lf::FunctionNode &lf_usage_node = graph_params.lf_graph.add_function(usage_lazy_function);
5015
5016 for (const bNodeSocket *bsocket : bnode.input_sockets()) {
5017 if (bsocket->is_available()) {
5018 graph_params.usage_by_bsocket.add(bsocket, &lf_usage_node.output(0));
5019 }
5020 }
5021 }
5022 }
5023
5024 void build_gizmo_node(const bNode &bnode, BuildGraphParams &graph_params)
5025 {
5026 auto &lazy_function = scope_.construct<LazyFunctionForGizmoNode>(
5027 bnode, mapping_->lf_index_by_bsocket);
5028 lf::FunctionNode &lf_gizmo_node = graph_params.lf_graph.add_function(lazy_function);
5029 lazy_function.self_node = &lf_gizmo_node;
5030
5031 for (const int i : lazy_function.gizmo_links.index_range()) {
5032 const bNodeLink &link = *lazy_function.gizmo_links[i];
5033 lf::InputSocket &lf_socket = lf_gizmo_node.input(i);
5034 graph_params.lf_input_by_multi_input_link.add(&link, &lf_socket);
5035 }
5036 for (const int i : bnode.input_sockets().drop_front(1).index_range()) {
5037 lf::InputSocket &lf_socket = lf_gizmo_node.input(i + lazy_function.gizmo_links.size());
5038 const bNodeSocket &bsocket = bnode.input_socket(i + 1);
5039 graph_params.lf_inputs_by_bsocket.add(&bsocket, &lf_socket);
5040 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
5041 }
5042 for (const int i : bnode.output_sockets().index_range()) {
5043 lf::OutputSocket &lf_socket = lf_gizmo_node.output(i);
5044 const bNodeSocket &bsocket = bnode.output_socket(i);
5045 graph_params.lf_output_by_bsocket.add(&bsocket, &lf_socket);
5046 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
5047 }
5048
5049 this->build_gizmo_node_socket_usage(bnode, graph_params, lf_gizmo_node);
5050
5051 mapping_->possible_side_effect_node_map.add(&bnode, &lf_gizmo_node);
5052 }
5053
5054 void build_gizmo_node_socket_usage(const bNode &bnode,
5055 BuildGraphParams &graph_params,
5056 const lf::FunctionNode &lf_gizmo_node)
5057 {
5058 const auto &usage_fn = scope_.construct<LazyFunctionForGizmoInputsUsage>(bnode, lf_gizmo_node);
5059 lf::FunctionNode &lf_usage_node = graph_params.lf_graph.add_function(usage_fn);
5060 for (const bNodeSocket *bsocket : bnode.input_sockets()) {
5061 graph_params.usage_by_bsocket.add(bsocket, &lf_usage_node.output(0));
5062 }
5063 }
5064
5065 lf::FunctionNode *insert_simulation_input_node(const bNodeTree &node_tree,
5066 const bNode &bnode,
5067 BuildGraphParams &graph_params)
5068 {
5069 const NodeGeometrySimulationInput *storage = static_cast<const NodeGeometrySimulationInput *>(
5070 bnode.storage);
5071 if (node_tree.node_by_id(storage->output_node_id) == nullptr) {
5072 return nullptr;
5073 }
5074
5075 std::unique_ptr<LazyFunction> lazy_function = get_simulation_input_lazy_function(
5076 node_tree, bnode, *lf_graph_info_);
5077 lf::FunctionNode &lf_node = graph_params.lf_graph.add_function(*lazy_function);
5078 scope_.add(std::move(lazy_function));
5079
5080 for (const int i : bnode.input_sockets().index_range().drop_back(1)) {
5081 const bNodeSocket &bsocket = bnode.input_socket(i);
5082 lf::InputSocket &lf_socket = lf_node.input(
5083 mapping_->lf_index_by_bsocket[bsocket.index_in_tree()]);
5084 graph_params.lf_inputs_by_bsocket.add(&bsocket, &lf_socket);
5085 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
5086 }
5087 for (const int i : bnode.output_sockets().index_range().drop_back(1)) {
5088 const bNodeSocket &bsocket = bnode.output_socket(i);
5089 lf::OutputSocket &lf_socket = lf_node.output(
5090 mapping_->lf_index_by_bsocket[bsocket.index_in_tree()]);
5091 graph_params.lf_output_by_bsocket.add(&bsocket, &lf_socket);
5092 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
5093 }
5094 return &lf_node;
5095 }
5096
5097 lf::FunctionNode &insert_simulation_output_node(const bNode &bnode,
5098 BuildGraphParams &graph_params)
5099 {
5100 std::unique_ptr<LazyFunction> lazy_function = get_simulation_output_lazy_function(
5101 bnode, *lf_graph_info_);
5102 lf::FunctionNode &lf_node = graph_params.lf_graph.add_function(*lazy_function);
5103 scope_.add(std::move(lazy_function));
5104
5105 for (const int i : bnode.input_sockets().index_range().drop_back(1)) {
5106 const bNodeSocket &bsocket = bnode.input_socket(i);
5107 lf::InputSocket &lf_socket = lf_node.input(
5108 mapping_->lf_index_by_bsocket[bsocket.index_in_tree()]);
5109 graph_params.lf_inputs_by_bsocket.add(&bsocket, &lf_socket);
5110 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
5111 }
5112 for (const int i : bnode.output_sockets().index_range().drop_back(1)) {
5113 const bNodeSocket &bsocket = bnode.output_socket(i);
5114 lf::OutputSocket &lf_socket = lf_node.output(
5115 mapping_->lf_index_by_bsocket[bsocket.index_in_tree()]);
5116 graph_params.lf_output_by_bsocket.add(&bsocket, &lf_socket);
5117 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
5118 }
5119
5120 mapping_->possible_side_effect_node_map.add(&bnode, &lf_node);
5121
5122 return lf_node;
5123 }
5124
5125 void build_bake_node(const bNode &bnode, BuildGraphParams &graph_params)
5126 {
5127 std::unique_ptr<LazyFunction> lazy_function = get_bake_lazy_function(bnode, *lf_graph_info_);
5128 lf::FunctionNode &lf_node = graph_params.lf_graph.add_function(*lazy_function);
5129 scope_.add(std::move(lazy_function));
5130
5131 for (const int i : bnode.input_sockets().index_range().drop_back(1)) {
5132 const bNodeSocket &bsocket = bnode.input_socket(i);
5133 lf::InputSocket &lf_socket = lf_node.input(
5134 mapping_->lf_index_by_bsocket[bsocket.index_in_tree()]);
5135 graph_params.lf_inputs_by_bsocket.add(&bsocket, &lf_socket);
5136 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
5137 }
5138 for (const int i : bnode.output_sockets().index_range().drop_back(1)) {
5139 const bNodeSocket &bsocket = bnode.output_socket(i);
5140 lf::OutputSocket &lf_socket = lf_node.output(
5141 mapping_->lf_index_by_bsocket[bsocket.index_in_tree()]);
5142 graph_params.lf_output_by_bsocket.add(&bsocket, &lf_socket);
5143 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
5144 }
5145
5146 mapping_->possible_side_effect_node_map.add(&bnode, &lf_node);
5147
5148 this->build_bake_node_socket_usage(bnode, graph_params);
5149 }
5150
5151 void build_bake_node_socket_usage(const bNode &bnode, BuildGraphParams &graph_params)
5152 {
5153 const LazyFunction &usage_fn = scope_.construct<LazyFunctionForBakeInputsUsage>(bnode);
5154 lf::FunctionNode &lf_usage_node = graph_params.lf_graph.add_function(usage_fn);
5155 const int items_num = bnode.input_sockets().size() - 1;
5156 for (const int i : IndexRange(items_num)) {
5157 graph_params.usage_by_bsocket.add(&bnode.input_socket(i), &lf_usage_node.output(0));
5158 }
5159 }
5160
5161 void build_switch_node(const bNode &bnode, BuildGraphParams &graph_params)
5162 {
5163 std::unique_ptr<LazyFunction> lazy_function = get_switch_node_lazy_function(bnode);
5164 lf::FunctionNode &lf_node = graph_params.lf_graph.add_function(*lazy_function);
5165 scope_.add(std::move(lazy_function));
5166
5167 for (const int i : bnode.input_sockets().index_range()) {
5168 graph_params.lf_inputs_by_bsocket.add(&bnode.input_socket(i), &lf_node.input(i));
5169 mapping_->bsockets_by_lf_socket_map.add(&lf_node.input(i), &bnode.input_socket(i));
5170 }
5171
5172 graph_params.lf_output_by_bsocket.add(&bnode.output_socket(0), &lf_node.output(0));
5173 mapping_->bsockets_by_lf_socket_map.add(&lf_node.output(0), &bnode.output_socket(0));
5174
5175 this->build_switch_node_socket_usage(bnode, graph_params);
5176 }
5177
5178 void build_switch_node_socket_usage(const bNode &bnode, BuildGraphParams &graph_params)
5179 {
5180 const bNodeSocket &switch_input_bsocket = bnode.input_socket(0);
5181 const bNodeSocket &false_input_bsocket = bnode.input_socket(1);
5182 const bNodeSocket &true_input_bsocket = bnode.input_socket(2);
5183 const bNodeSocket &output_bsocket = bnode.output_socket(0);
5184 lf::OutputSocket *output_is_used_socket = graph_params.usage_by_bsocket.lookup_default(
5185 &output_bsocket, nullptr);
5186 if (output_is_used_socket == nullptr) {
5187 return;
5188 }
5189 graph_params.usage_by_bsocket.add(&switch_input_bsocket, output_is_used_socket);
5190 if (switch_input_bsocket.is_directly_linked()) {
5191 /* The condition input is dynamic, so the usage of the other inputs is as well. */
5192 static const LazyFunctionForSwitchSocketUsage switch_socket_usage_fn;
5193 lf::Node &lf_node = graph_params.lf_graph.add_function(switch_socket_usage_fn);
5194 graph_params.lf_inputs_by_bsocket.add(&switch_input_bsocket, &lf_node.input(0));
5195 graph_params.usage_by_bsocket.add(&false_input_bsocket, &lf_node.output(0));
5196 graph_params.usage_by_bsocket.add(&true_input_bsocket, &lf_node.output(1));
5197 }
5198 else {
5199 if (switch_input_bsocket.default_value_typed<bNodeSocketValueBoolean>()->value) {
5200 graph_params.usage_by_bsocket.add(&true_input_bsocket, output_is_used_socket);
5201 }
5202 else {
5203 graph_params.usage_by_bsocket.add(&false_input_bsocket, output_is_used_socket);
5204 }
5205 }
5206 }
5207
5208 void build_index_switch_node(const bNode &bnode, BuildGraphParams &graph_params)
5209 {
5210 std::unique_ptr<LazyFunction> lazy_function = get_index_switch_node_lazy_function(
5211 bnode, *lf_graph_info_);
5212 lf::FunctionNode &lf_node = graph_params.lf_graph.add_function(*lazy_function);
5213 scope_.add(std::move(lazy_function));
5214
5215 for (const int i : bnode.input_sockets().drop_back(1).index_range()) {
5216 graph_params.lf_inputs_by_bsocket.add(&bnode.input_socket(i), &lf_node.input(i));
5217 mapping_->bsockets_by_lf_socket_map.add(&lf_node.input(i), &bnode.input_socket(i));
5218 }
5219
5220 graph_params.lf_output_by_bsocket.add(&bnode.output_socket(0), &lf_node.output(0));
5221 mapping_->bsockets_by_lf_socket_map.add(&lf_node.output(0), &bnode.output_socket(0));
5222
5223 this->build_index_switch_node_socket_usage(bnode, graph_params);
5224 }
5225
5226 void build_index_switch_node_socket_usage(const bNode &bnode, BuildGraphParams &graph_params)
5227 {
5228 const bNodeSocket &index_socket = bnode.input_socket(0);
5229 const int items_num = bnode.input_sockets().size() - 1;
5230
5231 lf::OutputSocket *output_is_used = graph_params.usage_by_bsocket.lookup_default(
5232 &bnode.output_socket(0), nullptr);
5233 if (output_is_used == nullptr) {
5234 return;
5235 }
5236 graph_params.usage_by_bsocket.add(&index_socket, output_is_used);
5237 if (index_socket.is_directly_linked()) {
5238 /* The condition input is dynamic, so the usage of the other inputs is as well. */
5239 auto usage_fn = std::make_unique<LazyFunctionForIndexSwitchSocketUsage>(bnode);
5240 lf::Node &lf_node = graph_params.lf_graph.add_function(*usage_fn);
5241 scope_.add(std::move(usage_fn));
5242
5243 graph_params.lf_inputs_by_bsocket.add(&index_socket, &lf_node.input(0));
5244 for (const int i : IndexRange(items_num)) {
5245 graph_params.usage_by_bsocket.add(&bnode.input_socket(i + 1), &lf_node.output(i));
5246 }
5247 }
5248 else {
5249 const int index = index_socket.default_value_typed<bNodeSocketValueInt>()->value;
5250 if (IndexRange(items_num).contains(index)) {
5251 graph_params.usage_by_bsocket.add(&bnode.input_socket(index + 1), output_is_used);
5252 }
5253 }
5254 }
5255
5256 void build_warning_node(const bNode &bnode, BuildGraphParams &graph_params)
5257 {
5258 auto lazy_function_ptr = get_warning_node_lazy_function(bnode);
5259 LazyFunction &lazy_function = *lazy_function_ptr;
5260 scope_.add(std::move(lazy_function_ptr));
5261
5262 lf::Node &lf_node = graph_params.lf_graph.add_function(lazy_function);
5263
5264 for (const int i : bnode.input_sockets().index_range()) {
5265 const bNodeSocket &bsocket = bnode.input_socket(i);
5266 lf::InputSocket &lf_socket = lf_node.input(i);
5267 graph_params.lf_inputs_by_bsocket.add(&bsocket, &lf_socket);
5268 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
5269 }
5270 for (const int i : bnode.output_sockets().index_range()) {
5271 const bNodeSocket &bsocket = bnode.output_socket(i);
5272 lf::OutputSocket &lf_socket = lf_node.output(i);
5273 graph_params.lf_output_by_bsocket.add(&bsocket, &lf_socket);
5274 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
5275 }
5276
5277 const bNodeSocket &output_bsocket = bnode.output_socket(0);
5278
5279 lf::OutputSocket *lf_usage = nullptr;
5280 if (output_bsocket.is_directly_linked()) {
5281 /* The warning node is only used if the output socket is used. */
5282 lf_usage = graph_params.usage_by_bsocket.lookup_default(&output_bsocket, nullptr);
5283 }
5284 else {
5285 /* The warning node is used if any of the output sockets is used. */
5286 lf_usage = this->or_socket_usages(group_output_used_sockets_, graph_params);
5287 }
5288 if (lf_usage) {
5289 for (const bNodeSocket *socket : bnode.input_sockets()) {
5290 graph_params.usage_by_bsocket.add(socket, lf_usage);
5291 }
5292 }
5293 }
5294
5295 void build_menu_switch_node(const bNode &bnode, BuildGraphParams &graph_params)
5296 {
5297 std::unique_ptr<LazyFunction> lazy_function = get_menu_switch_node_lazy_function(
5298 bnode, *lf_graph_info_);
5299 lf::FunctionNode &lf_node = graph_params.lf_graph.add_function(*lazy_function);
5300 scope_.add(std::move(lazy_function));
5301
5302 int input_index = 0;
5303 for (const bNodeSocket *bsocket : bnode.input_sockets().drop_back(1)) {
5304 if (bsocket->is_available()) {
5305 lf::InputSocket &lf_socket = lf_node.input(input_index);
5306 graph_params.lf_inputs_by_bsocket.add(bsocket, &lf_socket);
5307 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket);
5308 input_index++;
5309 }
5310 }
5311 for (const bNodeSocket *bsocket : bnode.output_sockets()) {
5312 if (bsocket->is_available()) {
5313 lf::OutputSocket &lf_socket = lf_node.output(0);
5314 graph_params.lf_output_by_bsocket.add(bsocket, &lf_socket);
5315 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket);
5316 break;
5317 }
5318 }
5319
5320 this->build_menu_switch_node_socket_usage(bnode, graph_params);
5321 }
5322
5323 void build_menu_switch_node_socket_usage(const bNode &bnode, BuildGraphParams &graph_params)
5324 {
5325 const NodeMenuSwitch &storage = *static_cast<NodeMenuSwitch *>(bnode.storage);
5326 const NodeEnumDefinition &enum_def = storage.enum_definition;
5327
5328 const bNodeSocket *switch_input_bsocket = bnode.input_sockets()[0];
5329 Vector<const bNodeSocket *> input_bsockets(enum_def.items_num);
5330 for (const int i : IndexRange(enum_def.items_num)) {
5331 input_bsockets[i] = bnode.input_sockets()[i + 1];
5332 }
5333 const bNodeSocket *output_bsocket = bnode.output_sockets()[0];
5334
5335 lf::OutputSocket *output_is_used_socket = graph_params.usage_by_bsocket.lookup_default(
5336 output_bsocket, nullptr);
5337 if (output_is_used_socket == nullptr) {
5338 return;
5339 }
5340 graph_params.usage_by_bsocket.add(switch_input_bsocket, output_is_used_socket);
5341 if (switch_input_bsocket->is_directly_linked()) {
5342 /* The condition input is dynamic, so the usage of the other inputs is as well. */
5343 std::unique_ptr<LazyFunction> lazy_function =
5345 lf::FunctionNode &lf_node = graph_params.lf_graph.add_function(*lazy_function);
5346 scope_.add(std::move(lazy_function));
5347
5348 graph_params.lf_inputs_by_bsocket.add(switch_input_bsocket, &lf_node.input(0));
5349 for (const int i : IndexRange(enum_def.items_num)) {
5350 graph_params.usage_by_bsocket.add(input_bsockets[i], &lf_node.output(i));
5351 }
5352 }
5353 else {
5354 const int condition =
5355 switch_input_bsocket->default_value_typed<bNodeSocketValueMenu>()->value;
5356 for (const int i : IndexRange(enum_def.items_num)) {
5357 const NodeEnumItem &enum_item = enum_def.items()[i];
5358 if (enum_item.identifier == condition) {
5359 graph_params.usage_by_bsocket.add(input_bsockets[i], output_is_used_socket);
5360 break;
5361 }
5362 }
5363 }
5364 }
5365
5366 void build_undefined_node(const bNode &bnode, BuildGraphParams &graph_params)
5367 {
5368 auto &lazy_function = scope_.construct<LazyFunctionForUndefinedNode>(
5369 bnode, mapping_->lf_index_by_bsocket);
5370 lf::FunctionNode &lf_node = graph_params.lf_graph.add_function(lazy_function);
5371
5372 for (const bNodeSocket *bsocket : bnode.output_sockets()) {
5373 const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()];
5374 if (lf_index == -1) {
5375 continue;
5376 }
5377 lf::OutputSocket &lf_socket = lf_node.output(lf_index);
5378 graph_params.lf_output_by_bsocket.add(bsocket, &lf_socket);
5379 mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket);
5380 }
5381 }
5382
5383 struct TypeWithLinks {
5384 const bke::bNodeSocketType *typeinfo;
5385 Vector<const bNodeLink *> links;
5386 };
5387
5388 void insert_links_from_socket(const bNodeSocket &from_bsocket,
5389 lf::OutputSocket &from_lf_socket,
5390 BuildGraphParams &graph_params)
5391 {
5392 if (from_bsocket.owner_node().is_dangling_reroute()) {
5393 return;
5394 }
5395
5396 const bke::bNodeSocketType &from_typeinfo = *from_bsocket.typeinfo;
5397
5398 /* Group available target sockets by type so that they can be handled together. */
5399 const Vector<TypeWithLinks> types_with_links = this->group_link_targets_by_type(from_bsocket);
5400
5401 for (const TypeWithLinks &type_with_links : types_with_links) {
5402 if (type_with_links.typeinfo == nullptr) {
5403 continue;
5404 }
5405 if (type_with_links.typeinfo->geometry_nodes_cpp_type == nullptr) {
5406 continue;
5407 }
5408 const bke::bNodeSocketType &to_typeinfo = *type_with_links.typeinfo;
5409 const CPPType &to_type = *to_typeinfo.geometry_nodes_cpp_type;
5410 const Span<const bNodeLink *> links = type_with_links.links;
5411
5412 lf::OutputSocket *converted_from_lf_socket = this->insert_type_conversion_if_necessary(
5413 from_lf_socket, from_typeinfo, to_typeinfo, graph_params.lf_graph);
5414
5415 for (const bNodeLink *link : links) {
5416 const Vector<lf::InputSocket *> lf_link_targets = this->find_link_targets(*link,
5417 graph_params);
5418 if (converted_from_lf_socket == nullptr) {
5419 const void *default_value = to_type.default_value();
5420 for (lf::InputSocket *to_lf_socket : lf_link_targets) {
5421 to_lf_socket->set_default_value(default_value);
5422 }
5423 }
5424 else {
5425 for (lf::InputSocket *to_lf_socket : lf_link_targets) {
5426 graph_params.lf_graph.add_link(*converted_from_lf_socket, *to_lf_socket);
5427 }
5428 }
5429 }
5430 }
5431 }
5432
5433 Vector<TypeWithLinks> group_link_targets_by_type(const bNodeSocket &from_bsocket)
5434 {
5435 const Span<const bNodeLink *> links_from_bsocket = from_bsocket.directly_linked_links();
5436 Vector<TypeWithLinks> types_with_links;
5437 for (const bNodeLink *link : links_from_bsocket) {
5438 if (link->is_muted()) {
5439 continue;
5440 }
5441 if (!link->is_available()) {
5442 continue;
5443 }
5444 const bNodeSocket &to_bsocket = *link->tosock;
5445 bool inserted = false;
5446 for (TypeWithLinks &types_with_links : types_with_links) {
5447 if (types_with_links.typeinfo == to_bsocket.typeinfo) {
5448 types_with_links.links.append(link);
5449 inserted = true;
5450 break;
5451 }
5452 }
5453 if (inserted) {
5454 continue;
5455 }
5456 types_with_links.append({to_bsocket.typeinfo, {link}});
5457 }
5458 return types_with_links;
5459 }
5460
5461 Vector<lf::InputSocket *> find_link_targets(const bNodeLink &link,
5462 const BuildGraphParams &graph_params)
5463 {
5464 if (lf::InputSocket *lf_input_socket = graph_params.lf_input_by_border_link.lookup_default(
5465 &link, nullptr))
5466 {
5467 return {lf_input_socket};
5468 }
5469
5470 const bNodeSocket &to_bsocket = *link.tosock;
5471 if (to_bsocket.is_multi_input()) {
5472 /* TODO: Cache this index on the link. */
5473 int link_index = 0;
5474 for (const bNodeLink *multi_input_link : to_bsocket.directly_linked_links()) {
5475 if (multi_input_link == &link) {
5476 break;
5477 }
5478 if (multi_input_link->is_muted() || !multi_input_link->fromsock->is_available() ||
5479 multi_input_link->fromnode->is_dangling_reroute())
5480 {
5481 continue;
5482 }
5483 link_index++;
5484 }
5485 if (to_bsocket.owner_node().is_muted()) {
5486 if (link_index == 0) {
5487 return Vector<lf::InputSocket *>(graph_params.lf_inputs_by_bsocket.lookup(&to_bsocket));
5488 }
5489 }
5490 else {
5491 lf::InputSocket *lf_multi_input_socket =
5492 graph_params.lf_input_by_multi_input_link.lookup_default(&link, nullptr);
5493 if (!lf_multi_input_socket) {
5494 return {};
5495 }
5496 return {lf_multi_input_socket};
5497 }
5498 }
5499 else {
5500 return Vector<lf::InputSocket *>(graph_params.lf_inputs_by_bsocket.lookup(&to_bsocket));
5501 }
5502 return {};
5503 }
5504
5505 lf::OutputSocket *insert_type_conversion_if_necessary(lf::OutputSocket &from_socket,
5506 const bke::bNodeSocketType &from_typeinfo,
5507 const bke::bNodeSocketType &to_typeinfo,
5508 lf::Graph &lf_graph)
5509 {
5510 if (from_typeinfo.type == to_typeinfo.type) {
5511 return &from_socket;
5512 }
5513 if (from_typeinfo.base_cpp_type && to_typeinfo.base_cpp_type) {
5514 if (conversions_->is_convertible(*from_typeinfo.base_cpp_type, *to_typeinfo.base_cpp_type)) {
5515 const MultiFunction &multi_fn = *conversions_->get_conversion_multi_function(
5516 mf::DataType::ForSingle(*from_typeinfo.base_cpp_type),
5517 mf::DataType::ForSingle(*to_typeinfo.base_cpp_type));
5518 auto &fn = scope_.construct<LazyFunctionForMultiFunctionConversion>(multi_fn);
5519 lf::Node &conversion_node = lf_graph.add_function(fn);
5520 lf_graph.add_link(from_socket, conversion_node.input(0));
5521 return &conversion_node.output(0);
5522 }
5523 }
5524 return nullptr;
5525 }
5526
5527 void add_default_inputs(BuildGraphParams &graph_params)
5528 {
5529 for (auto item : graph_params.lf_inputs_by_bsocket.items()) {
5530 const bNodeSocket &bsocket = *item.key;
5531 const Span<lf::InputSocket *> lf_sockets = item.value;
5532 for (lf::InputSocket *lf_socket : lf_sockets) {
5533 if (lf_socket->origin() != nullptr) {
5534 /* Is linked already. */
5535 continue;
5536 }
5537 this->add_default_input(bsocket, *lf_socket, graph_params);
5538 }
5539 }
5540 }
5541
5542 void add_default_input(const bNodeSocket &input_bsocket,
5543 lf::InputSocket &input_lf_socket,
5544 BuildGraphParams &graph_params)
5545 {
5546 if (this->try_add_implicit_input(input_bsocket, input_lf_socket, graph_params)) {
5547 return;
5548 }
5549 GMutablePointer value = get_socket_default_value(scope_.linear_allocator(), input_bsocket);
5550 if (value.get() == nullptr) {
5551 /* Not possible to add a default value. */
5552 return;
5553 }
5554 input_lf_socket.set_default_value(value.get());
5555 if (!value.type()->is_trivially_destructible()) {
5556 scope_.add_destruct_call([value]() mutable { value.destruct(); });
5557 }
5558 }
5559
5560 bool try_add_implicit_input(const bNodeSocket &input_bsocket,
5561 lf::InputSocket &input_lf_socket,
5562 BuildGraphParams &graph_params)
5563 {
5564 const bNode &bnode = input_bsocket.owner_node();
5565 const SocketDeclaration *socket_decl = input_bsocket.runtime->declaration;
5566 if (socket_decl == nullptr) {
5567 return false;
5568 }
5569 if (socket_decl->input_field_type != InputSocketFieldType::Implicit) {
5570 return false;
5571 }
5572 const ImplicitInputValueFn *implicit_input_fn = socket_decl->implicit_input_fn.get();
5573 if (implicit_input_fn == nullptr) {
5574 return false;
5575 }
5576 std::function<void(void *)> init_fn = [&bnode, implicit_input_fn](void *r_value) {
5577 (*implicit_input_fn)(bnode, r_value);
5578 };
5579 const CPPType &type = input_lf_socket.type();
5580 auto &lazy_function = scope_.construct<LazyFunctionForImplicitInput>(type, std::move(init_fn));
5581 lf::Node &lf_node = graph_params.lf_graph.add_function(lazy_function);
5582 graph_params.lf_graph.add_link(lf_node.output(0), input_lf_socket);
5583 return true;
5584 }
5585
5591 void build_attribute_propagation_input_node(lf::Graph &lf_graph)
5592 {
5593 const aal::RelationsInNode &tree_relations =
5594 btree_.runtime->anonymous_attribute_inferencing->tree_relations;
5595 Vector<int> output_indices;
5596 for (const aal::PropagateRelation &relation : tree_relations.propagate_relations) {
5597 output_indices.append_non_duplicates(relation.to_geometry_output);
5598 }
5599
5600 for (const int i : output_indices.index_range()) {
5601 const int output_index = output_indices[i];
5602 const char *name = btree_.interface_outputs()[output_index]->name;
5603 lf::GraphInputSocket &lf_socket = lf_graph.add_input(
5605 StringRef("Propagate: ") + (name ? name : ""));
5606 attribute_set_by_geometry_output_.add(output_index, &lf_socket);
5607 }
5608 }
5609
5614 lf::OutputSocket *or_socket_usages(MutableSpan<lf::OutputSocket *> usages,
5615 BuildGraphParams &graph_params)
5616 {
5617 if (usages.is_empty()) {
5618 return nullptr;
5619 }
5620 if (usages.size() == 1) {
5621 return usages[0];
5622 }
5623
5624 std::sort(usages.begin(), usages.end());
5625 return graph_params.socket_usages_combination_cache.lookup_or_add_cb_as(usages, [&]() {
5626 auto &logical_or_fn = scope_.construct<LazyFunctionForLogicalOr>(usages.size());
5627 lf::Node &logical_or_node = graph_params.lf_graph.add_function(logical_or_fn);
5628
5629 for (const int i : usages.index_range()) {
5630 graph_params.lf_graph.add_link(*usages[i], logical_or_node.input(i));
5631 }
5632 return &logical_or_node.output(0);
5633 });
5634 }
5635
5636 void build_output_socket_usages(const bNode &bnode, BuildGraphParams &graph_params)
5637 {
5638 /* Output sockets are used when any of their linked inputs are used. */
5639 for (const bNodeSocket *socket : bnode.output_sockets()) {
5640 if (!socket->is_available()) {
5641 continue;
5642 }
5643 /* Determine when linked target sockets are used. */
5644 Vector<lf::OutputSocket *> target_usages;
5645 for (const bNodeLink *link : socket->directly_linked_links()) {
5646 if (!link->is_used()) {
5647 continue;
5648 }
5649 const bNodeSocket &target_socket = *link->tosock;
5650 if (lf::OutputSocket *is_used_socket = graph_params.usage_by_bsocket.lookup_default(
5651 &target_socket, nullptr))
5652 {
5653 target_usages.append_non_duplicates(is_used_socket);
5654 }
5655 }
5656 /* Combine target socket usages into the usage of the current socket. */
5657 graph_params.usage_by_bsocket.add(socket,
5658 this->or_socket_usages(target_usages, graph_params));
5659 }
5660 }
5661
5662 void build_group_input_usages(BuildGraphParams &graph_params)
5663 {
5664 const Span<const bNode *> group_input_nodes = btree_.group_input_nodes();
5665 for (const int i : btree_.interface_inputs().index_range()) {
5666 Vector<lf::OutputSocket *> target_usages;
5667 for (const bNode *group_input_node : group_input_nodes) {
5668 if (lf::OutputSocket *lf_socket = graph_params.usage_by_bsocket.lookup_default(
5669 &group_input_node->output_socket(i), nullptr))
5670 {
5671 target_usages.append_non_duplicates(lf_socket);
5672 }
5673 }
5674
5675 lf::OutputSocket *lf_socket = this->or_socket_usages(target_usages, graph_params);
5676 lf::InputSocket *lf_group_output = const_cast<lf::InputSocket *>(
5677 group_input_usage_sockets_[i]);
5678 InputUsageHint input_usage_hint;
5679 if (lf_socket == nullptr) {
5680 static const bool static_false = false;
5681 lf_group_output->set_default_value(&static_false);
5682 input_usage_hint.type = InputUsageHintType::Never;
5683 }
5684 else {
5685 graph_params.lf_graph.add_link(*lf_socket, *lf_group_output);
5686 if (lf_socket->node().is_interface()) {
5687 /* Can support slightly more complex cases where it depends on more than one output in
5688 * the future. */
5689 input_usage_hint.type = InputUsageHintType::DependsOnOutput;
5690 input_usage_hint.output_dependencies = {
5691 group_output_used_sockets_.first_index_of(lf_socket)};
5692 }
5693 else {
5694 input_usage_hint.type = InputUsageHintType::DynamicSocket;
5695 }
5696 }
5697 lf_graph_info_->mapping.group_input_usage_hints.append(std::move(input_usage_hint));
5698 }
5699 }
5700
5712 void fix_link_cycles(lf::Graph &lf_graph, const Set<lf::InputSocket *> &socket_usage_inputs)
5713 {
5714 lf_graph.update_socket_indices();
5715 const int sockets_num = lf_graph.socket_num();
5716
5717 struct SocketState {
5718 bool done = false;
5719 bool in_stack = false;
5720 };
5721
5722 Array<SocketState> socket_states(sockets_num);
5723
5724 Vector<lf::Socket *> lf_sockets_to_check;
5725 for (lf::Node *lf_node : lf_graph.nodes()) {
5726 if (lf_node->is_function()) {
5727 for (lf::OutputSocket *lf_socket : lf_node->outputs()) {
5728 if (lf_socket->targets().is_empty()) {
5729 lf_sockets_to_check.append(lf_socket);
5730 }
5731 }
5732 }
5733 if (lf_node->outputs().is_empty()) {
5734 for (lf::InputSocket *lf_socket : lf_node->inputs()) {
5735 lf_sockets_to_check.append(lf_socket);
5736 }
5737 }
5738 }
5739 Vector<lf::Socket *> lf_socket_stack;
5740 while (!lf_sockets_to_check.is_empty()) {
5741 lf::Socket *lf_inout_socket = lf_sockets_to_check.last();
5742 lf::Node &lf_node = lf_inout_socket->node();
5743 SocketState &state = socket_states[lf_inout_socket->index_in_graph()];
5744
5745 if (!state.in_stack) {
5746 lf_socket_stack.append(lf_inout_socket);
5747 state.in_stack = true;
5748 }
5749
5750 Vector<lf::Socket *, 16> lf_origin_sockets;
5751 if (lf_inout_socket->is_input()) {
5752 lf::InputSocket &lf_input_socket = lf_inout_socket->as_input();
5753 if (lf::OutputSocket *lf_origin_socket = lf_input_socket.origin()) {
5754 lf_origin_sockets.append(lf_origin_socket);
5755 }
5756 }
5757 else {
5758 lf::OutputSocket &lf_output_socket = lf_inout_socket->as_output();
5759 if (lf_node.is_function()) {
5760 lf::FunctionNode &lf_function_node = static_cast<lf::FunctionNode &>(lf_node);
5761 const lf::LazyFunction &fn = lf_function_node.function();
5762 fn.possible_output_dependencies(
5763 lf_output_socket.index(), [&](const Span<int> input_indices) {
5764 for (const int input_index : input_indices) {
5765 lf_origin_sockets.append(&lf_node.input(input_index));
5766 }
5767 });
5768 }
5769 }
5770
5771 bool pushed_socket = false;
5772 bool detected_cycle = false;
5773 for (lf::Socket *lf_origin_socket : lf_origin_sockets) {
5774 if (socket_states[lf_origin_socket->index_in_graph()].in_stack) {
5775 /* A cycle has been detected. The cycle is broken by removing a link and replacing it
5776 * with a constant "true" input. This can only affect inputs which determine whether a
5777 * specific value is used. Therefore, setting it to a constant true can result in more
5778 * computation later, but does not change correctness.
5779 *
5780 * After the cycle is broken, the cycle-detection is "rolled back" to the socket where
5781 * the first socket of the cycle was found. This is necessary in case another cycle
5782 * goes through this socket. */
5783
5784 detected_cycle = true;
5785 const int index_in_socket_stack = lf_socket_stack.first_index_of(lf_origin_socket);
5786 const int index_in_sockets_to_check = lf_sockets_to_check.first_index_of(
5787 lf_origin_socket);
5788 const Span<lf::Socket *> cycle = lf_socket_stack.as_span().drop_front(
5789 index_in_socket_stack);
5790
5791 bool broke_cycle = false;
5792 for (lf::Socket *lf_cycle_socket : cycle) {
5793 if (lf_cycle_socket->is_input() &&
5794 socket_usage_inputs.contains(&lf_cycle_socket->as_input()))
5795 {
5796 lf::InputSocket &lf_cycle_input_socket = lf_cycle_socket->as_input();
5797 lf_graph.clear_origin(lf_cycle_input_socket);
5798 static const bool static_true = true;
5799 lf_cycle_input_socket.set_default_value(&static_true);
5800 broke_cycle = true;
5801 }
5802 /* This is actually removed from the stack when it is resized below. */
5803 SocketState &lf_cycle_socket_state = socket_states[lf_cycle_socket->index_in_graph()];
5804 lf_cycle_socket_state.in_stack = false;
5805 }
5806 if (!broke_cycle) {
5808 }
5809 /* Roll back algorithm by removing the sockets that corresponded to the cycle from the
5810 * stacks. */
5811 lf_socket_stack.resize(index_in_socket_stack);
5812 /* The +1 is there so that the socket itself is not removed. */
5813 lf_sockets_to_check.resize(index_in_sockets_to_check + 1);
5814 break;
5815 }
5816 else if (!socket_states[lf_origin_socket->index_in_graph()].done) {
5817 lf_sockets_to_check.append(lf_origin_socket);
5818 pushed_socket = true;
5819 }
5820 }
5821 if (detected_cycle) {
5822 continue;
5823 }
5824 if (pushed_socket) {
5825 continue;
5826 }
5827
5828 state.done = true;
5829 state.in_stack = false;
5830 lf_sockets_to_check.pop_last();
5831 lf_socket_stack.pop_last();
5832 }
5833 }
5834};
5835
5837 const bNodeTree &btree)
5838{
5839 btree.ensure_topology_cache();
5840 btree.ensure_interface_cache();
5841 if (btree.has_available_link_cycle()) {
5842 return nullptr;
5843 }
5844 const bNodeTreeZones *tree_zones = btree.zones();
5845 if (tree_zones == nullptr) {
5846 return nullptr;
5847 }
5848 for (const std::unique_ptr<bNodeTreeZone> &zone : tree_zones->zones) {
5849 if (zone->input_node == nullptr || zone->output_node == nullptr) {
5850 /* Simulations and repeats need input and output nodes. */
5851 return nullptr;
5852 }
5853 }
5854 if (const ID *id_orig = DEG_get_original_id(const_cast<ID *>(&btree.id))) {
5855 if (id_orig->tag & ID_TAG_MISSING) {
5856 return nullptr;
5857 }
5858 }
5859 for (const bNodeTreeInterfaceSocket *interface_bsocket : btree.interface_inputs()) {
5860 const bke::bNodeSocketType *typeinfo = interface_bsocket->socket_typeinfo();
5861 if (typeinfo->geometry_nodes_cpp_type == nullptr) {
5862 return nullptr;
5863 }
5864 }
5865 for (const bNodeTreeInterfaceSocket *interface_bsocket : btree.interface_outputs()) {
5866 const bke::bNodeSocketType *typeinfo = interface_bsocket->socket_typeinfo();
5867 if (typeinfo->geometry_nodes_cpp_type == nullptr) {
5868 return nullptr;
5869 }
5870 }
5871
5872 std::unique_ptr<GeometryNodesLazyFunctionGraphInfo> &lf_graph_info_ptr =
5873 btree.runtime->geometry_nodes_lazy_function_graph_info;
5874
5875 if (lf_graph_info_ptr) {
5876 return lf_graph_info_ptr.get();
5877 }
5878 std::lock_guard lock{btree.runtime->geometry_nodes_lazy_function_graph_info_mutex};
5879 if (lf_graph_info_ptr) {
5880 return lf_graph_info_ptr.get();
5881 }
5882
5883 auto lf_graph_info = std::make_unique<GeometryNodesLazyFunctionGraphInfo>();
5884 GeometryNodesLazyFunctionBuilder builder{btree, *lf_graph_info};
5885 builder.build();
5886
5887 lf_graph_info_ptr = std::move(lf_graph_info);
5888 return lf_graph_info_ptr.get();
5889}
5890
5895
5896void GeoNodesLFLocalUserData::ensure_tree_logger(const GeoNodesLFUserData &user_data) const
5897{
5899 tree_logger_.emplace(&log->get_local_tree_logger(*user_data.compute_context));
5900 return;
5901 }
5902 this->tree_logger_.emplace(nullptr);
5903}
5904
5905std::optional<FoundNestedNodeID> find_nested_node_id(const GeoNodesLFUserData &user_data,
5906 const int node_id)
5907{
5908 FoundNestedNodeID found;
5909 Vector<int> node_ids;
5910 for (const ComputeContext *context = user_data.compute_context; context != nullptr;
5911 context = context->parent())
5912 {
5913 if (const auto *node_context = dynamic_cast<const bke::GroupNodeComputeContext *>(context)) {
5914 node_ids.append(node_context->node_id());
5915 }
5916 else if (dynamic_cast<const bke::RepeatZoneComputeContext *>(context) != nullptr) {
5917 found.is_in_loop = true;
5918 }
5919 else if (dynamic_cast<const bke::SimulationZoneComputeContext *>(context) != nullptr) {
5920 found.is_in_simulation = true;
5921 }
5922 else if (dynamic_cast<const bke::ForeachGeometryElementZoneComputeContext *>(context) !=
5923 nullptr)
5924 {
5925 found.is_in_loop = true;
5926 }
5927 }
5928 std::reverse(node_ids.begin(), node_ids.end());
5929 node_ids.append(node_id);
5930 const bNestedNodeRef *nested_node_ref =
5931 user_data.call_data->root_ntree->nested_node_ref_from_node_id_path(node_ids);
5932 if (nested_node_ref == nullptr) {
5933 return std::nullopt;
5934 }
5935 found.id = nested_node_ref->id;
5936 return found;
5937}
5938
5940{
5941 if (Depsgraph *graph = this->extra) {
5942 DEG_graph_free(graph);
5943 }
5944}
5945
5946static const ID *get_only_evaluated_id(const Depsgraph &depsgraph, const ID &id_orig)
5947{
5948 const ID *id = DEG_get_evaluated_id(&depsgraph, const_cast<ID *>(&id_orig));
5949 if (id == &id_orig) {
5950 return nullptr;
5951 }
5952 return id;
5953}
5954
5956{
5957 if (const Depsgraph *graph = this->active) {
5958 if (const ID *id = get_only_evaluated_id(*graph, id_orig)) {
5959 return id;
5960 }
5961 }
5962 if (const Depsgraph *graph = this->extra) {
5963 if (const ID *id = get_only_evaluated_id(*graph, id_orig)) {
5964 return id;
5965 }
5966 }
5967 return nullptr;
5968}
5969
5971{
5972 if (this->modifier_data) {
5973 return this->modifier_data->self_object;
5974 }
5975 if (this->operator_data) {
5977 const_cast<Object *>(this->operator_data->self_object_orig));
5978 }
5979 return nullptr;
5980}
5981
5982} // namespace blender::nodes
Low-level operations for curves.
Low-level operations for grease pencil.
#define NODE_REROUTE
Definition BKE_node.hh:804
#define GEO_NODE_MENU_SWITCH
Definition BKE_node.hh:1354
#define GEO_NODE_GIZMO_LINEAR
Definition BKE_node.hh:1371
#define NODE_CUSTOM_GROUP
Definition BKE_node.hh:807
#define GEO_NODE_VIEWER
Definition BKE_node.hh:1201
#define GEO_NODE_GIZMO_DIAL
Definition BKE_node.hh:1372
#define GEO_NODE_FOREACH_GEOMETRY_ELEMENT_OUTPUT
Definition BKE_node.hh:1379
#define NODE_GROUP_OUTPUT
Definition BKE_node.hh:806
#define GEO_NODE_SIMULATION_OUTPUT
Definition BKE_node.hh:1331
#define GEO_NODE_SWITCH
Definition BKE_node.hh:1188
#define GEO_NODE_BAKE
Definition BKE_node.hh:1350
#define NODE_GROUP
Definition BKE_node.hh:800
#define GEO_NODE_WARNING
Definition BKE_node.hh:1377
#define GEO_NODE_GIZMO_TRANSFORM
Definition BKE_node.hh:1373
#define GEO_NODE_REPEAT_OUTPUT
Definition BKE_node.hh:1338
#define NODE_FRAME
Definition BKE_node.hh:803
#define NODE_GROUP_INPUT
Definition BKE_node.hh:805
#define GEO_NODE_INDEX_SWITCH
Definition BKE_node.hh:1348
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BUFFER_FOR_CPP_TYPE_VALUE(type, variable_name)
#define ELEM(...)
#define TIP_(msgid)
void DEG_graph_free(Depsgraph *graph)
Definition depsgraph.cc:301
ID * DEG_get_original_id(ID *id)
ID * DEG_get_evaluated_id(const Depsgraph *depsgraph, ID *id)
Object * DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
ID and Library types, which are fundamental for SDNA.
@ ID_TAG_MISSING
Definition DNA_ID.h:813
@ CD_PROP_STRING
eNodeSocketDatatype
@ SOCK_GEOMETRY
volatile int lock
__forceinline float extract(const int4 &b)
Definition binning.cpp:27
#define output
int64_t size() const
Definition BLI_array.hh:245
const T * end() const
Definition BLI_array.hh:314
IndexRange index_range() const
Definition BLI_array.hh:349
void fill(const T &value) const
Definition BLI_array.hh:261
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:388
const T * begin() const
Definition BLI_array.hh:310
void value_initialize_indices(void *ptr, const IndexMask &mask) const
StringRefNull name() const
static const CPPType & get()
void copy_construct(const void *src, void *dst) const
void to_static_type_tag(const Fn &fn) const
void move_construct(void *src, void *dst) const
void value_initialize(void *ptr) const
void print_stack(std::ostream &stream, StringRef name) const
const ComputeContextHash & hash() const
void get_to_uninitialized(int64_t index, void *r_value) const
constexpr int64_t size() const
static constexpr IndexRange from_begin_end(const int64_t begin, const int64_t end)
constexpr IndexRange index_range() const
destruct_ptr< T > construct(Args &&...args)
void * allocate(const int64_t size, const int64_t alignment)
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:271
const Value & lookup(const Key &key) const
Definition BLI_map.hh:506
Value lookup_default(const Key &key, const Value &default_value) const
Definition BLI_map.hh:531
Value & lookup_or_add_cb(const Key &key, const CreateValueF &create_value)
Definition BLI_map.hh:582
void add_new(const Key &key, const Value &value)
Definition BLI_map.hh:241
int64_t size() const
Definition BLI_map.hh:927
ItemIterator items() const
Definition BLI_map.hh:864
T & construct(Args &&...args)
void add_destruct_call(Func func)
LinearAllocator & linear_allocator()
T * add(std::unique_ptr< T > resource)
constexpr const T & first() const
Definition BLI_span.hh:316
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
constexpr bool is_empty() const
Definition BLI_span.hh:261
constexpr bool contains(const T &value) const
Definition BLI_span.hh:278
static const VectorCPPType * get_from_value(const CPPType &value)
void add_new(const Key &key)
int64_t index_of_try(const Key &key) const
IndexRange index_range() const
int64_t size() const
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)
Span< T > as_span() const
const T & first() const
std::shared_ptr< Set< std::string > > names
bool is_builtin(const StringRef attribute_id) const
void foreach_attribute(const FunctionRef< void(const AttributeIter &)> fn) const
GVArray adapt_domain(const GVArray &varray, const AttrDomain from_domain, const AttrDomain to_domain) const
GAttributeReader lookup(const StringRef attribute_id) const
int domain_size(const AttrDomain domain) const
bool contains(const StringRef attribute_id) const
MutableAttributeAccessor attributes_for_write()
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_
virtual std::optional< MutableAttributeAccessor > attributes_for_write()
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type)
void * allocate_single(eNodeSocketDatatype socket_type)
Vector< const bNodeLink * > border_links
Vector< bNodeTreeZone * > root_zones
const bNodeTreeZone * get_zone_by_node(const int32_t node_id) const
Vector< std::unique_ptr< bNodeTreeZone > > zones
Vector< const bNode * > nodes_outside_zones
bke::CurvesGeometry & strokes_for_write()
const bke::CurvesGeometry & strokes() const
virtual void for_each_field_input_recursive(FunctionRef< void(const FieldInput &)> fn) const
Definition field.cc:587
static std::shared_ptr< FieldOperation > Create(std::shared_ptr< const mf::MultiFunction > function, Vector< GField > inputs={})
Definition FN_field.hh:244
const FieldNode & node() const
Definition FN_field.hh:137
FunctionNode & add_function(const LazyFunction &fn)
void add_link(OutputSocket &from, InputSocket &to)
GraphOutputSocket & add_output(const CPPType &type, std::string name="")
std::string to_dot(const ToDotOptions &options={}) const
GraphInputSocket & add_input(const CPPType &type, std::string name="")
virtual void * init_storage(LinearAllocator<> &allocator) const
virtual std::string output_name(int index) const
virtual void destruct_storage(void *storage) const
virtual std::string input_name(int index) const
void execute(Params &params, const Context &context) const
const InputSocket & input(int index) const
const OutputSocket & output(int index) const
ParamType param_type(int param_index) const
virtual void call(const IndexMask &mask, Params params, Context context) const =0
IndexMask complement(const IndexMask &universe, IndexMaskMemory &memory) const
void foreach_index(Fn &&fn) const
void execute_node(const lf::FunctionNode &node, lf::Params &params, const lf::Context &context) const
Vector< const lf::FunctionNode * > get_nodes_with_side_effects(const lf::Context &context) const override
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 &) const override
void execute_impl(lf::Params &params, const lf::Context &) const override
static const LazyFunctionForAnonymousAttributeSetJoin & get_cached(const int amount, ResourceScope &scope)
void execute_impl(lf::Params &params, const lf::Context &context) const override
void execute_impl(lf::Params &params, const lf::Context &context) const override
void initialize_execution_graph(lf::Params &params, ForeachGeometryElementEvalStorage &eval_storage, const NodeGeometryForeachGeometryElementOutput &node_storage) const
void prepare_components(lf::Params &params, ForeachGeometryElementEvalStorage &eval_storage, const NodeGeometryForeachGeometryElementOutput &node_storage) const
std::optional< Array< GeometrySet > > try_extract_element_geometries(const GeometrySet &main_geometry, const ForeachElementComponentID &id, const IndexMask &mask, const AttributeFilter &attribute_filter) const
void * init_storage(LinearAllocator<> &allocator) const override
LazyFunctionForForeachGeometryElementZone(const bNodeTree &btree, const bNodeTreeZone &zone, ZoneBuildInfo &zone_info, const ZoneBodyFunction &body_fn)
void build_graph_contents(ForeachGeometryElementEvalStorage &eval_storage, const NodeGeometryForeachGeometryElementOutput &node_storage, Span< lf::GraphInputSocket * > graph_inputs, Span< lf::GraphOutputSocket * > graph_outputs) const
void execute_impl(lf::Params &params, const lf::Context &context) const override
std::string anonymous_attribute_name_for_output(const GeoNodesLFUserData &user_data, const int output_index) const
void output_anonymous_attribute_field(lf::Params &params, const GeoNodesLFUserData &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
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
void execute_impl(lf::Params &params, const lf::Context &) const override
void execute_impl(lf::Params &params, const lf::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 &) const override
void execute_impl(lf::Params &params, const lf::Context &) const override
LazyFunctionForMutedNode(const bNode &node, MutableSpan< int > r_lf_index_by_bsocket)
std::string output_name(const int i) const override
LazyFunctionForRepeatZone(const bNodeTree &btree, const bNodeTreeZone &zone, ZoneBuildInfo &zone_info, const ZoneBodyFunction &body_fn)
void * init_storage(LinearAllocator<> &allocator) const override
void initialize_execution_graph(lf::Params &params, RepeatEvalStorage &eval_storage, const NodeGeometryRepeatOutput &node_storage, GeoNodesLFUserData &user_data, GeoNodesLFLocalUserData &local_user_data) const
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
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
void execute_node(const lf::FunctionNode &node, lf::Params &params, const lf::Context &context) const
Vector< const lf::FunctionNode * > get_nodes_with_side_effects(const lf::Context &context) const override
linear_allocator::ChunkedList< WarningWithNode > node_warnings
linear_allocator::ChunkedList< DebugMessage > debug_messages
void log_viewer_node(const bNode &viewer_node, bke::GeometrySet geometry)
void log_value(const bNode &node, const bNodeSocket &socket, GPointer value)
local_group_size(16, 16) .push_constant(Type b
const Depsgraph * depsgraph
static ushort indices[]
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_device_inline float3 log(float3 v)
ccl_device_inline float4 mask(const int4 mask, const float4 a)
static ulong state[N]
int main()
void fill_index_range(MutableSpan< T > span, const T start=0)
void foreach_1_index(const BitSpanT &data, Fn &&fn)
std::optional< eNodeSocketDatatype > geo_nodes_base_cpp_type_to_socket_type(const CPPType &type)
Definition node.cc:4471
std::optional< AttrDomain > try_detect_field_domain(const GeometryComponent &component, const fn::GField &field)
const DataTypeConversions & get_implicit_type_conversions()
eCustomDataType cpp_type_to_custom_data_type(const CPPType &type)
bNodeType NodeTypeUndefined
Definition node.cc:135
bool try_capture_field_on_geometry(MutableAttributeAccessor attributes, const fn::FieldContext &field_context, const StringRef attribute_id, AttrDomain domain, const fn::Field< bool > &selection, const fn::GField &field)
const CPPType * socket_type_to_geo_nodes_base_cpp_type(eNodeSocketDatatype type)
Definition node.cc:4438
std::string hash_to_anonymous_attribute_name(Args &&...args)
bke::GeometrySet join_geometries(Span< bke::GeometrySet > geometries, const bke::AttributeFilter &attribute_filter, const std::optional< Span< bke::GeometryComponent::Type > > &component_types_to_join=std::nullopt)
static Type to_type(const eGPUType type)
static std::optional< AttrDomain > get_foreach_attribute_propagation_target_domain(const GeometryComponent::Type component_type)
static const ID * get_only_evaluated_id(const Depsgraph &depsgraph, const ID &id_orig)
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)
static void execute_multi_function_on_value_variant__single(const MultiFunction &fn, const Span< SocketValueVariant * > input_values, const Span< SocketValueVariant * > output_values)
std::unique_ptr< LazyFunction > get_warning_node_lazy_function(const bNode &node)
static bool ignore_zone_bsocket(const bNodeSocket &bsocket)
static bool should_log_socket_values_for_context(const GeoNodesLFUserData &user_data, const ComputeContextHash hash)
std::unique_ptr< LazyFunction > get_menu_switch_node_socket_usage_lazy_function(const bNode &node)
static std::string zone_wrapper_input_name(const ZoneBuildInfo &zone_info, const bNodeTreeZone &zone, const Span< lf::Input > inputs, const int lf_socket_i)
static bool gizmo_is_used(const GeoNodesLFUserData &user_data, const lf::FunctionNode &lf_gizmo_node)
std::unique_ptr< LazyFunction > get_simulation_input_lazy_function(const bNodeTree &node_tree, const bNode &node, GeometryNodesLazyFunctionGraphInfo &own_lf_graph_info)
static const CPPType * get_vector_type(const CPPType &type)
static void initialize_zone_wrapper(const bNodeTreeZone &zone, ZoneBuildInfo &zone_info, const ZoneBodyFunction &body_fn, Vector< lf::Input > &r_inputs, Vector< lf::Output > &r_outputs)
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)
void set_default_remaining_node_outputs(lf::Params &params, const bNode &node)
std::function< void(const bNode &node, void *r_value)> ImplicitInputValueFn
std::optional< FoundNestedNodeID > find_nested_node_id(const GeoNodesLFUserData &user_data, const int node_id)
static std::string zone_wrapper_output_name(const ZoneBuildInfo &zone_info, const bNodeTreeZone &zone, const Span< lf::Output > outputs, const int lf_socket_i)
Map< Vector< lf::OutputSocket * >, lf::OutputSocket * > JoinAttributeSetsCache
static void 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)
std::unique_ptr< LazyFunction > get_menu_switch_node_lazy_function(const bNode &node, GeometryNodesLazyFunctionGraphInfo &lf_graph_info)
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)
static GMutablePointer get_socket_default_value(LinearAllocator<> &allocator, const bNodeSocket &bsocket)
static void set_default_value_for_output_socket(lf::Params &params, const int lf_index, const bNodeSocket &bsocket)
static const CPPType * get_socket_cpp_type(const bke::bNodeSocketType &typeinfo)
std::unique_ptr< T, DestructValueAtAddress< T > > destruct_ptr
static blender::bke::bNodeSocketTemplate outputs[]
static blender::bke::bNodeSocketTemplate inputs[]
#define I
#define hash
Definition noise.c:154
Definition DNA_ID.h:413
char name[66]
Definition DNA_ID.h:425
NodeForeachGeometryElementInputItem * items
NodeForeachGeometryElementInputItems input_items
NodeForeachGeometryElementMainItems main_items
NodeForeachGeometryElementGenerationItems generation_items
NodeEnumDefinition enum_definition
bNodeSocketRuntimeHandle * runtime
bNodeSocketTypeHandle * typeinfo
void * default_value
char identifier[64]
bNodeTreeRuntimeHandle * runtime
bNodeTypeHandle * typeinfo
struct ID * id
char name[64]
void * storage
int32_t identifier
bool allow_skip(const StringRef name) const
void keep_only(Span< GeometryComponent::Type > component_types)
GeometryComponent & get_component_for_write(GeometryComponent::Type component_type)
const GreasePencil * get_grease_pencil() const
Vector< const GeometryComponent * > get_components() const
bool has(const GeometryComponent::Type component_type) const
const Curves * get_curves() const
const Instances * get_instances() const
const PointCloud * get_pointcloud() const
const Mesh * get_mesh() const
Defines a socket type.
Definition BKE_node.hh:151
const blender::CPPType * geometry_nodes_cpp_type
Definition BKE_node.hh:195
SocketGetGeometryNodesCPPValueFunction get_geometry_nodes_cpp_value
Definition BKE_node.hh:197
MultiValueMap< int, lf::InputSocket * > lf_attribute_set_input_by_caller_propagation_index
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_attribute_set_input_by_output_geometry_bsocket
MultiValueMap< int, lf::InputSocket * > lf_attribute_set_input_by_field_source_index
Map< const bNodeLink *, lf::InputSocket * > lf_input_by_multi_input_link
std::optional< Array< GeometrySet > > element_geometries
void emplace_field_context(const GeometrySet &geometry)
MutableAttributeAccessor attributes_for_write(GeometrySet &geometry) const
std::optional< bke::GeometryFieldContext > field_context
Array< Array< SocketValueVariant > > item_input_values
std::optional< LazyFunctionForReduceForeachGeometryElement > reduce_function
std::optional< ForeachGeometryElementZoneSideEffectProvider > side_effect_provider
std::optional< ForeachGeometryElementNodeExecuteWrapper > body_execute_wrapper
const Set< ComputeContextHash > * socket_log_contexts
const GeoNodesSideEffectNodes * side_effect_nodes
geo_eval_log::GeoTreeLogger * try_get_tree_logger(const GeoNodesLFUserData &user_data) const
destruct_ptr< lf::LocalUserData > get_local(LinearAllocator<> &allocator) override
MultiValueMap< std::pair< ComputeContextHash, int32_t >, int > iterations_by_iteration_zone
MultiValueMap< ComputeContextHash, const lf::FunctionNode * > nodes_by_context
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::@1337::@1339 attributes_to_propagate
struct blender::nodes::GeometryNodesGroupFunction::@1337 inputs
GeometryNodesLazyFunctionBuilder(const bNodeTree &btree, GeometryNodesLazyFunctionGraphInfo &lf_graph_info)
void handle_main_items_and_geometry(lf::Params &params, const lf::Context &context) const
void handle_generation_items_group(lf::Params &params, const lf::Context &context, int geometry_item_i, IndexRange generation_items_range) const
void handle_generation_item_groups(lf::Params &params, const lf::Context &context, int first_valid_item_i) const
void execute_impl(lf::Params &params, const lf::Context &context) const override
bool handle_generation_items_group_lazyness(lf::Params &params, const lf::Context &context, int geometry_item_i, IndexRange generation_items_range) const
void handle_generation_items(lf::Params &params, const lf::Context &context) const
std::shared_ptr< mf::MultiFunction > owned_fn
std::optional< LazyFunctionForLogicalOr > or_function
VectorSet< lf::FunctionNode * > lf_body_nodes
std::optional< lf::GraphExecutor > graph_executor
std::optional< RepeatBodyNodeExecuteWrapper > body_execute_wrapper
std::optional< RepeatZoneSideEffectProvider > side_effect_provider
struct blender::nodes::ZoneFunctionIndices::@1335 outputs
struct blender::nodes::ZoneFunctionIndices::@1334 inputs
wmTimer * timer