25using bke::node_tree_reference_lifetimes::ReferenceSetInfo;
45 : body_node_(&body_node)
60 if (side_effect_nodes_in_closure.
is_empty()) {
76 const bNode &output_bnode_;
79 std::shared_ptr<ClosureSignature> closure_signature_;
88 output_bnode_(*zone.output_node()),
89 zone_info_(zone_info),
97 btree.
runtime->reference_lifetimes_info->reference_sets[item.key];
98 if (reference_set.
type == ReferenceSetType::ClosureInputReferenceSet) {
101 if (reference_set.
type == ReferenceSetType::ClosureOutputData) {
102 if (&reference_set.
socket->owner_node() == zone_.output_node()) {
110 inputs_.append_and_get_index_as(
"Reference Set",
115 for (
const int i : zone_.border_links.index_range()) {
121 closure_signature_ = std::make_shared<ClosureSignature>();
123 for (
const int i :
IndexRange(storage.input_items.items_num)) {
124 const bNodeSocket &bsocket = zone_.input_node()->output_socket(
i);
127 for (
const int i :
IndexRange(storage.output_items.items_num)) {
128 const bNodeSocket &bsocket = zone_.output_node()->input_socket(
i);
138 for (
const int i : zone_.border_links.index_range()) {
139 params.set_output(zone_info_.indices.outputs.border_link_usages[
i],
true);
141 if (!
U.experimental.use_bundle_and_closure_nodes) {
148 std::unique_ptr<ResourceScope> closure_scope = std::make_unique<ResourceScope>();
155 for (
const int i :
IndexRange(storage.input_items.items_num)) {
157 const bNodeSocket &bsocket = zone_.input_node()->output_socket(
i);
161 lf_graph.
add_link(lf_graph_input, lf_body_node.input(body_fn_.indices.inputs.main[
i]));
165 lf_graph.
add_link(lf_body_node.output(body_fn_.indices.outputs.input_usages[
i]),
166 lf_graph_input_usage);
168 void *default_value = closure_scope->allocate_owned(cpp_type);
170 default_input_values.
append(default_value);
173 storage.input_items.items_num);
175 storage.input_items.items_num);
177 for (
const int i :
IndexRange(storage.output_items.items_num)) {
179 const bNodeSocket &bsocket = zone_.output_node()->input_socket(
i);
183 lf_graph.
add_link(lf_body_node.output(body_fn_.indices.outputs.main[
i]), lf_graph_output);
187 lf_graph.
add_link(lf_graph_output_usage,
188 lf_body_node.input(body_fn_.indices.inputs.output_usages[
i]));
191 storage.output_items.items_num);
193 storage.output_items.items_num);
195 for (
const int i : zone_.border_links.index_range()) {
196 const CPPType &cpp_type = *zone_.border_links[
i]->tosock->typeinfo->geometry_nodes_cpp_type;
197 void *input_ptr =
params.try_get_input_data_ptr(zone_info_.indices.inputs.border_links[
i]);
198 void *stored_ptr = closure_scope->allocate_owned(cpp_type);
200 lf_body_node.input(body_fn_.indices.inputs.border_links[
i]).set_default_value(stored_ptr);
203 for (
const auto &item : body_fn_.indices.inputs.reference_sets.items()) {
205 btree_.runtime->reference_lifetimes_info->reference_sets[item.key];
206 if (reference_set.
type == ReferenceSetType::ClosureOutputData) {
208 const bNode &node = socket.owner_node();
209 if (&node == zone_.output_node()) {
216 lf_body_node.input(body_fn_.indices.inputs.reference_sets.lookup(item.key)));
218 lf_graph_input.
index());
224 zone_info_.indices.inputs.reference_sets.lookup(item.key));
226 std::move(input_reference_set));
227 lf_body_node.input(body_fn_.indices.inputs.reference_sets.lookup(item.key))
228 .set_default_value(&stored);
232 if (btree_orig.
runtime->logged_zone_graphs) {
233 std::lock_guard
lock{btree_orig.
runtime->logged_zone_graphs->mutex};
234 btree_orig.
runtime->logged_zone_graphs->graph_by_zone_id.lookup_or_add_cb(
235 output_bnode_.identifier, [&]() { return lf_graph.to_dot(); });
240 const auto &side_effect_provider =
243 lf_graph,
nullptr, &side_effect_provider,
nullptr);
246 output_bnode_.identifier,
247 user_data.compute_context->hash(),
251 std::move(closure_scope),
254 std::move(default_input_values),
256 std::make_shared<ClosureEvalLog>())};
258 params.set_output(zone_info_.indices.outputs.main[0],
285 : btree_(bnode.owner_tree()), bnode_(bnode)
288 for (
const int i : bnode.input_sockets().index_range().drop_back(1)) {
289 const bNodeSocket &bsocket = bnode.input_socket(i);
290 indices_.inputs.main.append(inputs_.append_and_get_index_as(
291 bsocket.name, *bsocket.typeinfo->geometry_nodes_cpp_type, lf::ValueUsage::Maybe));
292 indices_.outputs.input_usages.append(
293 outputs_.append_and_get_index_as(
"Usage", CPPType::get<bool>()));
297 for (
const int i : bnode.output_sockets().index_range().drop_back(1)) {
298 const bNodeSocket &bsocket = bnode.output_socket(i);
299 indices_.outputs.main.append(outputs_.append_and_get_index_as(
300 bsocket.name, *bsocket.typeinfo->geometry_nodes_cpp_type));
301 indices_.inputs.output_usages.append(
302 inputs_.append_and_get_index_as(
"Usage", CPPType::get<bool>(), lf::ValueUsage::Maybe));
303 if (bke::node_tree_reference_lifetimes::can_contain_referenced_data(
304 eNodeSocketDatatype(bsocket.type)))
306 const int input_i = inputs_.append_and_get_index_as(
308 CPPType::get<bke::GeometryNodesReferenceSet>(),
309 lf::ValueUsage::Maybe);
310 indices_.inputs.reference_set_by_output.add(i, input_i);
328 if (s->graph_executor_storage) {
329 s->graph_executor->destruct_storage(s->graph_executor_storage);
342 if (!eval_storage.graph_executor) {
347 tree_logger->node_warnings.append(
348 *tree_logger->allocator,
350 {NodeWarningType::Error, TIP_(
"Recursive closure is not allowed")}});
358 if (eval_storage.closure) {
364 btree_orig.
id.
session_uid, bnode_.identifier, user_data.compute_context->hash()};
365 eval_storage.closure->log_evaluation(eval_location);
374 const std::optional<ClosureSourceLocation> closure_source_location =
375 eval_storage.closure ? eval_storage.closure->source_location() : std::nullopt;
378 user_data.compute_context, bnode_.identifier, &btree_, closure_source_location};
379 GeoNodesUserData closure_user_data = user_data;
380 closure_user_data.compute_context = &closure_compute_context;
382 user_data, closure_compute_context.
hash());
383 GeoNodesLocalUserData closure_local_user_data{closure_user_data};
386 eval_storage.graph_executor_storage, &closure_user_data, &closure_local_user_data};
387 eval_storage.graph_executor->execute(
params, eval_graph_context);
393 context = context->parent())
398 if (closure_context->node() == &bnode_) {
408 for (
const bNodeSocket *bsocket : bnode_.output_sockets().drop_back(1)) {
409 const int index = bsocket->index();
412 for (
const bNodeSocket *bsocket : bnode_.input_sockets().drop_back(1)) {
413 params.set_output(indices_.outputs.input_usages[bsocket->index()],
false);
421 const auto &user_data = *
static_cast<GeoNodesUserData *
>(context.user_data);
424 if (tree_logger ==
nullptr) {
429 Span{node_storage.input_items.items, node_storage.input_items.items_num})
439 {NodeWarningType::Error,
440 fmt::format(fmt::runtime(TIP_(
"Closure input has incompatible type: \"{}\"")),
449 NodeWarningType::Error,
450 fmt::format(fmt::runtime(TIP_(
"Closure does not have input: \"{}\"")), item.name),
455 Span{node_storage.output_items.items, node_storage.output_items.items_num})
457 if (
const std::optional<int>
i = signature.find_output_index(SocketInterfaceKey{item.name}))
459 const ClosureSignature::Item &closure_item = signature.outputs[*
i];
463 tree_logger->node_warnings.append(
464 *tree_logger->allocator,
466 {NodeWarningType::Error,
467 fmt::format(fmt::runtime(TIP_(
"Closure output has incompatible type: \"{}\"")),
472 tree_logger->node_warnings.append(
473 *tree_logger->allocator,
475 {NodeWarningType::Error,
476 fmt::format(fmt::runtime(TIP_(
"Closure does not have output: \"{}\"")),
514 static constexpr bool static_true =
true;
515 static constexpr bool static_false =
false;
517 lf_graph_outputs[indices_.outputs.input_usages[0]]->set_default_value(&static_true);
519 for (
const int input_item_i :
IndexRange(node_storage.input_items.items_num)) {
521 *lf_graph_outputs[indices_.outputs.input_usages[input_item_i + 1]];
522 if (
const std::optional<int> mapped_i = inputs_map[input_item_i]) {
525 lf::OutputSocket *lf_from = lf_graph_inputs[indices_.inputs.main[input_item_i + 1]];
535 lf_from = &conversion_node.
output(0);
559 return fallback_value;
562 for (
const int output_item_i :
IndexRange(node_storage.output_items.items_num)) {
564 *lf_graph_outputs[indices_.outputs.main[output_item_i]];
566 if (
const std::optional<int> mapped_i = outputs_map[output_item_i]) {
568 *closure_signature.
outputs[*mapped_i].type;
571 if (&closure_output_type != &main_output_type) {
573 closure_output_type, main_output_type, eval_storage.
scope))
579 lf_from = &conversion_node.
output(0);
583 void *fallback_value = get_output_default_value(main_output_type);
589 lf_graph.
add_link(*lf_from, lf_main_output);
590 lf_graph.
add_link(*lf_graph_inputs[indices_.inputs.output_usages[output_item_i]],
594 void *fallback_value = get_output_default_value(main_output_type);
601 if (lf_closure_input.
origin()) {
613 if (
const std::optional<int> lf_reference_set_input_i =
617 const int node_output_i = outputs_map.
as_span().first_index_try(
i);
618 if (node_output_i == -1) {
622 if (
const std::optional<int> lf_evaluate_node_reference_set_input_i =
623 indices_.inputs.reference_set_by_output.lookup_try(node_output_i))
625 lf_graph.
add_link(*lf_graph_inputs[*lf_evaluate_node_reference_set_input_i],
626 lf_reference_set_input);
633 if (!lf_closure_output.
targets().is_empty()) {
650 if (btree_orig.
runtime->logged_zone_graphs) {
651 std::lock_guard
lock{btree_orig.
runtime->logged_zone_graphs->mutex};
652 btree_orig.
runtime->logged_zone_graphs->graph_by_zone_id.lookup_or_add_cb(
653 bnode_.identifier, [&]() { return lf_graph.to_dot(); });
670 for (
const int output_item_i :
IndexRange(node_storage.output_items.items_num)) {
671 const bNodeSocket &output_bsocket = bnode_.output_socket(output_item_i);
675 *lf_graph_outputs[indices_.outputs.main[output_item_i]];
677 *lf_graph_inputs[indices_.inputs.output_usages[output_item_i]];
681 *lf_graph_inputs[indices_.inputs.main[input_bsocket->index()]];
683 *lf_graph_outputs[indices_.outputs.input_usages[input_bsocket->index()]];
685 if (&input_type == &output_type) {
686 lf_graph.
add_link(lf_main_input, lf_main_output);
687 lf_graph.
add_link(lf_usage_input, lf_usage_output);
691 input_type, output_type, eval_storage.
scope))
696 lf_graph.
add_link(lf_usage_input, lf_usage_output);
706 static constexpr bool static_false =
false;
707 for (
const int usage_i : indices_.outputs.input_usages) {
709 if (!lf_usage_output.
origin()) {
715 eval_storage.
graph_executor.emplace(lf_graph,
nullptr,
nullptr,
nullptr);
726 const int fn_inputs_num =
fn.inputs().size();
727 const int fn_outputs_num =
fn.outputs().size();
733 void *storage =
fn.init_storage(allocator);
751 for (
const int input_item_i :
params.inputs.index_range()) {
753 if (
const std::optional<int> mapped_i = inputs_map[input_item_i]) {
757 void *value = allocator.
allocate(to_cpp_type);
767 lf_input_values[
indices.inputs.main[*mapped_i]] = {to_cpp_type, value};
773 for (
const int output_item_i :
params.outputs.index_range()) {
774 if (
const std::optional<int> mapped_i = outputs_map[output_item_i]) {
776 lf_input_values[
indices.inputs.output_usages[*mapped_i]] = {
783 for (
const int main_input_i :
indices.inputs.main.index_range()) {
784 const int lf_input_i =
indices.inputs.main[main_input_i];
785 if (!lf_input_values[lf_input_i]) {
789 void *value = allocator.
allocate(cpp_type);
791 lf_input_values[lf_input_i] = {cpp_type, value};
793 lf_output_values[
indices.outputs.input_usages[main_input_i]] = allocator.
allocate<
bool>();
796 for (
const int output_usage_i :
indices.inputs.output_usages.index_range()) {
797 const int lf_input_i =
indices.inputs.output_usages[output_usage_i];
798 if (!lf_input_values[lf_input_i]) {
800 allocator.
construct<
bool>(
false).release()};
804 for (
auto &&[main_output_i, lf_input_i] :
indices.inputs.output_data_reference_sets.items()) {
807 lf_input_values[lf_input_i] = {value};
810 for (
const int main_output_i :
indices.outputs.main.index_range()) {
813 lf_output_values[
indices.outputs.main[main_output_i]] = {cpp_type,
818 fn, lf_input_values, lf_output_values, lf_input_usages, lf_output_usages, lf_set_outputs};
819 fn.execute(lf_params, lf_context);
820 fn.destruct_storage(storage);
822 for (
const int output_item_i :
params.outputs.index_range()) {
824 if (
const std::optional<int> mapped_i = outputs_map[output_item_i]) {
828 void *computed_value = lf_output_values[
indices.outputs.main[*mapped_i]].get();
850 if (lf_set_outputs[
i]) {
851 lf_output_values[
i].destruct();
T * DEG_get_original(T *id)
__forceinline float extract(const int4 &b)
for(;discarded_id_iter !=nullptr;discarded_id_iter=static_cast< ID * >(discarded_id_iter->next))
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()
void copy_construct(const void *src, void *dst) const
void move_construct(void *src, void *dst) const
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)
void * allocate_owned(const CPPType &type)
LinearAllocator & allocator()
constexpr bool is_empty() const
void append(const 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_input_index(const SocketInterfaceKey &key) const
std::optional< int > find_output_index(const SocketInterfaceKey &key) const
const ClosureSignature & signature() const
const fn::lazy_function::LazyFunction & function() const
const ClosureFunctionIndices & indices() const
const void * default_input_value(const int index) 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
InputSocket GraphOutputSocket
OutputSocket GraphInputSocket
static Type to_type(const eGPUType 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)
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)
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 bNodeSocket * evaluate_closure_node_internally_linked_input(const bNodeSocket &output_socket)
ImplicitSharingPtr< Closure > ClosurePtr
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 ¶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 blender::CPPType * geometry_nodes_cpp_type
const bNodeSocket * socket
const bke::bNodeSocketType * type
Map< int, int > output_data_reference_sets
struct blender::nodes::ClosureFunctionIndices::@073352157204141045153364120203156237255173125345 outputs
struct blender::nodes::ClosureFunctionIndices::@130131166372033256311270255121015303110143351140 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
struct blender::nodes::ZoneFunctionIndices::@165160011314225015162310017251113363101175306052 inputs
Vector< int > border_links
Map< ReferenceSetIndex, int > reference_sets