Geometry Nodes: decouple multi-function lifetimes from modifier
Previously, some multi-functions were allocated in a resource scope. This was fine as long as the multi-functions were only needed during the current evaluation of the node tree. However, now cases arise that require the multi-functions to be alive after the modifier is finished. For example, we want to evaluate fields created with geometry nodes outside of geometry nodes. To make this work, `std::shared_ptr` has to be used in a few more places. Realistically, this shouldn't have a noticable impact on performance. If this does become a bottleneck in the future, we can think about ways to make this work without using `shared_ptr` for multi-functions that are only used once.
This commit is contained in:
@@ -204,14 +204,14 @@ class FieldOperation : public FieldNode {
|
|||||||
* The multi-function used by this node. It is optionally owned.
|
* The multi-function used by this node. It is optionally owned.
|
||||||
* Multi-functions with mutable or vector parameters are not supported currently.
|
* Multi-functions with mutable or vector parameters are not supported currently.
|
||||||
*/
|
*/
|
||||||
std::unique_ptr<const MultiFunction> owned_function_;
|
std::shared_ptr<const MultiFunction> owned_function_;
|
||||||
const MultiFunction *function_;
|
const MultiFunction *function_;
|
||||||
|
|
||||||
/** Inputs to the operation. */
|
/** Inputs to the operation. */
|
||||||
blender::Vector<GField> inputs_;
|
blender::Vector<GField> inputs_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FieldOperation(std::unique_ptr<const MultiFunction> function, Vector<GField> inputs = {});
|
FieldOperation(std::shared_ptr<const MultiFunction> function, Vector<GField> inputs = {});
|
||||||
FieldOperation(const MultiFunction &function, Vector<GField> inputs = {});
|
FieldOperation(const MultiFunction &function, Vector<GField> inputs = {});
|
||||||
|
|
||||||
Span<GField> inputs() const;
|
Span<GField> inputs() const;
|
||||||
|
@@ -534,7 +534,7 @@ const GVArray *IndexFieldInput::get_varray_for_context(const fn::FieldContext &U
|
|||||||
* FieldOperation.
|
* FieldOperation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
FieldOperation::FieldOperation(std::unique_ptr<const MultiFunction> function,
|
FieldOperation::FieldOperation(std::shared_ptr<const MultiFunction> function,
|
||||||
Vector<GField> inputs)
|
Vector<GField> inputs)
|
||||||
: FieldOperation(*function, std::move(inputs))
|
: FieldOperation(*function, std::move(inputs))
|
||||||
{
|
{
|
||||||
|
@@ -924,7 +924,7 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
|
|||||||
{
|
{
|
||||||
blender::ResourceScope scope;
|
blender::ResourceScope scope;
|
||||||
blender::LinearAllocator<> &allocator = scope.linear_allocator();
|
blender::LinearAllocator<> &allocator = scope.linear_allocator();
|
||||||
blender::nodes::NodeMultiFunctions mf_by_node{tree, scope};
|
blender::nodes::NodeMultiFunctions mf_by_node{tree};
|
||||||
|
|
||||||
Map<DOutputSocket, GMutablePointer> group_inputs;
|
Map<DOutputSocket, GMutablePointer> group_inputs;
|
||||||
|
|
||||||
|
@@ -882,9 +882,9 @@ class GeometryNodesEvaluator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Use the multi-function implementation if it exists. */
|
/* Use the multi-function implementation if it exists. */
|
||||||
const MultiFunction *multi_function = params_.mf_by_node->try_get(node);
|
const nodes::NodeMultiFunctions::Item &fn_item = params_.mf_by_node->try_get(node);
|
||||||
if (multi_function != nullptr) {
|
if (fn_item.fn != nullptr) {
|
||||||
this->execute_multi_function_node(node, *multi_function, node_state);
|
this->execute_multi_function_node(node, fn_item, node_state);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -905,7 +905,7 @@ class GeometryNodesEvaluator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void execute_multi_function_node(const DNode node,
|
void execute_multi_function_node(const DNode node,
|
||||||
const MultiFunction &fn,
|
const nodes::NodeMultiFunctions::Item &fn_item,
|
||||||
NodeState &node_state)
|
NodeState &node_state)
|
||||||
{
|
{
|
||||||
if (node->idname().find("Legacy") != StringRef::not_found) {
|
if (node->idname().find("Legacy") != StringRef::not_found) {
|
||||||
@@ -933,7 +933,13 @@ class GeometryNodesEvaluator {
|
|||||||
input_fields.append(std::move(*(GField *)single_value.value));
|
input_fields.append(std::move(*(GField *)single_value.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto operation = std::make_shared<fn::FieldOperation>(fn, std::move(input_fields));
|
std::shared_ptr<fn::FieldOperation> operation;
|
||||||
|
if (fn_item.owned_fn) {
|
||||||
|
operation = std::make_shared<fn::FieldOperation>(fn_item.owned_fn, std::move(input_fields));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
operation = std::make_shared<fn::FieldOperation>(*fn_item.fn, std::move(input_fields));
|
||||||
|
}
|
||||||
|
|
||||||
/* Forward outputs. */
|
/* Forward outputs. */
|
||||||
int output_index = 0;
|
int output_index = 0;
|
||||||
|
@@ -33,15 +33,15 @@ class NodeMultiFunctions;
|
|||||||
*/
|
*/
|
||||||
class NodeMultiFunctionBuilder : NonCopyable, NonMovable {
|
class NodeMultiFunctionBuilder : NonCopyable, NonMovable {
|
||||||
private:
|
private:
|
||||||
ResourceScope &resource_scope_;
|
|
||||||
bNode &node_;
|
bNode &node_;
|
||||||
bNodeTree &tree_;
|
bNodeTree &tree_;
|
||||||
|
std::shared_ptr<MultiFunction> owned_built_fn_;
|
||||||
const MultiFunction *built_fn_ = nullptr;
|
const MultiFunction *built_fn_ = nullptr;
|
||||||
|
|
||||||
friend NodeMultiFunctions;
|
friend NodeMultiFunctions;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NodeMultiFunctionBuilder(ResourceScope &resource_scope, bNode &node, bNodeTree &tree);
|
NodeMultiFunctionBuilder(bNode &node, bNodeTree &tree);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assign a multi-function for the current node. The input and output parameters of the function
|
* Assign a multi-function for the current node. The input and output parameters of the function
|
||||||
@@ -58,31 +58,33 @@ class NodeMultiFunctionBuilder : NonCopyable, NonMovable {
|
|||||||
|
|
||||||
bNode &node();
|
bNode &node();
|
||||||
bNodeTree &tree();
|
bNodeTree &tree();
|
||||||
|
|
||||||
ResourceScope &resource_scope();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gives access to multi-functions for all nodes in a node tree that support them.
|
* Gives access to multi-functions for all nodes in a node tree that support them.
|
||||||
*/
|
*/
|
||||||
class NodeMultiFunctions {
|
class NodeMultiFunctions {
|
||||||
|
public:
|
||||||
|
struct Item {
|
||||||
|
const MultiFunction *fn = nullptr;
|
||||||
|
std::shared_ptr<MultiFunction> owned_fn;
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Map<const bNode *, const MultiFunction *> map_;
|
Map<const bNode *, Item> map_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NodeMultiFunctions(const DerivedNodeTree &tree, ResourceScope &resource_scope);
|
NodeMultiFunctions(const DerivedNodeTree &tree);
|
||||||
|
|
||||||
const MultiFunction *try_get(const DNode &node) const;
|
const Item &try_get(const DNode &node) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
/** \name #NodeMultiFunctionBuilder Inline Methods
|
/** \name #NodeMultiFunctionBuilder Inline Methods
|
||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
inline NodeMultiFunctionBuilder::NodeMultiFunctionBuilder(ResourceScope &resource_scope,
|
inline NodeMultiFunctionBuilder::NodeMultiFunctionBuilder(bNode &node, bNodeTree &tree)
|
||||||
bNode &node,
|
: node_(node), tree_(tree)
|
||||||
bNodeTree &tree)
|
|
||||||
: resource_scope_(resource_scope), node_(node), tree_(tree)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,11 +98,6 @@ inline bNodeTree &NodeMultiFunctionBuilder::tree()
|
|||||||
return tree_;
|
return tree_;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ResourceScope &NodeMultiFunctionBuilder::resource_scope()
|
|
||||||
{
|
|
||||||
return resource_scope_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void NodeMultiFunctionBuilder::set_matching_fn(const MultiFunction *fn)
|
inline void NodeMultiFunctionBuilder::set_matching_fn(const MultiFunction *fn)
|
||||||
{
|
{
|
||||||
built_fn_ = fn;
|
built_fn_ = fn;
|
||||||
@@ -108,14 +105,14 @@ inline void NodeMultiFunctionBuilder::set_matching_fn(const MultiFunction *fn)
|
|||||||
|
|
||||||
inline void NodeMultiFunctionBuilder::set_matching_fn(const MultiFunction &fn)
|
inline void NodeMultiFunctionBuilder::set_matching_fn(const MultiFunction &fn)
|
||||||
{
|
{
|
||||||
this->set_matching_fn(&fn);
|
built_fn_ = &fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename... Args>
|
template<typename T, typename... Args>
|
||||||
inline void NodeMultiFunctionBuilder::construct_and_set_matching_fn(Args &&...args)
|
inline void NodeMultiFunctionBuilder::construct_and_set_matching_fn(Args &&...args)
|
||||||
{
|
{
|
||||||
const T &fn = resource_scope_.construct<T>(std::forward<Args>(args)...);
|
owned_built_fn_ = std::make_shared<T>(std::forward<Args>(args)...);
|
||||||
this->set_matching_fn(&fn);
|
built_fn_ = &*owned_built_fn_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
@@ -124,9 +121,14 @@ inline void NodeMultiFunctionBuilder::construct_and_set_matching_fn(Args &&...ar
|
|||||||
/** \name #NodeMultiFunctions Inline Methods
|
/** \name #NodeMultiFunctions Inline Methods
|
||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
inline const MultiFunction *NodeMultiFunctions::try_get(const DNode &node) const
|
inline const NodeMultiFunctions::Item &NodeMultiFunctions::try_get(const DNode &node) const
|
||||||
{
|
{
|
||||||
return map_.lookup_default(node->bnode(), nullptr);
|
static Item empty_item;
|
||||||
|
const Item *item = map_.lookup_ptr(node->bnode());
|
||||||
|
if (item == nullptr) {
|
||||||
|
return empty_item;
|
||||||
|
}
|
||||||
|
return *item;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
namespace blender::nodes {
|
namespace blender::nodes {
|
||||||
|
|
||||||
NodeMultiFunctions::NodeMultiFunctions(const DerivedNodeTree &tree, ResourceScope &resource_scope)
|
NodeMultiFunctions::NodeMultiFunctions(const DerivedNodeTree &tree)
|
||||||
{
|
{
|
||||||
for (const NodeTreeRef *tree_ref : tree.used_node_tree_refs()) {
|
for (const NodeTreeRef *tree_ref : tree.used_node_tree_refs()) {
|
||||||
bNodeTree *btree = tree_ref->btree();
|
bNodeTree *btree = tree_ref->btree();
|
||||||
@@ -27,11 +27,10 @@ NodeMultiFunctions::NodeMultiFunctions(const DerivedNodeTree &tree, ResourceScop
|
|||||||
if (bnode->typeinfo->build_multi_function == nullptr) {
|
if (bnode->typeinfo->build_multi_function == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
NodeMultiFunctionBuilder builder{resource_scope, *bnode, *btree};
|
NodeMultiFunctionBuilder builder{*bnode, *btree};
|
||||||
bnode->typeinfo->build_multi_function(builder);
|
bnode->typeinfo->build_multi_function(builder);
|
||||||
const MultiFunction *fn = builder.built_fn_;
|
if (builder.built_fn_ != nullptr) {
|
||||||
if (fn != nullptr) {
|
map_.add_new(bnode, {builder.built_fn_, std::move(builder.owned_built_fn_)});
|
||||||
map_.add_new(bnode, fn);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user