Refactor: Geometry Nodes: extract value tracing to separate file
This moves code used for tracing bundles and closures to a separate file. This code is used to e.g. detect which Separate Bundle node a Combine Bundle node is linked to. This allows providing automatic socket update operators for these nodes. Similarly for closures. Pull Request: https://projects.blender.org/blender/blender/pulls/143734
This commit is contained in:
@@ -121,34 +121,6 @@ bool node_editor_is_for_geometry_nodes_modifier(const SpaceNode &snode,
|
||||
[[nodiscard]] const ComputeContext *compute_context_for_edittree_node(
|
||||
const SpaceNode &snode, bke::ComputeContextCache &compute_context_cache, const bNode &node);
|
||||
|
||||
/**
|
||||
* Attempts to find a compute context that the closure is evaluated in. If none is found, null is
|
||||
* returned. If multiple are found, it currently picks the first one it finds which is somewhat
|
||||
* arbitrary.
|
||||
*/
|
||||
[[nodiscard]] const ComputeContext *compute_context_for_closure_evaluation(
|
||||
const ComputeContext *closure_socket_context,
|
||||
const bNodeSocket &closure_socket,
|
||||
bke::ComputeContextCache &compute_context_cache,
|
||||
const std::optional<nodes::ClosureSourceLocation> &source_location);
|
||||
|
||||
Vector<nodes::BundleSignature> gather_linked_target_bundle_signatures(
|
||||
const ComputeContext *bundle_socket_context,
|
||||
const bNodeSocket &bundle_socket,
|
||||
bke::ComputeContextCache &compute_context_cache);
|
||||
Vector<nodes::BundleSignature> gather_linked_origin_bundle_signatures(
|
||||
const ComputeContext *bundle_socket_context,
|
||||
const bNodeSocket &bundle_socket,
|
||||
bke::ComputeContextCache &compute_context_cache);
|
||||
Vector<nodes::ClosureSignature> gather_linked_target_closure_signatures(
|
||||
const ComputeContext *closure_socket_context,
|
||||
const bNodeSocket &closure_socket,
|
||||
bke::ComputeContextCache &compute_context_cache);
|
||||
Vector<nodes::ClosureSignature> gather_linked_origin_closure_signatures(
|
||||
const ComputeContext *closure_socket_context,
|
||||
const bNodeSocket &closure_socket,
|
||||
bke::ComputeContextCache &compute_context_cache);
|
||||
|
||||
/**
|
||||
* Creates a compute context for the given zone. It takes e.g. the current inspection index into
|
||||
* account.
|
||||
@@ -157,6 +129,10 @@ Vector<nodes::ClosureSignature> gather_linked_origin_closure_signatures(
|
||||
const bke::bNodeTreeZone &zone,
|
||||
bke::ComputeContextCache &compute_context_cache,
|
||||
const ComputeContext *parent_compute_context);
|
||||
[[nodiscard]] const ComputeContext *compute_context_for_zones(
|
||||
const Span<const bke::bNodeTreeZone *> zones,
|
||||
bke::ComputeContextCache &compute_context_cache,
|
||||
const ComputeContext *parent_compute_context);
|
||||
|
||||
void ui_template_node_asset_menu_items(uiLayout &layout,
|
||||
const bContext &C,
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "NOD_node_in_compute_context.hh"
|
||||
#include "NOD_trace_values.hh"
|
||||
|
||||
#include "io_utils.hh"
|
||||
|
||||
@@ -421,10 +421,9 @@ const ComputeContext *compute_context_for_zone(const bke::bNodeTreeZone &zone,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static const ComputeContext *compute_context_for_zones(
|
||||
const Span<const bke::bNodeTreeZone *> zones,
|
||||
bke::ComputeContextCache &compute_context_cache,
|
||||
const ComputeContext *parent_compute_context)
|
||||
const ComputeContext *compute_context_for_zones(const Span<const bke::bNodeTreeZone *> zones,
|
||||
bke::ComputeContextCache &compute_context_cache,
|
||||
const ComputeContext *parent_compute_context)
|
||||
{
|
||||
const ComputeContext *current = parent_compute_context;
|
||||
for (const bke::bNodeTreeZone *zone : zones) {
|
||||
@@ -473,511 +472,6 @@ static std::optional<const ComputeContext *> compute_context_for_tree_path(
|
||||
return current;
|
||||
}
|
||||
|
||||
static bool is_evaluate_closure_node_input(const nodes::SocketInContext &socket)
|
||||
{
|
||||
return socket->is_input() && socket->index() == 0 &&
|
||||
socket.owner_node()->is_type("GeometryNodeEvaluateClosure");
|
||||
}
|
||||
|
||||
static bool is_closure_zone_output_socket(const nodes::SocketInContext &socket)
|
||||
{
|
||||
return socket->owner_node().is_type("GeometryNodeClosureOutput") && socket->is_output();
|
||||
}
|
||||
|
||||
static Vector<nodes::SocketInContext> find_origin_sockets_through_contexts(
|
||||
nodes::SocketInContext start_socket,
|
||||
bke::ComputeContextCache &compute_context_cache,
|
||||
FunctionRef<bool(const nodes::SocketInContext &)> handle_possible_origin_socket_fn,
|
||||
bool find_all);
|
||||
|
||||
static Vector<nodes::SocketInContext> find_target_sockets_through_contexts(
|
||||
const nodes::SocketInContext start_socket,
|
||||
bke::ComputeContextCache &compute_context_cache,
|
||||
const FunctionRef<bool(const nodes::SocketInContext &)> handle_possible_target_socket_fn,
|
||||
const bool find_all)
|
||||
{
|
||||
using BundlePath = Vector<std::string, 0>;
|
||||
|
||||
struct SocketToCheck {
|
||||
nodes::SocketInContext socket;
|
||||
BundlePath bundle_path;
|
||||
};
|
||||
|
||||
Stack<SocketToCheck> sockets_to_check;
|
||||
Set<nodes::SocketInContext> added_sockets;
|
||||
|
||||
auto add_if_new = [&](const nodes::SocketInContext &socket, BundlePath bundle_path) {
|
||||
if (added_sockets.add(socket)) {
|
||||
sockets_to_check.push({socket, std::move(bundle_path)});
|
||||
}
|
||||
};
|
||||
|
||||
add_if_new(start_socket, {});
|
||||
|
||||
VectorSet<nodes::SocketInContext> found_targets;
|
||||
|
||||
while (!sockets_to_check.is_empty()) {
|
||||
const SocketToCheck socket_to_check = sockets_to_check.pop();
|
||||
const nodes::SocketInContext socket = socket_to_check.socket;
|
||||
const BundlePath &bundle_path = socket_to_check.bundle_path;
|
||||
const nodes::NodeInContext &node = socket.owner_node();
|
||||
if (socket->is_input()) {
|
||||
if (node->is_muted()) {
|
||||
for (const bNodeLink &link : node->internal_links()) {
|
||||
if (link.fromsock == socket.socket) {
|
||||
add_if_new({socket.context, link.tosock}, bundle_path);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (bundle_path.is_empty() && handle_possible_target_socket_fn(socket)) {
|
||||
found_targets.add(socket);
|
||||
if (!find_all) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (node->is_reroute()) {
|
||||
add_if_new(node.output_socket(0), bundle_path);
|
||||
continue;
|
||||
}
|
||||
if (node->is_group()) {
|
||||
if (const bNodeTree *group = reinterpret_cast<const bNodeTree *>(node->id)) {
|
||||
group->ensure_topology_cache();
|
||||
const ComputeContext &group_compute_context = compute_context_cache.for_group_node(
|
||||
socket.context, node->identifier, &node->owner_tree());
|
||||
for (const bNode *input_node : group->group_input_nodes()) {
|
||||
const bNodeSocket &group_input_socket = input_node->output_socket(socket->index());
|
||||
if (group_input_socket.is_directly_linked()) {
|
||||
add_if_new({&group_compute_context, &group_input_socket}, bundle_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (node->is_group_output()) {
|
||||
if (const auto *group_context = dynamic_cast<const bke::GroupNodeComputeContext *>(
|
||||
socket.context))
|
||||
{
|
||||
const bNodeTree *caller_group = group_context->tree();
|
||||
const bNode *caller_group_node = group_context->node();
|
||||
if (caller_group && caller_group_node) {
|
||||
caller_group->ensure_topology_cache();
|
||||
const bNodeSocket &output_socket = caller_group_node->output_socket(socket->index());
|
||||
add_if_new({group_context->parent(), &output_socket}, bundle_path);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (node->is_type("GeometryNodeCombineBundle")) {
|
||||
const auto &storage = *static_cast<const NodeGeometryCombineBundle *>(node->storage);
|
||||
BundlePath new_bundle_path = bundle_path;
|
||||
new_bundle_path.append(storage.items[socket->index()].name);
|
||||
add_if_new(node.output_socket(0), std::move(new_bundle_path));
|
||||
continue;
|
||||
}
|
||||
if (node->is_type("GeometryNodeSeparateBundle")) {
|
||||
if (bundle_path.is_empty()) {
|
||||
continue;
|
||||
}
|
||||
const StringRef last_key = bundle_path.last();
|
||||
const auto &storage = *static_cast<const NodeGeometrySeparateBundle *>(node->storage);
|
||||
for (const int output_i : IndexRange(storage.items_num)) {
|
||||
if (last_key == storage.items[output_i].name) {
|
||||
add_if_new(node.output_socket(output_i), bundle_path.as_span().drop_back(1));
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (node->is_type("GeometryNodeClosureOutput")) {
|
||||
const auto &closure_storage = *static_cast<const NodeGeometryClosureOutput *>(
|
||||
node->storage);
|
||||
const StringRef key = closure_storage.output_items.items[socket->index()].name;
|
||||
const Vector<nodes::SocketInContext> target_sockets = find_target_sockets_through_contexts(
|
||||
node.output_socket(0), compute_context_cache, is_evaluate_closure_node_input, true);
|
||||
for (const auto &target_socket : target_sockets) {
|
||||
const nodes::NodeInContext evaluate_node = target_socket.owner_node();
|
||||
const auto &evaluate_storage = *static_cast<const NodeGeometryEvaluateClosure *>(
|
||||
evaluate_node->storage);
|
||||
for (const int i : IndexRange(evaluate_storage.output_items.items_num)) {
|
||||
const NodeGeometryEvaluateClosureOutputItem &item =
|
||||
evaluate_storage.output_items.items[i];
|
||||
if (key == item.name) {
|
||||
add_if_new(evaluate_node.output_socket(i), bundle_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (node->is_type("GeometryNodeEvaluateClosure")) {
|
||||
if (socket->index() == 0) {
|
||||
continue;
|
||||
}
|
||||
const auto &evaluate_storage = *static_cast<const NodeGeometryEvaluateClosure *>(
|
||||
node->storage);
|
||||
const StringRef key = evaluate_storage.input_items.items[socket->index() - 1].name;
|
||||
const Vector<nodes::SocketInContext> origin_sockets = find_origin_sockets_through_contexts(
|
||||
node.input_socket(0), compute_context_cache, is_closure_zone_output_socket, true);
|
||||
for (const nodes::SocketInContext origin_socket : origin_sockets) {
|
||||
const bNodeTree &closure_tree = origin_socket->owner_tree();
|
||||
const bke::bNodeTreeZones *closure_tree_zones = closure_tree.zones();
|
||||
if (!closure_tree_zones) {
|
||||
continue;
|
||||
}
|
||||
const auto &closure_output_node = origin_socket.owner_node();
|
||||
const bke::bNodeTreeZone *closure_zone = closure_tree_zones->get_zone_by_node(
|
||||
closure_output_node->identifier);
|
||||
if (!closure_zone) {
|
||||
continue;
|
||||
}
|
||||
const bNode *closure_input_node = closure_zone->input_node();
|
||||
if (!closure_input_node) {
|
||||
continue;
|
||||
}
|
||||
const ComputeContext &closure_context = compute_context_cache.for_evaluate_closure(
|
||||
node.context,
|
||||
node->identifier,
|
||||
&node->owner_tree(),
|
||||
nodes::ClosureSourceLocation{
|
||||
&closure_tree, closure_output_node->identifier, origin_socket.context_hash()});
|
||||
const auto &closure_output_storage = *static_cast<const NodeGeometryClosureOutput *>(
|
||||
closure_output_node->storage);
|
||||
for (const int i : IndexRange(closure_output_storage.input_items.items_num)) {
|
||||
const NodeGeometryClosureInputItem &item = closure_output_storage.input_items.items[i];
|
||||
if (key == item.name) {
|
||||
add_if_new({&closure_context, &closure_input_node->output_socket(i)}, bundle_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
const bke::bNodeTreeZones *zones = node->owner_tree().zones();
|
||||
if (!zones) {
|
||||
continue;
|
||||
}
|
||||
const bke::bNodeTreeZone *from_zone = zones->get_zone_by_socket(*socket.socket);
|
||||
for (const bNodeLink *link : socket->directly_linked_links()) {
|
||||
if (!link->is_used()) {
|
||||
continue;
|
||||
}
|
||||
bNodeSocket *to_socket = link->tosock;
|
||||
const bke::bNodeTreeZone *to_zone = zones->get_zone_by_socket(*to_socket);
|
||||
if (!zones->link_between_zones_is_allowed(from_zone, to_zone)) {
|
||||
continue;
|
||||
}
|
||||
const Vector<const bke::bNodeTreeZone *> zones_to_enter = zones->get_zones_to_enter(
|
||||
from_zone, to_zone);
|
||||
const ComputeContext *compute_context = compute_context_for_zones(
|
||||
zones_to_enter, compute_context_cache, socket.context);
|
||||
if (!compute_context) {
|
||||
continue;
|
||||
}
|
||||
add_if_new({compute_context, to_socket}, bundle_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
return found_targets.extract_vector();
|
||||
}
|
||||
|
||||
[[nodiscard]] const ComputeContext *compute_context_for_closure_evaluation(
|
||||
const ComputeContext *closure_socket_context,
|
||||
const bNodeSocket &closure_socket,
|
||||
bke::ComputeContextCache &compute_context_cache,
|
||||
const std::optional<nodes::ClosureSourceLocation> &source_location)
|
||||
{
|
||||
const Vector<nodes::SocketInContext> target_sockets = find_target_sockets_through_contexts(
|
||||
{closure_socket_context, &closure_socket},
|
||||
compute_context_cache,
|
||||
is_evaluate_closure_node_input,
|
||||
false);
|
||||
if (target_sockets.is_empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
const nodes::SocketInContext target_socket = target_sockets[0];
|
||||
const nodes::NodeInContext target_node = target_socket.owner_node();
|
||||
return &compute_context_cache.for_evaluate_closure(target_socket.context,
|
||||
target_node->identifier,
|
||||
&target_socket->owner_tree(),
|
||||
source_location);
|
||||
}
|
||||
|
||||
static Vector<nodes::SocketInContext> find_origin_sockets_through_contexts(
|
||||
const nodes::SocketInContext start_socket,
|
||||
bke::ComputeContextCache &compute_context_cache,
|
||||
const FunctionRef<bool(const nodes::SocketInContext &)> handle_possible_origin_socket_fn,
|
||||
const bool find_all)
|
||||
{
|
||||
using BundlePath = Vector<std::string, 0>;
|
||||
|
||||
struct SocketToCheck {
|
||||
nodes::SocketInContext socket;
|
||||
BundlePath bundle_path;
|
||||
};
|
||||
|
||||
Stack<SocketToCheck> sockets_to_check;
|
||||
Set<nodes::SocketInContext> added_sockets;
|
||||
|
||||
auto add_if_new = [&](const nodes::SocketInContext &socket, BundlePath bundle_path) {
|
||||
if (added_sockets.add(socket)) {
|
||||
sockets_to_check.push({socket, std::move(bundle_path)});
|
||||
}
|
||||
};
|
||||
|
||||
add_if_new(start_socket, {});
|
||||
|
||||
VectorSet<nodes::SocketInContext> found_origins;
|
||||
|
||||
while (!sockets_to_check.is_empty()) {
|
||||
const SocketToCheck socket_to_check = sockets_to_check.pop();
|
||||
const nodes::SocketInContext socket = socket_to_check.socket;
|
||||
const BundlePath &bundle_path = socket_to_check.bundle_path;
|
||||
const nodes::NodeInContext &node = socket.owner_node();
|
||||
if (socket->is_input()) {
|
||||
if (bundle_path.is_empty() && handle_possible_origin_socket_fn(socket)) {
|
||||
found_origins.add(socket);
|
||||
if (!find_all) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
const bke::bNodeTreeZones *zones = node->owner_tree().zones();
|
||||
if (!zones) {
|
||||
continue;
|
||||
}
|
||||
const bke::bNodeTreeZone *to_zone = zones->get_zone_by_socket(*socket.socket);
|
||||
for (const bNodeLink *link : socket->directly_linked_links()) {
|
||||
if (!link->is_used()) {
|
||||
continue;
|
||||
}
|
||||
const bNodeSocket *from_socket = link->fromsock;
|
||||
const bke::bNodeTreeZone *from_zone = zones->get_zone_by_socket(*from_socket);
|
||||
if (!zones->link_between_zones_is_allowed(from_zone, to_zone)) {
|
||||
continue;
|
||||
}
|
||||
const Vector<const bke::bNodeTreeZone *> zones_to_enter = zones->get_zones_to_enter(
|
||||
from_zone, to_zone);
|
||||
const ComputeContext *compute_context = socket.context;
|
||||
for (int i = zones_to_enter.size() - 1; i >= 0; i--) {
|
||||
if (!compute_context) {
|
||||
/* There must be a compute context when we are in a zone. */
|
||||
BLI_assert_unreachable();
|
||||
return found_origins.extract_vector();
|
||||
}
|
||||
/* Each zone corresponds to one compute context level. */
|
||||
compute_context = compute_context->parent();
|
||||
}
|
||||
add_if_new({compute_context, from_socket}, bundle_path);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (node->is_muted()) {
|
||||
for (const bNodeLink &link : node->internal_links()) {
|
||||
if (link.tosock == socket.socket) {
|
||||
add_if_new({socket.context, link.fromsock}, bundle_path);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (bundle_path.is_empty() && handle_possible_origin_socket_fn(socket)) {
|
||||
found_origins.add(socket);
|
||||
if (!find_all) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (node->is_reroute()) {
|
||||
add_if_new(node.input_socket(0), bundle_path);
|
||||
continue;
|
||||
}
|
||||
if (node->is_group()) {
|
||||
if (const bNodeTree *group = reinterpret_cast<const bNodeTree *>(node->id)) {
|
||||
group->ensure_topology_cache();
|
||||
if (const bNode *group_output_node = group->group_output_node()) {
|
||||
const ComputeContext &group_compute_context = compute_context_cache.for_group_node(
|
||||
socket.context, node->identifier, &node->owner_tree());
|
||||
add_if_new({&group_compute_context, &group_output_node->input_socket(socket->index())},
|
||||
bundle_path);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (node->is_group_input()) {
|
||||
if (const auto *group_context = dynamic_cast<const bke::GroupNodeComputeContext *>(
|
||||
socket.context))
|
||||
{
|
||||
const bNodeTree *caller_group = group_context->tree();
|
||||
const bNode *caller_group_node = group_context->node();
|
||||
if (caller_group && caller_group_node) {
|
||||
caller_group->ensure_topology_cache();
|
||||
const bNodeSocket &input_socket = caller_group_node->input_socket(socket->index());
|
||||
add_if_new({group_context->parent(), &input_socket}, bundle_path);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (node->is_type("GeometryNodeEvaluateClosure")) {
|
||||
const auto &evaluate_storage = *static_cast<const NodeGeometryEvaluateClosure *>(
|
||||
node->storage);
|
||||
const StringRef key = evaluate_storage.output_items.items[socket->index()].name;
|
||||
const Vector<nodes::SocketInContext> origin_sockets = find_origin_sockets_through_contexts(
|
||||
node.input_socket(0), compute_context_cache, is_closure_zone_output_socket, true);
|
||||
for (const nodes::SocketInContext origin_socket : origin_sockets) {
|
||||
const bNodeTree &closure_tree = origin_socket->owner_tree();
|
||||
const nodes::NodeInContext closure_output_node = origin_socket.owner_node();
|
||||
const auto &closure_storage = *static_cast<const NodeGeometryClosureOutput *>(
|
||||
closure_output_node->storage);
|
||||
const ComputeContext &closure_context = compute_context_cache.for_evaluate_closure(
|
||||
node.context,
|
||||
node->identifier,
|
||||
&node->owner_tree(),
|
||||
nodes::ClosureSourceLocation{
|
||||
&closure_tree, closure_output_node->identifier, origin_socket.context_hash()});
|
||||
for (const int i : IndexRange(closure_storage.output_items.items_num)) {
|
||||
const NodeGeometryClosureOutputItem &item = closure_storage.output_items.items[i];
|
||||
if (key == item.name) {
|
||||
add_if_new({&closure_context, &closure_output_node->input_socket(i)}, bundle_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (node->is_type("GeometryNodeClosureInput")) {
|
||||
const auto &input_storage = *static_cast<const NodeGeometryClosureInput *>(node->storage);
|
||||
const bNode *closure_output_node = node->owner_tree().node_by_id(
|
||||
input_storage.output_node_id);
|
||||
if (!closure_output_node) {
|
||||
continue;
|
||||
}
|
||||
const auto &output_storage = *static_cast<const NodeGeometryClosureOutput *>(
|
||||
closure_output_node->storage);
|
||||
const StringRef key = output_storage.input_items.items[socket->index()].name;
|
||||
const bNodeSocket &closure_output_socket = closure_output_node->output_socket(0);
|
||||
const Vector<nodes::SocketInContext> target_sockets = find_target_sockets_through_contexts(
|
||||
{socket.context, &closure_output_socket},
|
||||
compute_context_cache,
|
||||
is_evaluate_closure_node_input,
|
||||
true);
|
||||
for (const nodes::SocketInContext &target_socket : target_sockets) {
|
||||
const nodes::NodeInContext target_node = target_socket.owner_node();
|
||||
const auto &evaluate_storage = *static_cast<const NodeGeometryEvaluateClosure *>(
|
||||
target_node.node->storage);
|
||||
for (const int i : IndexRange(evaluate_storage.input_items.items_num)) {
|
||||
const NodeGeometryEvaluateClosureInputItem &item =
|
||||
evaluate_storage.input_items.items[i];
|
||||
if (key == item.name) {
|
||||
add_if_new(target_node.input_socket(i + 1), bundle_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (node->is_type("GeometryNodeCombineBundle")) {
|
||||
if (bundle_path.is_empty()) {
|
||||
continue;
|
||||
}
|
||||
const StringRef last_key = bundle_path.last();
|
||||
const auto &storage = *static_cast<const NodeGeometryCombineBundle *>(node->storage);
|
||||
for (const int input_i : IndexRange(storage.items_num)) {
|
||||
if (last_key == storage.items[input_i].name) {
|
||||
add_if_new(node.input_socket(input_i), bundle_path.as_span().drop_back(1));
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (node->is_type("GeometryNodeSeparateBundle")) {
|
||||
const auto &storage = *static_cast<const NodeGeometrySeparateBundle *>(node->storage);
|
||||
BundlePath new_bundle_path = bundle_path;
|
||||
new_bundle_path.append(storage.items[socket->index()].name);
|
||||
add_if_new(node.input_socket(0), std::move(new_bundle_path));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found_origins.extract_vector();
|
||||
}
|
||||
|
||||
Vector<nodes::BundleSignature> gather_linked_target_bundle_signatures(
|
||||
const ComputeContext *bundle_socket_context,
|
||||
const bNodeSocket &bundle_socket,
|
||||
bke::ComputeContextCache &compute_context_cache)
|
||||
{
|
||||
const Vector<nodes::SocketInContext> target_sockets = find_target_sockets_through_contexts(
|
||||
{bundle_socket_context, &bundle_socket},
|
||||
compute_context_cache,
|
||||
[](const nodes::SocketInContext &socket) {
|
||||
return socket->owner_node().is_type("GeometryNodeSeparateBundle");
|
||||
},
|
||||
true);
|
||||
Vector<nodes::BundleSignature> signatures;
|
||||
for (const nodes::SocketInContext &target_socket : target_sockets) {
|
||||
const nodes::NodeInContext &target_node = target_socket.owner_node();
|
||||
signatures.append(nodes::BundleSignature::from_separate_bundle_node(*target_node.node));
|
||||
}
|
||||
return signatures;
|
||||
}
|
||||
|
||||
Vector<nodes::BundleSignature> gather_linked_origin_bundle_signatures(
|
||||
const ComputeContext *bundle_socket_context,
|
||||
const bNodeSocket &bundle_socket,
|
||||
bke::ComputeContextCache &compute_context_cache)
|
||||
{
|
||||
const Vector<nodes::SocketInContext> origin_sockets = find_origin_sockets_through_contexts(
|
||||
{bundle_socket_context, &bundle_socket},
|
||||
compute_context_cache,
|
||||
[](const nodes::SocketInContext &socket) {
|
||||
return socket->owner_node().is_type("GeometryNodeCombineBundle");
|
||||
},
|
||||
true);
|
||||
Vector<nodes::BundleSignature> signatures;
|
||||
for (const nodes::SocketInContext &origin_socket : origin_sockets) {
|
||||
const nodes::NodeInContext &origin_node = origin_socket.owner_node();
|
||||
signatures.append(nodes::BundleSignature::from_combine_bundle_node(*origin_node.node));
|
||||
}
|
||||
return signatures;
|
||||
}
|
||||
|
||||
Vector<nodes::ClosureSignature> gather_linked_target_closure_signatures(
|
||||
const ComputeContext *closure_socket_context,
|
||||
const bNodeSocket &closure_socket,
|
||||
bke::ComputeContextCache &compute_context_cache)
|
||||
{
|
||||
const Vector<nodes::SocketInContext> target_sockets = find_target_sockets_through_contexts(
|
||||
{closure_socket_context, &closure_socket},
|
||||
compute_context_cache,
|
||||
is_evaluate_closure_node_input,
|
||||
true);
|
||||
Vector<nodes::ClosureSignature> signatures;
|
||||
for (const nodes::SocketInContext &target_socket : target_sockets) {
|
||||
const nodes::NodeInContext &target_node = target_socket.owner_node();
|
||||
signatures.append(nodes::ClosureSignature::from_evaluate_closure_node(*target_node.node));
|
||||
}
|
||||
return signatures;
|
||||
}
|
||||
|
||||
Vector<nodes::ClosureSignature> gather_linked_origin_closure_signatures(
|
||||
const ComputeContext *closure_socket_context,
|
||||
const bNodeSocket &closure_socket,
|
||||
bke::ComputeContextCache &compute_context_cache)
|
||||
{
|
||||
Vector<nodes::ClosureSignature> signatures;
|
||||
find_origin_sockets_through_contexts(
|
||||
{closure_socket_context, &closure_socket},
|
||||
compute_context_cache,
|
||||
[&](const nodes::SocketInContext &socket) {
|
||||
if (is_closure_zone_output_socket(socket)) {
|
||||
signatures.append(
|
||||
nodes::ClosureSignature::from_closure_output_node(socket->owner_node()));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
true);
|
||||
return signatures;
|
||||
}
|
||||
|
||||
static const ComputeContext *get_node_editor_root_compute_context(
|
||||
const SpaceNode &snode, bke::ComputeContextCache &compute_context_cache)
|
||||
{
|
||||
|
||||
@@ -99,6 +99,7 @@ set(SRC
|
||||
intern/socket_search_link.cc
|
||||
intern/socket_usage_inference.cc
|
||||
intern/sync_sockets.cc
|
||||
intern/trace_values.cc
|
||||
intern/value_elem.cc
|
||||
intern/volume_grid_function_eval.cc
|
||||
|
||||
@@ -148,6 +149,7 @@ set(SRC
|
||||
NOD_socket_usage_inference.hh
|
||||
NOD_socket_usage_inference_fwd.hh
|
||||
NOD_sync_sockets.hh
|
||||
NOD_trace_values.hh
|
||||
NOD_texture.h
|
||||
NOD_value_elem.hh
|
||||
NOD_value_elem_eval.hh
|
||||
|
||||
47
source/blender/nodes/NOD_trace_values.hh
Normal file
47
source/blender/nodes/NOD_trace_values.hh
Normal file
@@ -0,0 +1,47 @@
|
||||
/* SPDX-FileCopyrightText: 2025 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BKE_compute_context_cache_fwd.hh"
|
||||
|
||||
#include "BLI_compute_context.hh"
|
||||
|
||||
#include "DNA_node_types.h"
|
||||
|
||||
#include "NOD_geometry_nodes_bundle_signature.hh"
|
||||
#include "NOD_geometry_nodes_closure_location.hh"
|
||||
#include "NOD_geometry_nodes_closure_signature.hh"
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
/**
|
||||
* Attempts to find a compute context that the closure is evaluated in. If none is found, null is
|
||||
* returned. If multiple are found, it currently picks the first one it finds which is somewhat
|
||||
* arbitrary.
|
||||
*/
|
||||
[[nodiscard]] const ComputeContext *compute_context_for_closure_evaluation(
|
||||
const ComputeContext *closure_socket_context,
|
||||
const bNodeSocket &closure_socket,
|
||||
bke::ComputeContextCache &compute_context_cache,
|
||||
const std::optional<ClosureSourceLocation> &source_location);
|
||||
|
||||
Vector<BundleSignature> gather_linked_target_bundle_signatures(
|
||||
const ComputeContext *bundle_socket_context,
|
||||
const bNodeSocket &bundle_socket,
|
||||
bke::ComputeContextCache &compute_context_cache);
|
||||
Vector<BundleSignature> gather_linked_origin_bundle_signatures(
|
||||
const ComputeContext *bundle_socket_context,
|
||||
const bNodeSocket &bundle_socket,
|
||||
bke::ComputeContextCache &compute_context_cache);
|
||||
Vector<ClosureSignature> gather_linked_target_closure_signatures(
|
||||
const ComputeContext *closure_socket_context,
|
||||
const bNodeSocket &closure_socket,
|
||||
bke::ComputeContextCache &compute_context_cache);
|
||||
Vector<ClosureSignature> gather_linked_origin_closure_signatures(
|
||||
const ComputeContext *closure_socket_context,
|
||||
const bNodeSocket &closure_socket,
|
||||
bke::ComputeContextCache &compute_context_cache);
|
||||
|
||||
} // namespace blender::nodes
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "NOD_geo_closure.hh"
|
||||
#include "NOD_socket_items.hh"
|
||||
#include "NOD_sync_sockets.hh"
|
||||
#include "NOD_trace_values.hh"
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
@@ -62,9 +63,8 @@ static BundleSyncState get_sync_state_separate_bundle(const SpaceNode &snode,
|
||||
bke::ComputeContextCache compute_context_cache;
|
||||
const ComputeContext *current_context = ed::space_node::compute_context_for_edittree_socket(
|
||||
snode, compute_context_cache, bundle_socket);
|
||||
const Vector<nodes::BundleSignature> source_signatures =
|
||||
ed::space_node::gather_linked_origin_bundle_signatures(
|
||||
current_context, bundle_socket, compute_context_cache);
|
||||
const Vector<nodes::BundleSignature> source_signatures = gather_linked_origin_bundle_signatures(
|
||||
current_context, bundle_socket, compute_context_cache);
|
||||
if (source_signatures.is_empty()) {
|
||||
return {NodeSyncState::NoSyncSource};
|
||||
}
|
||||
@@ -90,9 +90,8 @@ static BundleSyncState get_sync_state_combine_bundle(const SpaceNode &snode,
|
||||
bke::ComputeContextCache compute_context_cache;
|
||||
const ComputeContext *current_context = ed::space_node::compute_context_for_edittree_socket(
|
||||
snode, compute_context_cache, bundle_socket);
|
||||
const Vector<nodes::BundleSignature> source_signatures =
|
||||
ed::space_node::gather_linked_target_bundle_signatures(
|
||||
current_context, bundle_socket, compute_context_cache);
|
||||
const Vector<nodes::BundleSignature> source_signatures = gather_linked_target_bundle_signatures(
|
||||
current_context, bundle_socket, compute_context_cache);
|
||||
if (source_signatures.is_empty()) {
|
||||
return {NodeSyncState::NoSyncSource};
|
||||
}
|
||||
@@ -118,7 +117,7 @@ static ClosureSyncState get_sync_state_closure_output(const SpaceNode &snode,
|
||||
const ComputeContext *current_context = ed::space_node::compute_context_for_edittree_socket(
|
||||
snode, compute_context_cache, closure_socket);
|
||||
const Vector<nodes::ClosureSignature> source_signatures =
|
||||
ed::space_node::gather_linked_target_closure_signatures(
|
||||
gather_linked_target_closure_signatures(
|
||||
current_context, closure_socket, compute_context_cache);
|
||||
if (source_signatures.is_empty()) {
|
||||
return {NodeSyncState::NoSyncSource};
|
||||
@@ -145,7 +144,7 @@ static ClosureSyncState get_sync_state_evaluate_closure(const SpaceNode &snode,
|
||||
const ComputeContext *current_context = ed::space_node::compute_context_for_edittree_socket(
|
||||
snode, compute_context_cache, closure_socket);
|
||||
const Vector<nodes::ClosureSignature> source_signatures =
|
||||
ed::space_node::gather_linked_origin_closure_signatures(
|
||||
gather_linked_origin_closure_signatures(
|
||||
current_context, closure_socket, compute_context_cache);
|
||||
if (source_signatures.is_empty()) {
|
||||
return {NodeSyncState::NoSyncSource};
|
||||
|
||||
523
source/blender/nodes/intern/trace_values.cc
Normal file
523
source/blender/nodes/intern/trace_values.cc
Normal file
@@ -0,0 +1,523 @@
|
||||
/* SPDX-FileCopyrightText: 2025 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BLI_stack.hh"
|
||||
|
||||
#include "NOD_geometry_nodes_bundle_signature.hh"
|
||||
#include "NOD_geometry_nodes_closure_location.hh"
|
||||
#include "NOD_geometry_nodes_closure_signature.hh"
|
||||
#include "NOD_node_in_compute_context.hh"
|
||||
|
||||
#include "BKE_compute_context_cache.hh"
|
||||
#include "BKE_node_tree_zones.hh"
|
||||
|
||||
#include "ED_node.hh"
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
static bool is_evaluate_closure_node_input(const SocketInContext &socket)
|
||||
{
|
||||
return socket->is_input() && socket->index() == 0 &&
|
||||
socket.owner_node()->is_type("GeometryNodeEvaluateClosure");
|
||||
}
|
||||
|
||||
static bool is_closure_zone_output_socket(const SocketInContext &socket)
|
||||
{
|
||||
return socket->owner_node().is_type("GeometryNodeClosureOutput") && socket->is_output();
|
||||
}
|
||||
|
||||
static Vector<SocketInContext> find_origin_sockets_through_contexts(
|
||||
SocketInContext start_socket,
|
||||
bke::ComputeContextCache &compute_context_cache,
|
||||
FunctionRef<bool(const SocketInContext &)> handle_possible_origin_socket_fn,
|
||||
bool find_all);
|
||||
|
||||
static Vector<SocketInContext> find_target_sockets_through_contexts(
|
||||
const SocketInContext start_socket,
|
||||
bke::ComputeContextCache &compute_context_cache,
|
||||
const FunctionRef<bool(const SocketInContext &)> handle_possible_target_socket_fn,
|
||||
const bool find_all)
|
||||
{
|
||||
using BundlePath = Vector<std::string, 0>;
|
||||
|
||||
struct SocketToCheck {
|
||||
SocketInContext socket;
|
||||
BundlePath bundle_path;
|
||||
};
|
||||
|
||||
Stack<SocketToCheck> sockets_to_check;
|
||||
Set<SocketInContext> added_sockets;
|
||||
|
||||
auto add_if_new = [&](const SocketInContext &socket, BundlePath bundle_path) {
|
||||
if (added_sockets.add(socket)) {
|
||||
sockets_to_check.push({socket, std::move(bundle_path)});
|
||||
}
|
||||
};
|
||||
|
||||
add_if_new(start_socket, {});
|
||||
|
||||
VectorSet<SocketInContext> found_targets;
|
||||
|
||||
while (!sockets_to_check.is_empty()) {
|
||||
const SocketToCheck socket_to_check = sockets_to_check.pop();
|
||||
const SocketInContext socket = socket_to_check.socket;
|
||||
const BundlePath &bundle_path = socket_to_check.bundle_path;
|
||||
const NodeInContext &node = socket.owner_node();
|
||||
if (socket->is_input()) {
|
||||
if (node->is_muted()) {
|
||||
for (const bNodeLink &link : node->internal_links()) {
|
||||
if (link.fromsock == socket.socket) {
|
||||
add_if_new({socket.context, link.tosock}, bundle_path);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (bundle_path.is_empty() && handle_possible_target_socket_fn(socket)) {
|
||||
found_targets.add(socket);
|
||||
if (!find_all) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (node->is_reroute()) {
|
||||
add_if_new(node.output_socket(0), bundle_path);
|
||||
continue;
|
||||
}
|
||||
if (node->is_group()) {
|
||||
if (const bNodeTree *group = reinterpret_cast<const bNodeTree *>(node->id)) {
|
||||
group->ensure_topology_cache();
|
||||
const ComputeContext &group_compute_context = compute_context_cache.for_group_node(
|
||||
socket.context, node->identifier, &node->owner_tree());
|
||||
for (const bNode *input_node : group->group_input_nodes()) {
|
||||
const bNodeSocket &group_input_socket = input_node->output_socket(socket->index());
|
||||
if (group_input_socket.is_directly_linked()) {
|
||||
add_if_new({&group_compute_context, &group_input_socket}, bundle_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (node->is_group_output()) {
|
||||
if (const auto *group_context = dynamic_cast<const bke::GroupNodeComputeContext *>(
|
||||
socket.context))
|
||||
{
|
||||
const bNodeTree *caller_group = group_context->tree();
|
||||
const bNode *caller_group_node = group_context->node();
|
||||
if (caller_group && caller_group_node) {
|
||||
caller_group->ensure_topology_cache();
|
||||
const bNodeSocket &output_socket = caller_group_node->output_socket(socket->index());
|
||||
add_if_new({group_context->parent(), &output_socket}, bundle_path);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (node->is_type("GeometryNodeCombineBundle")) {
|
||||
const auto &storage = *static_cast<const NodeGeometryCombineBundle *>(node->storage);
|
||||
BundlePath new_bundle_path = bundle_path;
|
||||
new_bundle_path.append(storage.items[socket->index()].name);
|
||||
add_if_new(node.output_socket(0), std::move(new_bundle_path));
|
||||
continue;
|
||||
}
|
||||
if (node->is_type("GeometryNodeSeparateBundle")) {
|
||||
if (bundle_path.is_empty()) {
|
||||
continue;
|
||||
}
|
||||
const StringRef last_key = bundle_path.last();
|
||||
const auto &storage = *static_cast<const NodeGeometrySeparateBundle *>(node->storage);
|
||||
for (const int output_i : IndexRange(storage.items_num)) {
|
||||
if (last_key == storage.items[output_i].name) {
|
||||
add_if_new(node.output_socket(output_i), bundle_path.as_span().drop_back(1));
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (node->is_type("GeometryNodeClosureOutput")) {
|
||||
const auto &closure_storage = *static_cast<const NodeGeometryClosureOutput *>(
|
||||
node->storage);
|
||||
const StringRef key = closure_storage.output_items.items[socket->index()].name;
|
||||
const Vector<SocketInContext> target_sockets = find_target_sockets_through_contexts(
|
||||
node.output_socket(0), compute_context_cache, is_evaluate_closure_node_input, true);
|
||||
for (const auto &target_socket : target_sockets) {
|
||||
const NodeInContext evaluate_node = target_socket.owner_node();
|
||||
const auto &evaluate_storage = *static_cast<const NodeGeometryEvaluateClosure *>(
|
||||
evaluate_node->storage);
|
||||
for (const int i : IndexRange(evaluate_storage.output_items.items_num)) {
|
||||
const NodeGeometryEvaluateClosureOutputItem &item =
|
||||
evaluate_storage.output_items.items[i];
|
||||
if (key == item.name) {
|
||||
add_if_new(evaluate_node.output_socket(i), bundle_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (node->is_type("GeometryNodeEvaluateClosure")) {
|
||||
if (socket->index() == 0) {
|
||||
continue;
|
||||
}
|
||||
const auto &evaluate_storage = *static_cast<const NodeGeometryEvaluateClosure *>(
|
||||
node->storage);
|
||||
const StringRef key = evaluate_storage.input_items.items[socket->index() - 1].name;
|
||||
const Vector<SocketInContext> origin_sockets = find_origin_sockets_through_contexts(
|
||||
node.input_socket(0), compute_context_cache, is_closure_zone_output_socket, true);
|
||||
for (const SocketInContext origin_socket : origin_sockets) {
|
||||
const bNodeTree &closure_tree = origin_socket->owner_tree();
|
||||
const bke::bNodeTreeZones *closure_tree_zones = closure_tree.zones();
|
||||
if (!closure_tree_zones) {
|
||||
continue;
|
||||
}
|
||||
const auto &closure_output_node = origin_socket.owner_node();
|
||||
const bke::bNodeTreeZone *closure_zone = closure_tree_zones->get_zone_by_node(
|
||||
closure_output_node->identifier);
|
||||
if (!closure_zone) {
|
||||
continue;
|
||||
}
|
||||
const bNode *closure_input_node = closure_zone->input_node();
|
||||
if (!closure_input_node) {
|
||||
continue;
|
||||
}
|
||||
const ComputeContext &closure_context = compute_context_cache.for_evaluate_closure(
|
||||
node.context,
|
||||
node->identifier,
|
||||
&node->owner_tree(),
|
||||
ClosureSourceLocation{
|
||||
&closure_tree, closure_output_node->identifier, origin_socket.context_hash()});
|
||||
const auto &closure_output_storage = *static_cast<const NodeGeometryClosureOutput *>(
|
||||
closure_output_node->storage);
|
||||
for (const int i : IndexRange(closure_output_storage.input_items.items_num)) {
|
||||
const NodeGeometryClosureInputItem &item = closure_output_storage.input_items.items[i];
|
||||
if (key == item.name) {
|
||||
add_if_new({&closure_context, &closure_input_node->output_socket(i)}, bundle_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
const bke::bNodeTreeZones *zones = node->owner_tree().zones();
|
||||
if (!zones) {
|
||||
continue;
|
||||
}
|
||||
const bke::bNodeTreeZone *from_zone = zones->get_zone_by_socket(*socket.socket);
|
||||
for (const bNodeLink *link : socket->directly_linked_links()) {
|
||||
if (!link->is_used()) {
|
||||
continue;
|
||||
}
|
||||
bNodeSocket *to_socket = link->tosock;
|
||||
const bke::bNodeTreeZone *to_zone = zones->get_zone_by_socket(*to_socket);
|
||||
if (!zones->link_between_zones_is_allowed(from_zone, to_zone)) {
|
||||
continue;
|
||||
}
|
||||
const Vector<const bke::bNodeTreeZone *> zones_to_enter = zones->get_zones_to_enter(
|
||||
from_zone, to_zone);
|
||||
const ComputeContext *compute_context = ed::space_node::compute_context_for_zones(
|
||||
zones_to_enter, compute_context_cache, socket.context);
|
||||
if (!compute_context) {
|
||||
continue;
|
||||
}
|
||||
add_if_new({compute_context, to_socket}, bundle_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
return found_targets.extract_vector();
|
||||
}
|
||||
|
||||
[[nodiscard]] const ComputeContext *compute_context_for_closure_evaluation(
|
||||
const ComputeContext *closure_socket_context,
|
||||
const bNodeSocket &closure_socket,
|
||||
bke::ComputeContextCache &compute_context_cache,
|
||||
const std::optional<ClosureSourceLocation> &source_location)
|
||||
{
|
||||
const Vector<SocketInContext> target_sockets = find_target_sockets_through_contexts(
|
||||
{closure_socket_context, &closure_socket},
|
||||
compute_context_cache,
|
||||
is_evaluate_closure_node_input,
|
||||
false);
|
||||
if (target_sockets.is_empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
const SocketInContext target_socket = target_sockets[0];
|
||||
const NodeInContext target_node = target_socket.owner_node();
|
||||
return &compute_context_cache.for_evaluate_closure(target_socket.context,
|
||||
target_node->identifier,
|
||||
&target_socket->owner_tree(),
|
||||
source_location);
|
||||
}
|
||||
|
||||
static Vector<SocketInContext> find_origin_sockets_through_contexts(
|
||||
const SocketInContext start_socket,
|
||||
bke::ComputeContextCache &compute_context_cache,
|
||||
const FunctionRef<bool(const SocketInContext &)> handle_possible_origin_socket_fn,
|
||||
const bool find_all)
|
||||
{
|
||||
using BundlePath = Vector<std::string, 0>;
|
||||
|
||||
struct SocketToCheck {
|
||||
SocketInContext socket;
|
||||
BundlePath bundle_path;
|
||||
};
|
||||
|
||||
Stack<SocketToCheck> sockets_to_check;
|
||||
Set<SocketInContext> added_sockets;
|
||||
|
||||
auto add_if_new = [&](const SocketInContext &socket, BundlePath bundle_path) {
|
||||
if (added_sockets.add(socket)) {
|
||||
sockets_to_check.push({socket, std::move(bundle_path)});
|
||||
}
|
||||
};
|
||||
|
||||
add_if_new(start_socket, {});
|
||||
|
||||
VectorSet<SocketInContext> found_origins;
|
||||
|
||||
while (!sockets_to_check.is_empty()) {
|
||||
const SocketToCheck socket_to_check = sockets_to_check.pop();
|
||||
const SocketInContext socket = socket_to_check.socket;
|
||||
const BundlePath &bundle_path = socket_to_check.bundle_path;
|
||||
const NodeInContext &node = socket.owner_node();
|
||||
if (socket->is_input()) {
|
||||
if (bundle_path.is_empty() && handle_possible_origin_socket_fn(socket)) {
|
||||
found_origins.add(socket);
|
||||
if (!find_all) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
const bke::bNodeTreeZones *zones = node->owner_tree().zones();
|
||||
if (!zones) {
|
||||
continue;
|
||||
}
|
||||
const bke::bNodeTreeZone *to_zone = zones->get_zone_by_socket(*socket.socket);
|
||||
for (const bNodeLink *link : socket->directly_linked_links()) {
|
||||
if (!link->is_used()) {
|
||||
continue;
|
||||
}
|
||||
const bNodeSocket *from_socket = link->fromsock;
|
||||
const bke::bNodeTreeZone *from_zone = zones->get_zone_by_socket(*from_socket);
|
||||
if (!zones->link_between_zones_is_allowed(from_zone, to_zone)) {
|
||||
continue;
|
||||
}
|
||||
const Vector<const bke::bNodeTreeZone *> zones_to_enter = zones->get_zones_to_enter(
|
||||
from_zone, to_zone);
|
||||
const ComputeContext *compute_context = socket.context;
|
||||
for (int i = zones_to_enter.size() - 1; i >= 0; i--) {
|
||||
if (!compute_context) {
|
||||
/* There must be a compute context when we are in a zone. */
|
||||
BLI_assert_unreachable();
|
||||
return found_origins.extract_vector();
|
||||
}
|
||||
/* Each zone corresponds to one compute context level. */
|
||||
compute_context = compute_context->parent();
|
||||
}
|
||||
add_if_new({compute_context, from_socket}, bundle_path);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (node->is_muted()) {
|
||||
for (const bNodeLink &link : node->internal_links()) {
|
||||
if (link.tosock == socket.socket) {
|
||||
add_if_new({socket.context, link.fromsock}, bundle_path);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (bundle_path.is_empty() && handle_possible_origin_socket_fn(socket)) {
|
||||
found_origins.add(socket);
|
||||
if (!find_all) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (node->is_reroute()) {
|
||||
add_if_new(node.input_socket(0), bundle_path);
|
||||
continue;
|
||||
}
|
||||
if (node->is_group()) {
|
||||
if (const bNodeTree *group = reinterpret_cast<const bNodeTree *>(node->id)) {
|
||||
group->ensure_topology_cache();
|
||||
if (const bNode *group_output_node = group->group_output_node()) {
|
||||
const ComputeContext &group_compute_context = compute_context_cache.for_group_node(
|
||||
socket.context, node->identifier, &node->owner_tree());
|
||||
add_if_new({&group_compute_context, &group_output_node->input_socket(socket->index())},
|
||||
bundle_path);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (node->is_group_input()) {
|
||||
if (const auto *group_context = dynamic_cast<const bke::GroupNodeComputeContext *>(
|
||||
socket.context))
|
||||
{
|
||||
const bNodeTree *caller_group = group_context->tree();
|
||||
const bNode *caller_group_node = group_context->node();
|
||||
if (caller_group && caller_group_node) {
|
||||
caller_group->ensure_topology_cache();
|
||||
const bNodeSocket &input_socket = caller_group_node->input_socket(socket->index());
|
||||
add_if_new({group_context->parent(), &input_socket}, bundle_path);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (node->is_type("GeometryNodeEvaluateClosure")) {
|
||||
const auto &evaluate_storage = *static_cast<const NodeGeometryEvaluateClosure *>(
|
||||
node->storage);
|
||||
const StringRef key = evaluate_storage.output_items.items[socket->index()].name;
|
||||
const Vector<SocketInContext> origin_sockets = find_origin_sockets_through_contexts(
|
||||
node.input_socket(0), compute_context_cache, is_closure_zone_output_socket, true);
|
||||
for (const SocketInContext origin_socket : origin_sockets) {
|
||||
const bNodeTree &closure_tree = origin_socket->owner_tree();
|
||||
const NodeInContext closure_output_node = origin_socket.owner_node();
|
||||
const auto &closure_storage = *static_cast<const NodeGeometryClosureOutput *>(
|
||||
closure_output_node->storage);
|
||||
const ComputeContext &closure_context = compute_context_cache.for_evaluate_closure(
|
||||
node.context,
|
||||
node->identifier,
|
||||
&node->owner_tree(),
|
||||
ClosureSourceLocation{
|
||||
&closure_tree, closure_output_node->identifier, origin_socket.context_hash()});
|
||||
for (const int i : IndexRange(closure_storage.output_items.items_num)) {
|
||||
const NodeGeometryClosureOutputItem &item = closure_storage.output_items.items[i];
|
||||
if (key == item.name) {
|
||||
add_if_new({&closure_context, &closure_output_node->input_socket(i)}, bundle_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (node->is_type("GeometryNodeClosureInput")) {
|
||||
const auto &input_storage = *static_cast<const NodeGeometryClosureInput *>(node->storage);
|
||||
const bNode *closure_output_node = node->owner_tree().node_by_id(
|
||||
input_storage.output_node_id);
|
||||
if (!closure_output_node) {
|
||||
continue;
|
||||
}
|
||||
const auto &output_storage = *static_cast<const NodeGeometryClosureOutput *>(
|
||||
closure_output_node->storage);
|
||||
const StringRef key = output_storage.input_items.items[socket->index()].name;
|
||||
const bNodeSocket &closure_output_socket = closure_output_node->output_socket(0);
|
||||
const Vector<SocketInContext> target_sockets = find_target_sockets_through_contexts(
|
||||
{socket.context, &closure_output_socket},
|
||||
compute_context_cache,
|
||||
is_evaluate_closure_node_input,
|
||||
true);
|
||||
for (const SocketInContext &target_socket : target_sockets) {
|
||||
const NodeInContext target_node = target_socket.owner_node();
|
||||
const auto &evaluate_storage = *static_cast<const NodeGeometryEvaluateClosure *>(
|
||||
target_node.node->storage);
|
||||
for (const int i : IndexRange(evaluate_storage.input_items.items_num)) {
|
||||
const NodeGeometryEvaluateClosureInputItem &item =
|
||||
evaluate_storage.input_items.items[i];
|
||||
if (key == item.name) {
|
||||
add_if_new(target_node.input_socket(i + 1), bundle_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (node->is_type("GeometryNodeCombineBundle")) {
|
||||
if (bundle_path.is_empty()) {
|
||||
continue;
|
||||
}
|
||||
const StringRef last_key = bundle_path.last();
|
||||
const auto &storage = *static_cast<const NodeGeometryCombineBundle *>(node->storage);
|
||||
for (const int input_i : IndexRange(storage.items_num)) {
|
||||
if (last_key == storage.items[input_i].name) {
|
||||
add_if_new(node.input_socket(input_i), bundle_path.as_span().drop_back(1));
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (node->is_type("GeometryNodeSeparateBundle")) {
|
||||
const auto &storage = *static_cast<const NodeGeometrySeparateBundle *>(node->storage);
|
||||
BundlePath new_bundle_path = bundle_path;
|
||||
new_bundle_path.append(storage.items[socket->index()].name);
|
||||
add_if_new(node.input_socket(0), std::move(new_bundle_path));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found_origins.extract_vector();
|
||||
}
|
||||
|
||||
Vector<BundleSignature> gather_linked_target_bundle_signatures(
|
||||
const ComputeContext *bundle_socket_context,
|
||||
const bNodeSocket &bundle_socket,
|
||||
bke::ComputeContextCache &compute_context_cache)
|
||||
{
|
||||
const Vector<SocketInContext> target_sockets = find_target_sockets_through_contexts(
|
||||
{bundle_socket_context, &bundle_socket},
|
||||
compute_context_cache,
|
||||
[](const SocketInContext &socket) {
|
||||
return socket->owner_node().is_type("GeometryNodeSeparateBundle");
|
||||
},
|
||||
true);
|
||||
Vector<BundleSignature> signatures;
|
||||
for (const SocketInContext &target_socket : target_sockets) {
|
||||
const NodeInContext &target_node = target_socket.owner_node();
|
||||
signatures.append(BundleSignature::from_separate_bundle_node(*target_node.node));
|
||||
}
|
||||
return signatures;
|
||||
}
|
||||
|
||||
Vector<BundleSignature> gather_linked_origin_bundle_signatures(
|
||||
const ComputeContext *bundle_socket_context,
|
||||
const bNodeSocket &bundle_socket,
|
||||
bke::ComputeContextCache &compute_context_cache)
|
||||
{
|
||||
const Vector<SocketInContext> origin_sockets = find_origin_sockets_through_contexts(
|
||||
{bundle_socket_context, &bundle_socket},
|
||||
compute_context_cache,
|
||||
[](const SocketInContext &socket) {
|
||||
return socket->owner_node().is_type("GeometryNodeCombineBundle");
|
||||
},
|
||||
true);
|
||||
Vector<BundleSignature> signatures;
|
||||
for (const SocketInContext &origin_socket : origin_sockets) {
|
||||
const NodeInContext &origin_node = origin_socket.owner_node();
|
||||
signatures.append(BundleSignature::from_combine_bundle_node(*origin_node.node));
|
||||
}
|
||||
return signatures;
|
||||
}
|
||||
|
||||
Vector<ClosureSignature> gather_linked_target_closure_signatures(
|
||||
const ComputeContext *closure_socket_context,
|
||||
const bNodeSocket &closure_socket,
|
||||
bke::ComputeContextCache &compute_context_cache)
|
||||
{
|
||||
const Vector<SocketInContext> target_sockets = find_target_sockets_through_contexts(
|
||||
{closure_socket_context, &closure_socket},
|
||||
compute_context_cache,
|
||||
is_evaluate_closure_node_input,
|
||||
true);
|
||||
Vector<ClosureSignature> signatures;
|
||||
for (const SocketInContext &target_socket : target_sockets) {
|
||||
const NodeInContext &target_node = target_socket.owner_node();
|
||||
signatures.append(ClosureSignature::from_evaluate_closure_node(*target_node.node));
|
||||
}
|
||||
return signatures;
|
||||
}
|
||||
|
||||
Vector<ClosureSignature> gather_linked_origin_closure_signatures(
|
||||
const ComputeContext *closure_socket_context,
|
||||
const bNodeSocket &closure_socket,
|
||||
bke::ComputeContextCache &compute_context_cache)
|
||||
{
|
||||
Vector<ClosureSignature> signatures;
|
||||
find_origin_sockets_through_contexts(
|
||||
{closure_socket_context, &closure_socket},
|
||||
compute_context_cache,
|
||||
[&](const SocketInContext &socket) {
|
||||
if (is_closure_zone_output_socket(socket)) {
|
||||
signatures.append(ClosureSignature::from_closure_output_node(socket->owner_node()));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
true);
|
||||
return signatures;
|
||||
}
|
||||
|
||||
} // namespace blender::nodes
|
||||
Reference in New Issue
Block a user