28using bke::node_tree_reference_lifetimes::ReferenceSetInfo;
48 : body_node_(&body_node)
63 if (side_effect_nodes_in_closure.
is_empty()) {
79 const bNode &output_bnode_;
82 std::shared_ptr<ClosureSignature> closure_signature_;
91 output_bnode_(*zone.output_node()),
92 zone_info_(zone_info),
100 btree.
runtime->reference_lifetimes_info->reference_sets[item.key];
101 if (reference_set.
type == ReferenceSetType::ClosureInputReferenceSet) {
104 if (reference_set.
type == ReferenceSetType::ClosureOutputData) {
105 if (&reference_set.
socket->owner_node() == zone_.output_node()) {
113 inputs_.append_and_get_index_as(
"Reference Set",
118 for (
const int i : zone_.border_links.index_range()) {
122 const auto &storage = *
static_cast<const NodeClosureOutput *
>(output_bnode_.storage);
124 closure_signature_ = std::make_shared<ClosureSignature>();
126 for (
const int i :
IndexRange(storage.input_items.items_num)) {
127 const bNodeSocket &bsocket = zone_.input_node()->output_socket(
i);
128 closure_signature_->inputs.add({bsocket.
name, bsocket.
typeinfo});
130 for (
const int i :
IndexRange(storage.output_items.items_num)) {
131 const bNodeSocket &bsocket = zone_.output_node()->input_socket(
i);
132 closure_signature_->outputs.add({bsocket.
name, bsocket.
typeinfo});
141 for (
const int i : zone_.border_links.index_range()) {
142 params.set_output(zone_info_.indices.outputs.border_link_usages[
i],
true);
145 const auto &storage = *
static_cast<const NodeClosureOutput *
>(output_bnode_.storage);
147 std::unique_ptr<ResourceScope> closure_scope = std::make_unique<ResourceScope>();
154 for (
const int i :
IndexRange(storage.input_items.items_num)) {
156 const bNodeSocket &bsocket = zone_.input_node()->output_socket(
i);
160 lf_graph.
add_link(lf_graph_input, lf_body_node.input(body_fn_.indices.inputs.main[
i]));
164 lf_graph.
add_link(lf_body_node.output(body_fn_.indices.outputs.input_usages[
i]),
165 lf_graph_input_usage);
167 default_input_values.
append(*bsocket.
typeinfo->geometry_nodes_default_value);
170 storage.input_items.items_num);
172 storage.input_items.items_num);
174 for (
const int i :
IndexRange(storage.output_items.items_num)) {
179 lf_graph.
add_link(lf_body_node.output(body_fn_.indices.outputs.main[
i]), lf_graph_output);
183 lf_graph.
add_link(lf_graph_output_usage,
184 lf_body_node.input(body_fn_.indices.inputs.output_usages[
i]));
187 storage.output_items.items_num);
189 storage.output_items.items_num);
191 for (
const int i : zone_.border_links.index_range()) {
193 zone_info_.indices.inputs.border_links[
i]);
195 std::move(*input_ptr));
196 lf_body_node.input(body_fn_.indices.inputs.border_links[
i]).set_default_value(&stored_ptr);
199 for (
const auto &item : body_fn_.indices.inputs.reference_sets.items()) {
201 btree_.runtime->reference_lifetimes_info->reference_sets[item.key];
202 if (reference_set.
type == ReferenceSetType::ClosureOutputData) {
204 const bNode &node = socket.owner_node();
205 if (&node == zone_.output_node()) {
212 lf_body_node.input(body_fn_.indices.inputs.reference_sets.lookup(item.key)));
214 lf_graph_input.
index());
220 zone_info_.indices.inputs.reference_sets.lookup(item.key));
222 std::move(input_reference_set));
223 lf_body_node.input(body_fn_.indices.inputs.reference_sets.lookup(item.key))
224 .set_default_value(&stored);
228 if (btree_orig.
runtime->logged_zone_graphs) {
229 std::lock_guard
lock{btree_orig.
runtime->logged_zone_graphs->mutex};
230 btree_orig.
runtime->logged_zone_graphs->graph_by_zone_id.lookup_or_add_cb(
231 output_bnode_.identifier, [&]() { return lf_graph.to_dot(); });
236 const auto &side_effect_provider =
239 lf_graph,
nullptr, &side_effect_provider,
nullptr);
242 output_bnode_.identifier,
243 user_data.compute_context->hash(),
247 std::move(closure_scope),
250 std::move(default_input_values),
252 std::make_shared<ClosureEvalLog>())};
254 params.set_output(zone_info_.indices.outputs.main[0],
281 : btree_(bnode.owner_tree()), bnode_(bnode)
284 for (
const int i : bnode.input_sockets().index_range().drop_back(1)) {
285 const bNodeSocket &bsocket = bnode.input_socket(i);
286 indices_.inputs.main.append(inputs_.append_and_get_index_as(
287 bsocket.name, CPPType::get<bke::SocketValueVariant>(), lf::ValueUsage::Maybe));
288 indices_.outputs.input_usages.append(
289 outputs_.append_and_get_index_as(
"Usage", CPPType::get<bool>()));
293 for (
const int i : bnode.output_sockets().index_range().drop_back(1)) {
294 const bNodeSocket &bsocket = bnode.output_socket(i);
295 indices_.outputs.main.append(
296 outputs_.append_and_get_index_as(bsocket.name, CPPType::get<bke::SocketValueVariant>()));
297 indices_.inputs.output_usages.append(
298 inputs_.append_and_get_index_as(
"Usage", CPPType::get<bool>(), lf::ValueUsage::Maybe));
299 if (bke::node_tree_reference_lifetimes::can_contain_referenced_data(
300 eNodeSocketDatatype(bsocket.type)))
302 const int input_i = inputs_.append_and_get_index_as(
304 CPPType::get<bke::GeometryNodesReferenceSet>(),
305 lf::ValueUsage::Maybe);
306 indices_.inputs.reference_set_by_output.add(i, input_i);
324 if (s->graph_executor_storage) {
325 s->graph_executor->destruct_storage(s->graph_executor_storage);
338 if (!eval_storage.graph_executor) {
343 tree_logger->node_warnings.append(
344 *tree_logger->allocator,
346 {NodeWarningType::Error, TIP_(
"Recursive closure is not allowed")}});
354 if (eval_storage.closure) {
360 btree_orig.
id.
session_uid, bnode_.identifier, user_data.compute_context->hash()};
361 eval_storage.closure->log_evaluation(eval_location);
370 const std::optional<ClosureSourceLocation> closure_source_location =
371 eval_storage.closure ? eval_storage.closure->source_location() : std::nullopt;
374 user_data.compute_context, bnode_.identifier, &btree_, closure_source_location};
375 GeoNodesUserData closure_user_data = user_data;
376 closure_user_data.compute_context = &closure_compute_context;
378 user_data, closure_compute_context.
hash());
379 GeoNodesLocalUserData closure_local_user_data{closure_user_data};
382 eval_storage.graph_executor_storage, &closure_user_data, &closure_local_user_data};
383 eval_storage.graph_executor->execute(
params, eval_graph_context);
389 context = context->parent())
394 if (closure_context->node() == &bnode_) {
404 for (
const bNodeSocket *bsocket : bnode_.output_sockets().drop_back(1)) {
405 const int index = bsocket->index();
408 for (
const bNodeSocket *bsocket : bnode_.input_sockets().drop_back(1)) {
409 params.set_output(indices_.outputs.input_usages[bsocket->index()],
false);
417 const auto &user_data = *
static_cast<GeoNodesUserData *
>(context.user_data);
420 if (tree_logger ==
nullptr) {
425 Span{node_storage.input_items.items, node_storage.input_items.items_num})
436 {NodeWarningType::Error,
437 fmt::format(
"{}: {} \"{}\" ({} " BLI_STR_UTF8_BLACK_RIGHT_POINTING_SMALL_TRIANGLE
439 TIP_(
"Conversion not supported when evaluating closure"),
442 TIP_(item_type->label),
443 TIP_(closure_item.type->label))}});
445 else if (item.socket_type != closure_item.type->type) {
449 {NodeWarningType::Info,
450 fmt::format(
"{}: {} \"{}\" ({} " BLI_STR_UTF8_BLACK_RIGHT_POINTING_SMALL_TRIANGLE
452 TIP_(
"Implicit type conversion when evaluating closure"),
455 TIP_(item_type->label),
456 TIP_(closure_item.type->label))}});
460 tree_logger->node_warnings.append(
461 *tree_logger->allocator,
464 NodeWarningType::Error,
465 fmt::format(fmt::runtime(TIP_(
"Closure does not have input: \"{}\"")), item.name),
470 Span{node_storage.output_items.items, node_storage.output_items.items_num})
472 const bke::bNodeSocketType *item_type = bke::node_socket_type_find_static(item.socket_type);
473 if (
const std::optional<int>
i = signature.find_output_index(item.name)) {
474 const ClosureSignature::Item &closure_item = signature.outputs[*
i];
478 tree_logger->node_warnings.append(
479 *tree_logger->allocator,
481 {NodeWarningType::Error,
482 fmt::format(
"{}: {} \"{}\" ({} " BLI_STR_UTF8_BLACK_RIGHT_POINTING_SMALL_TRIANGLE
484 TIP_(
"Conversion not supported when evaluating closure"),
487 TIP_(closure_item.type->label),
488 TIP_(item_type->label))}});
490 else if (item.socket_type != closure_item.type->type) {
491 tree_logger->node_warnings.append(
492 *tree_logger->allocator,
494 {NodeWarningType::Info,
495 fmt::format(
"{}: {} \"{}\" ({} " BLI_STR_UTF8_BLACK_RIGHT_POINTING_SMALL_TRIANGLE
497 TIP_(
"Implicit type conversion when evaluating closure"),
500 TIP_(closure_item.type->label),
501 TIP_(item_type->label))}});
505 tree_logger->node_warnings.append(
506 *tree_logger->allocator,
508 {NodeWarningType::Error,
509 fmt::format(fmt::runtime(TIP_(
"Closure does not have output: \"{}\"")),
536 inputs_map[
i] = closure_signature.
find_input_index(node_storage.input_items.items[
i].name);
541 node_storage.output_items.items[
i].name);
546 static constexpr bool static_true =
true;
547 static constexpr bool static_false =
false;
549 lf_graph_outputs[indices_.outputs.input_usages[0]]->set_default_value(&static_true);
551 for (
const int input_item_i :
IndexRange(node_storage.input_items.items_num)) {
553 *lf_graph_outputs[indices_.outputs.input_usages[input_item_i + 1]];
554 if (
const std::optional<int> mapped_i = inputs_map[input_item_i]) {
557 lf::OutputSocket *lf_from = lf_graph_inputs[indices_.inputs.main[input_item_i + 1]];
567 lf_from = &conversion_node.
output(0);
586 for (
const int output_item_i :
IndexRange(node_storage.output_items.items_num)) {
588 *lf_graph_outputs[indices_.outputs.main[output_item_i]];
590 if (
const std::optional<int> mapped_i = outputs_map[output_item_i]) {
592 *closure_signature.
outputs[*mapped_i].type;
595 if (&closure_output_type != &main_output_type) {
597 closure_output_type, main_output_type, eval_storage.
scope))
603 lf_from = &conversion_node.
output(0);
612 lf_graph.
add_link(*lf_from, lf_main_output);
613 lf_graph.
add_link(*lf_graph_inputs[indices_.inputs.output_usages[output_item_i]],
623 if (lf_closure_input.
origin()) {
634 if (
const std::optional<int> lf_reference_set_input_i =
638 const int node_output_i = outputs_map.
as_span().first_index_try(
i);
639 if (node_output_i == -1) {
643 if (
const std::optional<int> lf_evaluate_node_reference_set_input_i =
644 indices_.inputs.reference_set_by_output.lookup_try(node_output_i))
646 lf_graph.
add_link(*lf_graph_inputs[*lf_evaluate_node_reference_set_input_i],
647 lf_reference_set_input);
654 if (!lf_closure_output.
targets().is_empty()) {
671 if (btree_orig.
runtime->logged_zone_graphs) {
672 std::lock_guard
lock{btree_orig.
runtime->logged_zone_graphs->mutex};
673 btree_orig.
runtime->logged_zone_graphs->graph_by_zone_id.lookup_or_add_cb(
674 bnode_.identifier, [&]() { return lf_graph.to_dot(); });
691 for (
const int output_item_i :
IndexRange(node_storage.output_items.items_num)) {
692 const bNodeSocket &output_bsocket = bnode_.output_socket(output_item_i);
696 *lf_graph_outputs[indices_.outputs.main[output_item_i]];
698 *lf_graph_inputs[indices_.inputs.output_usages[output_item_i]];
702 *lf_graph_inputs[indices_.inputs.main[input_bsocket->index()]];
704 *lf_graph_outputs[indices_.outputs.input_usages[input_bsocket->index()]];
706 if (&input_type == &output_type) {
707 lf_graph.
add_link(lf_main_input, lf_main_output);
708 lf_graph.
add_link(lf_usage_input, lf_usage_output);
712 input_type, output_type, eval_storage.
scope))
717 lf_graph.
add_link(lf_usage_input, lf_usage_output);
724 static constexpr bool static_false =
false;
725 for (
const int usage_i : indices_.outputs.input_usages) {
727 if (!lf_usage_output.
origin()) {
733 eval_storage.
graph_executor.emplace(lf_graph,
nullptr,
nullptr,
nullptr);
744 const int fn_inputs_num =
fn.inputs().size();
745 const int fn_outputs_num =
fn.outputs().size();
751 void *storage =
fn.init_storage(allocator);
769 for (
const int input_item_i :
params.inputs.index_range()) {
771 if (
const std::optional<int> mapped_i = inputs_map[input_item_i]) {
778 input_value = *value;
781 input_value = *
to_type.geometry_nodes_default_value;
783 lf_input_values[
indices.inputs.main[*mapped_i]] = {
791 for (
const int output_item_i :
params.outputs.index_range()) {
792 if (
const std::optional<int> mapped_i = outputs_map[output_item_i]) {
794 lf_input_values[
indices.inputs.output_usages[*mapped_i]] = {
801 for (
const int main_input_i :
indices.inputs.main.index_range()) {
802 const int lf_input_i =
indices.inputs.main[main_input_i];
803 if (!lf_input_values[lf_input_i]) {
806 lf_input_values[lf_input_i] = &value;
808 lf_output_values[
indices.outputs.input_usages[main_input_i]] = allocator.
allocate<
bool>();
811 for (
const int output_usage_i :
indices.inputs.output_usages.index_range()) {
812 const int lf_input_i =
indices.inputs.output_usages[output_usage_i];
813 if (!lf_input_values[lf_input_i]) {
815 allocator.
construct<
bool>(
false).release()};
819 for (
auto &&[main_output_i, lf_input_i] :
indices.inputs.output_data_reference_sets.items()) {
822 lf_input_values[lf_input_i] = {value};
825 for (
const int main_output_i :
indices.outputs.main.index_range()) {
826 lf_output_values[
indices.outputs.main[main_output_i]] =
831 fn, lf_input_values, lf_output_values, lf_input_usages, lf_output_usages, lf_set_outputs};
832 fn.execute(lf_params, lf_context);
833 fn.destruct_storage(storage);
835 for (
const int output_item_i :
params.outputs.index_range()) {
837 if (
const std::optional<int> mapped_i = outputs_map[output_item_i]) {
863 if (lf_set_outputs[
i]) {
864 lf_output_values[
i].destruct();
T * DEG_get_original(T *id)
__forceinline float extract(const int4 &b)
static const CPPType & get()
std::optional< Value > lookup_try(const Key &key) const
void add_new(const Key &key, const Value &value)
ItemIterator items() const &
Span< T > as_span() const
IndexRange index_range() const
static const CPPType & get()
const ComputeContextHash & hash() const
constexpr IndexRange index_range() const
destruct_ptr< T > construct(Args &&...args)
void * allocate(const int64_t size, const int64_t alignment)
T & construct(Args &&...args)
LinearAllocator & allocator()
constexpr bool is_empty() const
void append(const T &value)
static SocketValueVariant From(T &&value)
void update_node_indices()
Span< GraphInputSocket * > graph_inputs()
FunctionNode & add_function(const LazyFunction &fn)
void add_link(OutputSocket &from, InputSocket &to)
Span< GraphOutputSocket * > graph_outputs()
GraphOutputSocket & add_output(const CPPType &type, std::string name="")
GraphInputSocket & add_input(const CPPType &type, std::string name="")
Vector< Output > outputs_
const InputSocket & input(int index) const
const OutputSocket & output(int index) const
Span< InputSocket * > targets()
std::optional< int > find_output_index(StringRef key) const
CustomIDVectorSet< Item, ItemKeyGetter > inputs
std::optional< int > find_input_index(StringRef key) const
CustomIDVectorSet< Item, ItemKeyGetter > outputs
const ClosureSignature & signature() const
const fn::lazy_function::LazyFunction & function() const
const bke::SocketValueVariant & default_input_value(const int index) const
const ClosureFunctionIndices & indices() const
LazyFunctionForClosureZone(const bNodeTree &btree, const bke::bNodeTreeZone &zone, ZoneBuildInfo &zone_info, const ZoneBodyFunction &body_fn)
void execute_impl(lf::Params ¶ms, const lf::Context &context) const override
LazyFunctionForEvaluateClosureNode(const bNode &bnode)
EvaluateClosureFunctionIndices indices() const
bool is_recursive_call(const GeoNodesUserData &user_data) const
void destruct_storage(void *storage) const override
void initialize_execution_graph(EvaluateClosureEvalStorage &eval_storage) const
void initialize_pass_through_graph(EvaluateClosureEvalStorage &eval_storage) const
void generate_closure_compatibility_warnings(const Closure &closure, const lf::Context &context) const
void * init_storage(LinearAllocator<> &allocator) const override
void execute_impl(lf::Params ¶ms, const lf::Context &context) const override
void set_default_outputs(lf::Params ¶ms) const
linear_allocator::ChunkedList< WarningWithNode > node_warnings
LinearAllocator * allocator
bNodeSocketType * node_socket_type_find_static(int type, int subtype=0)
InputSocket GraphOutputSocket
OutputSocket GraphInputSocket
static Type to_type(const GPUType type)
void evaluate_closure_eagerly(const Closure &closure, ClosureEagerEvalParams ¶ms)
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)
void construct_socket_default_value(const bke::bNodeSocketType &stype, void *r_value)
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)
const LazyFunction * build_implicit_conversion_lazy_function(const bke::bNodeSocketType &from_type, const bke::bNodeSocketType &to_type, ResourceScope &scope)
std::optional< SocketValueVariant > implicitly_convert_socket_value(const bke::bNodeSocketType &from_type, const SocketValueVariant &from_value, const bke::bNodeSocketType &to_type)
const bNodeSocket * evaluate_closure_node_internally_linked_input(const bNodeSocket &output_socket)
ImplicitSharingPtr< Closure > ClosurePtr
void set_default_value_for_output_socket(lf::Params ¶ms, const int lf_index, const bNodeSocket &bsocket)
EvaluateClosureFunction build_evaluate_closure_node_lazy_function(ResourceScope &scope, const bNode &bnode)
bNodeSocketTypeHandle * typeinfo
bNodeTreeRuntimeHandle * runtime
const SocketValueVariant * geometry_nodes_default_value
const bNodeSocket * socket
const bke::bNodeSocketType * type
bke::SocketValueVariant * value
Map< int, int > output_data_reference_sets
struct blender::nodes::ClosureFunctionIndices::@226263262065312210267224327362010175040155163171 outputs
struct blender::nodes::ClosureFunctionIndices::@337045024022036116043042002001100361150157266076 inputs
const bke::bNodeSocketType * type
std::optional< lf::GraphExecutor > graph_executor
void * graph_executor_storage
std::optional< ClosureIntermediateGraphSideEffectProvider > side_effect_provider
const LazyFunction * lazy_function
EvaluateClosureFunctionIndices indices
const GeoNodesSideEffectNodes * side_effect_nodes
MultiValueMap< ComputeContextHash, const lf::FunctionNode * > nodes_by_context
const ComputeContext * compute_context
const GeoNodesCallData * call_data
ZoneFunctionIndices indices
ZoneFunctionIndices indices
Vector< int > border_links
struct blender::nodes::ZoneFunctionIndices::@273312016272125124266321211240073263106341134120 inputs
Map< ReferenceSetIndex, int > reference_sets