Previously, the modifier name was used to identify it in a compute context or viewer path. Using `ModifierData.persistent_uid` (which was only introduced later) has two main benefits: * It is stable even when the modifier name changes. * It's cheaper and easier to work with since it's just an integer instead of a string. Note: Pinned viewer nodes will need to be re-pinned after the change. Pull Request: https://projects.blender.org/blender/blender/pulls/138864
98 lines
4.7 KiB
C++
98 lines
4.7 KiB
C++
/* SPDX-FileCopyrightText: 2025 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
#pragma once
|
|
|
|
#include "BKE_compute_context_cache_fwd.hh"
|
|
#include "BKE_compute_contexts.hh"
|
|
|
|
#include "BLI_linear_allocator.hh"
|
|
#include "BLI_map.hh"
|
|
#include "BLI_vector.hh"
|
|
|
|
namespace blender::bke {
|
|
|
|
/**
|
|
* When traversing the computation of a node tree (like in `socket_usage_inference.cc` or
|
|
* `partial_eval.cc`) one often enters and exists the same compute contexts. The cache implemented
|
|
* here avoids re-creating the same compute contexts over and over again. While requiring less
|
|
* memory and having potentially better performance, it can also be used to ensure that the same
|
|
* compute context will always have the same pointer, even if it's created in two different places.
|
|
*
|
|
* Constructing compute contexts through this cache can also be a bit more convenient.
|
|
*/
|
|
class ComputeContextCache {
|
|
/** Allocator used to allocate the compute contexts. */
|
|
LinearAllocator<> allocator_;
|
|
/** The allocated computed contexts that need to be destructed in the end. */
|
|
Vector<destruct_ptr<ComputeContext>> cache_;
|
|
|
|
Map<std::pair<const ComputeContext *, int>, const ModifierComputeContext *>
|
|
modifier_contexts_cache_;
|
|
Map<const ComputeContext *, const OperatorComputeContext *> operator_contexts_cache_;
|
|
Map<std::pair<const ComputeContext *, int32_t>, const GroupNodeComputeContext *>
|
|
group_node_contexts_cache_;
|
|
Map<std::pair<const ComputeContext *, int32_t>, const SimulationZoneComputeContext *>
|
|
simulation_zone_contexts_cache_;
|
|
Map<std::pair<const ComputeContext *, std::pair<int32_t, int>>, const RepeatZoneComputeContext *>
|
|
repeat_zone_contexts_cache_;
|
|
Map<std::pair<const ComputeContext *, std::pair<int32_t, int>>,
|
|
const ForeachGeometryElementZoneComputeContext *>
|
|
foreach_geometry_element_zone_contexts_cache_;
|
|
Map<std::pair<const ComputeContext *, int32_t>, const EvaluateClosureComputeContext *>
|
|
evaluate_closure_contexts_cache_;
|
|
|
|
public:
|
|
const ModifierComputeContext &for_modifier(const ComputeContext *parent,
|
|
const NodesModifierData &nmd);
|
|
const ModifierComputeContext &for_modifier(const ComputeContext *parent, int modifier_uid);
|
|
|
|
const OperatorComputeContext &for_operator(const ComputeContext *parent);
|
|
const OperatorComputeContext &for_operator(const ComputeContext *parent, const bNodeTree &tree);
|
|
|
|
const GroupNodeComputeContext &for_group_node(const ComputeContext *parent, int32_t node_id);
|
|
const GroupNodeComputeContext &for_group_node(const ComputeContext *parent,
|
|
const bNode &caller_group_node,
|
|
const bNodeTree &caller_tree);
|
|
|
|
const SimulationZoneComputeContext &for_simulation_zone(const ComputeContext *parent,
|
|
int output_node_id);
|
|
const SimulationZoneComputeContext &for_simulation_zone(const ComputeContext *parent,
|
|
const bNode &output_node);
|
|
|
|
const RepeatZoneComputeContext &for_repeat_zone(const ComputeContext *parent,
|
|
int32_t output_node_id,
|
|
int iteration);
|
|
const RepeatZoneComputeContext &for_repeat_zone(const ComputeContext *parent,
|
|
const bNode &output_node,
|
|
int iteration);
|
|
|
|
const ForeachGeometryElementZoneComputeContext &for_foreach_geometry_element_zone(
|
|
const ComputeContext *parent, int32_t output_node_id, int index);
|
|
const ForeachGeometryElementZoneComputeContext &for_foreach_geometry_element_zone(
|
|
const ComputeContext *parent, const bNode &output_node, int index);
|
|
|
|
const EvaluateClosureComputeContext &for_evaluate_closure(const ComputeContext *parent,
|
|
int32_t node_id);
|
|
const EvaluateClosureComputeContext &for_evaluate_closure(
|
|
const ComputeContext *parent,
|
|
int32_t evaluate_node_id,
|
|
const bNode *evaluate_node,
|
|
const std::optional<nodes::ClosureSourceLocation> &closure_source_location);
|
|
|
|
/**
|
|
* A fallback that does not use caching and can be used for any compute context.
|
|
* More constructors like the ones above can be added as they become necessary.
|
|
*/
|
|
template<typename T, typename... Args> const T &for_any_uncached(Args &&...args)
|
|
{
|
|
destruct_ptr<T> compute_context = allocator_.construct<T>(std::forward<Args>(args)...);
|
|
const T &result = *compute_context;
|
|
cache_.append(std::move(compute_context));
|
|
return result;
|
|
}
|
|
};
|
|
|
|
} // namespace blender::bke
|