diff --git a/source/blender/depsgraph/intern/builder/deg_builder_remove_noop.cc b/source/blender/depsgraph/intern/builder/deg_builder_remove_noop.cc index 992620a6f03..89e590111a3 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_remove_noop.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_remove_noop.cc @@ -30,9 +30,28 @@ static inline bool is_unused_noop(OperationNode *op_node) return op_node->is_noop() && op_node->outlinks.is_empty(); } +static inline bool is_removable_relation(const Relation *relation) +{ + if (relation->from->type != NodeType::OPERATION || relation->to->type != NodeType::OPERATION) { + return true; + } + + const OperationNode *operation_from = static_cast(relation->from); + const OperationNode *operation_to = static_cast(relation->to); + + /* If the relation connects two different IDs there is a high risk that the removal of the + * relation will make it so visibility flushing is not possible at runtime. This happens with + * relations like the DoF on camera of custom shape on bines: such relation do not lead to an + * actual depsgraph evaluation operation as they are handled on render engine level. + * + * The indirectly linked objects could have some of their components invisible as well, so + * also keep relations which connect different components of the same object so that visibility + * tracking happens correct in those cases as well. */ + return operation_from->owner == operation_to->owner; +} + void deg_graph_remove_unused_noops(Depsgraph *graph) { - int num_removed_relations = 0; deque queue; for (OperationNode *node : graph->operations) { @@ -41,18 +60,19 @@ void deg_graph_remove_unused_noops(Depsgraph *graph) } } + Vector relations_to_remove; + while (!queue.empty()) { OperationNode *to_remove = queue.front(); queue.pop_front(); - while (!to_remove->inlinks.is_empty()) { - Relation *rel_in = to_remove->inlinks[0]; - Node *dependency = rel_in->from; + for (Relation *rel_in : to_remove->inlinks) { + if (!is_removable_relation(rel_in)) { + continue; + } - /* Remove the relation. */ - rel_in->unlink(); - delete rel_in; - num_removed_relations++; + Node *dependency = rel_in->from; + relations_to_remove.append(rel_in); /* Queue parent no-op node that has now become unused. */ OperationNode *operation = dependency->get_exit_operation(); @@ -64,8 +84,16 @@ void deg_graph_remove_unused_noops(Depsgraph *graph) /* TODO(Sybren): Remove the node itself. */ } - DEG_DEBUG_PRINTF( - (::Depsgraph *)graph, BUILD, "Removed %d relations to no-op nodes\n", num_removed_relations); + /* Remove the relations. */ + for (Relation *relation : relations_to_remove) { + relation->unlink(); + delete relation; + } + + DEG_DEBUG_PRINTF((::Depsgraph *)graph, + BUILD, + "Removed %d relations to no-op nodes\n", + int(relations_to_remove.size())); } } // namespace blender::deg