Fix #146345: assert when tracing closure value through nested zones

There were two issues:
* Missing null checks when the compute context of a socket can't be detected
  statically.
* Incorrect parent compute context detection for closures. The tricky aspect is
  that closures can be evaluated in a different compute context from where they
  are created.

Pull Request: https://projects.blender.org/blender/blender/pulls/146922
This commit is contained in:
Jacques Lucke
2025-09-28 15:39:17 +02:00
parent 7e25ed26f0
commit 99f84a8987
5 changed files with 35 additions and 12 deletions

View File

@@ -413,6 +413,7 @@ const ComputeContext *compute_context_for_zone(const bke::bNodeTreeZone &zone,
source_location.compute_context_hash = parent_compute_context ?
parent_compute_context->hash() :
ComputeContextHash{};
source_location.compute_context = parent_compute_context;
return compute_context_for_closure_evaluation(parent_compute_context,
output_node.output_socket(0),
compute_context_cache,

View File

@@ -29,6 +29,8 @@ struct ClosureSourceLocation {
const bNodeTree *tree;
int closure_output_node_id;
ComputeContextHash compute_context_hash;
/** Optional actual compute context. If it is set, its hash should be the same as above. */
const ComputeContext *compute_context = nullptr;
};
struct ClosureEvalLog {

View File

@@ -723,7 +723,8 @@ class ShaderNodesInliner {
closure_output_node.identifier,
closure_zone_value->closure_creation_context ?
closure_zone_value->closure_creation_context->hash() :
ComputeContextHash{}};
ComputeContextHash{},
closure_zone_value->closure_creation_context};
const bke::EvaluateClosureComputeContext &closure_eval_context =
compute_context_cache_.for_evaluate_closure(socket.context,
evaluate_closure_node->identifier,

View File

@@ -68,6 +68,9 @@ static BundleSyncState get_sync_state_separate_bundle(
bke::ComputeContextCache compute_context_cache;
const ComputeContext *current_context = ed::space_node::compute_context_for_edittree_socket(
snode, compute_context_cache, *src_bundle_socket);
if (!current_context) {
return {NodeSyncState::NoSyncSource};
}
const LinkedBundleSignatures linked_signatures = gather_linked_origin_bundle_signatures(
current_context, *src_bundle_socket, compute_context_cache);
if (linked_signatures.items.is_empty()) {
@@ -103,6 +106,9 @@ static BundleSyncState get_sync_state_combine_bundle(
bke::ComputeContextCache compute_context_cache;
const ComputeContext *current_context = ed::space_node::compute_context_for_edittree_socket(
snode, compute_context_cache, *src_bundle_socket);
if (!current_context) {
return {NodeSyncState::NoSyncSource};
}
const LinkedBundleSignatures linked_signatures = gather_linked_target_bundle_signatures(
current_context, *src_bundle_socket, compute_context_cache);
if (linked_signatures.items.is_empty()) {
@@ -137,6 +143,9 @@ static ClosureSyncState get_sync_state_closure_output(
bke::ComputeContextCache compute_context_cache;
const ComputeContext *current_context = ed::space_node::compute_context_for_edittree_socket(
snode, compute_context_cache, *src_closure_socket);
if (!current_context) {
return {NodeSyncState::NoSyncSource};
}
const LinkedClosureSignatures linked_signatures = gather_linked_target_closure_signatures(
current_context, *src_closure_socket, compute_context_cache);
if (linked_signatures.items.is_empty()) {
@@ -171,6 +180,9 @@ static ClosureSyncState get_sync_state_evaluate_closure(
bke::ComputeContextCache compute_context_cache;
const ComputeContext *current_context = ed::space_node::compute_context_for_edittree_socket(
snode, compute_context_cache, *src_closure_socket);
if (!current_context) {
return {NodeSyncState::NoSyncSource};
}
const LinkedClosureSignatures linked_signatures = gather_linked_origin_closure_signatures(
current_context, *src_closure_socket, compute_context_cache);
if (linked_signatures.items.is_empty()) {

View File

@@ -204,7 +204,8 @@ static Vector<SocketInContext> find_target_sockets_through_contexts(
&node->owner_tree(),
ClosureSourceLocation{&closure_tree,
closure_output_node->identifier,
origin_socket.context_hash()});
origin_socket.context_hash(),
origin_socket.context});
if (closure_context.is_recursive()) {
continue;
}
@@ -373,17 +374,22 @@ static Vector<SocketInContext> find_origin_sockets_through_contexts(
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();
for (const bke::bNodeTreeZone *zone = to_zone; zone != from_zone; zone = zone->parent_zone)
{
if (const auto *evaluate_closure_context =
dynamic_cast<const bke::EvaluateClosureComputeContext *>(compute_context))
{
const std::optional<nodes::ClosureSourceLocation> &source_location =
evaluate_closure_context->closure_source_location();
/* This is expected to be available during value tracing. */
BLI_assert(source_location);
BLI_assert(source_location->compute_context);
compute_context = source_location->compute_context;
}
else {
compute_context = compute_context->parent();
}
/* Each zone corresponds to one compute context level. */
compute_context = compute_context->parent();
}
add_if_new({compute_context, from_socket}, bundle_path);
}
@@ -457,7 +463,8 @@ static Vector<SocketInContext> find_origin_sockets_through_contexts(
&node->owner_tree(),
ClosureSourceLocation{&closure_tree,
closure_output_node->identifier,
origin_socket.context_hash()});
origin_socket.context_hash(),
origin_socket.context});
if (closure_context.is_recursive()) {
continue;
}