Files
test2/source/blender/blenkernel/BKE_compute_context_cache.hh
Jacques Lucke a0444a5a2d Geometry Nodes: support viewers in closures
This adds support for having viewer nodes in closures. The code attempt to
detect where the closure is evaluated and shows the data from there.

If the closure is evaluated in multiple Evaluate Closure nodes, currently it
just picks the first one it finds. Support for more user control in this case
may be added a bit later. If the Evaluate Closure node is in e.g. the repeat or
foreach zone, it will automatically use the inspection index of that zone to
determine what evaluation to look at specifically.

Overall, not too much had to change conceptually to support viewers in closures.
Just some code like converting between viewer paths and compute contexts had to
be generalized a little bit.

Pull Request: https://projects.blender.org/blender/blender/pulls/137625
2025-04-16 23:35:59 +02:00

99 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 *, StringRef>, 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,
StringRef modifier_name);
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