Files
test/source/blender/blenkernel/BKE_compute_context_cache.hh
Jacques Lucke aab2b6004b Geometry Nodes: add compute context cache
For various purposes we traverse the computation done by a node tree (e.g. for
gizmos and socket usage infeferencing). For that we generally have to keep track
of the compute context we're in at any given time. During the traversal, it's
common to enter and exist the same compute contexts multiple times. Currently,
we'd always build a new compute context when that happens. That happens even
though the old one is generally still around, because other data may reference
it. This patch implements a `ComputeContextHash` type that avoids rebuilding the
same compute contexts over and over again.

I'm considering to also replace the usage of `ComputeContextBuilder` with this
cache somehow, but will see how that works out.

The reason I'm working on this now is that I have to traverse the node tree a
bit again to find where closures might be evaluated. I wanted to be able to
cache the compute contexts for a while already.

Pull Request: https://projects.blender.org/blender/blender/pulls/137360
2025-04-11 21:36:41 +02:00

59 lines
2.4 KiB
C++

/* SPDX-FileCopyrightText: 2025 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include "BKE_compute_contexts.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 *, StringRef>, const ModifierComputeContext *>
modifier_contexts_cache_;
Map<std::pair<const ComputeContext *, int32_t>, const GroupNodeComputeContext *>
group_node_contexts_cache_;
public:
const ModifierComputeContext &for_modifier(const ComputeContext *parent,
const NodesModifierData &nmd);
const ModifierComputeContext &for_modifier(const ComputeContext *parent,
StringRef modifier_name);
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);
/**
* 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