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
22
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 }
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,
254 own_lf_graph_info_.mapping.lf_input_index_for_output_bsocket_usage,
255 own_lf_graph_info_.mapping.lf_input_index_for_attribute_propagation_to_output,
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 =
274 own_lf_graph_info_.mapping.lf_input_index_for_attribute_propagation_to_output
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
528static void execute_multi_function_on_value_variant(const MultiFunction &fn,
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:
646 LazyFunctionForMultiFunctionConversion(const MultiFunction &fn) : fn_(fn)
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,
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)) {
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) {
980 return;
981 }
982 const std::optional<FoundNestedNodeID> found_id = find_nested_node_id(
983 user_data, output_bnode_->identifier);
984 if (!found_id) {
986 return;
987 }
988 if (found_id->is_in_loop) {
990 return;
991 }
992 SimulationZoneBehavior *zone_behavior = call_data.simulation_params->get(found_id->id);
993 if (!zone_behavior) {
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) {
1035 return;
1036 }
1037 const std::optional<FoundNestedNodeID> found_id = find_nested_node_id(user_data,
1038 bnode_->identifier);
1039 if (!found_id) {
1041 return;
1042 }
1043 if (found_id->is_in_loop || found_id->is_in_simulation) {
1045 return;
1046 }
1047 BakeNodeBehavior *behavior = user_data.call_data->bake_params->get(found_id->id);
1048 if (!behavior) {
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;
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()) {
1108 own_lf_graph_info.mapping.lf_input_index_for_output_bsocket_usage
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 =
1120 group_lf_graph_info.function.inputs.attributes_to_propagate.geometry_outputs[i];
1121 const bNodeSocket &output_bsocket = group_node_.output_socket(output_index);
1122 own_lf_graph_info.mapping.lf_input_index_for_attribute_propagation_to_output
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. */
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>());
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();
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(
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
1583
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,
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;
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(
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(
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,
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;
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
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. */
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 :
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;
2188 const lf::Context &context,
2189 int first_valid_item_i) const;
2191 const lf::Context &context,
2192 int geometry_item_i,
2193 IndexRange generation_items_range) const;
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;
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
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) {
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();
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();
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 :
2767 body_fn_.indices.inputs.attributes_by_caller_propagation_index.items())
2768 {
2769 lf_graph.add_link(
2770 *graph_inputs[zone_info_.indices.inputs.attributes_by_caller_propagation_index
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
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)) {
2869 const NodeForeachGeometryElementGenerationItem &item =
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)) {
2889 const NodeForeachGeometryElementGenerationItem &item =
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) {
2902 case GeometryComponent::Type::Mesh:
2903 case GeometryComponent::Type::PointCloud:
2904 return AttrDomain::Point;
2905 case GeometryComponent::Type::Curve:
2906 return AttrDomain::Curve;
2907 case GeometryComponent::Type::Instance:
2908 return AttrDomain::Instance;
2909 case GeometryComponent::Type::GreasePencil:
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. */
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 {
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 :
3143 {GeometryComponent::Type::Mesh,
3144 GeometryComponent::Type::PointCloud,
3145 GeometryComponent::Type::Curve,
3146 GeometryComponent::Type::GreasePencil,
3147 GeometryComponent::Type::Instance})
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 :
3220 {GeometryComponent::Type::Mesh,
3221 GeometryComponent::Type::PointCloud,
3222 GeometryComponent::Type::Curve,
3223 GeometryComponent::Type::GreasePencil})
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
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
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
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(
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(
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;
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 }
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();
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) {
5976 return DEG_get_evaluated_object(this->operator_data->depsgraphs->active,
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.
struct ID ID
@ ID_TAG_MISSING
Definition DNA_ID.h:813
@ CD_PROP_STRING
struct bNodeTreeInterfaceSocket bNodeTreeInterfaceSocket
struct NodeMenuSwitch NodeMenuSwitch
struct NodeGeometrySimulationInput NodeGeometrySimulationInput
struct bNodeSocketValueMenu bNodeSocketValueMenu
struct bNodeSocketValueInt bNodeSocketValueInt
struct NodeGeometrySimulationOutput NodeGeometrySimulationOutput
struct NodeEnumDefinition NodeEnumDefinition
struct bNodeLink bNodeLink
struct bNode bNode
eNodeSocketDatatype
@ SOCK_GEOMETRY
struct bNodeSocketValueBoolean bNodeSocketValueBoolean
struct bNodeTree bNodeTree
struct NodeEnumItem NodeEnumItem
struct bNodeSocket bNodeSocket
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Map
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its and value channels Color Retrieve a color attribute
volatile int lock
AttrDomain
__forceinline float extract(const int4 &b)
Definition binning.cpp:27
int main(int argc, char *argv[])
BPy_StructRNA * depsgraph
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
#define output
void fill(const T &value) const
Definition BLI_array.hh:261
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:388
constexpr IndexRange drop_back(int64_t n) const
static constexpr IndexRange from_begin_size(const int64_t begin, const int64_t size)
constexpr IndexRange take_back(int64_t n) const
KeyIterator keys() const
Definition BLI_map.hh:837
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
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
MapType::KeyIterator keys() const
MapType::ItemIterator items() const
void add(const Key &key, const Value &value)
constexpr int64_t size() const
Definition BLI_span.hh:494
constexpr bool is_empty() const
Definition BLI_span.hh:510
constexpr T * end() const
Definition BLI_span.hh:549
constexpr T * begin() const
Definition BLI_span.hh:545
constexpr IndexRange index_range() const
Definition BLI_span.hh:671
bool contains(const Key &key) const
Definition BLI_set.hh:291
bool add(const Key &key)
Definition BLI_set.hh:248
void add_new(const Key &key)
Definition BLI_set.hh:233
std::unique_ptr< ImplicitInputValueFn > implicit_input_fn
InputSocketFieldType input_field_type
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
void add_new(const Key &key)
IndexRange index_range() const
Span< Key > as_span() const
int64_t size() const
T pop_last()
int64_t append_and_get_index(const T &value)
void append(const T &value)
const T & last(const int64_t n=0) const
bool is_empty() const
IndexRange index_range() const
void resize(const int64_t new_size)
int64_t first_index_of(const T &value) const
void extend(Span< T > array)
void append_non_duplicates(const T &value)
T * end()
Span< T > as_span() const
T * begin()
const bNode * output_node
const bNode * input_node
Vector< const bNodeLink * > border_links
Vector< bNodeTreeZone * > child_zones
Vector< const bNode * > child_nodes
int64_t size() const
Definition BLI_array.hh:245
const T & last(const int64_t n=0) const
Definition BLI_array.hh:285
IndexRange index_range() const
Definition BLI_array.hh:349
void value_initialize_indices(void *ptr, const IndexMask &mask) const
void fill_assign_n(const void *value, void *dst, int64_t n) const
bool has_special_member_functions() const
static const CPPType & get()
bool is() const
void copy_construct(const void *src, void *dst) const
void destruct(void *ptr) const
int64_t size() const
int64_t alignment() const
const void * default_value() 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)
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
T & construct(Args &&...args)
constexpr const T & first() const
Definition BLI_span.hh:316
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)
IndexRange index_range() 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)
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< std::unique_ptr< bNodeTreeZone > > 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="")
void clear_origin(InputSocket &socket)
GraphInputSocket & add_input(const CPPType &type, std::string name="")
virtual void possible_output_dependencies(int output_index, FunctionRef< void(Span< int >)> fn) const
Span< const InputSocket * > inputs() const
Span< const OutputSocket * > outputs() const
const InputSocket & input(int index) const
const OutputSocket & output(int index) const
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
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
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]
#define T
void fill_index_range(MutableSpan< T > span, const T start=0)
void foreach_1_index(const BitSpanT &data, Fn &&fn)
bool attribute_name_is_anonymous(const StringRef name)
std::optional< eNodeSocketDatatype > geo_nodes_base_cpp_type_to_socket_type(const CPPType &type)
Definition node.cc: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)
Array< bke::Instances * > extract_instances(const bke::Instances &instances, const IndexMask &mask, const bke::AttributeFilter &attribute_filter)
Array< GreasePencil * > extract_greasepencil_layer_points(const GreasePencil &grease_pencil, int layer_i, const IndexMask &mask, const bke::AttributeFilter &attribute_filter)
Array< Mesh * > extract_mesh_faces(const Mesh &mesh, const IndexMask &mask, const bke::AttributeFilter &attribute_filter)
Array< Mesh * > extract_mesh_vertices(const Mesh &mesh, const IndexMask &mask, const bke::AttributeFilter &attribute_filter)
Array< Curves * > extract_curves(const Curves &curves, const IndexMask &mask, const bke::AttributeFilter &attribute_filter)
Array< Curves * > extract_curves_points(const Curves &curves, const IndexMask &mask, const bke::AttributeFilter &attribute_filter)
Array< GreasePencil * > extract_greasepencil_layers(const GreasePencil &grease_pencil, const IndexMask &mask, const bke::AttributeFilter &attribute_filter)
Array< GreasePencil * > extract_greasepencil_layer_curves(const GreasePencil &grease_pencil, int layer_i, const IndexMask &mask, const bke::AttributeFilter &attribute_filter)
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)
Array< PointCloud * > extract_pointcloud_points(const PointCloud &pointcloud, const IndexMask &mask, const bke::AttributeFilter &attribute_filter)
Array< Mesh * > extract_mesh_edges(const Mesh &mesh, const IndexMask &mask, const bke::AttributeFilter &attribute_filter)
static Type to_type(const eGPUType type)
void index(const bNode &, void *r_value)
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
int16_t type
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
struct blender::nodes::GeometryNodesGroupFunction::@000115334025155014211241101024303251321212251042::@165376366322230201261276177143336154337260306235 attributes_to_propagate
struct blender::nodes::GeometryNodesGroupFunction::@000115334025155014211241101024303251321212251042 inputs
GeometryNodesLazyFunctionBuilder(const bNodeTree &btree, GeometryNodesLazyFunctionGraphInfo &lf_graph_info)
LazyFunctionForReduceForeachGeometryElement(const LazyFunctionForForeachGeometryElementZone &parent, ForeachGeometryElementEvalStorage &eval_storage)
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::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::@274124016254070041337206117335112252202012007076 inputs
struct blender::nodes::ZoneFunctionIndices::@225106150207216174220043355174065221360052164063 outputs
wmTimer * timer