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) {
110 inputs_.append_and_get_index_as(
"Reference Set",
121 closure_signature_ = std::make_shared<ClosureSignature>();
123 for (
const int i :
IndexRange(storage.input_items.items_num)) {
127 for (
const int i :
IndexRange(storage.output_items.items_num)) {
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)) {
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)) {
187 lf_graph.
add_link(lf_graph_output_usage,
191 storage.output_items.items_num);
193 storage.output_items.items_num);
196 const CPPType &cpp_type = *zone_.
border_links[i]->tosock->typeinfo->geometry_nodes_cpp_type;
198 void *stored_ptr = closure_scope->allocate_owned(cpp_type);
205 btree_.
runtime->reference_lifetimes_info->reference_sets[item.key];
206 if (reference_set.
type == ReferenceSetType::ClosureOutputData) {
218 lf_graph_input.
index());
226 std::move(input_reference_set));
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);
247 user_data.compute_context->hash(),
251 std::move(closure_scope),
254 std::move(default_input_values),
256 std::make_shared<ClosureEvalLog>())};
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);
291 bsocket.
name, *bsocket.
typeinfo->geometry_nodes_cpp_type, lf::ValueUsage::Maybe));
297 for (
const int i : bnode.output_sockets().index_range().drop_back(1)) {
298 const bNodeSocket &bsocket = bnode.output_socket(i);
300 bsocket.
name, *bsocket.
typeinfo->geometry_nodes_cpp_type));
306 const int input_i =
inputs_.append_and_get_index_as(
309 lf::ValueUsage::Maybe);
328 if (s->graph_executor_storage) {
342 if (!eval_storage.graph_executor) {
347 tree_logger->node_warnings.append(
348 *tree_logger->allocator,
358 if (eval_storage.closure) {
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;
377 bke::EvaluateClosureComputeContext closure_compute_context{
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};
385 lf::Context eval_graph_context{
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)) {
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: \"{}\"")),
445 tree_logger->node_warnings.append(
446 *tree_logger->allocator,
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;
519 for (
const int input_item_i :
IndexRange(node_storage.input_items.items_num)) {
522 if (
const std::optional<int> mapped_i = inputs_map[input_item_i]) {
527 if (&from_type != &to_type) {
529 from_type, to_type, eval_storage.
scope))
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);
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 =
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]];
681 *lf_graph_inputs[indices_.
inputs.
main[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;
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();
751 for (
const int input_item_i :
params.inputs.index_range()) {
753 if (
const std::optional<int> mapped_i = inputs_map[input_item_i]) {
758 if (&from_type == &to_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]] = {
777 CPPType::get<bool>(), allocator.
construct<
bool>(
true).release()};
778 lf_output_usages[
indices.outputs.main[*mapped_i]] = lf::ValueUsage::Used;
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]) {
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]) {
799 lf_input_values[lf_input_i] = {CPPType::get<bool>(),
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);
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();
829 if (&from_type == &to_type) {
849 for (
const int i : lf_output_values.
index_range()) {
850 if (lf_set_outputs[i]) {
851 lf_output_values[i].destruct();
870 info.lazy_function = &fn;
T * DEG_get_original(T *id)
__forceinline float extract(const int4 &b)
static void set_default_value(ShaderInput *input, BL::NodeSocket &b_sock, BL::BlendData &b_data, BL::ID &b_id)
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)
std::optional< Value > lookup_try(const Key &key) const
bool add(const Key &key, const Value &value)
const Value & lookup(const Key &key) const
void add_new(const Key &key, const Value &value)
ItemIterator items() const &
T & construct(Args &&...args)
void * allocate_owned(const CPPType &type)
LinearAllocator & allocator()
constexpr bool is_empty() const
void append(const T &value)
IndexRange index_range() const
const bNode * output_node() const
Vector< const bNodeLink * > border_links
const bNode * input_node() const
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_
virtual void * init_storage(LinearAllocator<> &allocator) const
Span< Input > inputs() const
Span< Output > outputs() const
virtual void destruct_storage(void *storage) const
void execute(Params ¶ms, const Context &context) const
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
bool can_contain_referenced_data(eNodeSocketDatatype socket_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)
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
bNodeTreeTypeHandle * typeinfo
bNodeTypeHandle * typeinfo
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::@1303 outputs
struct blender::nodes::ClosureFunctionIndices::@1302 inputs
const bke::bNodeSocketType * type
std::optional< lf::GraphExecutor > graph_executor
void * graph_executor_storage
std::optional< ClosureIntermediateGraphSideEffectProvider > side_effect_provider
struct blender::nodes::EvaluateClosureFunctionIndices::@1309 inputs
Vector< int > input_usages
struct blender::nodes::EvaluateClosureFunctionIndices::@1310 outputs
Vector< int > output_usages
Map< int, int > reference_set_by_output
const GeoNodesSideEffectNodes * side_effect_nodes
MultiValueMap< ComputeContextHash, const lf::FunctionNode * > nodes_by_context
const ComputeContext * compute_context
const GeoNodesCallData * call_data
ZoneFunctionIndices indices
const LazyFunction * function
ZoneFunctionIndices indices
struct blender::nodes::ZoneFunctionIndices::@1308 outputs
Vector< int > input_usages
Vector< int > border_links
Vector< int > border_link_usages
struct blender::nodes::ZoneFunctionIndices::@1307 inputs
Map< ReferenceSetIndex, int > reference_sets
Vector< int > output_usages