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
@ NTREE_GEOMETRY
struct bNodeSocketValueMenu bNodeSocketValueMenu
struct bNodeSocketValueInt bNodeSocketValueInt
struct NodeGeometrySimulationOutput NodeGeometrySimulationOutput
struct NodeEnumDefinition NodeEnumDefinition
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::@311217322151273055243347055333132220230004041004 inputs
struct blender::nodes::GeometryNodesGroupFunction::@311217322151273055243347055333132220230004041004::@376313040076355172126342102314323105254352264056 references_to_propagate
GeometryNodesLazyFunctionBuilder(const bNodeTree &btree, GeometryNodesLazyFunctionGraphInfo &lf_graph_info)
struct blender::nodes::ZoneFunctionIndices::@173065033344053234236040134022155223204356216034 outputs
struct blender::nodes::ZoneFunctionIndices::@161333072231042214103235126320201117323126120040 inputs
i
Definition text_draw.cc:230
wmTimer * timer