diff options
author | Sergey Sharybin <sergey@blender.org> | 2022-07-20 11:04:02 +0300 |
---|---|---|
committer | Sergey Sharybin <sergey@blender.org> | 2022-07-21 10:49:16 +0300 |
commit | 0dcee6a386645bb1e976d11aa2d1ae45b01f968a (patch) | |
tree | 4597d5a758b74dcc88fcde60f545821665c0d7c8 /source/blender/depsgraph/intern/builder | |
parent | 4089b7b80ba291dc04266a0dc58820ceeb48eb7b (diff) |
Fix T99733: Objects with driven visibility are evaluated when not needed
The issue was caused by the fact that objects with driven or animated
visibility were considered visible by the dependency graph evaluation.
This change makes it so the dependency graph evaluation is aware of
visibility which might be changing. This is achieved by evaluating the
path of the graph which affects objects visibility and adjusts to it
before evaluating the rest of the graph.
There is some time penalty to this, but there does not seem to be a
way to fully avoid this penalty.
With the production shot from the heist project the FPS drops by a
tenth of a frame (~9.4 vs ~9.3 fps) when adding a driver to an object
which keeps it visible. Note that this is a bit hard to measure since
the FPS fluctuates quite a bit throughout the playback. On the other
hand, having a driver on a visibility of a heavy object from character
and setting visibility to false gives big speedup.
Also worth noting that there is no penalty at all when there are no
animated visibilities in the scene.
Differential Revision: https://developer.blender.org/D15498
Diffstat (limited to 'source/blender/depsgraph/intern/builder')
5 files changed, 56 insertions, 93 deletions
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc index 1fec1fb3219..5353f71685c 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder.cc @@ -29,6 +29,7 @@ #include "intern/depsgraph_tag.h" #include "intern/depsgraph_type.h" #include "intern/eval/deg_eval_copy_on_write.h" +#include "intern/eval/deg_eval_visibility.h" #include "intern/node/deg_node.h" #include "intern/node/deg_node_component.h" #include "intern/node/deg_node_id.h" @@ -71,10 +72,15 @@ bool DepsgraphBuilder::need_pull_base_into_graph(const Base *base) if (base->flag & base_flag) { return true; } + /* More involved check: since we don't support dynamic changes in dependency graph topology and * all visible objects are to be part of dependency graph, we pull all objects which has animated * visibility. */ - const Object *object = base->object; + return is_object_visibility_animated(base->object); +} + +bool DepsgraphBuilder::is_object_visibility_animated(const Object *object) +{ AnimatedPropertyID property_id; if (graph_->mode == DAG_EVAL_VIEWPORT) { property_id = AnimatedPropertyID(&object->id, &RNA_Object, "hide_viewport"); @@ -127,84 +133,9 @@ bool DepsgraphBuilder::check_pchan_has_bbone_segments(const Object *object, cons /** \name Builder Finalizer. * \{ */ -namespace { - -void deg_graph_build_flush_visibility(Depsgraph *graph) -{ - enum { - DEG_NODE_VISITED = (1 << 0), - }; - - BLI_Stack *stack = BLI_stack_new(sizeof(OperationNode *), "DEG flush layers stack"); - for (IDNode *id_node : graph->id_nodes) { - for (ComponentNode *comp_node : id_node->components.values()) { - comp_node->affects_directly_visible |= id_node->is_directly_visible; - } - } - - for (OperationNode *op_node : graph->operations) { - op_node->custom_flags = 0; - op_node->num_links_pending = 0; - for (Relation *rel : op_node->outlinks) { - if ((rel->from->type == NodeType::OPERATION) && (rel->flag & RELATION_FLAG_CYCLIC) == 0) { - ++op_node->num_links_pending; - } - } - if (op_node->num_links_pending == 0) { - BLI_stack_push(stack, &op_node); - op_node->custom_flags |= DEG_NODE_VISITED; - } - } - - while (!BLI_stack_is_empty(stack)) { - OperationNode *op_node; - BLI_stack_pop(stack, &op_node); - /* Flush layers to parents. */ - for (Relation *rel : op_node->inlinks) { - if (rel->from->type == NodeType::OPERATION) { - OperationNode *op_from = (OperationNode *)rel->from; - ComponentNode *comp_from = op_from->owner; - const bool target_directly_visible = op_node->owner->affects_directly_visible; - - /* Visibility component forces all components of the current ID to be considered as - * affecting directly visible. */ - if (comp_from->type == NodeType::VISIBILITY) { - if (target_directly_visible) { - IDNode *id_node_from = comp_from->owner; - for (ComponentNode *comp_node : id_node_from->components.values()) { - comp_node->affects_directly_visible |= target_directly_visible; - } - } - } - else { - comp_from->affects_directly_visible |= target_directly_visible; - } - } - } - /* Schedule parent nodes. */ - for (Relation *rel : op_node->inlinks) { - if (rel->from->type == NodeType::OPERATION) { - OperationNode *op_from = (OperationNode *)rel->from; - if ((rel->flag & RELATION_FLAG_CYCLIC) == 0) { - BLI_assert(op_from->num_links_pending > 0); - --op_from->num_links_pending; - } - if ((op_from->num_links_pending == 0) && (op_from->custom_flags & DEG_NODE_VISITED) == 0) { - BLI_stack_push(stack, &op_from); - op_from->custom_flags |= DEG_NODE_VISITED; - } - } - } - } - BLI_stack_free(stack); -} - -} // namespace - void deg_graph_build_finalize(Main *bmain, Depsgraph *graph) { - /* Make sure dependencies of visible ID data-blocks are visible. */ - deg_graph_build_flush_visibility(graph); + deg_graph_flush_visibility_flags(graph); deg_graph_remove_unused_noops(graph); /* Re-tag IDs for update if it was tagged before the relations diff --git a/source/blender/depsgraph/intern/builder/deg_builder.h b/source/blender/depsgraph/intern/builder/deg_builder.h index 950ebfb35ba..c44e5fd5f4d 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.h +++ b/source/blender/depsgraph/intern/builder/deg_builder.h @@ -24,6 +24,8 @@ class DepsgraphBuilder { virtual bool need_pull_base_into_graph(const Base *base); + virtual bool is_object_visibility_animated(const Object *object); + virtual bool check_pchan_has_bbone(const Object *object, const bPoseChannel *pchan); virtual bool check_pchan_has_bbone_segments(const Object *object, const bPoseChannel *pchan); virtual bool check_pchan_has_bbone_segments(const Object *object, const char *bone_name); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 473dda2290c..c65c4beeed6 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -107,6 +107,7 @@ #include "intern/depsgraph_tag.h" #include "intern/depsgraph_type.h" #include "intern/eval/deg_eval_copy_on_write.h" +#include "intern/eval/deg_eval_visibility.h" #include "intern/node/deg_node.h" #include "intern/node/deg_node_component.h" #include "intern/node/deg_node_id.h" @@ -179,11 +180,27 @@ IDNode *DepsgraphNodeBuilder::add_id_node(ID *id) } ComponentNode *visibility_component = id_node->add_component(NodeType::VISIBILITY); - OperationNode *visibility_operation = visibility_component->add_operation( - nullptr, OperationCode::VISIBILITY); + OperationNode *visibility_operation; + + /* Optimization: currently only objects need a special visibility evaluation. For the rest ID + * types keep the node as a NO-OP so that relations can still be routed, but without penalty + * during the graph evaluation. */ + if (id_type == ID_OB) { + visibility_operation = visibility_component->add_operation( + [id_node](::Depsgraph *depsgraph) { + deg_evaluate_object_node_visibility(depsgraph, id_node); + }, + OperationCode::VISIBILITY); + } + else { + visibility_operation = visibility_component->add_operation(nullptr, + OperationCode::VISIBILITY); + } + /* Pin the node so that it and its relations are preserved by the unused nodes/relations * deletion. This is mainly to make it easier to debug visibility. */ - visibility_operation->flag |= OperationFlag::DEPSOP_FLAG_PINNED; + visibility_operation->flag |= (OperationFlag::DEPSOP_FLAG_PINNED | + OperationFlag::DEPSOP_FLAG_AFFECTS_VISIBILITY); graph_->operations.append(visibility_operation); } return id_node; @@ -652,7 +669,7 @@ void DepsgraphNodeBuilder::build_collection(LayerCollection *from_layer_collecti IDNode *id_node; if (built_map_.checkIsBuiltAndTag(collection)) { id_node = find_id_node(&collection->id); - if (is_collection_visible && id_node->is_directly_visible == false && + if (is_collection_visible && id_node->is_visible_on_build == false && id_node->is_collection_fully_expanded == true) { /* Collection became visible, make sure nested collections and * objects are poked with the new visibility flag, since they @@ -669,7 +686,7 @@ void DepsgraphNodeBuilder::build_collection(LayerCollection *from_layer_collecti else { /* Collection itself. */ id_node = add_id_node(&collection->id); - id_node->is_directly_visible = is_collection_visible; + id_node->is_visible_on_build = is_collection_visible; build_idproperties(collection->id.properties); add_operation_node(&collection->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_DONE); @@ -716,7 +733,7 @@ void DepsgraphNodeBuilder::build_object(int base_index, build_object_flags(base_index, object, linked_state); } id_node->linked_state = max(id_node->linked_state, linked_state); - id_node->is_directly_visible |= is_visible; + id_node->is_visible_on_build |= is_visible; id_node->has_base |= (base_index != -1); /* There is no relation path which will connect current object with all the ones which come @@ -735,10 +752,10 @@ void DepsgraphNodeBuilder::build_object(int base_index, * Probably need to assign that to something non-nullptr, but then the logic here will still be * somewhat weird. */ if (scene_ != nullptr && object == scene_->camera) { - id_node->is_directly_visible = true; + id_node->is_visible_on_build = true; } else { - id_node->is_directly_visible = is_visible; + id_node->is_visible_on_build = is_visible; } id_node->has_base |= (base_index != -1); /* Various flags, flushing from bases/collections. */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc index 32ec94211a0..5af9e7d4fe9 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc @@ -92,14 +92,20 @@ void DepsgraphNodeBuilder::build_view_layer(Scene *scene, int base_index = 0; LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { /* object itself */ - if (need_pull_base_into_graph(base)) { - /* NOTE: We consider object visible even if it's currently - * restricted by the base/restriction flags. Otherwise its drivers - * will never be evaluated. - * - * TODO(sergey): Need to go more granular on visibility checks. */ - build_object(base_index, base->object, linked_state, true); - base_index++; + if (!need_pull_base_into_graph(base)) { + continue; + } + + /* NOTE: We consider object visible even if it's currently + * restricted by the base/restriction flags. Otherwise its drivers + * will never be evaluated. + * + * TODO(sergey): Need to go more granular on visibility checks. */ + build_object(base_index, base->object, linked_state, true); + base_index++; + + if (!graph_->has_animated_visibility) { + graph_->has_animated_visibility |= is_object_visibility_animated(base->object); } } build_layer_collections(&view_layer->layer_collections); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 4fe8a626af5..f2646ebc1f1 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -810,6 +810,13 @@ void DepsgraphRelationBuilder::build_object(Object *object) /* Parameters. */ build_parameters(&object->id); + + /* Visibility. + * Evaluate visibility node after the object's base_flags has been updated to the current state + * of collections restrict and object's restrict flags. */ + const ComponentKey object_from_layer_entry_key(&object->id, NodeType::OBJECT_FROM_LAYER); + const ComponentKey visibility_key(&object->id, NodeType::VISIBILITY); + add_relation(object_from_layer_entry_key, visibility_key, "Object Visibility"); } /* NOTE: Implies that the object has base in the current view layer. */ |