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