Files
test/source/blender/nodes/NOD_geometry_nodes_closure.hh
Jacques Lucke 951d2d2b3a Refactor: Geometry Nodes: use SocketValueVariant instead of raw pointers
Refactor to get us closer to being able to remove `bNodeSocketType::geometry_nodes_cpp_type`
which is always `SocketValueVariant` now.

Pull Request: https://projects.blender.org/blender/blender/pulls/144419
2025-08-12 16:03:09 +02:00

131 lines
3.7 KiB
C++

/* SPDX-FileCopyrightText: 2025 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include "BKE_node_socket_value.hh"
#include "NOD_geometry_nodes_closure_fwd.hh"
#include "NOD_geometry_nodes_closure_location.hh"
#include "NOD_geometry_nodes_closure_signature.hh"
#include "BLI_resource_scope.hh"
#include "FN_lazy_function.hh"
namespace blender::nodes {
/**
* Describes the meaning of the various inputs and outputs of the lazy-function that's contained
* in the closure.
*/
struct ClosureFunctionIndices {
struct {
IndexRange main;
/** A boolean input for each output indicating whether that output is used. */
IndexRange output_usages;
/**
* A #GeometryNodesReferenceSet input for a subset of the outputs. This is used to tell the
* closure which attributes it has to propagate to the outputs.
*
* Main output index -> input `lf` socket index.
*/
Map<int, int> output_data_reference_sets;
} inputs;
struct {
IndexRange main;
/** A boolean output for each input indicating whether that input is used. */
IndexRange input_usages;
} outputs;
};
/**
* A closure is like a node group that is passed around as a value. It's typically evaluated using
* the Evaluate Closure node.
*
* Internally, a closure is a lazy-function. So the inputs that are passed to the closure are
* requested lazily. It's *not* yet supported to request the potentially captured values from the
* Closure Zone lazily.
*/
class Closure : public ImplicitSharingMixin {
private:
std::shared_ptr<ClosureSignature> signature_;
std::optional<ClosureSourceLocation> source_location_;
std::shared_ptr<ClosureEvalLog> eval_log_;
/**
* When building complex lazy-functions, e.g. from Geometry Nodes, one often has to allocate
* various additional resources (e.g. the lazy-functions for the individual nodes). Using
* #ResourceScope provides a simple way to pass ownership of all these additional resources to
* the Closure.
*/
std::unique_ptr<ResourceScope> scope_;
const fn::lazy_function::LazyFunction &function_;
ClosureFunctionIndices indices_;
Vector<bke::SocketValueVariant> default_input_values_;
public:
Closure(std::shared_ptr<ClosureSignature> signature,
std::unique_ptr<ResourceScope> scope,
const fn::lazy_function::LazyFunction &function,
ClosureFunctionIndices indices,
Vector<bke::SocketValueVariant> default_input_values,
std::optional<ClosureSourceLocation> source_location,
std::shared_ptr<ClosureEvalLog> eval_log)
: signature_(signature),
source_location_(source_location),
eval_log_(eval_log),
scope_(std::move(scope)),
function_(function),
indices_(indices),
default_input_values_(std::move(default_input_values))
{
}
const ClosureSignature &signature() const
{
return *signature_;
}
const ClosureFunctionIndices &indices() const
{
return indices_;
}
const fn::lazy_function::LazyFunction &function() const
{
return function_;
}
const std::optional<ClosureSourceLocation> &source_location() const
{
return source_location_;
}
const std::shared_ptr<ClosureEvalLog> &eval_log_ptr() const
{
return eval_log_;
}
const bke::SocketValueVariant &default_input_value(const int index) const
{
return default_input_values_[index];
}
void delete_self() override
{
MEM_delete(this);
}
void log_evaluation(const ClosureEvalLocation &location) const
{
if (!eval_log_) {
return;
}
std::lock_guard lock{eval_log_->mutex};
eval_log_->evaluations.append(location);
}
};
} // namespace blender::nodes