From e12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 17 Apr 2019 06:17:24 +0200 Subject: ClangFormat: apply to source, most of intern Apply clang format as proposed in T53211. For details on usage and instructions for migrating branches without conflicts, see: https://wiki.blender.org/wiki/Tools/ClangFormat --- .../depsgraph/intern/builder/deg_builder.cc | 243 +- .../blender/depsgraph/intern/builder/deg_builder.h | 17 +- .../depsgraph/intern/builder/deg_builder_cycle.cc | 281 +- .../depsgraph/intern/builder/deg_builder_cycle.h | 1 - .../depsgraph/intern/builder/deg_builder_map.cc | 20 +- .../depsgraph/intern/builder/deg_builder_map.h | 55 +- .../depsgraph/intern/builder/deg_builder_nodes.cc | 2509 ++++++----- .../depsgraph/intern/builder/deg_builder_nodes.h | 357 +- .../intern/builder/deg_builder_nodes_rig.cc | 570 ++- .../intern/builder/deg_builder_nodes_view_layer.cc | 206 +- .../intern/builder/deg_builder_pchanmap.cc | 137 +- .../intern/builder/deg_builder_pchanmap.h | 42 +- .../intern/builder/deg_builder_relations.cc | 4415 +++++++++----------- .../intern/builder/deg_builder_relations.h | 521 ++- .../intern/builder/deg_builder_relations_impl.h | 304 +- .../intern/builder/deg_builder_relations_keys.cc | 199 +- .../intern/builder/deg_builder_relations_rig.cc | 900 ++-- .../builder/deg_builder_relations_view_layer.cc | 138 +- .../depsgraph/intern/builder/deg_builder_rna.cc | 549 ++- .../depsgraph/intern/builder/deg_builder_rna.h | 72 +- .../intern/builder/deg_builder_transitive.cc | 96 +- source/blender/depsgraph/intern/debug/deg_debug.cc | 26 +- source/blender/depsgraph/intern/debug/deg_debug.h | 34 +- .../intern/debug/deg_debug_relations_graphviz.cc | 865 ++-- .../intern/debug/deg_debug_stats_gnuplot.cc | 176 +- source/blender/depsgraph/intern/depsgraph.cc | 383 +- source/blender/depsgraph/intern/depsgraph.h | 195 +- source/blender/depsgraph/intern/depsgraph_build.cc | 341 +- source/blender/depsgraph/intern/depsgraph_debug.cc | 492 ++- source/blender/depsgraph/intern/depsgraph_eval.cc | 54 +- .../blender/depsgraph/intern/depsgraph_physics.cc | 292 +- source/blender/depsgraph/intern/depsgraph_query.cc | 300 +- .../depsgraph/intern/depsgraph_query_filter.cc | 292 +- .../depsgraph/intern/depsgraph_query_foreach.cc | 286 +- .../depsgraph/intern/depsgraph_query_iter.cc | 510 ++- source/blender/depsgraph/intern/depsgraph_tag.cc | 1110 +++-- source/blender/depsgraph/intern/depsgraph_tag.h | 7 +- source/blender/depsgraph/intern/depsgraph_type.cc | 21 +- source/blender/depsgraph/intern/depsgraph_type.h | 187 +- .../blender/depsgraph/intern/depsgraph_update.cc | 22 +- source/blender/depsgraph/intern/depsgraph_update.h | 6 +- source/blender/depsgraph/intern/eval/deg_eval.cc | 415 +- .../intern/eval/deg_eval_copy_on_write.cc | 1612 ++++--- .../depsgraph/intern/eval/deg_eval_copy_on_write.h | 9 +- .../depsgraph/intern/eval/deg_eval_flush.cc | 534 ++- .../depsgraph/intern/eval/deg_eval_stats.cc | 35 +- source/blender/depsgraph/intern/node/deg_node.cc | 177 +- source/blender/depsgraph/intern/node/deg_node.h | 275 +- .../depsgraph/intern/node/deg_node_component.cc | 477 +-- .../depsgraph/intern/node/deg_node_component.h | 244 +- .../depsgraph/intern/node/deg_node_factory.cc | 15 +- .../depsgraph/intern/node/deg_node_factory.h | 23 +- .../depsgraph/intern/node/deg_node_factory_impl.h | 48 +- .../blender/depsgraph/intern/node/deg_node_id.cc | 244 +- source/blender/depsgraph/intern/node/deg_node_id.h | 88 +- .../depsgraph/intern/node/deg_node_operation.cc | 315 +- .../depsgraph/intern/node/deg_node_operation.h | 383 +- .../blender/depsgraph/intern/node/deg_node_time.cc | 8 +- .../blender/depsgraph/intern/node/deg_node_time.h | 14 +- 59 files changed, 10563 insertions(+), 11584 deletions(-) (limited to 'source/blender/depsgraph/intern') diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc index b6e516ee9b4..ef36dec6f34 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder.cc @@ -58,65 +58,63 @@ namespace DEG { namespace { struct VisibilityCheckData { - eEvaluationMode eval_mode; - bool is_visibility_animated; + eEvaluationMode eval_mode; + bool is_visibility_animated; }; void visibility_animated_check_cb(ID * /*id*/, FCurve *fcu, void *user_data) { - VisibilityCheckData *data = - reinterpret_cast(user_data); - if (data->is_visibility_animated) { - return; - } - if (data->eval_mode == DAG_EVAL_VIEWPORT) { - if (STREQ(fcu->rna_path, "hide_viewport")) { - data->is_visibility_animated = true; - } - } - else if (data->eval_mode == DAG_EVAL_RENDER) { - if (STREQ(fcu->rna_path, "hide_render")) { - data->is_visibility_animated = true; - } - } + VisibilityCheckData *data = reinterpret_cast(user_data); + if (data->is_visibility_animated) { + return; + } + if (data->eval_mode == DAG_EVAL_VIEWPORT) { + if (STREQ(fcu->rna_path, "hide_viewport")) { + data->is_visibility_animated = true; + } + } + else if (data->eval_mode == DAG_EVAL_RENDER) { + if (STREQ(fcu->rna_path, "hide_render")) { + data->is_visibility_animated = true; + } + } } bool is_object_visibility_animated(const Depsgraph *graph, Object *object) { - AnimData *anim_data = BKE_animdata_from_id(&object->id); - if (anim_data == NULL) { - return false; - } - VisibilityCheckData data; - data.eval_mode = graph->mode; - data.is_visibility_animated = false; - BKE_fcurves_id_cb(&object->id, visibility_animated_check_cb, &data); - return data.is_visibility_animated; + AnimData *anim_data = BKE_animdata_from_id(&object->id); + if (anim_data == NULL) { + return false; + } + VisibilityCheckData data; + data.eval_mode = graph->mode; + data.is_visibility_animated = false; + BKE_fcurves_id_cb(&object->id, visibility_animated_check_cb, &data); + return data.is_visibility_animated; } } // namespace bool deg_check_base_available_for_build(const Depsgraph *graph, Base *base) { - const int base_flag = (graph->mode == DAG_EVAL_VIEWPORT) ? - BASE_ENABLED_VIEWPORT : BASE_ENABLED_RENDER; - if (base->flag & base_flag) { - return true; - } - if (is_object_visibility_animated(graph, base->object)) { - return true; - } - return false; + const int base_flag = (graph->mode == DAG_EVAL_VIEWPORT) ? BASE_ENABLED_VIEWPORT : + BASE_ENABLED_RENDER; + if (base->flag & base_flag) { + return true; + } + if (is_object_visibility_animated(graph, base->object)) { + return true; + } + return false; } -DepsgraphBuilder::DepsgraphBuilder(Main *bmain, Depsgraph *graph) - : bmain_(bmain), - graph_(graph) { +DepsgraphBuilder::DepsgraphBuilder(Main *bmain, Depsgraph *graph) : bmain_(bmain), graph_(graph) +{ } bool DepsgraphBuilder::need_pull_base_into_graph(Base *base) { - return deg_check_base_available_for_build(graph_, base); + return deg_check_base_available_for_build(graph_, base); } /******************************************************************************* @@ -127,101 +125,90 @@ 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) { - GHASH_FOREACH_BEGIN(ComponentNode *, comp_node, id_node->components) - { - comp_node->affects_directly_visible |= id_node->is_directly_visible; - } - GHASH_FOREACH_END(); - } - 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; - op_from->owner->affects_directly_visible |= - op_node->owner->affects_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); + 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) { + GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) { + comp_node->affects_directly_visible |= id_node->is_directly_visible; + } + GHASH_FOREACH_END(); + } + 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; + op_from->owner->affects_directly_visible |= op_node->owner->affects_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 datablocks are visible. */ - deg_graph_build_flush_visibility(graph); - /* Re-tag IDs for update if it was tagged before the relations - * update tag. */ - for (IDNode *id_node : graph->id_nodes) { - ID *id = id_node->id_orig; - id_node->finalize_build(graph); - int flag = 0; - /* Tag rebuild if special evaluation flags changed. */ - if (id_node->eval_flags != id_node->previous_eval_flags) { - flag |= ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY; - } - /* Tag rebuild if the custom data mask changed. */ - if (id_node->customdata_masks != id_node->previous_customdata_masks) { - flag |= ID_RECALC_GEOMETRY; - } - if (!deg_copy_on_write_is_expanded(id_node->id_cow)) { - flag |= ID_RECALC_COPY_ON_WRITE; - /* This means ID is being added to the dependency graph first - * time, which is similar to "ob-visible-change" */ - if (GS(id->name) == ID_OB) { - flag |= ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY; - } - } - if (flag != 0) { - graph_id_tag_update(bmain, - graph, - id_node->id_orig, - flag, - DEG_UPDATE_SOURCE_RELATIONS); - } - } + /* Make sure dependencies of visible ID datablocks are visible. */ + deg_graph_build_flush_visibility(graph); + /* Re-tag IDs for update if it was tagged before the relations + * update tag. */ + for (IDNode *id_node : graph->id_nodes) { + ID *id = id_node->id_orig; + id_node->finalize_build(graph); + int flag = 0; + /* Tag rebuild if special evaluation flags changed. */ + if (id_node->eval_flags != id_node->previous_eval_flags) { + flag |= ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY; + } + /* Tag rebuild if the custom data mask changed. */ + if (id_node->customdata_masks != id_node->previous_customdata_masks) { + flag |= ID_RECALC_GEOMETRY; + } + if (!deg_copy_on_write_is_expanded(id_node->id_cow)) { + flag |= ID_RECALC_COPY_ON_WRITE; + /* This means ID is being added to the dependency graph first + * time, which is similar to "ob-visible-change" */ + if (GS(id->name) == ID_OB) { + flag |= ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY; + } + } + if (flag != 0) { + graph_id_tag_update(bmain, graph, id_node->id_orig, flag, DEG_UPDATE_SOURCE_RELATIONS); + } + } } } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder.h b/source/blender/depsgraph/intern/builder/deg_builder.h index 2461ca2211f..310944f2f28 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.h +++ b/source/blender/depsgraph/intern/builder/deg_builder.h @@ -31,19 +31,18 @@ namespace DEG { struct Depsgraph; class DepsgraphBuilder { -public: - bool need_pull_base_into_graph(struct Base *base); + public: + bool need_pull_base_into_graph(struct Base *base); -protected: - DepsgraphBuilder(Main *bmain, Depsgraph *graph); + protected: + DepsgraphBuilder(Main *bmain, Depsgraph *graph); - /* State which never changes, same for the whole builder time. */ - Main *bmain_; - Depsgraph *graph_; + /* State which never changes, same for the whole builder time. */ + Main *bmain_; + Depsgraph *graph_; }; -bool deg_check_base_available_for_build(const Depsgraph *graph, - Base *base); +bool deg_check_base_available_for_build(const Depsgraph *graph, Base *base); void deg_graph_build_finalize(struct Main *bmain, struct Depsgraph *graph); } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc index a6d86f5178f..af5c4e7130b 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc @@ -41,89 +41,88 @@ namespace DEG { namespace { enum eCyclicCheckVisitedState { - /* Not is not visited at all during traversal. */ - NODE_NOT_VISITED = 0, - /* Node has been visited during traversal and not in current stack. */ - NODE_VISITED = 1, - /* Node has been visited during traversal and is in current stack. */ - NODE_IN_STACK = 2, + /* Not is not visited at all during traversal. */ + NODE_NOT_VISITED = 0, + /* Node has been visited during traversal and not in current stack. */ + NODE_VISITED = 1, + /* Node has been visited during traversal and is in current stack. */ + NODE_IN_STACK = 2, }; struct StackEntry { - OperationNode *node; - StackEntry *from; - Relation *via_relation; + OperationNode *node; + StackEntry *from; + Relation *via_relation; }; struct CyclesSolverState { - CyclesSolverState(Depsgraph *graph) - : graph(graph), - traversal_stack(BLI_stack_new(sizeof(StackEntry), - "DEG detect cycles stack")), - num_cycles(0) - { - /* pass */ - } - ~CyclesSolverState() { - BLI_stack_free(traversal_stack); - if (num_cycles != 0) { - printf("Detected %d dependency cycles\n", num_cycles); - } - } - Depsgraph *graph; - BLI_Stack *traversal_stack; - int num_cycles; + CyclesSolverState(Depsgraph *graph) + : graph(graph), + traversal_stack(BLI_stack_new(sizeof(StackEntry), "DEG detect cycles stack")), + num_cycles(0) + { + /* pass */ + } + ~CyclesSolverState() + { + BLI_stack_free(traversal_stack); + if (num_cycles != 0) { + printf("Detected %d dependency cycles\n", num_cycles); + } + } + Depsgraph *graph; + BLI_Stack *traversal_stack; + int num_cycles; }; -BLI_INLINE void set_node_visited_state(Node *node, - eCyclicCheckVisitedState state) +BLI_INLINE void set_node_visited_state(Node *node, eCyclicCheckVisitedState state) { - node->custom_flags = (node->custom_flags & ~0x3) | (int)state; + node->custom_flags = (node->custom_flags & ~0x3) | (int)state; } BLI_INLINE eCyclicCheckVisitedState get_node_visited_state(Node *node) { - return (eCyclicCheckVisitedState)(node->custom_flags & 0x3); + return (eCyclicCheckVisitedState)(node->custom_flags & 0x3); } BLI_INLINE void set_node_num_visited_children(Node *node, int num_children) { - node->custom_flags = (node->custom_flags & 0x3) | (num_children << 2); + node->custom_flags = (node->custom_flags & 0x3) | (num_children << 2); } BLI_INLINE int get_node_num_visited_children(Node *node) { - return node->custom_flags >> 2; + return node->custom_flags >> 2; } void schedule_node_to_stack(CyclesSolverState *state, OperationNode *node) { - StackEntry entry; - entry.node = node; - entry.from = NULL; - entry.via_relation = NULL; - BLI_stack_push(state->traversal_stack, &entry); - set_node_visited_state(node, NODE_IN_STACK); + StackEntry entry; + entry.node = node; + entry.from = NULL; + entry.via_relation = NULL; + BLI_stack_push(state->traversal_stack, &entry); + set_node_visited_state(node, NODE_IN_STACK); } /* Schedule leaf nodes (node without input links) for traversal. */ void schedule_leaf_nodes(CyclesSolverState *state) { - for (OperationNode *node : state->graph->operations) { - bool has_inlinks = false; - for (Relation *rel : node->inlinks) { - if (rel->from->type == NodeType::OPERATION) { - has_inlinks = true; - } - } - node->custom_flags = 0; - if (has_inlinks == false) { - schedule_node_to_stack(state, node); - } - else { - set_node_visited_state(node, NODE_NOT_VISITED); - } - } + for (OperationNode *node : state->graph->operations) { + bool has_inlinks = false; + for (Relation *rel : node->inlinks) { + if (rel->from->type == NodeType::OPERATION) { + has_inlinks = true; + } + } + node->custom_flags = 0; + if (has_inlinks == false) { + schedule_node_to_stack(state, node); + } + else { + set_node_visited_state(node, NODE_NOT_VISITED); + } + } } /* Schedule node which was not checked yet for being belong to @@ -131,113 +130,111 @@ void schedule_leaf_nodes(CyclesSolverState *state) */ bool schedule_non_checked_node(CyclesSolverState *state) { - for (OperationNode *node : state->graph->operations) { - if (get_node_visited_state(node) == NODE_NOT_VISITED) { - schedule_node_to_stack(state, node); - return true; - } - } - return false; + for (OperationNode *node : state->graph->operations) { + if (get_node_visited_state(node) == NODE_NOT_VISITED) { + schedule_node_to_stack(state, node); + return true; + } + } + return false; } bool check_relation_can_murder(Relation *relation) { - if (relation->flag & RELATION_FLAG_GODMODE) { - return false; - } - return true; + if (relation->flag & RELATION_FLAG_GODMODE) { + return false; + } + return true; } -Relation *select_relation_to_murder(Relation *relation, - StackEntry *cycle_start_entry) +Relation *select_relation_to_murder(Relation *relation, StackEntry *cycle_start_entry) { - /* More or less russian roulette solver, which will make sure only - * specially marked relations are kept alive. - * - * TODO(sergey): There might be better strategies here. */ - if (check_relation_can_murder(relation)) { - return relation; - } - StackEntry *current = cycle_start_entry; - OperationNode *to_node = (OperationNode *)relation->to; - while (current->node != to_node) { - if (check_relation_can_murder(current->via_relation)) { - return current->via_relation; - } - current = current->from; - } - return relation; + /* More or less russian roulette solver, which will make sure only + * specially marked relations are kept alive. + * + * TODO(sergey): There might be better strategies here. */ + if (check_relation_can_murder(relation)) { + return relation; + } + StackEntry *current = cycle_start_entry; + OperationNode *to_node = (OperationNode *)relation->to; + while (current->node != to_node) { + if (check_relation_can_murder(current->via_relation)) { + return current->via_relation; + } + current = current->from; + } + return relation; } /* Solve cycles with all nodes which are scheduled for traversal. */ void solve_cycles(CyclesSolverState *state) { - BLI_Stack *traversal_stack = state->traversal_stack; - while (!BLI_stack_is_empty(traversal_stack)) { - StackEntry *entry = (StackEntry *)BLI_stack_peek(traversal_stack); - OperationNode *node = entry->node; - bool all_child_traversed = true; - const int num_visited = get_node_num_visited_children(node); - for (int i = num_visited; i < node->outlinks.size(); ++i) { - Relation *rel = node->outlinks[i]; - if (rel->to->type == NodeType::OPERATION) { - OperationNode *to = (OperationNode *)rel->to; - eCyclicCheckVisitedState to_state = get_node_visited_state(to); - if (to_state == NODE_IN_STACK) { - printf("Dependency cycle detected:\n"); - printf(" '%s' depends on '%s' through '%s'\n", - to->full_identifier().c_str(), - node->full_identifier().c_str(), - rel->name); - StackEntry *current = entry; - while (current->node != to) { - BLI_assert(current != NULL); - printf(" '%s' depends on '%s' through '%s'\n", - current->node->full_identifier().c_str(), - current->from->node->full_identifier().c_str(), - current->via_relation->name); - current = current->from; - } - Relation *sacrificial_relation = - select_relation_to_murder(rel, entry); - sacrificial_relation->flag |= RELATION_FLAG_CYCLIC; - ++state->num_cycles; - } - else if (to_state == NODE_NOT_VISITED) { - StackEntry new_entry; - new_entry.node = to; - new_entry.from = entry; - new_entry.via_relation = rel; - BLI_stack_push(traversal_stack, &new_entry); - set_node_visited_state(node, NODE_IN_STACK); - all_child_traversed = false; - set_node_num_visited_children(node, i); - break; - } - } - } - if (all_child_traversed) { - set_node_visited_state(node, NODE_VISITED); - BLI_stack_discard(traversal_stack); - } - } + BLI_Stack *traversal_stack = state->traversal_stack; + while (!BLI_stack_is_empty(traversal_stack)) { + StackEntry *entry = (StackEntry *)BLI_stack_peek(traversal_stack); + OperationNode *node = entry->node; + bool all_child_traversed = true; + const int num_visited = get_node_num_visited_children(node); + for (int i = num_visited; i < node->outlinks.size(); ++i) { + Relation *rel = node->outlinks[i]; + if (rel->to->type == NodeType::OPERATION) { + OperationNode *to = (OperationNode *)rel->to; + eCyclicCheckVisitedState to_state = get_node_visited_state(to); + if (to_state == NODE_IN_STACK) { + printf("Dependency cycle detected:\n"); + printf(" '%s' depends on '%s' through '%s'\n", + to->full_identifier().c_str(), + node->full_identifier().c_str(), + rel->name); + StackEntry *current = entry; + while (current->node != to) { + BLI_assert(current != NULL); + printf(" '%s' depends on '%s' through '%s'\n", + current->node->full_identifier().c_str(), + current->from->node->full_identifier().c_str(), + current->via_relation->name); + current = current->from; + } + Relation *sacrificial_relation = select_relation_to_murder(rel, entry); + sacrificial_relation->flag |= RELATION_FLAG_CYCLIC; + ++state->num_cycles; + } + else if (to_state == NODE_NOT_VISITED) { + StackEntry new_entry; + new_entry.node = to; + new_entry.from = entry; + new_entry.via_relation = rel; + BLI_stack_push(traversal_stack, &new_entry); + set_node_visited_state(node, NODE_IN_STACK); + all_child_traversed = false; + set_node_num_visited_children(node, i); + break; + } + } + } + if (all_child_traversed) { + set_node_visited_state(node, NODE_VISITED); + BLI_stack_discard(traversal_stack); + } + } } } // namespace void deg_graph_detect_cycles(Depsgraph *graph) { - CyclesSolverState state(graph); - /* First we solve cycles which are reachable from leaf nodes. */ - schedule_leaf_nodes(&state); - solve_cycles(&state); - /* We are not done yet. It is possible to have closed loop cycle, - * for example A -> B -> C -> A. These nodes were not scheduled - * yet (since they all have inlinks), and were not traversed since - * nobody else points to them. */ - while (schedule_non_checked_node(&state)) { - solve_cycles(&state); - } + CyclesSolverState state(graph); + /* First we solve cycles which are reachable from leaf nodes. */ + schedule_leaf_nodes(&state); + solve_cycles(&state); + /* We are not done yet. It is possible to have closed loop cycle, + * for example A -> B -> C -> A. These nodes were not scheduled + * yet (since they all have inlinks), and were not traversed since + * nobody else points to them. */ + while (schedule_non_checked_node(&state)) { + solve_cycles(&state); + } } } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.h b/source/blender/depsgraph/intern/builder/deg_builder_cycle.h index 2fe24d1795a..aafdcdbea04 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.h @@ -21,7 +21,6 @@ * \ingroup depsgraph */ - #pragma once namespace DEG { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_map.cc b/source/blender/depsgraph/intern/builder/deg_builder_map.cc index cc5ea98ca93..a519f3e60b5 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_map.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_map.cc @@ -32,32 +32,32 @@ namespace DEG { BuilderMap::BuilderMap() { - set = BLI_gset_ptr_new("deg builder gset"); + set = BLI_gset_ptr_new("deg builder gset"); } BuilderMap::~BuilderMap() { - BLI_gset_free(set, NULL); + BLI_gset_free(set, NULL); } bool BuilderMap::checkIsBuilt(ID *id) { - return BLI_gset_haskey(set, id); + return BLI_gset_haskey(set, id); } void BuilderMap::tagBuild(ID *id) { - BLI_gset_insert(set, id); + BLI_gset_insert(set, id); } bool BuilderMap::checkIsBuiltAndTag(ID *id) { - void **key_p; - if (!BLI_gset_ensure_p_ex(set, id, &key_p)) { - *key_p = id; - return false; - } - return true; + void **key_p; + if (!BLI_gset_ensure_p_ex(set, id, &key_p)) { + *key_p = id; + return false; + } + return true; } } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_map.h b/source/blender/depsgraph/intern/builder/deg_builder_map.h index 193a7837aa6..c1db1d9d2bb 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_map.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_map.h @@ -29,32 +29,35 @@ struct ID; namespace DEG { class BuilderMap { -public: - BuilderMap(); - ~BuilderMap(); - - /* Check whether given ID is already handled by builder (or if it's being - * handled). */ - bool checkIsBuilt(ID *id); - - /* Tag given ID as handled/built. */ - void tagBuild(ID *id); - - /* Combination of previous two functions, returns truth if ID was already - * handled, or tags is handled otherwise and return false. */ - bool checkIsBuiltAndTag(ID *id); - - template bool checkIsBuilt(T *datablock) { - return checkIsBuilt(&datablock->id); - } - template void tagBuild(T *datablock) { - tagBuild(&datablock->id); - } - template bool checkIsBuiltAndTag(T *datablock) { - return checkIsBuiltAndTag(&datablock->id); - } - - GSet *set; + public: + BuilderMap(); + ~BuilderMap(); + + /* Check whether given ID is already handled by builder (or if it's being + * handled). */ + bool checkIsBuilt(ID *id); + + /* Tag given ID as handled/built. */ + void tagBuild(ID *id); + + /* Combination of previous two functions, returns truth if ID was already + * handled, or tags is handled otherwise and return false. */ + bool checkIsBuiltAndTag(ID *id); + + template bool checkIsBuilt(T *datablock) + { + return checkIsBuilt(&datablock->id); + } + template void tagBuild(T *datablock) + { + tagBuild(&datablock->id); + } + template bool checkIsBuiltAndTag(T *datablock) + { + return checkIsBuiltAndTag(&datablock->id); + } + + GSet *set; }; } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 0cc1c2aa211..b37ecb45ac8 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -114,16 +114,15 @@ namespace { void free_copy_on_write_datablock(void *id_info_v) { - DepsgraphNodeBuilder::IDInfo *id_info = - (DepsgraphNodeBuilder::IDInfo *)id_info_v; - if (id_info->id_cow != NULL) { - deg_free_copy_on_write_datablock(id_info->id_cow); - MEM_freeN(id_info->id_cow); - } - MEM_freeN(id_info); + DepsgraphNodeBuilder::IDInfo *id_info = (DepsgraphNodeBuilder::IDInfo *)id_info_v; + if (id_info->id_cow != NULL) { + deg_free_copy_on_write_datablock(id_info->id_cow); + MEM_freeN(id_info->id_cow); + } + MEM_freeN(id_info); } -} /* namespace */ +} /* namespace */ /* ************ */ /* Node Builder */ @@ -143,131 +142,122 @@ DepsgraphNodeBuilder::DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph) DepsgraphNodeBuilder::~DepsgraphNodeBuilder() { - if (id_info_hash_ != NULL) { - BLI_ghash_free(id_info_hash_, NULL, free_copy_on_write_datablock); - } + if (id_info_hash_ != NULL) { + BLI_ghash_free(id_info_hash_, NULL, free_copy_on_write_datablock); + } } IDNode *DepsgraphNodeBuilder::add_id_node(ID *id) { - IDNode *id_node = NULL; - ID *id_cow = NULL; - IDComponentsMask previously_visible_components_mask = 0; - uint32_t previous_eval_flags = 0; - DEGCustomDataMeshMasks previous_customdata_masks; - IDInfo *id_info = (IDInfo *)BLI_ghash_lookup(id_info_hash_, id); - if (id_info != NULL) { - id_cow = id_info->id_cow; - previously_visible_components_mask = - id_info->previously_visible_components_mask; - previous_eval_flags = id_info->previous_eval_flags; - previous_customdata_masks = id_info->previous_customdata_masks; - /* Tag ID info to not free the CoW ID pointer. */ - id_info->id_cow = NULL; - } - id_node = graph_->add_id_node(id, id_cow); - id_node->previously_visible_components_mask = - previously_visible_components_mask; - id_node->previous_eval_flags = previous_eval_flags; - id_node->previous_customdata_masks = previous_customdata_masks; - /* Currently all ID nodes are supposed to have copy-on-write logic. - * - * NOTE: Zero number of components indicates that ID node was just created. */ - if (BLI_ghash_len(id_node->components) == 0) { - ComponentNode *comp_cow = - id_node->add_component(NodeType::COPY_ON_WRITE); - OperationNode *op_cow = comp_cow->add_operation( - function_bind(deg_evaluate_copy_on_write, _1, id_node), - OperationCode::COPY_ON_WRITE, - "", -1); - graph_->operations.push_back(op_cow); - } - return id_node; + IDNode *id_node = NULL; + ID *id_cow = NULL; + IDComponentsMask previously_visible_components_mask = 0; + uint32_t previous_eval_flags = 0; + DEGCustomDataMeshMasks previous_customdata_masks; + IDInfo *id_info = (IDInfo *)BLI_ghash_lookup(id_info_hash_, id); + if (id_info != NULL) { + id_cow = id_info->id_cow; + previously_visible_components_mask = id_info->previously_visible_components_mask; + previous_eval_flags = id_info->previous_eval_flags; + previous_customdata_masks = id_info->previous_customdata_masks; + /* Tag ID info to not free the CoW ID pointer. */ + id_info->id_cow = NULL; + } + id_node = graph_->add_id_node(id, id_cow); + id_node->previously_visible_components_mask = previously_visible_components_mask; + id_node->previous_eval_flags = previous_eval_flags; + id_node->previous_customdata_masks = previous_customdata_masks; + /* Currently all ID nodes are supposed to have copy-on-write logic. + * + * NOTE: Zero number of components indicates that ID node was just created. */ + if (BLI_ghash_len(id_node->components) == 0) { + ComponentNode *comp_cow = id_node->add_component(NodeType::COPY_ON_WRITE); + OperationNode *op_cow = comp_cow->add_operation( + function_bind(deg_evaluate_copy_on_write, _1, id_node), + OperationCode::COPY_ON_WRITE, + "", + -1); + graph_->operations.push_back(op_cow); + } + return id_node; } IDNode *DepsgraphNodeBuilder::find_id_node(ID *id) { - return graph_->find_id_node(id); + return graph_->find_id_node(id); } TimeSourceNode *DepsgraphNodeBuilder::add_time_source() { - return graph_->add_time_source(); + return graph_->add_time_source(); } -ComponentNode *DepsgraphNodeBuilder::add_component_node( - ID *id, - NodeType comp_type, - const char *comp_name) +ComponentNode *DepsgraphNodeBuilder::add_component_node(ID *id, + NodeType comp_type, + const char *comp_name) { - IDNode *id_node = add_id_node(id); - ComponentNode *comp_node = id_node->add_component(comp_type, comp_name); - comp_node->owner = id_node; - return comp_node; + IDNode *id_node = add_id_node(id); + ComponentNode *comp_node = id_node->add_component(comp_type, comp_name); + comp_node->owner = id_node; + return comp_node; } -OperationNode *DepsgraphNodeBuilder::add_operation_node( - ComponentNode *comp_node, - OperationCode opcode, - const DepsEvalOperationCb& op, - const char *name, - int name_tag) +OperationNode *DepsgraphNodeBuilder::add_operation_node(ComponentNode *comp_node, + OperationCode opcode, + const DepsEvalOperationCb &op, + const char *name, + int name_tag) { - OperationNode *op_node = comp_node->find_operation(opcode, name, name_tag); - if (op_node == NULL) { - op_node = comp_node->add_operation(op, opcode, name, name_tag); - graph_->operations.push_back(op_node); - } - else { - fprintf(stderr, - "add_operation: Operation already exists - %s has %s at %p\n", - comp_node->identifier().c_str(), - op_node->identifier().c_str(), - op_node); - BLI_assert(!"Should not happen!"); - } - return op_node; + OperationNode *op_node = comp_node->find_operation(opcode, name, name_tag); + if (op_node == NULL) { + op_node = comp_node->add_operation(op, opcode, name, name_tag); + graph_->operations.push_back(op_node); + } + else { + fprintf(stderr, + "add_operation: Operation already exists - %s has %s at %p\n", + comp_node->identifier().c_str(), + op_node->identifier().c_str(), + op_node); + BLI_assert(!"Should not happen!"); + } + return op_node; } -OperationNode *DepsgraphNodeBuilder::add_operation_node( - ID *id, - NodeType comp_type, - const char *comp_name, - OperationCode opcode, - const DepsEvalOperationCb& op, - const char *name, - int name_tag) +OperationNode *DepsgraphNodeBuilder::add_operation_node(ID *id, + NodeType comp_type, + const char *comp_name, + OperationCode opcode, + const DepsEvalOperationCb &op, + const char *name, + int name_tag) { - ComponentNode *comp_node = add_component_node(id, comp_type, comp_name); - return add_operation_node(comp_node, opcode, op, name, name_tag); + ComponentNode *comp_node = add_component_node(id, comp_type, comp_name); + return add_operation_node(comp_node, opcode, op, name, name_tag); } -OperationNode *DepsgraphNodeBuilder::add_operation_node( - ID *id, - NodeType comp_type, - OperationCode opcode, - const DepsEvalOperationCb& op, - const char *name, - int name_tag) +OperationNode *DepsgraphNodeBuilder::add_operation_node(ID *id, + NodeType comp_type, + OperationCode opcode, + const DepsEvalOperationCb &op, + const char *name, + int name_tag) { - return add_operation_node( - id, comp_type, "", opcode, op, name, name_tag); + return add_operation_node(id, comp_type, "", opcode, op, name, name_tag); } -OperationNode *DepsgraphNodeBuilder::ensure_operation_node( - ID *id, - NodeType comp_type, - OperationCode opcode, - const DepsEvalOperationCb& op, - const char *name, - int name_tag) +OperationNode *DepsgraphNodeBuilder::ensure_operation_node(ID *id, + NodeType comp_type, + OperationCode opcode, + const DepsEvalOperationCb &op, + const char *name, + int name_tag) { - OperationNode *operation = - find_operation_node(id, comp_type, opcode, name, name_tag); - if (operation != NULL) { - return operation; - } - return add_operation_node(id, comp_type, opcode, op, name, name_tag); + OperationNode *operation = find_operation_node(id, comp_type, opcode, name, name_tag); + if (operation != NULL) { + return operation; + } + return add_operation_node(id, comp_type, opcode, op, name, name_tag); } bool DepsgraphNodeBuilder::has_operation_node(ID *id, @@ -277,266 +267,245 @@ bool DepsgraphNodeBuilder::has_operation_node(ID *id, const char *name, int name_tag) { - return find_operation_node( - id, comp_type, comp_name, opcode, name, name_tag) != NULL; + return find_operation_node(id, comp_type, comp_name, opcode, name, name_tag) != NULL; } -OperationNode *DepsgraphNodeBuilder::find_operation_node( - ID *id, - NodeType comp_type, - const char *comp_name, - OperationCode opcode, - const char *name, - int name_tag) +OperationNode *DepsgraphNodeBuilder::find_operation_node(ID *id, + NodeType comp_type, + const char *comp_name, + OperationCode opcode, + const char *name, + int name_tag) { - ComponentNode *comp_node = add_component_node(id, comp_type, comp_name); - return comp_node->find_operation(opcode, name, name_tag); + ComponentNode *comp_node = add_component_node(id, comp_type, comp_name); + return comp_node->find_operation(opcode, name, name_tag); } OperationNode *DepsgraphNodeBuilder::find_operation_node( - ID *id, - NodeType comp_type, - OperationCode opcode, - const char *name, - int name_tag) + ID *id, NodeType comp_type, OperationCode opcode, const char *name, int name_tag) { - return find_operation_node(id, comp_type, "", opcode, name, name_tag); + return find_operation_node(id, comp_type, "", opcode, name, name_tag); } ID *DepsgraphNodeBuilder::get_cow_id(const ID *id_orig) const { - return graph_->get_cow_id(id_orig); + return graph_->get_cow_id(id_orig); } ID *DepsgraphNodeBuilder::ensure_cow_id(ID *id_orig) { - if (id_orig->tag & LIB_TAG_COPIED_ON_WRITE) { - /* ID is already remapped to copy-on-write. */ - return id_orig; - } - IDNode *id_node = add_id_node(id_orig); - return id_node->id_cow; + if (id_orig->tag & LIB_TAG_COPIED_ON_WRITE) { + /* ID is already remapped to copy-on-write. */ + return id_orig; + } + IDNode *id_node = add_id_node(id_orig); + return id_node->id_cow; } /* **** Build functions for entity nodes **** */ void DepsgraphNodeBuilder::begin_build() { - /* Store existing copy-on-write versions of datablock, so we can re-use - * them for new ID nodes. */ - id_info_hash_ = BLI_ghash_ptr_new("Depsgraph id hash"); - for (IDNode *id_node : graph_->id_nodes) { - IDInfo *id_info = (IDInfo *)MEM_mallocN( - sizeof(IDInfo), "depsgraph id info"); - if (deg_copy_on_write_is_expanded(id_node->id_cow) && - id_node->id_orig != id_node->id_cow) - { - id_info->id_cow = id_node->id_cow; - } - else { - id_info->id_cow = NULL; - } - id_info->previously_visible_components_mask = - id_node->visible_components_mask; - id_info->previous_eval_flags = id_node->eval_flags; - id_info->previous_customdata_masks = id_node->customdata_masks; - BLI_ghash_insert(id_info_hash_, id_node->id_orig, id_info); - id_node->id_cow = NULL; - } - - GSET_FOREACH_BEGIN(OperationNode *, op_node, graph_->entry_tags) - { - ComponentNode *comp_node = op_node->owner; - IDNode *id_node = comp_node->owner; - - SavedEntryTag entry_tag; - entry_tag.id_orig = id_node->id_orig; - entry_tag.component_type = comp_node->type; - entry_tag.opcode = op_node->opcode; - entry_tag.name = op_node->name; - entry_tag.name_tag = op_node->name_tag; - saved_entry_tags_.push_back(entry_tag); - }; - GSET_FOREACH_END(); - - /* Make sure graph has no nodes left from previous state. */ - graph_->clear_all_nodes(); - graph_->operations.clear(); - BLI_gset_clear(graph_->entry_tags, NULL); + /* Store existing copy-on-write versions of datablock, so we can re-use + * them for new ID nodes. */ + id_info_hash_ = BLI_ghash_ptr_new("Depsgraph id hash"); + for (IDNode *id_node : graph_->id_nodes) { + IDInfo *id_info = (IDInfo *)MEM_mallocN(sizeof(IDInfo), "depsgraph id info"); + if (deg_copy_on_write_is_expanded(id_node->id_cow) && id_node->id_orig != id_node->id_cow) { + id_info->id_cow = id_node->id_cow; + } + else { + id_info->id_cow = NULL; + } + id_info->previously_visible_components_mask = id_node->visible_components_mask; + id_info->previous_eval_flags = id_node->eval_flags; + id_info->previous_customdata_masks = id_node->customdata_masks; + BLI_ghash_insert(id_info_hash_, id_node->id_orig, id_info); + id_node->id_cow = NULL; + } + + GSET_FOREACH_BEGIN (OperationNode *, op_node, graph_->entry_tags) { + ComponentNode *comp_node = op_node->owner; + IDNode *id_node = comp_node->owner; + + SavedEntryTag entry_tag; + entry_tag.id_orig = id_node->id_orig; + entry_tag.component_type = comp_node->type; + entry_tag.opcode = op_node->opcode; + entry_tag.name = op_node->name; + entry_tag.name_tag = op_node->name_tag; + saved_entry_tags_.push_back(entry_tag); + }; + GSET_FOREACH_END(); + + /* Make sure graph has no nodes left from previous state. */ + graph_->clear_all_nodes(); + graph_->operations.clear(); + BLI_gset_clear(graph_->entry_tags, NULL); } void DepsgraphNodeBuilder::end_build() { - for (const SavedEntryTag& entry_tag : saved_entry_tags_) { - IDNode *id_node = find_id_node(entry_tag.id_orig); - if (id_node == NULL) { - continue; - } - ComponentNode *comp_node = - id_node->find_component(entry_tag.component_type); - if (comp_node == NULL) { - continue; - } - OperationNode *op_node = comp_node->find_operation( - entry_tag.opcode, entry_tag.name.c_str(), entry_tag.name_tag); - if (op_node == NULL) { - continue; - } - /* Since the tag is coming from a saved copy of entry tags, this means - * that originally node was explicitly tagged for user update. */ - op_node->tag_update(graph_, DEG_UPDATE_SOURCE_USER_EDIT); - } + for (const SavedEntryTag &entry_tag : saved_entry_tags_) { + IDNode *id_node = find_id_node(entry_tag.id_orig); + if (id_node == NULL) { + continue; + } + ComponentNode *comp_node = id_node->find_component(entry_tag.component_type); + if (comp_node == NULL) { + continue; + } + OperationNode *op_node = comp_node->find_operation( + entry_tag.opcode, entry_tag.name.c_str(), entry_tag.name_tag); + if (op_node == NULL) { + continue; + } + /* Since the tag is coming from a saved copy of entry tags, this means + * that originally node was explicitly tagged for user update. */ + op_node->tag_update(graph_, DEG_UPDATE_SOURCE_USER_EDIT); + } } void DepsgraphNodeBuilder::build_id(ID *id) { - if (id == NULL) { - return; - } - switch (GS(id->name)) { - case ID_AC: - build_action((bAction *)id); - break; - case ID_AR: - build_armature((bArmature *)id); - break; - case ID_CA: - build_camera((Camera *)id); - break; - case ID_GR: - build_collection(NULL, (Collection *)id); - break; - case ID_OB: - /* TODO(sergey): Get visibility from a "parent" somehow. - * - * NOTE: Using `false` visibility here should be fine, since if this - * driver affects on something invisible we don't really care if the - * driver gets evaluated (and even don't want this to force object - * to become visible). - * - * If this happened to be affecting visible object, then it is up to - * deg_graph_build_flush_visibility() to ensure visibility of the - * object is true. */ - build_object(-1, (Object *)id, DEG_ID_LINKED_INDIRECTLY, false); - break; - case ID_KE: - build_shapekeys((Key *)id); - break; - case ID_LA: - build_light((Light *)id); - break; - case ID_LP: - build_lightprobe((LightProbe *)id); - break; - case ID_NT: - build_nodetree((bNodeTree *)id); - break; - case ID_MA: - build_material((Material *)id); - break; - case ID_TE: - build_texture((Tex *)id); - break; - case ID_IM: - build_image((Image *)id); - break; - case ID_WO: - build_world((World *)id); - break; - case ID_MSK: - build_mask((Mask *)id); - break; - case ID_MC: - build_movieclip((MovieClip *)id); - break; - case ID_ME: - case ID_CU: - case ID_MB: - case ID_LT: - /* TODO(sergey): Get visibility from a "parent" somehow. - * - * NOTE: Similarly to above, we don't want false-positives on - * visibility. */ - build_object_data_geometry_datablock(id, false); - break; - case ID_SPK: - build_speaker((Speaker *)id); - break; - case ID_TXT: - /* Not a part of dependency graph. */ - break; - case ID_CF: - build_cachefile((CacheFile *)id); - break; - default: - fprintf(stderr, "Unhandled ID %s\n", id->name); - BLI_assert(!"Should never happen"); - break; - } + if (id == NULL) { + return; + } + switch (GS(id->name)) { + case ID_AC: + build_action((bAction *)id); + break; + case ID_AR: + build_armature((bArmature *)id); + break; + case ID_CA: + build_camera((Camera *)id); + break; + case ID_GR: + build_collection(NULL, (Collection *)id); + break; + case ID_OB: + /* TODO(sergey): Get visibility from a "parent" somehow. + * + * NOTE: Using `false` visibility here should be fine, since if this + * driver affects on something invisible we don't really care if the + * driver gets evaluated (and even don't want this to force object + * to become visible). + * + * If this happened to be affecting visible object, then it is up to + * deg_graph_build_flush_visibility() to ensure visibility of the + * object is true. */ + build_object(-1, (Object *)id, DEG_ID_LINKED_INDIRECTLY, false); + break; + case ID_KE: + build_shapekeys((Key *)id); + break; + case ID_LA: + build_light((Light *)id); + break; + case ID_LP: + build_lightprobe((LightProbe *)id); + break; + case ID_NT: + build_nodetree((bNodeTree *)id); + break; + case ID_MA: + build_material((Material *)id); + break; + case ID_TE: + build_texture((Tex *)id); + break; + case ID_IM: + build_image((Image *)id); + break; + case ID_WO: + build_world((World *)id); + break; + case ID_MSK: + build_mask((Mask *)id); + break; + case ID_MC: + build_movieclip((MovieClip *)id); + break; + case ID_ME: + case ID_CU: + case ID_MB: + case ID_LT: + /* TODO(sergey): Get visibility from a "parent" somehow. + * + * NOTE: Similarly to above, we don't want false-positives on + * visibility. */ + build_object_data_geometry_datablock(id, false); + break; + case ID_SPK: + build_speaker((Speaker *)id); + break; + case ID_TXT: + /* Not a part of dependency graph. */ + break; + case ID_CF: + build_cachefile((CacheFile *)id); + break; + default: + fprintf(stderr, "Unhandled ID %s\n", id->name); + BLI_assert(!"Should never happen"); + break; + } } -void DepsgraphNodeBuilder::build_collection( - LayerCollection *from_layer_collection, - Collection *collection) +void DepsgraphNodeBuilder::build_collection(LayerCollection *from_layer_collection, + Collection *collection) { - const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT) - ? COLLECTION_RESTRICT_VIEW - : COLLECTION_RESTRICT_RENDER; - const bool is_collection_restricted = (collection->flag & restrict_flag); - const bool is_collection_visible = - !is_collection_restricted && is_parent_collection_visible_; - 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 && - 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 - * might become visible too. */ - } - else if (from_layer_collection == NULL && - !id_node->is_collection_fully_expanded) - { - /* Initially collection was built from layer now, and was requested - * to not recurs into object. But nw it's asked to recurs into all - * objects. */ - } - else { - return; - } - } - else { - /* Collection itself. */ - id_node = add_id_node(&collection->id); - id_node->is_directly_visible = is_collection_visible; - } - if (from_layer_collection != NULL) { - /* If we came from layer collection we don't go deeper, view layer - * builder takes care of going deeper. */ - return; - } - /* Backup state. */ - Collection *current_state_collection = collection_; - const bool is_current_parent_collection_visible = - is_parent_collection_visible_; - /* Modify state as we've entered new collection/ */ - collection_ = collection; - is_parent_collection_visible_ = is_collection_visible; - /* Build collection objects. */ - LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { - build_object( - -1, cob->ob, DEG_ID_LINKED_INDIRECTLY, is_collection_visible); - } - /* Build child collections. */ - LISTBASE_FOREACH (CollectionChild *, child, &collection->children) { - build_collection(NULL, child->collection); - } - /* Restore state. */ - collection_ = current_state_collection; - is_parent_collection_visible_ = is_current_parent_collection_visible; - id_node->is_collection_fully_expanded = true; + const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT) ? COLLECTION_RESTRICT_VIEW : + COLLECTION_RESTRICT_RENDER; + const bool is_collection_restricted = (collection->flag & restrict_flag); + const bool is_collection_visible = !is_collection_restricted && is_parent_collection_visible_; + 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 && + 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 + * might become visible too. */ + } + else if (from_layer_collection == NULL && !id_node->is_collection_fully_expanded) { + /* Initially collection was built from layer now, and was requested + * to not recurs into object. But nw it's asked to recurs into all + * objects. */ + } + else { + return; + } + } + else { + /* Collection itself. */ + id_node = add_id_node(&collection->id); + id_node->is_directly_visible = is_collection_visible; + } + if (from_layer_collection != NULL) { + /* If we came from layer collection we don't go deeper, view layer + * builder takes care of going deeper. */ + return; + } + /* Backup state. */ + Collection *current_state_collection = collection_; + const bool is_current_parent_collection_visible = is_parent_collection_visible_; + /* Modify state as we've entered new collection/ */ + collection_ = collection; + is_parent_collection_visible_ = is_collection_visible; + /* Build collection objects. */ + LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { + build_object(-1, cob->ob, DEG_ID_LINKED_INDIRECTLY, is_collection_visible); + } + /* Build child collections. */ + LISTBASE_FOREACH (CollectionChild *, child, &collection->children) { + build_collection(NULL, child->collection); + } + /* Restore state. */ + collection_ = current_state_collection; + is_parent_collection_visible_ = is_current_parent_collection_visible; + id_node->is_collection_fully_expanded = true; } void DepsgraphNodeBuilder::build_object(int base_index, @@ -544,252 +513,236 @@ void DepsgraphNodeBuilder::build_object(int base_index, eDepsNode_LinkedState_Type linked_state, bool is_visible) { - const bool has_object = built_map_.checkIsBuiltAndTag(object); - /* Skip rest of components if the ID node was already there. */ - if (has_object) { - IDNode *id_node = find_id_node(&object->id); - /* We need to build some extra stuff if object becomes linked - * directly. */ - if (id_node->linked_state == DEG_ID_LINKED_INDIRECTLY) { - build_object_flags(base_index, object, linked_state); - } - id_node->linked_state = max(id_node->linked_state, linked_state); - if (id_node->linked_state == DEG_ID_LINKED_DIRECTLY) { - id_node->is_directly_visible |= is_visible; - } - return; - } - /* Create ID node for object and begin init. */ - IDNode *id_node = add_id_node(&object->id); - Object *object_cow = get_cow_datablock(object); - id_node->linked_state = linked_state; - if (object == scene_->camera) { - id_node->is_directly_visible = true; - } - else { - id_node->is_directly_visible = is_visible; - } - /* Various flags, flushing from bases/collections. */ - build_object_flags(base_index, object, linked_state); - /* Transform. */ - build_object_transform(object); - /* Parent. */ - if (object->parent != NULL) { - build_object( - -1, object->parent, DEG_ID_LINKED_INDIRECTLY, is_visible); - } - /* Modifiers. */ - if (object->modifiers.first != NULL) { - BuilderWalkUserData data; - data.builder = this; - data.is_parent_visible = is_visible; - modifiers_foreachIDLink(object, modifier_walk, &data); - } - /* Grease Pencil Modifiers. */ - if (object->greasepencil_modifiers.first != NULL) { - BuilderWalkUserData data; - data.builder = this; - data.is_parent_visible = is_visible; - BKE_gpencil_modifiers_foreachIDLink(object, modifier_walk, &data); - } - /* Shader FX. */ - if (object->shader_fx.first != NULL) { - BuilderWalkUserData data; - data.builder = this; - data.is_parent_visible = is_visible; - BKE_shaderfx_foreachIDLink(object, modifier_walk, &data); - } - /* Constraints. */ - if (object->constraints.first != NULL) { - BuilderWalkUserData data; - data.builder = this; - data.is_parent_visible = is_visible; - BKE_constraints_id_loop(&object->constraints, constraint_walk, &data); - } - /* Object data. */ - build_object_data(object, is_visible); - /* Paramaters, used by both drivers/animation and also to inform dependency - * from object's data. */ - build_parameters(&object->id); - /* Build animation data, - * - * Do it now because it's possible object data will affect - * on object's level animation, for example in case of rebuilding - * pose for proxy. */ - build_animdata(&object->id); - /* Particle systems. */ - if (object->particlesystem.first != NULL) { - build_particle_systems(object, is_visible); - } - /* Proxy object to copy from. */ - if (object->proxy_from != NULL) { - build_object( - -1, object->proxy_from, DEG_ID_LINKED_INDIRECTLY, is_visible); - } - if (object->proxy_group != NULL) { - build_object( - -1, object->proxy_group, DEG_ID_LINKED_INDIRECTLY, is_visible); - } - /* Object dupligroup. */ - if (object->instance_collection != NULL) { - const bool is_current_parent_collection_visible = - is_parent_collection_visible_; - is_parent_collection_visible_ = is_visible; - build_collection(NULL, object->instance_collection); - is_parent_collection_visible_ = is_current_parent_collection_visible; - add_operation_node( - &object->id, NodeType::DUPLI, OperationCode::DUPLI); - } - /* Syncronization back to original object. */ - add_operation_node(&object->id, - NodeType::SYNCHRONIZATION, - OperationCode::SYNCHRONIZE_TO_ORIGINAL, - function_bind(BKE_object_synchronize_to_original, - _1, - object_cow)); + const bool has_object = built_map_.checkIsBuiltAndTag(object); + /* Skip rest of components if the ID node was already there. */ + if (has_object) { + IDNode *id_node = find_id_node(&object->id); + /* We need to build some extra stuff if object becomes linked + * directly. */ + if (id_node->linked_state == DEG_ID_LINKED_INDIRECTLY) { + build_object_flags(base_index, object, linked_state); + } + id_node->linked_state = max(id_node->linked_state, linked_state); + if (id_node->linked_state == DEG_ID_LINKED_DIRECTLY) { + id_node->is_directly_visible |= is_visible; + } + return; + } + /* Create ID node for object and begin init. */ + IDNode *id_node = add_id_node(&object->id); + Object *object_cow = get_cow_datablock(object); + id_node->linked_state = linked_state; + if (object == scene_->camera) { + id_node->is_directly_visible = true; + } + else { + id_node->is_directly_visible = is_visible; + } + /* Various flags, flushing from bases/collections. */ + build_object_flags(base_index, object, linked_state); + /* Transform. */ + build_object_transform(object); + /* Parent. */ + if (object->parent != NULL) { + build_object(-1, object->parent, DEG_ID_LINKED_INDIRECTLY, is_visible); + } + /* Modifiers. */ + if (object->modifiers.first != NULL) { + BuilderWalkUserData data; + data.builder = this; + data.is_parent_visible = is_visible; + modifiers_foreachIDLink(object, modifier_walk, &data); + } + /* Grease Pencil Modifiers. */ + if (object->greasepencil_modifiers.first != NULL) { + BuilderWalkUserData data; + data.builder = this; + data.is_parent_visible = is_visible; + BKE_gpencil_modifiers_foreachIDLink(object, modifier_walk, &data); + } + /* Shader FX. */ + if (object->shader_fx.first != NULL) { + BuilderWalkUserData data; + data.builder = this; + data.is_parent_visible = is_visible; + BKE_shaderfx_foreachIDLink(object, modifier_walk, &data); + } + /* Constraints. */ + if (object->constraints.first != NULL) { + BuilderWalkUserData data; + data.builder = this; + data.is_parent_visible = is_visible; + BKE_constraints_id_loop(&object->constraints, constraint_walk, &data); + } + /* Object data. */ + build_object_data(object, is_visible); + /* Paramaters, used by both drivers/animation and also to inform dependency + * from object's data. */ + build_parameters(&object->id); + /* Build animation data, + * + * Do it now because it's possible object data will affect + * on object's level animation, for example in case of rebuilding + * pose for proxy. */ + build_animdata(&object->id); + /* Particle systems. */ + if (object->particlesystem.first != NULL) { + build_particle_systems(object, is_visible); + } + /* Proxy object to copy from. */ + if (object->proxy_from != NULL) { + build_object(-1, object->proxy_from, DEG_ID_LINKED_INDIRECTLY, is_visible); + } + if (object->proxy_group != NULL) { + build_object(-1, object->proxy_group, DEG_ID_LINKED_INDIRECTLY, is_visible); + } + /* Object dupligroup. */ + if (object->instance_collection != NULL) { + const bool is_current_parent_collection_visible = is_parent_collection_visible_; + is_parent_collection_visible_ = is_visible; + build_collection(NULL, object->instance_collection); + is_parent_collection_visible_ = is_current_parent_collection_visible; + add_operation_node(&object->id, NodeType::DUPLI, OperationCode::DUPLI); + } + /* Syncronization back to original object. */ + add_operation_node(&object->id, + NodeType::SYNCHRONIZATION, + OperationCode::SYNCHRONIZE_TO_ORIGINAL, + function_bind(BKE_object_synchronize_to_original, _1, object_cow)); } -void DepsgraphNodeBuilder::build_object_flags( - int base_index, - Object *object, - eDepsNode_LinkedState_Type linked_state) +void DepsgraphNodeBuilder::build_object_flags(int base_index, + Object *object, + eDepsNode_LinkedState_Type linked_state) { - if (base_index == -1) { - return; - } - Scene *scene_cow = get_cow_datablock(scene_); - Object *object_cow = get_cow_datablock(object); - const bool is_from_set = (linked_state == DEG_ID_LINKED_VIA_SET); - /* TODO(sergey): Is this really best component to be used? */ - add_operation_node(&object->id, - NodeType::OBJECT_FROM_LAYER, - OperationCode::OBJECT_BASE_FLAGS, - function_bind(BKE_object_eval_eval_base_flags, - _1, - scene_cow, - view_layer_index_, - object_cow, base_index, - is_from_set)); + if (base_index == -1) { + return; + } + Scene *scene_cow = get_cow_datablock(scene_); + Object *object_cow = get_cow_datablock(object); + const bool is_from_set = (linked_state == DEG_ID_LINKED_VIA_SET); + /* TODO(sergey): Is this really best component to be used? */ + add_operation_node(&object->id, + NodeType::OBJECT_FROM_LAYER, + OperationCode::OBJECT_BASE_FLAGS, + function_bind(BKE_object_eval_eval_base_flags, + _1, + scene_cow, + view_layer_index_, + object_cow, + base_index, + is_from_set)); } -void DepsgraphNodeBuilder::build_object_data( - Object *object, bool is_object_visible) +void DepsgraphNodeBuilder::build_object_data(Object *object, bool is_object_visible) { - if (object->data == NULL) { - return; - } - /* type-specific data. */ - switch (object->type) { - case OB_MESH: - case OB_CURVE: - case OB_FONT: - case OB_SURF: - case OB_MBALL: - case OB_LATTICE: - case OB_GPENCIL: - build_object_data_geometry(object, is_object_visible); - break; - case OB_ARMATURE: - if (ID_IS_LINKED(object) && object->proxy_from != NULL) { - build_proxy_rig(object); - } - else { - build_rig(object, is_object_visible); - } - break; - case OB_LAMP: - build_object_data_light(object); - break; - case OB_CAMERA: - build_object_data_camera(object); - break; - case OB_LIGHTPROBE: - build_object_data_lightprobe(object); - break; - case OB_SPEAKER: - build_object_data_speaker(object); - break; - default: - { - ID *obdata = (ID *)object->data; - if (built_map_.checkIsBuilt(obdata) == 0) { - build_animdata(obdata); - } - break; - } - } + if (object->data == NULL) { + return; + } + /* type-specific data. */ + switch (object->type) { + case OB_MESH: + case OB_CURVE: + case OB_FONT: + case OB_SURF: + case OB_MBALL: + case OB_LATTICE: + case OB_GPENCIL: + build_object_data_geometry(object, is_object_visible); + break; + case OB_ARMATURE: + if (ID_IS_LINKED(object) && object->proxy_from != NULL) { + build_proxy_rig(object); + } + else { + build_rig(object, is_object_visible); + } + break; + case OB_LAMP: + build_object_data_light(object); + break; + case OB_CAMERA: + build_object_data_camera(object); + break; + case OB_LIGHTPROBE: + build_object_data_lightprobe(object); + break; + case OB_SPEAKER: + build_object_data_speaker(object); + break; + default: { + ID *obdata = (ID *)object->data; + if (built_map_.checkIsBuilt(obdata) == 0) { + build_animdata(obdata); + } + break; + } + } } void DepsgraphNodeBuilder::build_object_data_camera(Object *object) { - Camera *camera = (Camera *)object->data; - build_camera(camera); + Camera *camera = (Camera *)object->data; + build_camera(camera); } void DepsgraphNodeBuilder::build_object_data_light(Object *object) { - Light *lamp = (Light *)object->data; - build_light(lamp); + Light *lamp = (Light *)object->data; + build_light(lamp); } void DepsgraphNodeBuilder::build_object_data_lightprobe(Object *object) { - LightProbe *probe = (LightProbe *)object->data; - build_lightprobe(probe); - add_operation_node( - &object->id, NodeType::PARAMETERS, OperationCode::LIGHT_PROBE_EVAL); + LightProbe *probe = (LightProbe *)object->data; + build_lightprobe(probe); + add_operation_node(&object->id, NodeType::PARAMETERS, OperationCode::LIGHT_PROBE_EVAL); } void DepsgraphNodeBuilder::build_object_data_speaker(Object *object) { - Speaker *speaker = (Speaker *)object->data; - build_speaker(speaker); - add_operation_node( - &object->id, NodeType::PARAMETERS, OperationCode::SPEAKER_EVAL); + Speaker *speaker = (Speaker *)object->data; + build_speaker(speaker); + add_operation_node(&object->id, NodeType::PARAMETERS, OperationCode::SPEAKER_EVAL); } void DepsgraphNodeBuilder::build_object_transform(Object *object) { - OperationNode *op_node; - Object *ob_cow = get_cow_datablock(object); - /* Transform entry operation. */ - op_node = add_operation_node( - &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_INIT); - op_node->set_as_entry(); - /* Local transforms (from transform channels - loc/rot/scale + deltas). */ - add_operation_node(&object->id, NodeType::TRANSFORM, - OperationCode::TRANSFORM_LOCAL, - function_bind(BKE_object_eval_local_transform, - _1, - ob_cow)); - /* Object parent. */ - if (object->parent != NULL) { - add_operation_node(&object->id, NodeType::TRANSFORM, - OperationCode::TRANSFORM_PARENT, - function_bind(BKE_object_eval_parent, _1, ob_cow)); - } - /* Object constraints. */ - if (object->constraints.first != NULL) { - build_object_constraints(object); - } - /* Rest of transformation update. */ - add_operation_node(&object->id, NodeType::TRANSFORM, - OperationCode::TRANSFORM_EVAL, - function_bind(BKE_object_eval_uber_transform, - _1, - ob_cow)); - /* Operation to take of rigid body simulation. soft bodies and other firends - * in the context of point cache invalidation. */ - add_operation_node(&object->id, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_SIMULATION_INIT); - /* Object transform is done. */ - op_node = add_operation_node(&object->id, NodeType::TRANSFORM, - OperationCode::TRANSFORM_FINAL, - function_bind(BKE_object_eval_transform_final, - _1, - ob_cow)); - op_node->set_as_exit(); + OperationNode *op_node; + Object *ob_cow = get_cow_datablock(object); + /* Transform entry operation. */ + op_node = add_operation_node(&object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_INIT); + op_node->set_as_entry(); + /* Local transforms (from transform channels - loc/rot/scale + deltas). */ + add_operation_node(&object->id, + NodeType::TRANSFORM, + OperationCode::TRANSFORM_LOCAL, + function_bind(BKE_object_eval_local_transform, _1, ob_cow)); + /* Object parent. */ + if (object->parent != NULL) { + add_operation_node(&object->id, + NodeType::TRANSFORM, + OperationCode::TRANSFORM_PARENT, + function_bind(BKE_object_eval_parent, _1, ob_cow)); + } + /* Object constraints. */ + if (object->constraints.first != NULL) { + build_object_constraints(object); + } + /* Rest of transformation update. */ + add_operation_node(&object->id, + NodeType::TRANSFORM, + OperationCode::TRANSFORM_EVAL, + function_bind(BKE_object_eval_uber_transform, _1, ob_cow)); + /* Operation to take of rigid body simulation. soft bodies and other firends + * in the context of point cache invalidation. */ + add_operation_node(&object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_SIMULATION_INIT); + /* Object transform is done. */ + op_node = add_operation_node(&object->id, + NodeType::TRANSFORM, + OperationCode::TRANSFORM_FINAL, + function_bind(BKE_object_eval_transform_final, _1, ob_cow)); + op_node->set_as_exit(); } /** @@ -811,29 +764,26 @@ void DepsgraphNodeBuilder::build_object_transform(Object *object) */ void DepsgraphNodeBuilder::build_object_constraints(Object *object) { - /* create node for constraint stack */ - add_operation_node(&object->id, NodeType::TRANSFORM, - OperationCode::TRANSFORM_CONSTRAINTS, - function_bind(BKE_object_eval_constraints, - _1, - get_cow_datablock(scene_), - get_cow_datablock(object))); + /* create node for constraint stack */ + add_operation_node( + &object->id, + NodeType::TRANSFORM, + OperationCode::TRANSFORM_CONSTRAINTS, + function_bind( + BKE_object_eval_constraints, _1, get_cow_datablock(scene_), get_cow_datablock(object))); } void DepsgraphNodeBuilder::build_object_pointcache(Object *object) { - if (!BKE_ptcache_object_has(scene_, object, 0)) { - return; - } - Scene *scene_cow = get_cow_datablock(scene_); - Object *object_cow = get_cow_datablock(object); - add_operation_node(&object->id, - NodeType::POINT_CACHE, - OperationCode::POINT_CACHE_RESET, - function_bind(BKE_object_eval_ptcache_reset, - _1, - scene_cow, - object_cow)); + if (!BKE_ptcache_object_has(scene_, object, 0)) { + return; + } + Scene *scene_cow = get_cow_datablock(scene_); + Object *object_cow = get_cow_datablock(object); + add_operation_node(&object->id, + NodeType::POINT_CACHE, + OperationCode::POINT_CACHE_RESET, + function_bind(BKE_object_eval_ptcache_reset, _1, scene_cow, object_cow)); } /** @@ -842,58 +792,55 @@ void DepsgraphNodeBuilder::build_object_pointcache(Object *object) */ void DepsgraphNodeBuilder::build_animdata(ID *id) { - /* Special handling for animated images/sequences. */ - build_animation_images(id); - /* Regular animation. */ - AnimData *adt = BKE_animdata_from_id(id); - if (adt == NULL) { - return; - } - if (adt->action != NULL) { - build_action(adt->action); - } - /* Make sure ID node exists. */ - (void) add_id_node(id); - ID *id_cow = get_cow_id(id); - if (adt->action != NULL || !BLI_listbase_is_empty(&adt->nla_tracks)) { - OperationNode *operation_node; - /* Explicit entry operation. */ - operation_node = add_operation_node( - id, NodeType::ANIMATION, OperationCode::ANIMATION_ENTRY); - operation_node->set_as_entry(); - /* All the evaluation nodes. */ - add_operation_node( - id, - NodeType::ANIMATION, - OperationCode::ANIMATION_EVAL, - function_bind(BKE_animsys_eval_animdata, _1, id_cow)); - /* Explicit exit operation. */ - operation_node = add_operation_node( - id, NodeType::ANIMATION, OperationCode::ANIMATION_EXIT); - operation_node->set_as_exit(); - } - /* NLA strips contain actions. */ - LISTBASE_FOREACH (NlaTrack *, nlt, &adt->nla_tracks) { - build_animdata_nlastrip_targets(&nlt->strips); - } - /* Drivers. */ - int driver_index = 0; - LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) { - /* create driver */ - build_driver(id, fcu, driver_index++); - } + /* Special handling for animated images/sequences. */ + build_animation_images(id); + /* Regular animation. */ + AnimData *adt = BKE_animdata_from_id(id); + if (adt == NULL) { + return; + } + if (adt->action != NULL) { + build_action(adt->action); + } + /* Make sure ID node exists. */ + (void)add_id_node(id); + ID *id_cow = get_cow_id(id); + if (adt->action != NULL || !BLI_listbase_is_empty(&adt->nla_tracks)) { + OperationNode *operation_node; + /* Explicit entry operation. */ + operation_node = add_operation_node(id, NodeType::ANIMATION, OperationCode::ANIMATION_ENTRY); + operation_node->set_as_entry(); + /* All the evaluation nodes. */ + add_operation_node(id, + NodeType::ANIMATION, + OperationCode::ANIMATION_EVAL, + function_bind(BKE_animsys_eval_animdata, _1, id_cow)); + /* Explicit exit operation. */ + operation_node = add_operation_node(id, NodeType::ANIMATION, OperationCode::ANIMATION_EXIT); + operation_node->set_as_exit(); + } + /* NLA strips contain actions. */ + LISTBASE_FOREACH (NlaTrack *, nlt, &adt->nla_tracks) { + build_animdata_nlastrip_targets(&nlt->strips); + } + /* Drivers. */ + int driver_index = 0; + LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) { + /* create driver */ + build_driver(id, fcu, driver_index++); + } } void DepsgraphNodeBuilder::build_animdata_nlastrip_targets(ListBase *strips) { - LISTBASE_FOREACH (NlaStrip *, strip, strips) { - if (strip->act != NULL) { - build_action(strip->act); - } - else if (strip->strips.first != NULL) { - build_animdata_nlastrip_targets(&strip->strips); - } - } + LISTBASE_FOREACH (NlaStrip *, strip, strips) { + if (strip->act != NULL) { + build_action(strip->act); + } + else if (strip->strips.first != NULL) { + build_animdata_nlastrip_targets(&strip->strips); + } + } } /** @@ -901,22 +848,21 @@ void DepsgraphNodeBuilder::build_animdata_nlastrip_targets(ListBase *strips) */ void DepsgraphNodeBuilder::build_animation_images(ID *id) { - if (BKE_image_user_id_has_animation(id)) { - ID *id_cow = get_cow_id(id); - add_operation_node(id, - NodeType::ANIMATION, - OperationCode::IMAGE_ANIMATION, - function_bind(BKE_image_user_id_eval_animation, _1, id_cow)); - } + if (BKE_image_user_id_has_animation(id)) { + ID *id_cow = get_cow_id(id); + add_operation_node(id, + NodeType::ANIMATION, + OperationCode::IMAGE_ANIMATION, + function_bind(BKE_image_user_id_eval_animation, _1, id_cow)); + } } void DepsgraphNodeBuilder::build_action(bAction *action) { - if (built_map_.checkIsBuiltAndTag(action)) { - return; - } - add_operation_node( - &action->id, NodeType::ANIMATION, OperationCode::ANIMATION_EVAL); + if (built_map_.checkIsBuiltAndTag(action)) { + return; + } + add_operation_node(&action->id, NodeType::ANIMATION, OperationCode::ANIMATION_EVAL); } /** @@ -927,754 +873,675 @@ void DepsgraphNodeBuilder::build_action(bAction *action) */ void DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcurve, int driver_index) { - /* Create data node for this driver */ - ID *id_cow = get_cow_id(id); - ChannelDriver *driver_orig = fcurve->driver; - - /* TODO(sergey): ideally we could pass the COW of fcu, but since it - * has not yet been allocated at this point we can't. As a workaround - * the animation systems allocates an array so we can do a fast lookup - * with the driver index. */ - ensure_operation_node(id, - NodeType::PARAMETERS, - OperationCode::DRIVER, - function_bind(BKE_animsys_eval_driver, _1, id_cow, driver_index, driver_orig), - fcurve->rna_path ? fcurve->rna_path : "", - fcurve->array_index); - build_driver_variables(id, fcurve); + /* Create data node for this driver */ + ID *id_cow = get_cow_id(id); + ChannelDriver *driver_orig = fcurve->driver; + + /* TODO(sergey): ideally we could pass the COW of fcu, but since it + * has not yet been allocated at this point we can't. As a workaround + * the animation systems allocates an array so we can do a fast lookup + * with the driver index. */ + ensure_operation_node( + id, + NodeType::PARAMETERS, + OperationCode::DRIVER, + function_bind(BKE_animsys_eval_driver, _1, id_cow, driver_index, driver_orig), + fcurve->rna_path ? fcurve->rna_path : "", + fcurve->array_index); + build_driver_variables(id, fcurve); } -void DepsgraphNodeBuilder::build_driver_variables(ID * id, FCurve *fcurve) +void DepsgraphNodeBuilder::build_driver_variables(ID *id, FCurve *fcurve) { - build_driver_id_property(id, fcurve->rna_path); - LISTBASE_FOREACH (DriverVar *, dvar, &fcurve->driver->variables) { - DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar) - { - if (dtar->id == NULL) { - continue; - } - build_id(dtar->id); - build_driver_id_property(dtar->id, dtar->rna_path); - /* Corresponds to dtar_id_ensure_proxy_from(). */ - if ((GS(dtar->id->name) == ID_OB) && - (((Object *)dtar->id)->proxy_from != NULL)) - { - Object *proxy_from = ((Object *)dtar->id)->proxy_from; - build_id(&proxy_from->id); - build_driver_id_property(&proxy_from->id, dtar->rna_path); - } - } - DRIVER_TARGETS_LOOPER_END; - } + build_driver_id_property(id, fcurve->rna_path); + LISTBASE_FOREACH (DriverVar *, dvar, &fcurve->driver->variables) { + DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { + if (dtar->id == NULL) { + continue; + } + build_id(dtar->id); + build_driver_id_property(dtar->id, dtar->rna_path); + /* Corresponds to dtar_id_ensure_proxy_from(). */ + if ((GS(dtar->id->name) == ID_OB) && (((Object *)dtar->id)->proxy_from != NULL)) { + Object *proxy_from = ((Object *)dtar->id)->proxy_from; + build_id(&proxy_from->id); + build_driver_id_property(&proxy_from->id, dtar->rna_path); + } + } + DRIVER_TARGETS_LOOPER_END; + } } -void DepsgraphNodeBuilder::build_driver_id_property(ID *id, - const char *rna_path) +void DepsgraphNodeBuilder::build_driver_id_property(ID *id, const char *rna_path) { - if (id == NULL || rna_path == NULL) { - return; - } - PointerRNA id_ptr, ptr; - PropertyRNA *prop; - RNA_id_pointer_create(id, &id_ptr); - if (!RNA_path_resolve_full(&id_ptr, rna_path, &ptr, &prop, NULL)) { - return; - } - if (prop == NULL) { - return; - } - if (!RNA_property_is_idprop(prop)) { - return; - } - const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop); - ensure_operation_node(id, - NodeType::PARAMETERS, - OperationCode::ID_PROPERTY, - NULL, - prop_identifier); + if (id == NULL || rna_path == NULL) { + return; + } + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + RNA_id_pointer_create(id, &id_ptr); + if (!RNA_path_resolve_full(&id_ptr, rna_path, &ptr, &prop, NULL)) { + return; + } + if (prop == NULL) { + return; + } + if (!RNA_property_is_idprop(prop)) { + return; + } + const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop); + ensure_operation_node( + id, NodeType::PARAMETERS, OperationCode::ID_PROPERTY, NULL, prop_identifier); } void DepsgraphNodeBuilder::build_parameters(ID *id) { - (void) add_id_node(id); - OperationNode *op_node; - /* Explicit entry. */ - op_node = add_operation_node( - id, NodeType::PARAMETERS, OperationCode::PARAMETERS_ENTRY); - op_node->set_as_entry(); - /* Generic evaluation node. */ - add_operation_node( - id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL); - /* Explicit exit operation. */ - op_node = add_operation_node( - id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EXIT); - op_node->set_as_exit(); + (void)add_id_node(id); + OperationNode *op_node; + /* Explicit entry. */ + op_node = add_operation_node(id, NodeType::PARAMETERS, OperationCode::PARAMETERS_ENTRY); + op_node->set_as_entry(); + /* Generic evaluation node. */ + add_operation_node(id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL); + /* Explicit exit operation. */ + op_node = add_operation_node(id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EXIT); + op_node->set_as_exit(); } /* Recursively build graph for world */ void DepsgraphNodeBuilder::build_world(World *world) { - if (built_map_.checkIsBuiltAndTag(world)) { - return; - } - /* World itself. */ - add_id_node(&world->id); - World *world_cow = get_cow_datablock(world); - /* Shading update. */ - add_operation_node(&world->id, - NodeType::SHADING, - OperationCode::WORLD_UPDATE, - function_bind(BKE_world_eval, _1, world_cow)); - /* Animation. */ - build_animdata(&world->id); - build_parameters(&world->id); - /* World's nodetree. */ - build_nodetree(world->nodetree); + if (built_map_.checkIsBuiltAndTag(world)) { + return; + } + /* World itself. */ + add_id_node(&world->id); + World *world_cow = get_cow_datablock(world); + /* Shading update. */ + add_operation_node(&world->id, + NodeType::SHADING, + OperationCode::WORLD_UPDATE, + function_bind(BKE_world_eval, _1, world_cow)); + /* Animation. */ + build_animdata(&world->id); + build_parameters(&world->id); + /* World's nodetree. */ + build_nodetree(world->nodetree); } /* Rigidbody Simulation - Scene Level */ void DepsgraphNodeBuilder::build_rigidbody(Scene *scene) { - RigidBodyWorld *rbw = scene->rigidbody_world; - Scene *scene_cow = get_cow_datablock(scene); - - /** - * Rigidbody Simulation Nodes - * ========================== - * - * There are 3 nodes related to Rigidbody Simulation: - * 1) "Initialize/Rebuild World" - this is called sparingly, only when the - * simulation needs to be rebuilt (mainly after file reload, or moving - * back to start frame) - * 2) "Do Simulation" - perform a simulation step - interleaved between the - * evaluation steps for clusters of objects (i.e. between those affected - * and/or not affected by the sim for instance). - * - * 3) "Pull Results" - grab the specific transforms applied for a specific - * object - performed as part of object's transform-stack building. */ - - /* Create nodes --------------------------------------------------------- */ - - /* XXX: is this the right component, or do we want to use another one - * instead? */ - - /* Init/rebuild operation. */ - add_operation_node(&scene->id, NodeType::TRANSFORM, - OperationCode::RIGIDBODY_REBUILD, - function_bind(BKE_rigidbody_rebuild_sim, _1, scene_cow)); - /* Do-sim operation. */ - OperationNode *sim_node = add_operation_node( - &scene->id, NodeType::TRANSFORM, - OperationCode::RIGIDBODY_SIM, - function_bind(BKE_rigidbody_eval_simulation, _1, scene_cow)); - sim_node->set_as_entry(); - sim_node->set_as_exit(); - sim_node->owner->entry_operation = sim_node; - /* Objects - simulation participants. */ - if (rbw->group != NULL) { - build_collection(NULL, rbw->group); - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object) - { - if (object->type != OB_MESH) { - continue; - } - /* Create operation for flushing results. */ - /* Object's transform component - where the rigidbody operation - * lives. */ - add_operation_node(&object->id, - NodeType::TRANSFORM, - OperationCode::RIGIDBODY_TRANSFORM_COPY, - function_bind( - BKE_rigidbody_object_sync_transforms, - _1, - scene_cow, - get_cow_datablock(object))); - } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - } - /* Constraints. */ - if (rbw->constraints != NULL) { - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, object) - { - RigidBodyCon *rbc = object->rigidbody_constraint; - if (rbc == NULL || rbc->ob1 == NULL || rbc->ob2 == NULL) { - /* When either ob1 or ob2 is NULL, the constraint doesn't work. */ - continue; - } - /* Make sure indirectly linked objects are fully built. */ - build_object(-1, object, DEG_ID_LINKED_INDIRECTLY, false); - build_object(-1, rbc->ob1, DEG_ID_LINKED_INDIRECTLY, false); - build_object(-1, rbc->ob2, DEG_ID_LINKED_INDIRECTLY, false); - } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - } + RigidBodyWorld *rbw = scene->rigidbody_world; + Scene *scene_cow = get_cow_datablock(scene); + + /** + * Rigidbody Simulation Nodes + * ========================== + * + * There are 3 nodes related to Rigidbody Simulation: + * 1) "Initialize/Rebuild World" - this is called sparingly, only when the + * simulation needs to be rebuilt (mainly after file reload, or moving + * back to start frame) + * 2) "Do Simulation" - perform a simulation step - interleaved between the + * evaluation steps for clusters of objects (i.e. between those affected + * and/or not affected by the sim for instance). + * + * 3) "Pull Results" - grab the specific transforms applied for a specific + * object - performed as part of object's transform-stack building. */ + + /* Create nodes --------------------------------------------------------- */ + + /* XXX: is this the right component, or do we want to use another one + * instead? */ + + /* Init/rebuild operation. */ + add_operation_node(&scene->id, + NodeType::TRANSFORM, + OperationCode::RIGIDBODY_REBUILD, + function_bind(BKE_rigidbody_rebuild_sim, _1, scene_cow)); + /* Do-sim operation. */ + OperationNode *sim_node = add_operation_node( + &scene->id, + NodeType::TRANSFORM, + OperationCode::RIGIDBODY_SIM, + function_bind(BKE_rigidbody_eval_simulation, _1, scene_cow)); + sim_node->set_as_entry(); + sim_node->set_as_exit(); + sim_node->owner->entry_operation = sim_node; + /* Objects - simulation participants. */ + if (rbw->group != NULL) { + build_collection(NULL, rbw->group); + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, object) { + if (object->type != OB_MESH) { + continue; + } + /* Create operation for flushing results. */ + /* Object's transform component - where the rigidbody operation + * lives. */ + add_operation_node( + &object->id, + NodeType::TRANSFORM, + OperationCode::RIGIDBODY_TRANSFORM_COPY, + function_bind( + BKE_rigidbody_object_sync_transforms, _1, scene_cow, get_cow_datablock(object))); + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + } + /* Constraints. */ + if (rbw->constraints != NULL) { + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->constraints, object) { + RigidBodyCon *rbc = object->rigidbody_constraint; + if (rbc == NULL || rbc->ob1 == NULL || rbc->ob2 == NULL) { + /* When either ob1 or ob2 is NULL, the constraint doesn't work. */ + continue; + } + /* Make sure indirectly linked objects are fully built. */ + build_object(-1, object, DEG_ID_LINKED_INDIRECTLY, false); + build_object(-1, rbc->ob1, DEG_ID_LINKED_INDIRECTLY, false); + build_object(-1, rbc->ob2, DEG_ID_LINKED_INDIRECTLY, false); + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + } } -void DepsgraphNodeBuilder::build_particle_systems(Object *object, - bool is_object_visible) +void DepsgraphNodeBuilder::build_particle_systems(Object *object, bool is_object_visible) { - /** - * Particle Systems Nodes - * ====================== - * - * There are two types of nodes associated with representing - * particle systems: - * 1) Component (EVAL_PARTICLES) - This is the particle-system - * evaluation context for an object. It acts as the container - * for all the nodes associated with a particular set of particle - * systems. - * 2) Particle System Eval Operation - This operation node acts as a - * blackbox evaluation step for one particle system referenced by - * the particle systems stack. All dependencies link to this operation. */ - /* Component for all particle systems. */ - ComponentNode *psys_comp = - add_component_node(&object->id, NodeType::PARTICLE_SYSTEM); - - Object *ob_cow = get_cow_datablock(object); - OperationNode *op_node; - op_node = add_operation_node(psys_comp, - OperationCode::PARTICLE_SYSTEM_INIT, - function_bind(BKE_particle_system_eval_init, - _1, - ob_cow)); - op_node->set_as_entry(); - /* Build all particle systems. */ - LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) { - ParticleSettings *part = psys->part; - /* Build particle settings operations. - * - * NOTE: The call itself ensures settings are only build once. */ - build_particle_settings(part); - /* Particle system evaluation. */ - add_operation_node(psys_comp, - OperationCode::PARTICLE_SYSTEM_EVAL, - NULL, - psys->name); - /* Keyed particle targets. */ - if (part->phystype == PART_PHYS_KEYED) { - LISTBASE_FOREACH (ParticleTarget *, particle_target, &psys->targets) { - if (particle_target->ob == NULL || - particle_target->ob == object) - { - continue; - } - build_object(-1, - particle_target->ob, - DEG_ID_LINKED_INDIRECTLY, - is_object_visible); - } - } - /* Visualization of particle system. */ - switch (part->ren_as) { - case PART_DRAW_OB: - if (part->instance_object != NULL) { - build_object(-1, - part->instance_object, - DEG_ID_LINKED_INDIRECTLY, - is_object_visible); - } - break; - case PART_DRAW_GR: - if (part->instance_collection != NULL) { - build_collection(NULL, part->instance_collection); - } - break; - } - } - op_node = add_operation_node( - psys_comp, OperationCode::PARTICLE_SYSTEM_DONE); - op_node->set_as_exit(); + /** + * Particle Systems Nodes + * ====================== + * + * There are two types of nodes associated with representing + * particle systems: + * 1) Component (EVAL_PARTICLES) - This is the particle-system + * evaluation context for an object. It acts as the container + * for all the nodes associated with a particular set of particle + * systems. + * 2) Particle System Eval Operation - This operation node acts as a + * blackbox evaluation step for one particle system referenced by + * the particle systems stack. All dependencies link to this operation. */ + /* Component for all particle systems. */ + ComponentNode *psys_comp = add_component_node(&object->id, NodeType::PARTICLE_SYSTEM); + + Object *ob_cow = get_cow_datablock(object); + OperationNode *op_node; + op_node = add_operation_node(psys_comp, + OperationCode::PARTICLE_SYSTEM_INIT, + function_bind(BKE_particle_system_eval_init, _1, ob_cow)); + op_node->set_as_entry(); + /* Build all particle systems. */ + LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) { + ParticleSettings *part = psys->part; + /* Build particle settings operations. + * + * NOTE: The call itself ensures settings are only build once. */ + build_particle_settings(part); + /* Particle system evaluation. */ + add_operation_node(psys_comp, OperationCode::PARTICLE_SYSTEM_EVAL, NULL, psys->name); + /* Keyed particle targets. */ + if (part->phystype == PART_PHYS_KEYED) { + LISTBASE_FOREACH (ParticleTarget *, particle_target, &psys->targets) { + if (particle_target->ob == NULL || particle_target->ob == object) { + continue; + } + build_object(-1, particle_target->ob, DEG_ID_LINKED_INDIRECTLY, is_object_visible); + } + } + /* Visualization of particle system. */ + switch (part->ren_as) { + case PART_DRAW_OB: + if (part->instance_object != NULL) { + build_object(-1, part->instance_object, DEG_ID_LINKED_INDIRECTLY, is_object_visible); + } + break; + case PART_DRAW_GR: + if (part->instance_collection != NULL) { + build_collection(NULL, part->instance_collection); + } + break; + } + } + op_node = add_operation_node(psys_comp, OperationCode::PARTICLE_SYSTEM_DONE); + op_node->set_as_exit(); } -void DepsgraphNodeBuilder::build_particle_settings( - ParticleSettings *particle_settings) { - if (built_map_.checkIsBuiltAndTag(particle_settings)) { - return; - } - /* Make sure we've got proper copied ID pointer. */ - add_id_node(&particle_settings->id); - ParticleSettings *particle_settings_cow = - get_cow_datablock(particle_settings); - /* Animation data. */ - build_animdata(&particle_settings->id); - build_parameters(&particle_settings->id); - /* Parameters change. */ - OperationNode *op_node; - op_node = add_operation_node(&particle_settings->id, - NodeType::PARTICLE_SETTINGS, - OperationCode::PARTICLE_SETTINGS_INIT); - op_node->set_as_entry(); - add_operation_node(&particle_settings->id, - NodeType::PARTICLE_SETTINGS, - OperationCode::PARTICLE_SETTINGS_RESET, - function_bind(BKE_particle_settings_eval_reset, - _1, - particle_settings_cow)); - op_node = add_operation_node(&particle_settings->id, - NodeType::PARTICLE_SETTINGS, - OperationCode::PARTICLE_SETTINGS_EVAL); - op_node->set_as_exit(); - /* Texture slots. */ - for (int mtex_index = 0; mtex_index < MAX_MTEX; ++mtex_index) { - MTex *mtex = particle_settings->mtex[mtex_index]; - if (mtex == NULL || mtex->tex == NULL) { - continue; - } - build_texture(mtex->tex); - } +void DepsgraphNodeBuilder::build_particle_settings(ParticleSettings *particle_settings) +{ + if (built_map_.checkIsBuiltAndTag(particle_settings)) { + return; + } + /* Make sure we've got proper copied ID pointer. */ + add_id_node(&particle_settings->id); + ParticleSettings *particle_settings_cow = get_cow_datablock(particle_settings); + /* Animation data. */ + build_animdata(&particle_settings->id); + build_parameters(&particle_settings->id); + /* Parameters change. */ + OperationNode *op_node; + op_node = add_operation_node( + &particle_settings->id, NodeType::PARTICLE_SETTINGS, OperationCode::PARTICLE_SETTINGS_INIT); + op_node->set_as_entry(); + add_operation_node(&particle_settings->id, + NodeType::PARTICLE_SETTINGS, + OperationCode::PARTICLE_SETTINGS_RESET, + function_bind(BKE_particle_settings_eval_reset, _1, particle_settings_cow)); + op_node = add_operation_node( + &particle_settings->id, NodeType::PARTICLE_SETTINGS, OperationCode::PARTICLE_SETTINGS_EVAL); + op_node->set_as_exit(); + /* Texture slots. */ + for (int mtex_index = 0; mtex_index < MAX_MTEX; ++mtex_index) { + MTex *mtex = particle_settings->mtex[mtex_index]; + if (mtex == NULL || mtex->tex == NULL) { + continue; + } + build_texture(mtex->tex); + } } /* Shapekeys */ void DepsgraphNodeBuilder::build_shapekeys(Key *key) { - if (built_map_.checkIsBuiltAndTag(key)) { - return; - } - build_animdata(&key->id); - build_parameters(&key->id); - /* This is an exit operation for the entire key datablock, is what is used - * as dependency for modifiers evaluation. */ - add_operation_node( - &key->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_SHAPEKEY); - /* Create per-key block properties, allowing tricky inter-dependnecies for - * drivers evaluation. */ - LISTBASE_FOREACH (KeyBlock *, key_block, &key->block) { - add_operation_node(&key->id, - NodeType::PARAMETERS, - OperationCode::PARAMETERS_EVAL, - NULL, - key_block->name); - } + if (built_map_.checkIsBuiltAndTag(key)) { + return; + } + build_animdata(&key->id); + build_parameters(&key->id); + /* This is an exit operation for the entire key datablock, is what is used + * as dependency for modifiers evaluation. */ + add_operation_node(&key->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_SHAPEKEY); + /* Create per-key block properties, allowing tricky inter-dependnecies for + * drivers evaluation. */ + LISTBASE_FOREACH (KeyBlock *, key_block, &key->block) { + add_operation_node( + &key->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, NULL, key_block->name); + } } /* ObData Geometry Evaluation */ // XXX: what happens if the datablock is shared! -void DepsgraphNodeBuilder::build_object_data_geometry( - Object *object, - bool is_object_visible) +void DepsgraphNodeBuilder::build_object_data_geometry(Object *object, bool is_object_visible) { - OperationNode *op_node; - Scene *scene_cow = get_cow_datablock(scene_); - Object *object_cow = get_cow_datablock(object); - /* Entry operation, takes care of initialization, and some other - * relations which needs to be run prior actual geometry evaluation. */ - op_node = add_operation_node( - &object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT); - op_node->set_as_entry(); - /* Geometry evaluation. */ - op_node = add_operation_node(&object->id, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL, - function_bind(BKE_object_eval_uber_data, - _1, - scene_cow, - object_cow)); - op_node->set_as_exit(); - /* Materials. */ - if (object->totcol != 0) { - if (object->type == OB_MESH) { - add_operation_node(&object->id, - NodeType::SHADING, - OperationCode::SHADING, - function_bind(BKE_object_eval_update_shading, - _1, - object_cow)); - } - for (int a = 1; a <= object->totcol; a++) { - Material *ma = give_current_material(object, a); - if (ma != NULL) { - build_material(ma); - } - } - } - /* Point caches. */ - build_object_pointcache(object); - /* Geometry. */ - build_object_data_geometry_datablock((ID *)object->data, is_object_visible); + OperationNode *op_node; + Scene *scene_cow = get_cow_datablock(scene_); + Object *object_cow = get_cow_datablock(object); + /* Entry operation, takes care of initialization, and some other + * relations which needs to be run prior actual geometry evaluation. */ + op_node = add_operation_node(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT); + op_node->set_as_entry(); + /* Geometry evaluation. */ + op_node = add_operation_node( + &object->id, + NodeType::GEOMETRY, + OperationCode::GEOMETRY_EVAL, + function_bind(BKE_object_eval_uber_data, _1, scene_cow, object_cow)); + op_node->set_as_exit(); + /* Materials. */ + if (object->totcol != 0) { + if (object->type == OB_MESH) { + add_operation_node(&object->id, + NodeType::SHADING, + OperationCode::SHADING, + function_bind(BKE_object_eval_update_shading, _1, object_cow)); + } + for (int a = 1; a <= object->totcol; a++) { + Material *ma = give_current_material(object, a); + if (ma != NULL) { + build_material(ma); + } + } + } + /* Point caches. */ + build_object_pointcache(object); + /* Geometry. */ + build_object_data_geometry_datablock((ID *)object->data, is_object_visible); } -void DepsgraphNodeBuilder::build_object_data_geometry_datablock( - ID *obdata, - bool is_object_visible) +void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata, bool is_object_visible) { - if (built_map_.checkIsBuiltAndTag(obdata)) { - return; - } - OperationNode *op_node; - /* Make sure we've got an ID node before requesting CoW pointer. */ - (void) add_id_node((ID *)obdata); - ID *obdata_cow = get_cow_id(obdata); - /* Animation. */ - build_animdata(obdata); - /* ShapeKeys */ - Key *key = BKE_key_from_id(obdata); - if (key) { - build_shapekeys(key); - } - /* Nodes for result of obdata's evaluation, and geometry - * evaluation on object. */ - const ID_Type id_type = GS(obdata->name); - switch (id_type) { - case ID_ME: - { - op_node = add_operation_node(obdata, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL, - function_bind(BKE_mesh_eval_geometry, - _1, - (Mesh *)obdata_cow)); - op_node->set_as_entry(); - break; - } - case ID_MB: - { - op_node = add_operation_node( - obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); - op_node->set_as_entry(); - break; - } - case ID_CU: - { - op_node = add_operation_node(obdata, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL, - function_bind(BKE_curve_eval_geometry, - _1, - (Curve *)obdata_cow)); - op_node->set_as_entry(); - /* Make sure objects used for bevel.taper are in the graph. - * NOTE: This objects might be not linked to the scene. */ - Curve *cu = (Curve *)obdata; - if (cu->bevobj != NULL) { - build_object(-1, - cu->bevobj, - DEG_ID_LINKED_INDIRECTLY, - is_object_visible); - } - if (cu->taperobj != NULL) { - build_object(-1, - cu->taperobj, - DEG_ID_LINKED_INDIRECTLY, - is_object_visible); - } - if (cu->textoncurve != NULL) { - build_object(-1, - cu->textoncurve, - DEG_ID_LINKED_INDIRECTLY, - is_object_visible); - } - break; - } - case ID_LT: - { - op_node = add_operation_node(obdata, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL, - function_bind(BKE_lattice_eval_geometry, - _1, - (Lattice *)obdata_cow)); - op_node->set_as_entry(); - break; - } - - case ID_GD: - { - /* GPencil evaluation operations. */ - op_node = add_operation_node(obdata, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL, - function_bind(BKE_gpencil_eval_geometry, - _1, - (bGPdata *)obdata_cow)); - op_node->set_as_entry(); - break; - } - default: - BLI_assert(!"Should not happen"); - break; - } - op_node = add_operation_node( - obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_DONE); - op_node->set_as_exit(); - /* Parameters for driver sources. */ - build_parameters(obdata); - /* Batch cache. */ - add_operation_node(obdata, - NodeType::BATCH_CACHE, - OperationCode::GEOMETRY_SELECT_UPDATE, - function_bind(BKE_object_data_select_update, - _1, - obdata_cow)); + if (built_map_.checkIsBuiltAndTag(obdata)) { + return; + } + OperationNode *op_node; + /* Make sure we've got an ID node before requesting CoW pointer. */ + (void)add_id_node((ID *)obdata); + ID *obdata_cow = get_cow_id(obdata); + /* Animation. */ + build_animdata(obdata); + /* ShapeKeys */ + Key *key = BKE_key_from_id(obdata); + if (key) { + build_shapekeys(key); + } + /* Nodes for result of obdata's evaluation, and geometry + * evaluation on object. */ + const ID_Type id_type = GS(obdata->name); + switch (id_type) { + case ID_ME: { + op_node = add_operation_node(obdata, + NodeType::GEOMETRY, + OperationCode::GEOMETRY_EVAL, + function_bind(BKE_mesh_eval_geometry, _1, (Mesh *)obdata_cow)); + op_node->set_as_entry(); + break; + } + case ID_MB: { + op_node = add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); + op_node->set_as_entry(); + break; + } + case ID_CU: { + op_node = add_operation_node( + obdata, + NodeType::GEOMETRY, + OperationCode::GEOMETRY_EVAL, + function_bind(BKE_curve_eval_geometry, _1, (Curve *)obdata_cow)); + op_node->set_as_entry(); + /* Make sure objects used for bevel.taper are in the graph. + * NOTE: This objects might be not linked to the scene. */ + Curve *cu = (Curve *)obdata; + if (cu->bevobj != NULL) { + build_object(-1, cu->bevobj, DEG_ID_LINKED_INDIRECTLY, is_object_visible); + } + if (cu->taperobj != NULL) { + build_object(-1, cu->taperobj, DEG_ID_LINKED_INDIRECTLY, is_object_visible); + } + if (cu->textoncurve != NULL) { + build_object(-1, cu->textoncurve, DEG_ID_LINKED_INDIRECTLY, is_object_visible); + } + break; + } + case ID_LT: { + op_node = add_operation_node( + obdata, + NodeType::GEOMETRY, + OperationCode::GEOMETRY_EVAL, + function_bind(BKE_lattice_eval_geometry, _1, (Lattice *)obdata_cow)); + op_node->set_as_entry(); + break; + } + + case ID_GD: { + /* GPencil evaluation operations. */ + op_node = add_operation_node( + obdata, + NodeType::GEOMETRY, + OperationCode::GEOMETRY_EVAL, + function_bind(BKE_gpencil_eval_geometry, _1, (bGPdata *)obdata_cow)); + op_node->set_as_entry(); + break; + } + default: + BLI_assert(!"Should not happen"); + break; + } + op_node = add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_DONE); + op_node->set_as_exit(); + /* Parameters for driver sources. */ + build_parameters(obdata); + /* Batch cache. */ + add_operation_node(obdata, + NodeType::BATCH_CACHE, + OperationCode::GEOMETRY_SELECT_UPDATE, + function_bind(BKE_object_data_select_update, _1, obdata_cow)); } void DepsgraphNodeBuilder::build_armature(bArmature *armature) { - if (built_map_.checkIsBuiltAndTag(armature)) { - return; - } - build_animdata(&armature->id); - build_parameters(&armature->id); - /* Make sure pose is up-to-date with armature updates. */ - add_operation_node( - &armature->id, NodeType::PARAMETERS, OperationCode::ARMATURE_EVAL); + if (built_map_.checkIsBuiltAndTag(armature)) { + return; + } + build_animdata(&armature->id); + build_parameters(&armature->id); + /* Make sure pose is up-to-date with armature updates. */ + add_operation_node(&armature->id, NodeType::PARAMETERS, OperationCode::ARMATURE_EVAL); } void DepsgraphNodeBuilder::build_camera(Camera *camera) { - if (built_map_.checkIsBuiltAndTag(camera)) { - return; - } - build_animdata(&camera->id); - build_parameters(&camera->id); + if (built_map_.checkIsBuiltAndTag(camera)) { + return; + } + build_animdata(&camera->id); + build_parameters(&camera->id); } void DepsgraphNodeBuilder::build_light(Light *lamp) { - if (built_map_.checkIsBuiltAndTag(lamp)) { - return; - } - build_animdata(&lamp->id); - build_parameters(&lamp->id); - /* light's nodetree */ - build_nodetree(lamp->nodetree); + if (built_map_.checkIsBuiltAndTag(lamp)) { + return; + } + build_animdata(&lamp->id); + build_parameters(&lamp->id); + /* light's nodetree */ + build_nodetree(lamp->nodetree); } void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree) { - if (ntree == NULL) { - return; - } - if (built_map_.checkIsBuiltAndTag(ntree)) { - return; - } - /* nodetree itself */ - add_id_node(&ntree->id); - bNodeTree *ntree_cow = get_cow_datablock(ntree); - /* General parameters. */ - build_parameters(&ntree->id); - /* Animation, */ - build_animdata(&ntree->id); - /* Shading update. */ - add_operation_node( - &ntree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE); - /* NOTE: We really pass original and CoW node trees here, this is how the - * callback works. Ideally we need to find a better way for that. */ - add_operation_node(&ntree->id, - NodeType::SHADING_PARAMETERS, - OperationCode::MATERIAL_UPDATE, - function_bind(BKE_nodetree_shading_params_eval, - _1, - ntree_cow, - ntree)); - /* nodetree's nodes... */ - LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) { - ID *id = bnode->id; - if (id == NULL) { - continue; - } - ID_Type id_type = GS(id->name); - if (id_type == ID_MA) { - build_material((Material *)id); - } - else if (id_type == ID_TE) { - build_texture((Tex *)id); - } - else if (id_type == ID_IM) { - build_image((Image *)id); - } - else if (id_type == ID_OB) { - /* TODO(sergey): Use visibility of owner of the node tree. */ - build_object(-1, (Object *)id, DEG_ID_LINKED_INDIRECTLY, true); - } - else if (id_type == ID_SCE) { - /* Scenes are used by compositor trees, and handled by render - * pipeline. No need to build dependencies for them here. */ - } - else if (id_type == ID_TXT) { - /* Ignore script nodes. */ - } - else if (id_type == ID_MSK) { - build_mask((Mask *)id); - } - else if (id_type == ID_MC) { - build_movieclip((MovieClip *)id); - } - else if (ELEM(bnode->type, NODE_GROUP, NODE_CUSTOM_GROUP)) { - bNodeTree *group_ntree = (bNodeTree *)id; - build_nodetree(group_ntree); - } - else { - BLI_assert(!"Unknown ID type used for node"); - } - } - - // TODO: link from nodetree to owner_component? + if (ntree == NULL) { + return; + } + if (built_map_.checkIsBuiltAndTag(ntree)) { + return; + } + /* nodetree itself */ + add_id_node(&ntree->id); + bNodeTree *ntree_cow = get_cow_datablock(ntree); + /* General parameters. */ + build_parameters(&ntree->id); + /* Animation, */ + build_animdata(&ntree->id); + /* Shading update. */ + add_operation_node(&ntree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE); + /* NOTE: We really pass original and CoW node trees here, this is how the + * callback works. Ideally we need to find a better way for that. */ + add_operation_node(&ntree->id, + NodeType::SHADING_PARAMETERS, + OperationCode::MATERIAL_UPDATE, + function_bind(BKE_nodetree_shading_params_eval, _1, ntree_cow, ntree)); + /* nodetree's nodes... */ + LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) { + ID *id = bnode->id; + if (id == NULL) { + continue; + } + ID_Type id_type = GS(id->name); + if (id_type == ID_MA) { + build_material((Material *)id); + } + else if (id_type == ID_TE) { + build_texture((Tex *)id); + } + else if (id_type == ID_IM) { + build_image((Image *)id); + } + else if (id_type == ID_OB) { + /* TODO(sergey): Use visibility of owner of the node tree. */ + build_object(-1, (Object *)id, DEG_ID_LINKED_INDIRECTLY, true); + } + else if (id_type == ID_SCE) { + /* Scenes are used by compositor trees, and handled by render + * pipeline. No need to build dependencies for them here. */ + } + else if (id_type == ID_TXT) { + /* Ignore script nodes. */ + } + else if (id_type == ID_MSK) { + build_mask((Mask *)id); + } + else if (id_type == ID_MC) { + build_movieclip((MovieClip *)id); + } + else if (ELEM(bnode->type, NODE_GROUP, NODE_CUSTOM_GROUP)) { + bNodeTree *group_ntree = (bNodeTree *)id; + build_nodetree(group_ntree); + } + else { + BLI_assert(!"Unknown ID type used for node"); + } + } + + // TODO: link from nodetree to owner_component? } /* Recursively build graph for material */ void DepsgraphNodeBuilder::build_material(Material *material) { - if (built_map_.checkIsBuiltAndTag(material)) { - return; - } - /* Material itself. */ - add_id_node(&material->id); - Material *material_cow = get_cow_datablock(material); - /* Shading update. */ - add_operation_node(&material->id, - NodeType::SHADING, - OperationCode::MATERIAL_UPDATE, - function_bind(BKE_material_eval, - _1, - material_cow)); - /* Material animation. */ - build_animdata(&material->id); - build_parameters(&material->id); - /* Material's nodetree. */ - build_nodetree(material->nodetree); + if (built_map_.checkIsBuiltAndTag(material)) { + return; + } + /* Material itself. */ + add_id_node(&material->id); + Material *material_cow = get_cow_datablock(material); + /* Shading update. */ + add_operation_node(&material->id, + NodeType::SHADING, + OperationCode::MATERIAL_UPDATE, + function_bind(BKE_material_eval, _1, material_cow)); + /* Material animation. */ + build_animdata(&material->id); + build_parameters(&material->id); + /* Material's nodetree. */ + build_nodetree(material->nodetree); } /* Recursively build graph for texture */ void DepsgraphNodeBuilder::build_texture(Tex *texture) { - if (built_map_.checkIsBuiltAndTag(texture)) { - return; - } - /* Texture itself. */ - build_animdata(&texture->id); - build_parameters(&texture->id); - /* Texture's nodetree. */ - build_nodetree(texture->nodetree); - /* Special cases for different IDs which texture uses. */ - if (texture->type == TEX_IMAGE) { - if (texture->ima != NULL) { - build_image(texture->ima); - } - } - add_operation_node(&texture->id, - NodeType::GENERIC_DATABLOCK, - OperationCode::GENERIC_DATABLOCK_UPDATE); + if (built_map_.checkIsBuiltAndTag(texture)) { + return; + } + /* Texture itself. */ + build_animdata(&texture->id); + build_parameters(&texture->id); + /* Texture's nodetree. */ + build_nodetree(texture->nodetree); + /* Special cases for different IDs which texture uses. */ + if (texture->type == TEX_IMAGE) { + if (texture->ima != NULL) { + build_image(texture->ima); + } + } + add_operation_node( + &texture->id, NodeType::GENERIC_DATABLOCK, OperationCode::GENERIC_DATABLOCK_UPDATE); } -void DepsgraphNodeBuilder::build_image(Image *image) { - if (built_map_.checkIsBuiltAndTag(image)) { - return; - } - build_parameters(&image->id); - add_operation_node(&image->id, - NodeType::GENERIC_DATABLOCK, - OperationCode::GENERIC_DATABLOCK_UPDATE); +void DepsgraphNodeBuilder::build_image(Image *image) +{ + if (built_map_.checkIsBuiltAndTag(image)) { + return; + } + build_parameters(&image->id); + add_operation_node( + &image->id, NodeType::GENERIC_DATABLOCK, OperationCode::GENERIC_DATABLOCK_UPDATE); } void DepsgraphNodeBuilder::build_compositor(Scene *scene) { - /* For now, just a plain wrapper? */ - // TODO: create compositing component? - // XXX: component type undefined! - //graph->get_node(&scene->id, NULL, NodeType::COMPOSITING, NULL); - - /* for now, nodetrees are just parameters; compositing occurs in internals - * of renderer... */ - add_component_node(&scene->id, NodeType::PARAMETERS); - build_nodetree(scene->nodetree); + /* For now, just a plain wrapper? */ + // TODO: create compositing component? + // XXX: component type undefined! + //graph->get_node(&scene->id, NULL, NodeType::COMPOSITING, NULL); + + /* for now, nodetrees are just parameters; compositing occurs in internals + * of renderer... */ + add_component_node(&scene->id, NodeType::PARAMETERS); + build_nodetree(scene->nodetree); } void DepsgraphNodeBuilder::build_gpencil(bGPdata *gpd) { - if (built_map_.checkIsBuiltAndTag(gpd)) { - return; - } - ID *gpd_id = &gpd->id; - - /* TODO(sergey): what about multiple users of same datablock? This should - * only get added once. */ - - /* The main reason Grease Pencil is included here is because the animation - * (and drivers) need to be hosted somewhere. */ - build_animdata(gpd_id); - build_parameters(gpd_id); + if (built_map_.checkIsBuiltAndTag(gpd)) { + return; + } + ID *gpd_id = &gpd->id; + + /* TODO(sergey): what about multiple users of same datablock? This should + * only get added once. */ + + /* The main reason Grease Pencil is included here is because the animation + * (and drivers) need to be hosted somewhere. */ + build_animdata(gpd_id); + build_parameters(gpd_id); } void DepsgraphNodeBuilder::build_cachefile(CacheFile *cache_file) { - if (built_map_.checkIsBuiltAndTag(cache_file)) { - return; - } - ID *cache_file_id = &cache_file->id; - /* Animation, */ - build_animdata(cache_file_id); - build_parameters(cache_file_id); - /* Cache evaluation itself. */ - add_operation_node( - cache_file_id, NodeType::CACHE, OperationCode::FILE_CACHE_UPDATE); + if (built_map_.checkIsBuiltAndTag(cache_file)) { + return; + } + ID *cache_file_id = &cache_file->id; + /* Animation, */ + build_animdata(cache_file_id); + build_parameters(cache_file_id); + /* Cache evaluation itself. */ + add_operation_node(cache_file_id, NodeType::CACHE, OperationCode::FILE_CACHE_UPDATE); } void DepsgraphNodeBuilder::build_mask(Mask *mask) { - if (built_map_.checkIsBuiltAndTag(mask)) { - return; - } - ID *mask_id = &mask->id; - Mask *mask_cow = get_cow_datablock(mask); - /* F-Curve based animation. */ - build_animdata(mask_id); - build_parameters(mask_id); - /* Animation based on mask's shapes. */ - add_operation_node(mask_id, - NodeType::ANIMATION, - OperationCode::MASK_ANIMATION, - function_bind(BKE_mask_eval_animation, _1, mask_cow)); - /* Final mask evaluation. */ - add_operation_node(mask_id, - NodeType::PARAMETERS, - OperationCode::MASK_EVAL, - function_bind(BKE_mask_eval_update, _1, mask_cow)); + if (built_map_.checkIsBuiltAndTag(mask)) { + return; + } + ID *mask_id = &mask->id; + Mask *mask_cow = get_cow_datablock(mask); + /* F-Curve based animation. */ + build_animdata(mask_id); + build_parameters(mask_id); + /* Animation based on mask's shapes. */ + add_operation_node(mask_id, + NodeType::ANIMATION, + OperationCode::MASK_ANIMATION, + function_bind(BKE_mask_eval_animation, _1, mask_cow)); + /* Final mask evaluation. */ + add_operation_node(mask_id, + NodeType::PARAMETERS, + OperationCode::MASK_EVAL, + function_bind(BKE_mask_eval_update, _1, mask_cow)); } void DepsgraphNodeBuilder::build_movieclip(MovieClip *clip) { - if (built_map_.checkIsBuiltAndTag(clip)) { - return; - } - ID *clip_id = &clip->id; - MovieClip *clip_cow = (MovieClip *)ensure_cow_id(clip_id); - /* Animation. */ - build_animdata(clip_id); - build_parameters(clip_id); - /* Movie clip evaluation. */ - add_operation_node(clip_id, - NodeType::PARAMETERS, - OperationCode::MOVIECLIP_EVAL, - function_bind(BKE_movieclip_eval_update, _1, clip_cow)); - - add_operation_node(clip_id, - NodeType::BATCH_CACHE, - OperationCode::MOVIECLIP_SELECT_UPDATE, - function_bind(BKE_movieclip_eval_selection_update, _1, clip_cow)); + if (built_map_.checkIsBuiltAndTag(clip)) { + return; + } + ID *clip_id = &clip->id; + MovieClip *clip_cow = (MovieClip *)ensure_cow_id(clip_id); + /* Animation. */ + build_animdata(clip_id); + build_parameters(clip_id); + /* Movie clip evaluation. */ + add_operation_node(clip_id, + NodeType::PARAMETERS, + OperationCode::MOVIECLIP_EVAL, + function_bind(BKE_movieclip_eval_update, _1, clip_cow)); + + add_operation_node(clip_id, + NodeType::BATCH_CACHE, + OperationCode::MOVIECLIP_SELECT_UPDATE, + function_bind(BKE_movieclip_eval_selection_update, _1, clip_cow)); } void DepsgraphNodeBuilder::build_lightprobe(LightProbe *probe) { - if (built_map_.checkIsBuiltAndTag(probe)) { - return; - } - /* Placeholder so we can add relations and tag ID node for update. */ - add_operation_node( - &probe->id, NodeType::PARAMETERS, OperationCode::LIGHT_PROBE_EVAL); - build_animdata(&probe->id); - build_parameters(&probe->id); + if (built_map_.checkIsBuiltAndTag(probe)) { + return; + } + /* Placeholder so we can add relations and tag ID node for update. */ + add_operation_node(&probe->id, NodeType::PARAMETERS, OperationCode::LIGHT_PROBE_EVAL); + build_animdata(&probe->id); + build_parameters(&probe->id); } void DepsgraphNodeBuilder::build_speaker(Speaker *speaker) { - if (built_map_.checkIsBuiltAndTag(speaker)) { - return; - } - /* Placeholder so we can add relations and tag ID node for update. */ - add_operation_node( - &speaker->id, NodeType::PARAMETERS, OperationCode::SPEAKER_EVAL); - build_animdata(&speaker->id); - build_parameters(&speaker->id); + if (built_map_.checkIsBuiltAndTag(speaker)) { + return; + } + /* Placeholder so we can add relations and tag ID node for update. */ + add_operation_node(&speaker->id, NodeType::PARAMETERS, OperationCode::SPEAKER_EVAL); + build_animdata(&speaker->id); + build_parameters(&speaker->id); } /* **** ID traversal callbacks functions **** */ @@ -1684,24 +1551,22 @@ void DepsgraphNodeBuilder::modifier_walk(void *user_data, struct ID **idpoin, int /*cb_flag*/) { - BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; - ID *id = *idpoin; - if (id == NULL) { - return; - } - switch (GS(id->name)) { - case ID_OB: - /* Special case for object, so we take owner visibility into - * account. */ - data->builder->build_object(-1, - (Object *)id, - DEG_ID_LINKED_INDIRECTLY, - data->is_parent_visible); - break; - default: - data->builder->build_id(id); - break; - } + BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; + ID *id = *idpoin; + if (id == NULL) { + return; + } + switch (GS(id->name)) { + case ID_OB: + /* Special case for object, so we take owner visibility into + * account. */ + data->builder->build_object( + -1, (Object *)id, DEG_ID_LINKED_INDIRECTLY, data->is_parent_visible); + break; + default: + data->builder->build_id(id); + break; + } } void DepsgraphNodeBuilder::constraint_walk(bConstraint * /*con*/, @@ -1709,24 +1574,22 @@ void DepsgraphNodeBuilder::constraint_walk(bConstraint * /*con*/, bool /*is_reference*/, void *user_data) { - BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; - ID *id = *idpoin; - if (id == NULL) { - return; - } - switch (GS(id->name)) { - case ID_OB: - /* Special case for object, so we take owner visibility into - * account. */ - data->builder->build_object(-1, - (Object *)id, - DEG_ID_LINKED_INDIRECTLY, - data->is_parent_visible); - break; - default: - data->builder->build_id(id); - break; - } + BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; + ID *id = *idpoin; + if (id == NULL) { + return; + } + switch (GS(id->name)) { + case ID_OB: + /* Special case for object, so we take owner visibility into + * account. */ + data->builder->build_object( + -1, (Object *)id, DEG_ID_LINKED_INDIRECTLY, data->is_parent_visible); + break; + default: + data->builder->build_id(id); + break; + } } } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index d5d1ac2d33a..d88f5a792e0 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -75,209 +75,196 @@ struct OperationNode; struct TimeSourceNode; class DepsgraphNodeBuilder : public DepsgraphBuilder { -public: - DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph); - ~DepsgraphNodeBuilder(); + public: + DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph); + ~DepsgraphNodeBuilder(); - /* For given original ID get ID which is created by CoW system. */ - ID *get_cow_id(const ID *id_orig) const; - /* Similar to above, but for the cases when there is no ID node we create - * one. */ - ID *ensure_cow_id(ID *id_orig); + /* For given original ID get ID which is created by CoW system. */ + ID *get_cow_id(const ID *id_orig) const; + /* Similar to above, but for the cases when there is no ID node we create + * one. */ + ID *ensure_cow_id(ID *id_orig); - /* Helper wrapper function which wraps get_cow_id with a needed type cast. */ - template - T *get_cow_datablock(const T *orig) const { - return (T *)get_cow_id(&orig->id); - } + /* Helper wrapper function which wraps get_cow_id with a needed type cast. */ + template T *get_cow_datablock(const T *orig) const + { + return (T *)get_cow_id(&orig->id); + } - /* For a given COW datablock get corresponding original one. */ - template - T *get_orig_datablock(const T *cow) const { - return (T *)cow->id.orig_id; - } + /* For a given COW datablock get corresponding original one. */ + template T *get_orig_datablock(const T *cow) const + { + return (T *)cow->id.orig_id; + } - void begin_build(); - void end_build(); + void begin_build(); + void end_build(); - IDNode *add_id_node(ID *id); - IDNode *find_id_node(ID *id); - TimeSourceNode *add_time_source(); + IDNode *add_id_node(ID *id); + IDNode *find_id_node(ID *id); + TimeSourceNode *add_time_source(); - ComponentNode *add_component_node(ID *id, - NodeType comp_type, - const char *comp_name = ""); + ComponentNode *add_component_node(ID *id, NodeType comp_type, const char *comp_name = ""); - OperationNode *add_operation_node(ComponentNode *comp_node, - OperationCode opcode, - const DepsEvalOperationCb& op = NULL, - const char *name = "", - int name_tag = -1); - OperationNode *add_operation_node(ID *id, - NodeType comp_type, - const char *comp_name, - OperationCode opcode, - const DepsEvalOperationCb& op = NULL, - const char *name = "", - int name_tag = -1); - OperationNode *add_operation_node(ID *id, - NodeType comp_type, - OperationCode opcode, - const DepsEvalOperationCb& op = NULL, - const char *name = "", - int name_tag = -1); + OperationNode *add_operation_node(ComponentNode *comp_node, + OperationCode opcode, + const DepsEvalOperationCb &op = NULL, + const char *name = "", + int name_tag = -1); + OperationNode *add_operation_node(ID *id, + NodeType comp_type, + const char *comp_name, + OperationCode opcode, + const DepsEvalOperationCb &op = NULL, + const char *name = "", + int name_tag = -1); + OperationNode *add_operation_node(ID *id, + NodeType comp_type, + OperationCode opcode, + const DepsEvalOperationCb &op = NULL, + const char *name = "", + int name_tag = -1); - OperationNode *ensure_operation_node(ID *id, - NodeType comp_type, - OperationCode opcode, - const DepsEvalOperationCb& op = NULL, - const char *name = "", - int name_tag = -1); + OperationNode *ensure_operation_node(ID *id, + NodeType comp_type, + OperationCode opcode, + const DepsEvalOperationCb &op = NULL, + const char *name = "", + int name_tag = -1); - bool has_operation_node(ID *id, - NodeType comp_type, - const char *comp_name, - OperationCode opcode, - const char *name = "", - int name_tag = -1); + bool has_operation_node(ID *id, + NodeType comp_type, + const char *comp_name, + OperationCode opcode, + const char *name = "", + int name_tag = -1); - OperationNode *find_operation_node(ID *id, - NodeType comp_type, - const char *comp_name, - OperationCode opcode, - const char *name = "", - int name_tag = -1); + OperationNode *find_operation_node(ID *id, + NodeType comp_type, + const char *comp_name, + OperationCode opcode, + const char *name = "", + int name_tag = -1); - OperationNode *find_operation_node(ID *id, - NodeType comp_type, - OperationCode opcode, - const char *name = "", - int name_tag = -1); + OperationNode *find_operation_node( + ID *id, NodeType comp_type, OperationCode opcode, const char *name = "", int name_tag = -1); - void build_id(ID *id); - void build_layer_collections(ListBase *lb); - void build_view_layer(Scene *scene, - ViewLayer *view_layer, - eDepsNode_LinkedState_Type linked_state); - void build_collection(LayerCollection *from_layer_collection, - Collection *collection); - void build_object(int base_index, - Object *object, - eDepsNode_LinkedState_Type linked_state, - bool is_visible); - void build_object_flags(int base_index, - Object *object, - eDepsNode_LinkedState_Type linked_state); - void build_object_data(Object *object, bool is_object_visible); - void build_object_data_camera(Object *object); - void build_object_data_geometry(Object *object, bool is_object_visible); - void build_object_data_geometry_datablock(ID *obdata, - bool is_object_visible); - void build_object_data_light(Object *object); - void build_object_data_lightprobe(Object *object); - void build_object_data_speaker(Object *object); - void build_object_transform(Object *object); - void build_object_constraints(Object *object); - void build_object_pointcache(Object *object); - void build_pose_constraints(Object *object, - bPoseChannel *pchan, - int pchan_index, - bool is_object_visible); - void build_rigidbody(Scene *scene); - void build_particle_systems(Object *object, bool is_object_visible); - void build_particle_settings(ParticleSettings *part); - void build_animdata(ID *id); - void build_animdata_nlastrip_targets(ListBase *strips); - void build_animation_images(ID *id); - void build_action(bAction *action); - void build_driver(ID *id, FCurve *fcurve, int driver_index); - void build_driver_variables(ID *id, FCurve *fcurve); - void build_driver_id_property(ID *id, const char *rna_path); - void build_parameters(ID *id); - void build_ik_pose(Object *object, - bPoseChannel *pchan, - bConstraint *con); - void build_splineik_pose(Object *object, - bPoseChannel *pchan, - bConstraint *con); - void build_rig(Object *object, bool is_object_visible); - void build_proxy_rig(Object *object); - void build_armature(bArmature *armature); - void build_shapekeys(Key *key); - void build_camera(Camera *camera); - void build_light(Light *lamp); - void build_nodetree(bNodeTree *ntree); - void build_material(Material *ma); - void build_texture(Tex *tex); - void build_image(Image *image); - void build_world(World *world); - void build_compositor(Scene *scene); - void build_gpencil(bGPdata *gpd); - void build_cachefile(CacheFile *cache_file); - void build_mask(Mask *mask); - void build_movieclip(MovieClip *clip); - void build_lightprobe(LightProbe *probe); - void build_speaker(Speaker *speaker); + void build_id(ID *id); + void build_layer_collections(ListBase *lb); + void build_view_layer(Scene *scene, + ViewLayer *view_layer, + eDepsNode_LinkedState_Type linked_state); + void build_collection(LayerCollection *from_layer_collection, Collection *collection); + void build_object(int base_index, + Object *object, + eDepsNode_LinkedState_Type linked_state, + bool is_visible); + void build_object_flags(int base_index, Object *object, eDepsNode_LinkedState_Type linked_state); + void build_object_data(Object *object, bool is_object_visible); + void build_object_data_camera(Object *object); + void build_object_data_geometry(Object *object, bool is_object_visible); + void build_object_data_geometry_datablock(ID *obdata, bool is_object_visible); + void build_object_data_light(Object *object); + void build_object_data_lightprobe(Object *object); + void build_object_data_speaker(Object *object); + void build_object_transform(Object *object); + void build_object_constraints(Object *object); + void build_object_pointcache(Object *object); + void build_pose_constraints(Object *object, + bPoseChannel *pchan, + int pchan_index, + bool is_object_visible); + void build_rigidbody(Scene *scene); + void build_particle_systems(Object *object, bool is_object_visible); + void build_particle_settings(ParticleSettings *part); + void build_animdata(ID *id); + void build_animdata_nlastrip_targets(ListBase *strips); + void build_animation_images(ID *id); + void build_action(bAction *action); + void build_driver(ID *id, FCurve *fcurve, int driver_index); + void build_driver_variables(ID *id, FCurve *fcurve); + void build_driver_id_property(ID *id, const char *rna_path); + void build_parameters(ID *id); + void build_ik_pose(Object *object, bPoseChannel *pchan, bConstraint *con); + void build_splineik_pose(Object *object, bPoseChannel *pchan, bConstraint *con); + void build_rig(Object *object, bool is_object_visible); + void build_proxy_rig(Object *object); + void build_armature(bArmature *armature); + void build_shapekeys(Key *key); + void build_camera(Camera *camera); + void build_light(Light *lamp); + void build_nodetree(bNodeTree *ntree); + void build_material(Material *ma); + void build_texture(Tex *tex); + void build_image(Image *image); + void build_world(World *world); + void build_compositor(Scene *scene); + void build_gpencil(bGPdata *gpd); + void build_cachefile(CacheFile *cache_file); + void build_mask(Mask *mask); + void build_movieclip(MovieClip *clip); + void build_lightprobe(LightProbe *probe); + void build_speaker(Speaker *speaker); - /* Per-ID information about what was already in the dependency graph. - * Allows to re-use certain values, to speed up following evaluation. */ - struct IDInfo { - /* Copy-on-written pointer of the corresponding ID. */ - ID *id_cow; - /* Mask of visible components from previous state of the - * dependency graph. */ - IDComponentsMask previously_visible_components_mask; - /* Special evaluation flag mask from the previous depsgraph. */ - uint32_t previous_eval_flags; - /* Mesh CustomData mask from the previous depsgraph. */ - DEGCustomDataMeshMasks previous_customdata_masks; - }; + /* Per-ID information about what was already in the dependency graph. + * Allows to re-use certain values, to speed up following evaluation. */ + struct IDInfo { + /* Copy-on-written pointer of the corresponding ID. */ + ID *id_cow; + /* Mask of visible components from previous state of the + * dependency graph. */ + IDComponentsMask previously_visible_components_mask; + /* Special evaluation flag mask from the previous depsgraph. */ + uint32_t previous_eval_flags; + /* Mesh CustomData mask from the previous depsgraph. */ + DEGCustomDataMeshMasks previous_customdata_masks; + }; -protected: - /* Allows to identify an operation which was tagged for update at the time - * relations are being updated. We can not reuse operation node pointer - * since it will change during dependency graph construction. */ - struct SavedEntryTag { - ID *id_orig; - NodeType component_type; - OperationCode opcode; - string name; - int name_tag; - }; - vector saved_entry_tags_; + protected: + /* Allows to identify an operation which was tagged for update at the time + * relations are being updated. We can not reuse operation node pointer + * since it will change during dependency graph construction. */ + struct SavedEntryTag { + ID *id_orig; + NodeType component_type; + OperationCode opcode; + string name; + int name_tag; + }; + vector saved_entry_tags_; - struct BuilderWalkUserData { - DepsgraphNodeBuilder *builder; - /* Denotes whether object the walk is invoked from is visible. */ - bool is_parent_visible; - }; - static void modifier_walk(void *user_data, - struct Object *object, - struct ID **idpoin, - int cb_flag); - static void constraint_walk(bConstraint *constraint, - ID **idpoin, - bool is_reference, - void *user_data); + struct BuilderWalkUserData { + DepsgraphNodeBuilder *builder; + /* Denotes whether object the walk is invoked from is visible. */ + bool is_parent_visible; + }; + static void modifier_walk(void *user_data, + struct Object *object, + struct ID **idpoin, + int cb_flag); + static void constraint_walk(bConstraint *constraint, + ID **idpoin, + bool is_reference, + void *user_data); - /* State which demotes currently built entities. */ - Scene *scene_; - ViewLayer *view_layer_; - int view_layer_index_; - /* NOTE: Collection are possibly built recursively, so be careful when - * setting the current state. */ - Collection *collection_; - /* Accumulated flag over the hierarchy opf currently building collections. - * Denotes whether all the hierarchy from parent of collection_ to the - * very root is visible (aka not restricted.). */ - bool is_parent_collection_visible_; + /* State which demotes currently built entities. */ + Scene *scene_; + ViewLayer *view_layer_; + int view_layer_index_; + /* NOTE: Collection are possibly built recursively, so be careful when + * setting the current state. */ + Collection *collection_; + /* Accumulated flag over the hierarchy opf currently building collections. + * Denotes whether all the hierarchy from parent of collection_ to the + * very root is visible (aka not restricted.). */ + bool is_parent_collection_visible_; - /* Indexed by original ID, values are IDInfo. */ - GHash *id_info_hash_; + /* Indexed by original ID, values are IDInfo. */ + GHash *id_info_hash_; - /* Set of IDs which were already build. Makes it easier to keep track of - * what was already built and what was not. */ - BuilderMap built_map_; + /* Set of IDs which were already build. Makes it easier to keep track of + * what was already built and what was not. */ + BuilderMap built_map_; }; } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc index 132600f2fdd..6f141bd7222 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc @@ -58,60 +58,56 @@ extern "C" { namespace DEG { -void DepsgraphNodeBuilder::build_pose_constraints( - Object *object, - bPoseChannel *pchan, - int pchan_index, - bool is_object_visible) +void DepsgraphNodeBuilder::build_pose_constraints(Object *object, + bPoseChannel *pchan, + int pchan_index, + bool is_object_visible) { - /* Pull indirect dependencies via constraints. */ - BuilderWalkUserData data; - data.builder = this; - data.is_parent_visible = is_object_visible; - BKE_constraints_id_loop(&pchan->constraints, constraint_walk, &data); - /* Create node for constraint stack. */ - add_operation_node(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_CONSTRAINTS, - function_bind(BKE_pose_constraints_evaluate, - _1, - get_cow_datablock(scene_), - get_cow_datablock(object), - pchan_index)); + /* Pull indirect dependencies via constraints. */ + BuilderWalkUserData data; + data.builder = this; + data.is_parent_visible = is_object_visible; + BKE_constraints_id_loop(&pchan->constraints, constraint_walk, &data); + /* Create node for constraint stack. */ + add_operation_node(&object->id, + NodeType::BONE, + pchan->name, + OperationCode::BONE_CONSTRAINTS, + function_bind(BKE_pose_constraints_evaluate, + _1, + get_cow_datablock(scene_), + get_cow_datablock(object), + pchan_index)); } /* IK Solver Eval Steps */ -void DepsgraphNodeBuilder::build_ik_pose(Object *object, - bPoseChannel *pchan, - bConstraint *con) +void DepsgraphNodeBuilder::build_ik_pose(Object *object, bPoseChannel *pchan, bConstraint *con) { - bKinematicConstraint *data = (bKinematicConstraint *)con->data; - - /* Find the chain's root. */ - bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data); - if (rootchan == NULL) { - return; - } - - if (has_operation_node(&object->id, NodeType::EVAL_POSE, rootchan->name, - OperationCode::POSE_IK_SOLVER)) - { - return; - } - - int rootchan_index = BLI_findindex(&object->pose->chanbase, rootchan); - BLI_assert(rootchan_index != -1); - /* Operation node for evaluating/running IK Solver. */ - add_operation_node(&object->id, - NodeType::EVAL_POSE, - rootchan->name, - OperationCode::POSE_IK_SOLVER, - function_bind(BKE_pose_iktree_evaluate, - _1, - get_cow_datablock(scene_), - get_cow_datablock(object), - rootchan_index)); + bKinematicConstraint *data = (bKinematicConstraint *)con->data; + + /* Find the chain's root. */ + bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data); + if (rootchan == NULL) { + return; + } + + if (has_operation_node( + &object->id, NodeType::EVAL_POSE, rootchan->name, OperationCode::POSE_IK_SOLVER)) { + return; + } + + int rootchan_index = BLI_findindex(&object->pose->chanbase, rootchan); + BLI_assert(rootchan_index != -1); + /* Operation node for evaluating/running IK Solver. */ + add_operation_node(&object->id, + NodeType::EVAL_POSE, + rootchan->name, + OperationCode::POSE_IK_SOLVER, + function_bind(BKE_pose_iktree_evaluate, + _1, + get_cow_datablock(scene_), + get_cow_datablock(object), + rootchan_index)); } /* Spline IK Eval Steps */ @@ -119,277 +115,229 @@ void DepsgraphNodeBuilder::build_splineik_pose(Object *object, bPoseChannel *pchan, bConstraint *con) { - bSplineIKConstraint *data = (bSplineIKConstraint *)con->data; - - /* Find the chain's root. */ - bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data); - - /* Operation node for evaluating/running Spline IK Solver. - * Store the "root bone" of this chain in the solver, so it knows where to - * start. */ - int rootchan_index = BLI_findindex(&object->pose->chanbase, rootchan); - BLI_assert(rootchan_index != -1); - add_operation_node(&object->id, - NodeType::EVAL_POSE, - rootchan->name, - OperationCode::POSE_SPLINE_IK_SOLVER, - function_bind(BKE_pose_splineik_evaluate, - _1, - get_cow_datablock(scene_), - get_cow_datablock(object), - rootchan_index)); + bSplineIKConstraint *data = (bSplineIKConstraint *)con->data; + + /* Find the chain's root. */ + bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data); + + /* Operation node for evaluating/running Spline IK Solver. + * Store the "root bone" of this chain in the solver, so it knows where to + * start. */ + int rootchan_index = BLI_findindex(&object->pose->chanbase, rootchan); + BLI_assert(rootchan_index != -1); + add_operation_node(&object->id, + NodeType::EVAL_POSE, + rootchan->name, + OperationCode::POSE_SPLINE_IK_SOLVER, + function_bind(BKE_pose_splineik_evaluate, + _1, + get_cow_datablock(scene_), + get_cow_datablock(object), + rootchan_index)); } /* Pose/Armature Bones Graph */ void DepsgraphNodeBuilder::build_rig(Object *object, bool is_object_visible) { - bArmature *armature = (bArmature *)object->data; - Scene *scene_cow = get_cow_datablock(scene_); - Object *object_cow = get_cow_datablock(object); - OperationNode *op_node; - /* Animation and/or drivers linking posebones to base-armature used to - * define them. - * - * NOTE: AnimData here is really used to control animated deform properties, - * which ideally should be able to be unique across different - * instances. Eventually, we need some type of proxy/isolation - * mechanism in-between here to ensure that we can use same rig - * multiple times in same scene. */ - /* Armature. */ - build_armature(armature); - /* Rebuild pose if not up to date. */ - if (object->pose == NULL || (object->pose->flag & POSE_RECALC)) { - /* By definition, no need to tag depsgraph as dirty from here, so we can pass NULL bmain. */ - BKE_pose_rebuild(NULL, object, armature, true); - } - /* Speed optimization for animation lookups. */ - if (object->pose != NULL) { - BKE_pose_channels_hash_make(object->pose); - if (object->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { - BKE_pose_update_constraint_flags(object->pose); - } - } - /** - * Pose Rig Graph - * ============== - * - * Pose Component: - * - Mainly used for referencing Bone components. - * - This is where the evaluation operations for init/exec/cleanup - * (ik) solvers live, and are later hooked up (so that they can be - * interleaved during runtime) with bone-operations they depend on/affect. - * - init_pose_eval() and cleanup_pose_eval() are absolute first and last - * steps of pose eval process. ALL bone operations must be performed - * between these two... - * - * Bone Component: - * - Used for representing each bone within the rig - * - Acts to encapsulate the evaluation operations (base matrix + parenting, - * and constraint stack) so that they can be easily found. - * - Everything else which depends on bone-results hook up to the component - * only so that we can redirect those to point at either the - * post-IK/post-constraint/post-matrix steps, as needed. */ - /* Pose eval context. */ - op_node = add_operation_node(&object->id, - NodeType::EVAL_POSE, - OperationCode::POSE_INIT, - function_bind(BKE_pose_eval_init, - _1, - scene_cow, - object_cow)); - op_node->set_as_entry(); - - op_node = add_operation_node(&object->id, - NodeType::EVAL_POSE, - OperationCode::POSE_INIT_IK, - function_bind(BKE_pose_eval_init_ik, - _1, - scene_cow, - object_cow)); - - add_operation_node(&object->id, - NodeType::EVAL_POSE, - OperationCode::POSE_CLEANUP, - function_bind(BKE_pose_eval_cleanup, - _1, - scene_cow, - object_cow)); - - op_node = add_operation_node(&object->id, - NodeType::EVAL_POSE, - OperationCode::POSE_DONE, - function_bind(BKE_pose_eval_done, - _1, - object_cow)); - op_node->set_as_exit(); - /* Bones. */ - int pchan_index = 0; - LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { - /* Node for bone evaluation. */ - op_node = add_operation_node(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_LOCAL); - op_node->set_as_entry(); - - add_operation_node(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_POSE_PARENT, - function_bind(BKE_pose_eval_bone, _1, - scene_cow, - object_cow, - pchan_index)); - - /* NOTE: Dedicated noop for easier relationship construction. */ - add_operation_node(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_READY); - - op_node = add_operation_node(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_DONE, - function_bind(BKE_pose_bone_done, - _1, - object_cow, - pchan_index)); - - /* B-Bone shape computation - the real last step if present. */ - if (pchan->bone != NULL && pchan->bone->segments > 1) { - op_node = add_operation_node(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_SEGMENTS, - function_bind(BKE_pose_eval_bbone_segments, _1, - object_cow, - pchan_index)); - } - - op_node->set_as_exit(); - - /* Custom properties. */ - if (pchan->prop != NULL) { - add_operation_node(&object->id, - NodeType::PARAMETERS, - OperationCode::PARAMETERS_EVAL, - NULL, - pchan->name); - } - /* Build constraints. */ - if (pchan->constraints.first != NULL) { - build_pose_constraints( - object, pchan, pchan_index, is_object_visible); - } - /** - * IK Solvers. - * - * - These require separate processing steps are pose-level - * to be executed between chains of bones (i.e. once the - * base transforms of a bunch of bones is done) - * - * Unsolved Issues: - * - Care is needed to ensure that multi-headed trees work out the same - * as in ik-tree building - * - Animated chain-lengths are a problem. */ - LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) { - switch (con->type) { - case CONSTRAINT_TYPE_KINEMATIC: - build_ik_pose(object, pchan, con); - break; - - case CONSTRAINT_TYPE_SPLINEIK: - build_splineik_pose(object, pchan, con); - break; - - default: - break; - } - } - /* Custom shape. */ - if (pchan->custom != NULL) { - /* TODO(sergey): Use own visibility. */ - build_object( - -1, - pchan->custom, - DEG_ID_LINKED_INDIRECTLY, - is_object_visible); - } - pchan_index++; - } + bArmature *armature = (bArmature *)object->data; + Scene *scene_cow = get_cow_datablock(scene_); + Object *object_cow = get_cow_datablock(object); + OperationNode *op_node; + /* Animation and/or drivers linking posebones to base-armature used to + * define them. + * + * NOTE: AnimData here is really used to control animated deform properties, + * which ideally should be able to be unique across different + * instances. Eventually, we need some type of proxy/isolation + * mechanism in-between here to ensure that we can use same rig + * multiple times in same scene. */ + /* Armature. */ + build_armature(armature); + /* Rebuild pose if not up to date. */ + if (object->pose == NULL || (object->pose->flag & POSE_RECALC)) { + /* By definition, no need to tag depsgraph as dirty from here, so we can pass NULL bmain. */ + BKE_pose_rebuild(NULL, object, armature, true); + } + /* Speed optimization for animation lookups. */ + if (object->pose != NULL) { + BKE_pose_channels_hash_make(object->pose); + if (object->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { + BKE_pose_update_constraint_flags(object->pose); + } + } + /** + * Pose Rig Graph + * ============== + * + * Pose Component: + * - Mainly used for referencing Bone components. + * - This is where the evaluation operations for init/exec/cleanup + * (ik) solvers live, and are later hooked up (so that they can be + * interleaved during runtime) with bone-operations they depend on/affect. + * - init_pose_eval() and cleanup_pose_eval() are absolute first and last + * steps of pose eval process. ALL bone operations must be performed + * between these two... + * + * Bone Component: + * - Used for representing each bone within the rig + * - Acts to encapsulate the evaluation operations (base matrix + parenting, + * and constraint stack) so that they can be easily found. + * - Everything else which depends on bone-results hook up to the component + * only so that we can redirect those to point at either the + * post-IK/post-constraint/post-matrix steps, as needed. */ + /* Pose eval context. */ + op_node = add_operation_node(&object->id, + NodeType::EVAL_POSE, + OperationCode::POSE_INIT, + function_bind(BKE_pose_eval_init, _1, scene_cow, object_cow)); + op_node->set_as_entry(); + + op_node = add_operation_node(&object->id, + NodeType::EVAL_POSE, + OperationCode::POSE_INIT_IK, + function_bind(BKE_pose_eval_init_ik, _1, scene_cow, object_cow)); + + add_operation_node(&object->id, + NodeType::EVAL_POSE, + OperationCode::POSE_CLEANUP, + function_bind(BKE_pose_eval_cleanup, _1, scene_cow, object_cow)); + + op_node = add_operation_node(&object->id, + NodeType::EVAL_POSE, + OperationCode::POSE_DONE, + function_bind(BKE_pose_eval_done, _1, object_cow)); + op_node->set_as_exit(); + /* Bones. */ + int pchan_index = 0; + LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { + /* Node for bone evaluation. */ + op_node = add_operation_node( + &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL); + op_node->set_as_entry(); + + add_operation_node(&object->id, + NodeType::BONE, + pchan->name, + OperationCode::BONE_POSE_PARENT, + function_bind(BKE_pose_eval_bone, _1, scene_cow, object_cow, pchan_index)); + + /* NOTE: Dedicated noop for easier relationship construction. */ + add_operation_node(&object->id, NodeType::BONE, pchan->name, OperationCode::BONE_READY); + + op_node = add_operation_node(&object->id, + NodeType::BONE, + pchan->name, + OperationCode::BONE_DONE, + function_bind(BKE_pose_bone_done, _1, object_cow, pchan_index)); + + /* B-Bone shape computation - the real last step if present. */ + if (pchan->bone != NULL && pchan->bone->segments > 1) { + op_node = add_operation_node( + &object->id, + NodeType::BONE, + pchan->name, + OperationCode::BONE_SEGMENTS, + function_bind(BKE_pose_eval_bbone_segments, _1, object_cow, pchan_index)); + } + + op_node->set_as_exit(); + + /* Custom properties. */ + if (pchan->prop != NULL) { + add_operation_node( + &object->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, NULL, pchan->name); + } + /* Build constraints. */ + if (pchan->constraints.first != NULL) { + build_pose_constraints(object, pchan, pchan_index, is_object_visible); + } + /** + * IK Solvers. + * + * - These require separate processing steps are pose-level + * to be executed between chains of bones (i.e. once the + * base transforms of a bunch of bones is done) + * + * Unsolved Issues: + * - Care is needed to ensure that multi-headed trees work out the same + * as in ik-tree building + * - Animated chain-lengths are a problem. */ + LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) { + switch (con->type) { + case CONSTRAINT_TYPE_KINEMATIC: + build_ik_pose(object, pchan, con); + break; + + case CONSTRAINT_TYPE_SPLINEIK: + build_splineik_pose(object, pchan, con); + break; + + default: + break; + } + } + /* Custom shape. */ + if (pchan->custom != NULL) { + /* TODO(sergey): Use own visibility. */ + build_object(-1, pchan->custom, DEG_ID_LINKED_INDIRECTLY, is_object_visible); + } + pchan_index++; + } } void DepsgraphNodeBuilder::build_proxy_rig(Object *object) { - bArmature *armature = (bArmature *)object->data; - OperationNode *op_node; - Object *object_cow = get_cow_datablock(object); - /* Sanity check. */ - BLI_assert(object->pose != NULL); - /* Armature. */ - build_armature(armature); - /* speed optimization for animation lookups */ - BKE_pose_channels_hash_make(object->pose); - if (object->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { - BKE_pose_update_constraint_flags(object->pose); - } - op_node = add_operation_node(&object->id, - NodeType::EVAL_POSE, - OperationCode::POSE_INIT, - function_bind(BKE_pose_eval_proxy_init, - _1, - object_cow)); - op_node->set_as_entry(); - - int pchan_index = 0; - LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { - op_node = add_operation_node(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_LOCAL); - op_node->set_as_entry(); - /* Bone is ready for solvers. */ - add_operation_node(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_READY); - /* Bone is fully evaluated. */ - op_node = add_operation_node( - &object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_DONE, - function_bind(BKE_pose_eval_proxy_copy_bone, - _1, - object_cow, - pchan_index)); - op_node->set_as_exit(); - - /* Custom properties. */ - if (pchan->prop != NULL) { - add_operation_node(&object->id, - NodeType::PARAMETERS, - OperationCode::PARAMETERS_EVAL, - NULL, - pchan->name); - } - - pchan_index++; - } - op_node = add_operation_node(&object->id, - NodeType::EVAL_POSE, - OperationCode::POSE_CLEANUP, - function_bind(BKE_pose_eval_proxy_cleanup, - _1, - object_cow)); - op_node = add_operation_node(&object->id, - NodeType::EVAL_POSE, - OperationCode::POSE_DONE, - function_bind(BKE_pose_eval_proxy_done, - _1, - object_cow)); - op_node->set_as_exit(); + bArmature *armature = (bArmature *)object->data; + OperationNode *op_node; + Object *object_cow = get_cow_datablock(object); + /* Sanity check. */ + BLI_assert(object->pose != NULL); + /* Armature. */ + build_armature(armature); + /* speed optimization for animation lookups */ + BKE_pose_channels_hash_make(object->pose); + if (object->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { + BKE_pose_update_constraint_flags(object->pose); + } + op_node = add_operation_node(&object->id, + NodeType::EVAL_POSE, + OperationCode::POSE_INIT, + function_bind(BKE_pose_eval_proxy_init, _1, object_cow)); + op_node->set_as_entry(); + + int pchan_index = 0; + LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { + op_node = add_operation_node( + &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL); + op_node->set_as_entry(); + /* Bone is ready for solvers. */ + add_operation_node(&object->id, NodeType::BONE, pchan->name, OperationCode::BONE_READY); + /* Bone is fully evaluated. */ + op_node = add_operation_node( + &object->id, + NodeType::BONE, + pchan->name, + OperationCode::BONE_DONE, + function_bind(BKE_pose_eval_proxy_copy_bone, _1, object_cow, pchan_index)); + op_node->set_as_exit(); + + /* Custom properties. */ + if (pchan->prop != NULL) { + add_operation_node( + &object->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, NULL, pchan->name); + } + + pchan_index++; + } + op_node = add_operation_node(&object->id, + NodeType::EVAL_POSE, + OperationCode::POSE_CLEANUP, + function_bind(BKE_pose_eval_proxy_cleanup, _1, object_cow)); + op_node = add_operation_node(&object->id, + NodeType::EVAL_POSE, + OperationCode::POSE_DONE, + function_bind(BKE_pose_eval_proxy_done, _1, object_cow)); + op_node->set_as_exit(); } } // namespace DEG 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 36a9d53d670..60b711d76d3 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 @@ -60,115 +60,111 @@ namespace DEG { void DepsgraphNodeBuilder::build_layer_collections(ListBase *lb) { - const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT) ? - COLLECTION_RESTRICT_VIEW : COLLECTION_RESTRICT_RENDER; + const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT) ? COLLECTION_RESTRICT_VIEW : + COLLECTION_RESTRICT_RENDER; - for (LayerCollection *lc = (LayerCollection *)lb->first; lc; lc = lc->next) { - if (lc->collection->flag & restrict_flag) { - continue; - } - if ((lc->flag & LAYER_COLLECTION_EXCLUDE) == 0) { - build_collection(lc, lc->collection); - } - build_layer_collections(&lc->layer_collections); - } + for (LayerCollection *lc = (LayerCollection *)lb->first; lc; lc = lc->next) { + if (lc->collection->flag & restrict_flag) { + continue; + } + if ((lc->flag & LAYER_COLLECTION_EXCLUDE) == 0) { + build_collection(lc, lc->collection); + } + build_layer_collections(&lc->layer_collections); + } } -void DepsgraphNodeBuilder::build_view_layer( - Scene *scene, - ViewLayer *view_layer, - eDepsNode_LinkedState_Type linked_state) +void DepsgraphNodeBuilder::build_view_layer(Scene *scene, + ViewLayer *view_layer, + eDepsNode_LinkedState_Type linked_state) { - /* NOTE: Pass view layer index of 0 since after scene CoW there is - * only one view layer in there. */ - view_layer_index_ = 0; - /* Scene ID block. */ - IDNode *id_node = add_id_node(&scene->id); - id_node->linked_state = linked_state; - /* Time source. */ - add_time_source(); - /* Setup currently building context. */ - scene_ = scene; - view_layer_ = view_layer; - /* Get pointer to a CoW version of scene ID. */ - Scene *scene_cow = get_cow_datablock(scene); - /* Scene objects. */ - int select_id = 1; - /* NOTE: Base is used for function bindings as-is, so need to pass CoW base, - * but object is expected to be an original one. Hence we go into some - * tricks here iterating over the view layer. */ - 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; - } - base->object->select_id = select_id++; - } - build_layer_collections(&view_layer->layer_collections); - if (scene->camera != NULL) { - build_object(-1, scene->camera, DEG_ID_LINKED_INDIRECTLY, true); - } - /* Rigidbody. */ - if (scene->rigidbody_world != NULL) { - build_rigidbody(scene); - } - /* Scene's animation and drivers. */ - if (scene->adt != NULL) { - build_animdata(&scene->id); - } - /* World. */ - if (scene->world != NULL) { - build_world(scene->world); - } - /* Compositor nodes */ - if (scene->nodetree != NULL) { - build_compositor(scene); - } - /* Cache file. */ - LISTBASE_FOREACH (CacheFile *, cachefile, &bmain_->cachefiles) { - build_cachefile(cachefile); - } - /* Masks. */ - LISTBASE_FOREACH (Mask *, mask, &bmain_->masks) { - build_mask(mask); - } - /* Movie clips. */ - LISTBASE_FOREACH (MovieClip *, clip, &bmain_->movieclips) { - build_movieclip(clip); - } - /* Material override. */ - if (view_layer->mat_override != NULL) { - build_material(view_layer->mat_override); - } - /* Freestyle collections. */ - LISTBASE_FOREACH (FreestyleLineSet *, fls, &view_layer->freestyle_config.linesets) { - if (fls->group != NULL) { - build_collection(NULL, fls->group); - } - } - /* Collections. */ - add_operation_node(&scene->id, - NodeType::LAYER_COLLECTIONS, - OperationCode::VIEW_LAYER_EVAL, - function_bind(BKE_layer_eval_view_layer_indexed, - _1, - scene_cow, - view_layer_index_)); - /* Parameters evaluation for scene relations mainly. */ - add_operation_node( - &scene->id, NodeType::PARAMETERS, OperationCode::SCENE_EVAL); - /* Build all set scenes. */ - if (scene->set != NULL) { - ViewLayer *set_view_layer = BKE_view_layer_default_render(scene->set); - build_view_layer(scene->set, set_view_layer, DEG_ID_LINKED_VIA_SET); - } + /* NOTE: Pass view layer index of 0 since after scene CoW there is + * only one view layer in there. */ + view_layer_index_ = 0; + /* Scene ID block. */ + IDNode *id_node = add_id_node(&scene->id); + id_node->linked_state = linked_state; + /* Time source. */ + add_time_source(); + /* Setup currently building context. */ + scene_ = scene; + view_layer_ = view_layer; + /* Get pointer to a CoW version of scene ID. */ + Scene *scene_cow = get_cow_datablock(scene); + /* Scene objects. */ + int select_id = 1; + /* NOTE: Base is used for function bindings as-is, so need to pass CoW base, + * but object is expected to be an original one. Hence we go into some + * tricks here iterating over the view layer. */ + 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; + } + base->object->select_id = select_id++; + } + build_layer_collections(&view_layer->layer_collections); + if (scene->camera != NULL) { + build_object(-1, scene->camera, DEG_ID_LINKED_INDIRECTLY, true); + } + /* Rigidbody. */ + if (scene->rigidbody_world != NULL) { + build_rigidbody(scene); + } + /* Scene's animation and drivers. */ + if (scene->adt != NULL) { + build_animdata(&scene->id); + } + /* World. */ + if (scene->world != NULL) { + build_world(scene->world); + } + /* Compositor nodes */ + if (scene->nodetree != NULL) { + build_compositor(scene); + } + /* Cache file. */ + LISTBASE_FOREACH (CacheFile *, cachefile, &bmain_->cachefiles) { + build_cachefile(cachefile); + } + /* Masks. */ + LISTBASE_FOREACH (Mask *, mask, &bmain_->masks) { + build_mask(mask); + } + /* Movie clips. */ + LISTBASE_FOREACH (MovieClip *, clip, &bmain_->movieclips) { + build_movieclip(clip); + } + /* Material override. */ + if (view_layer->mat_override != NULL) { + build_material(view_layer->mat_override); + } + /* Freestyle collections. */ + LISTBASE_FOREACH (FreestyleLineSet *, fls, &view_layer->freestyle_config.linesets) { + if (fls->group != NULL) { + build_collection(NULL, fls->group); + } + } + /* Collections. */ + add_operation_node( + &scene->id, + NodeType::LAYER_COLLECTIONS, + OperationCode::VIEW_LAYER_EVAL, + function_bind(BKE_layer_eval_view_layer_indexed, _1, scene_cow, view_layer_index_)); + /* Parameters evaluation for scene relations mainly. */ + add_operation_node(&scene->id, NodeType::PARAMETERS, OperationCode::SCENE_EVAL); + /* Build all set scenes. */ + if (scene->set != NULL) { + ViewLayer *set_view_layer = BKE_view_layer_default_render(scene->set); + build_view_layer(scene->set, set_view_layer, DEG_ID_LINKED_VIA_SET); + } } } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc index 9316a15c278..6d979724e7e 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc @@ -33,98 +33,97 @@ namespace DEG { static void free_rootpchanmap_valueset(void *val) { - /* Just need to free the set itself - the names stored are all references. */ - GSet *values = (GSet *)val; - BLI_gset_free(values, NULL); + /* Just need to free the set itself - the names stored are all references. */ + GSet *values = (GSet *)val; + BLI_gset_free(values, NULL); } RootPChanMap::RootPChanMap() { - /* Just create empty map. */ - map_ = BLI_ghash_str_new("RootPChanMap"); + /* Just create empty map. */ + map_ = BLI_ghash_str_new("RootPChanMap"); } RootPChanMap::~RootPChanMap() { - /* Free the map, and all the value sets. */ - BLI_ghash_free(map_, NULL, free_rootpchanmap_valueset); + /* Free the map, and all the value sets. */ + BLI_ghash_free(map_, NULL, free_rootpchanmap_valueset); } /* Debug contents of map */ void RootPChanMap::print_debug() { - GHashIterator it1; - GSetIterator it2; - - printf("Root PChan Map:\n"); - GHASH_ITER(it1, map_) { - const char *item = (const char *)BLI_ghashIterator_getKey(&it1); - GSet *values = (GSet *)BLI_ghashIterator_getValue(&it1); - - printf(" %s : { ", item); - GSET_ITER(it2, values) { - const char *val = (const char *)BLI_gsetIterator_getKey(&it2); - printf("%s, ", val); - } - printf("}\n"); - } + GHashIterator it1; + GSetIterator it2; + + printf("Root PChan Map:\n"); + GHASH_ITER (it1, map_) { + const char *item = (const char *)BLI_ghashIterator_getKey(&it1); + GSet *values = (GSet *)BLI_ghashIterator_getValue(&it1); + + printf(" %s : { ", item); + GSET_ITER (it2, values) { + const char *val = (const char *)BLI_gsetIterator_getKey(&it2); + printf("%s, ", val); + } + printf("}\n"); + } } /* Add a mapping. */ void RootPChanMap::add_bone(const char *bone, const char *root) { - if (BLI_ghash_haskey(map_, bone)) { - /* Add new entry, but only add the root if it doesn't already - * exist in there. */ - GSet *values = (GSet *)BLI_ghash_lookup(map_, bone); - BLI_gset_add(values, (void *)root); - } - else { - /* Create new set and mapping. */ - GSet *values = BLI_gset_new(BLI_ghashutil_strhash_p, - BLI_ghashutil_strcmp, - "RootPChanMap Value Set"); - BLI_ghash_insert(map_, (void *)bone, (void *)values); - - /* Add new entry now. */ - BLI_gset_insert(values, (void *)root); - } + if (BLI_ghash_haskey(map_, bone)) { + /* Add new entry, but only add the root if it doesn't already + * exist in there. */ + GSet *values = (GSet *)BLI_ghash_lookup(map_, bone); + BLI_gset_add(values, (void *)root); + } + else { + /* Create new set and mapping. */ + GSet *values = BLI_gset_new( + BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, "RootPChanMap Value Set"); + BLI_ghash_insert(map_, (void *)bone, (void *)values); + + /* Add new entry now. */ + BLI_gset_insert(values, (void *)root); + } } /* Check if there's a common root bone between two bones. */ bool RootPChanMap::has_common_root(const char *bone1, const char *bone2) { - /* Ensure that both are in the map... */ - if (BLI_ghash_haskey(map_, bone1) == false) { - //fprintf("RootPChanMap: bone1 '%s' not found (%s => %s)\n", bone1, bone1, bone2); - //print_debug(); - return false; - } - - if (BLI_ghash_haskey(map_, bone2) == false) { - //fprintf("RootPChanMap: bone2 '%s' not found (%s => %s)\n", bone2, bone1, bone2); - //print_debug(); - return false; - } - - GSet *bone1_roots = (GSet *)BLI_ghash_lookup(map_, (void *)bone1); - GSet *bone2_roots = (GSet *)BLI_ghash_lookup(map_, (void *)bone2); - - GSetIterator it1, it2; - GSET_ITER(it1, bone1_roots) { - GSET_ITER(it2, bone2_roots) { - const char *v1 = (const char *)BLI_gsetIterator_getKey(&it1); - const char *v2 = (const char *)BLI_gsetIterator_getKey(&it2); - - if (strcmp(v1, v2) == 0) { - //fprintf("RootPchanMap: %s in common for %s => %s\n", v1, bone1, bone2); - return true; - } - } - } - - //fprintf("RootPChanMap: No common root found (%s => %s)\n", bone1, bone2); - return false; + /* Ensure that both are in the map... */ + if (BLI_ghash_haskey(map_, bone1) == false) { + //fprintf("RootPChanMap: bone1 '%s' not found (%s => %s)\n", bone1, bone1, bone2); + //print_debug(); + return false; + } + + if (BLI_ghash_haskey(map_, bone2) == false) { + //fprintf("RootPChanMap: bone2 '%s' not found (%s => %s)\n", bone2, bone1, bone2); + //print_debug(); + return false; + } + + GSet *bone1_roots = (GSet *)BLI_ghash_lookup(map_, (void *)bone1); + GSet *bone2_roots = (GSet *)BLI_ghash_lookup(map_, (void *)bone2); + + GSetIterator it1, it2; + GSET_ITER (it1, bone1_roots) { + GSET_ITER (it2, bone2_roots) { + const char *v1 = (const char *)BLI_gsetIterator_getKey(&it1); + const char *v2 = (const char *)BLI_gsetIterator_getKey(&it2); + + if (strcmp(v1, v2) == 0) { + //fprintf("RootPchanMap: %s in common for %s => %s\n", v1, bone1, bone2); + return true; + } + } + } + + //fprintf("RootPChanMap: No common root found (%s => %s)\n", bone1, bone2); + return false; } } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h index 1fb634a8707..0c1d22f9345 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h @@ -28,27 +28,27 @@ struct GHash; namespace DEG { struct RootPChanMap { - /* ctor and dtor - Create and free the internal map respectively. */ - RootPChanMap(); - ~RootPChanMap(); - - /* Debug contents of map. */ - void print_debug(); - - /* Add a mapping. */ - void add_bone(const char *bone, const char *root); - - /* Check if there's a common root bone between two bones. */ - bool has_common_root(const char *bone1, const char *bone2); - -protected: - /* The actual map: - * - Keys are "strings" (const char *) - not dynamically allocated. - * - Values are "sets" (const char *) - not dynamically allocated. - * - * We don't use the C++ maps here, as it's more convenient to use - * Blender's GHash and be able to compare by-value instead of by-ref. */ - struct GHash *map_; + /* ctor and dtor - Create and free the internal map respectively. */ + RootPChanMap(); + ~RootPChanMap(); + + /* Debug contents of map. */ + void print_debug(); + + /* Add a mapping. */ + void add_bone(const char *bone, const char *root); + + /* Check if there's a common root bone between two bones. */ + bool has_common_root(const char *bone1, const char *bone2); + + protected: + /* The actual map: + * - Keys are "strings" (const char *) - not dynamically allocated. + * - Values are "sets" (const char *) - not dynamically allocated. + * + * We don't use the C++ maps here, as it's more convenient to use + * Blender's GHash and be able to compare by-value instead of by-ref. */ + struct GHash *map_; }; } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 489b688eaaa..87a8875f819 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -27,7 +27,7 @@ #include #include -#include /* required for STREQ later on. */ +#include /* required for STREQ later on. */ #include "MEM_guardedalloc.h" @@ -121,61 +121,60 @@ namespace DEG { */ static bool python_driver_depends_on_time(ChannelDriver *driver) { - if (driver->expression[0] == '\0') { - /* Empty expression depends on nothing. */ - return false; - } - if (strchr(driver->expression, '(') != NULL) { - /* Function calls are considered dependent on a time. */ - return true; - } - if (strstr(driver->expression, "frame") != NULL) { - /* Variable `frame` depends on time. */ - /* TODO(sergey): This is a bit weak, but not sure about better way of - * handling this. */ - return true; - } - /* Possible indirect time relation s should be handled via variable - * targets. */ - return false; + if (driver->expression[0] == '\0') { + /* Empty expression depends on nothing. */ + return false; + } + if (strchr(driver->expression, '(') != NULL) { + /* Function calls are considered dependent on a time. */ + return true; + } + if (strstr(driver->expression, "frame") != NULL) { + /* Variable `frame` depends on time. */ + /* TODO(sergey): This is a bit weak, but not sure about better way of + * handling this. */ + return true; + } + /* Possible indirect time relation s should be handled via variable + * targets. */ + return false; } static bool particle_system_depends_on_time(ParticleSystem *psys) { - ParticleSettings *part = psys->part; - /* Non-hair particles we always consider dependent on time. */ - if (part->type != PART_HAIR) { - return true; - } - /* Dynamics always depends on time. */ - if (psys->flag & PSYS_HAIR_DYNAMICS) { - return true; - } - /* TODO(sergey): Check what else makes hair dependent on time. */ - return false; + ParticleSettings *part = psys->part; + /* Non-hair particles we always consider dependent on time. */ + if (part->type != PART_HAIR) { + return true; + } + /* Dynamics always depends on time. */ + if (psys->flag & PSYS_HAIR_DYNAMICS) { + return true; + } + /* TODO(sergey): Check what else makes hair dependent on time. */ + return false; } static bool object_particles_depends_on_time(Object *object) { - if (object->type != OB_MESH) { - return false; - } - LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) { - if (particle_system_depends_on_time(psys)) { - return true; - } - } - return false; + if (object->type != OB_MESH) { + return false; + } + LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) { + if (particle_system_depends_on_time(psys)) { + return true; + } + } + return false; } static bool check_id_has_anim_component(ID *id) { - AnimData *adt = BKE_animdata_from_id(id); - if (adt == NULL) { - return false; - } - return (adt->action != NULL) || - (!BLI_listbase_is_empty(&adt->nla_tracks)); + AnimData *adt = BKE_animdata_from_id(id); + if (adt == NULL) { + return false; + } + return (adt->action != NULL) || (!BLI_listbase_is_empty(&adt->nla_tracks)); } static OperationCode bone_target_opcode(ID *target, @@ -184,267 +183,251 @@ static OperationCode bone_target_opcode(ID *target, const char *component_subdata, RootPChanMap *root_map) { - /* Same armature. */ - if (target == id) { - /* Using "done" here breaks in-chain deps, while using - * "ready" here breaks most production rigs instead. - * So, we do a compromise here, and only do this when an - * IK chain conflict may occur. */ - if (root_map->has_common_root(component_subdata, subtarget)) { - return OperationCode::BONE_READY; - } - } - return OperationCode::BONE_DONE; + /* Same armature. */ + if (target == id) { + /* Using "done" here breaks in-chain deps, while using + * "ready" here breaks most production rigs instead. + * So, we do a compromise here, and only do this when an + * IK chain conflict may occur. */ + if (root_map->has_common_root(component_subdata, subtarget)) { + return OperationCode::BONE_READY; + } + } + return OperationCode::BONE_DONE; } static bool bone_has_segments(Object *object, const char *bone_name) { - /* Proxies don't have BONE_SEGMENTS */ - if (ID_IS_LINKED(object) && object->proxy_from != NULL) { - return false; - } - /* Only B-Bones have segments. */ - bPoseChannel *pchan = BKE_pose_channel_find_name(object->pose, bone_name); - return pchan && pchan->bone && pchan->bone->segments > 1; + /* Proxies don't have BONE_SEGMENTS */ + if (ID_IS_LINKED(object) && object->proxy_from != NULL) { + return false; + } + /* Only B-Bones have segments. */ + bPoseChannel *pchan = BKE_pose_channel_find_name(object->pose, bone_name); + return pchan && pchan->bone && pchan->bone->segments > 1; } /* **** General purpose functions **** */ -DepsgraphRelationBuilder::DepsgraphRelationBuilder(Main *bmain, - Depsgraph *graph) - : DepsgraphBuilder(bmain, graph), - scene_(NULL), - rna_node_query_(graph) +DepsgraphRelationBuilder::DepsgraphRelationBuilder(Main *bmain, Depsgraph *graph) + : DepsgraphBuilder(bmain, graph), scene_(NULL), rna_node_query_(graph) { } -TimeSourceNode *DepsgraphRelationBuilder::get_node( - const TimeSourceKey &key) const +TimeSourceNode *DepsgraphRelationBuilder::get_node(const TimeSourceKey &key) const { - if (key.id) { - /* XXX TODO */ - return NULL; - } - else { - return graph_->time_source; - } + if (key.id) { + /* XXX TODO */ + return NULL; + } + else { + return graph_->time_source; + } } -ComponentNode *DepsgraphRelationBuilder::get_node( - const ComponentKey &key) const +ComponentNode *DepsgraphRelationBuilder::get_node(const ComponentKey &key) const { - IDNode *id_node = graph_->find_id_node(key.id); - if (!id_node) { - fprintf(stderr, "find_node component: Could not find ID %s\n", - (key.id != NULL) ? key.id->name : ""); - return NULL; - } + IDNode *id_node = graph_->find_id_node(key.id); + if (!id_node) { + fprintf(stderr, + "find_node component: Could not find ID %s\n", + (key.id != NULL) ? key.id->name : ""); + return NULL; + } - ComponentNode *node = id_node->find_component(key.type, key.name); - return node; + ComponentNode *node = id_node->find_component(key.type, key.name); + return node; } -OperationNode *DepsgraphRelationBuilder::get_node( - const OperationKey &key) const +OperationNode *DepsgraphRelationBuilder::get_node(const OperationKey &key) const { - OperationNode *op_node = find_node(key); - if (op_node == NULL) { - fprintf(stderr, "find_node_operation: Failed for (%s, '%s')\n", - operationCodeAsString(key.opcode), key.name); - } - return op_node; + OperationNode *op_node = find_node(key); + if (op_node == NULL) { + fprintf(stderr, + "find_node_operation: Failed for (%s, '%s')\n", + operationCodeAsString(key.opcode), + key.name); + } + return op_node; } Node *DepsgraphRelationBuilder::get_node(const RNAPathKey &key) { - return rna_node_query_.find_node(&key.ptr, key.prop, key.source); + return rna_node_query_.find_node(&key.ptr, key.prop, key.source); } -OperationNode *DepsgraphRelationBuilder::find_node( - const OperationKey &key) const +OperationNode *DepsgraphRelationBuilder::find_node(const OperationKey &key) const { - IDNode *id_node = graph_->find_id_node(key.id); - if (!id_node) { - return NULL; - } - ComponentNode *comp_node = id_node->find_component(key.component_type, - key.component_name); - if (!comp_node) { - return NULL; - } - return comp_node->find_operation(key.opcode, key.name, key.name_tag); + IDNode *id_node = graph_->find_id_node(key.id); + if (!id_node) { + return NULL; + } + ComponentNode *comp_node = id_node->find_component(key.component_type, key.component_name); + if (!comp_node) { + return NULL; + } + return comp_node->find_operation(key.opcode, key.name, key.name_tag); } bool DepsgraphRelationBuilder::has_node(const OperationKey &key) const { - return find_node(key) != NULL; + return find_node(key) != NULL; } -void DepsgraphRelationBuilder::add_modifier_to_transform_relation( - const DepsNodeHandle *handle, - const char *description) +void DepsgraphRelationBuilder::add_modifier_to_transform_relation(const DepsNodeHandle *handle, + const char *description) { - IDNode *id_node = handle->node->owner->owner; - ID *id = id_node->id_orig; - ComponentKey geometry_key(id, NodeType::GEOMETRY); - /* Wire up the actual relation. */ - add_depends_on_transform_relation(id, geometry_key, description); + IDNode *id_node = handle->node->owner->owner; + ID *id = id_node->id_orig; + ComponentKey geometry_key(id, NodeType::GEOMETRY); + /* Wire up the actual relation. */ + add_depends_on_transform_relation(id, geometry_key, description); } -void DepsgraphRelationBuilder::add_customdata_mask( - Object *object, - const DEGCustomDataMeshMasks &customdata_masks) +void DepsgraphRelationBuilder::add_customdata_mask(Object *object, + const DEGCustomDataMeshMasks &customdata_masks) { - if (customdata_masks != DEGCustomDataMeshMasks() && object != NULL && object->type == OB_MESH) { - DEG::IDNode *id_node = graph_->find_id_node(&object->id); + if (customdata_masks != DEGCustomDataMeshMasks() && object != NULL && object->type == OB_MESH) { + DEG::IDNode *id_node = graph_->find_id_node(&object->id); - if (id_node == NULL) { - BLI_assert(!"ID should always be valid"); - } - else { - id_node->customdata_masks |= customdata_masks; - } - } + if (id_node == NULL) { + BLI_assert(!"ID should always be valid"); + } + else { + id_node->customdata_masks |= customdata_masks; + } + } } void DepsgraphRelationBuilder::add_special_eval_flag(ID *id, uint32_t flag) { - DEG::IDNode *id_node = graph_->find_id_node(id); - if (id_node == NULL) { - BLI_assert(!"ID should always be valid"); - } - else { - id_node->eval_flags |= flag; - } -} - -Relation *DepsgraphRelationBuilder::add_time_relation( - TimeSourceNode *timesrc, - Node *node_to, - const char *description, - int flags) -{ - if (timesrc && node_to) { - return graph_->add_new_relation( - timesrc, node_to, description, flags); - } - else { - DEG_DEBUG_PRINTF((::Depsgraph *)graph_, - BUILD, "add_time_relation(%p = %s, %p = %s, %s) Failed\n", - timesrc, (timesrc) ? timesrc->identifier().c_str() : "", - node_to, (node_to) ? node_to->identifier().c_str() : "", - description); - } - return NULL; -} - -Relation *DepsgraphRelationBuilder::add_operation_relation( - OperationNode *node_from, - OperationNode *node_to, - const char *description, - int flags) -{ - if (node_from && node_to) { - return graph_->add_new_relation(node_from, - node_to, - description, - flags); - } - else { - DEG_DEBUG_PRINTF((::Depsgraph *)graph_, - BUILD, "add_operation_relation(%p = %s, %p = %s, %s) Failed\n", - node_from, (node_from) ? node_from->identifier().c_str() : "", - node_to, (node_to) ? node_to->identifier().c_str() : "", - description); - } - return NULL; -} - -void DepsgraphRelationBuilder::add_particle_collision_relations( - const OperationKey &key, - Object *object, - Collection *collection, - const char *name) -{ - ListBase *relations = build_collision_relations(graph_, collection, eModifierType_Collision); - - LISTBASE_FOREACH (CollisionRelation *, relation, relations) { - if (relation->ob != object) { - ComponentKey trf_key(&relation->ob->id, NodeType::TRANSFORM); - add_relation(trf_key, key, name); - - ComponentKey coll_key(&relation->ob->id, NodeType::GEOMETRY); - add_relation(coll_key, key, name); - } - } -} - -void DepsgraphRelationBuilder::add_particle_forcefield_relations( - const OperationKey &key, - Object *object, - ParticleSystem *psys, - EffectorWeights *eff, - bool add_absorption, - const char *name) -{ - ListBase *relations = build_effector_relations(graph_, eff->group); - - LISTBASE_FOREACH (EffectorRelation *, relation, relations) { - if (relation->ob != object) { - /* Relation to forcefield object, optionally including geometry. */ - ComponentKey eff_key(&relation->ob->id, NodeType::TRANSFORM); - add_relation(eff_key, key, name); - - if (ELEM(relation->pd->shape, PFIELD_SHAPE_SURFACE, PFIELD_SHAPE_POINTS) || - relation->pd->forcefield == PFIELD_GUIDE) - { - ComponentKey mod_key(&relation->ob->id, NodeType::GEOMETRY); - add_relation(mod_key, key, name); - } - - /* Smoke flow relations. */ - if (relation->pd->forcefield == PFIELD_SMOKEFLOW && relation->pd->f_source) { - ComponentKey trf_key(&relation->pd->f_source->id, - NodeType::TRANSFORM); - add_relation(trf_key, key, "Smoke Force Domain"); - ComponentKey eff_key(&relation->pd->f_source->id, - NodeType::GEOMETRY); - add_relation(eff_key, key, "Smoke Force Domain"); - } - - /* Absorption forces need collision relation. */ - if (add_absorption && (relation->pd->flag & PFIELD_VISIBILITY)) { - add_particle_collision_relations(key, - object, - NULL, - "Force Absorption"); - } - } - - if (relation->psys) { - if (relation->ob != object) { - ComponentKey eff_key(&relation->ob->id, - NodeType::PARTICLE_SYSTEM); - add_relation(eff_key, key, name); - /* TODO: remove this when/if EVAL_PARTICLES is sufficient - * for up to date particles. */ - ComponentKey mod_key(&relation->ob->id, NodeType::GEOMETRY); - add_relation(mod_key, key, name); - } - else if (relation->psys != psys) { - OperationKey eff_key(&relation->ob->id, - NodeType::PARTICLE_SYSTEM, - OperationCode::PARTICLE_SYSTEM_EVAL, - relation->psys->name); - add_relation(eff_key, key, name); - } - } - } + DEG::IDNode *id_node = graph_->find_id_node(id); + if (id_node == NULL) { + BLI_assert(!"ID should always be valid"); + } + else { + id_node->eval_flags |= flag; + } +} + +Relation *DepsgraphRelationBuilder::add_time_relation(TimeSourceNode *timesrc, + Node *node_to, + const char *description, + int flags) +{ + if (timesrc && node_to) { + return graph_->add_new_relation(timesrc, node_to, description, flags); + } + else { + DEG_DEBUG_PRINTF((::Depsgraph *)graph_, + BUILD, + "add_time_relation(%p = %s, %p = %s, %s) Failed\n", + timesrc, + (timesrc) ? timesrc->identifier().c_str() : "", + node_to, + (node_to) ? node_to->identifier().c_str() : "", + description); + } + return NULL; +} + +Relation *DepsgraphRelationBuilder::add_operation_relation(OperationNode *node_from, + OperationNode *node_to, + const char *description, + int flags) +{ + if (node_from && node_to) { + return graph_->add_new_relation(node_from, node_to, description, flags); + } + else { + DEG_DEBUG_PRINTF((::Depsgraph *)graph_, + BUILD, + "add_operation_relation(%p = %s, %p = %s, %s) Failed\n", + node_from, + (node_from) ? node_from->identifier().c_str() : "", + node_to, + (node_to) ? node_to->identifier().c_str() : "", + description); + } + return NULL; +} + +void DepsgraphRelationBuilder::add_particle_collision_relations(const OperationKey &key, + Object *object, + Collection *collection, + const char *name) +{ + ListBase *relations = build_collision_relations(graph_, collection, eModifierType_Collision); + + LISTBASE_FOREACH (CollisionRelation *, relation, relations) { + if (relation->ob != object) { + ComponentKey trf_key(&relation->ob->id, NodeType::TRANSFORM); + add_relation(trf_key, key, name); + + ComponentKey coll_key(&relation->ob->id, NodeType::GEOMETRY); + add_relation(coll_key, key, name); + } + } +} + +void DepsgraphRelationBuilder::add_particle_forcefield_relations(const OperationKey &key, + Object *object, + ParticleSystem *psys, + EffectorWeights *eff, + bool add_absorption, + const char *name) +{ + ListBase *relations = build_effector_relations(graph_, eff->group); + + LISTBASE_FOREACH (EffectorRelation *, relation, relations) { + if (relation->ob != object) { + /* Relation to forcefield object, optionally including geometry. */ + ComponentKey eff_key(&relation->ob->id, NodeType::TRANSFORM); + add_relation(eff_key, key, name); + + if (ELEM(relation->pd->shape, PFIELD_SHAPE_SURFACE, PFIELD_SHAPE_POINTS) || + relation->pd->forcefield == PFIELD_GUIDE) { + ComponentKey mod_key(&relation->ob->id, NodeType::GEOMETRY); + add_relation(mod_key, key, name); + } + + /* Smoke flow relations. */ + if (relation->pd->forcefield == PFIELD_SMOKEFLOW && relation->pd->f_source) { + ComponentKey trf_key(&relation->pd->f_source->id, NodeType::TRANSFORM); + add_relation(trf_key, key, "Smoke Force Domain"); + ComponentKey eff_key(&relation->pd->f_source->id, NodeType::GEOMETRY); + add_relation(eff_key, key, "Smoke Force Domain"); + } + + /* Absorption forces need collision relation. */ + if (add_absorption && (relation->pd->flag & PFIELD_VISIBILITY)) { + add_particle_collision_relations(key, object, NULL, "Force Absorption"); + } + } + + if (relation->psys) { + if (relation->ob != object) { + ComponentKey eff_key(&relation->ob->id, NodeType::PARTICLE_SYSTEM); + add_relation(eff_key, key, name); + /* TODO: remove this when/if EVAL_PARTICLES is sufficient + * for up to date particles. */ + ComponentKey mod_key(&relation->ob->id, NodeType::GEOMETRY); + add_relation(mod_key, key, name); + } + else if (relation->psys != psys) { + OperationKey eff_key(&relation->ob->id, + NodeType::PARTICLE_SYSTEM, + OperationCode::PARTICLE_SYSTEM_EVAL, + relation->psys->name); + add_relation(eff_key, key, name); + } + } + } } Depsgraph *DepsgraphRelationBuilder::getGraph() { - return graph_; + return graph_; } /* **** Functions to build relations between entities **** */ @@ -455,549 +438,491 @@ void DepsgraphRelationBuilder::begin_build() void DepsgraphRelationBuilder::build_id(ID *id) { - if (id == NULL) { - return; - } - switch (GS(id->name)) { - case ID_AC: - build_action((bAction *)id); - break; - case ID_AR: - build_armature((bArmature *)id); - break; - case ID_CA: - build_camera((Camera *)id); - break; - case ID_GR: - build_collection(NULL, NULL, (Collection *)id); - break; - case ID_OB: - build_object(NULL, (Object *)id); - break; - case ID_KE: - build_shapekeys((Key *)id); - break; - case ID_LA: - build_light((Light *)id); - break; - case ID_LP: - build_lightprobe((LightProbe *)id); - break; - case ID_NT: - build_nodetree((bNodeTree *)id); - break; - case ID_MA: - build_material((Material *)id); - break; - case ID_TE: - build_texture((Tex *)id); - break; - case ID_IM: - build_image((Image *)id); - break; - case ID_WO: - build_world((World *)id); - break; - case ID_MSK: - build_mask((Mask *)id); - break; - case ID_MC: - build_movieclip((MovieClip *)id); - break; - case ID_ME: - case ID_CU: - case ID_MB: - case ID_LT: - build_object_data_geometry_datablock(id); - break; - case ID_SPK: - build_speaker((Speaker *)id); - break; - case ID_TXT: - /* Not a part of dependency graph. */ - break; - case ID_CF: - build_cachefile((CacheFile *)id); - break; - default: - fprintf(stderr, "Unhandled ID %s\n", id->name); - BLI_assert(!"Should never happen"); - break; - } -} - -void DepsgraphRelationBuilder::build_collection( - LayerCollection *from_layer_collection, - Object *object, - Collection *collection) -{ - if (from_layer_collection != NULL) { - /* If we came from layer collection we don't go deeper, view layer - * builder takes care of going deeper. - * - * NOTE: Do early output before tagging build as done, so possbile - * subsequent builds from outside of the layer collection properly - * recurses into all the nested objects and collections. */ - return; - } - const bool group_done = built_map_.checkIsBuiltAndTag(collection); - OperationKey object_transform_final_key(object != NULL ? &object->id : NULL, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_FINAL); - ComponentKey duplicator_key(object != NULL ? &object->id : NULL, - NodeType::DUPLI); - if (!group_done) { - LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { - build_object(NULL, cob->ob); - } - LISTBASE_FOREACH (CollectionChild *, child, &collection->children) { - build_collection(NULL, NULL, child->collection); - } - } - if (object != NULL) { - FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(collection, ob, graph_->mode) - { - ComponentKey dupli_transform_key(&ob->id, NodeType::TRANSFORM); - add_relation(dupli_transform_key, - object_transform_final_key, - "Dupligroup"); - /* Hook to special component, to ensure proper visibility/evaluation - * optimizations. */ - add_relation(dupli_transform_key, duplicator_key, "Dupligroup"); - const NodeType dupli_geometry_component_type = - geometry_tag_to_component(&ob->id); - if (dupli_geometry_component_type != NodeType::UNDEFINED) { - ComponentKey dupli_geometry_component_key( - &ob->id, dupli_geometry_component_type); - add_relation(dupli_geometry_component_key, - duplicator_key, - "Dupligroup"); - } - } - FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; - } + if (id == NULL) { + return; + } + switch (GS(id->name)) { + case ID_AC: + build_action((bAction *)id); + break; + case ID_AR: + build_armature((bArmature *)id); + break; + case ID_CA: + build_camera((Camera *)id); + break; + case ID_GR: + build_collection(NULL, NULL, (Collection *)id); + break; + case ID_OB: + build_object(NULL, (Object *)id); + break; + case ID_KE: + build_shapekeys((Key *)id); + break; + case ID_LA: + build_light((Light *)id); + break; + case ID_LP: + build_lightprobe((LightProbe *)id); + break; + case ID_NT: + build_nodetree((bNodeTree *)id); + break; + case ID_MA: + build_material((Material *)id); + break; + case ID_TE: + build_texture((Tex *)id); + break; + case ID_IM: + build_image((Image *)id); + break; + case ID_WO: + build_world((World *)id); + break; + case ID_MSK: + build_mask((Mask *)id); + break; + case ID_MC: + build_movieclip((MovieClip *)id); + break; + case ID_ME: + case ID_CU: + case ID_MB: + case ID_LT: + build_object_data_geometry_datablock(id); + break; + case ID_SPK: + build_speaker((Speaker *)id); + break; + case ID_TXT: + /* Not a part of dependency graph. */ + break; + case ID_CF: + build_cachefile((CacheFile *)id); + break; + default: + fprintf(stderr, "Unhandled ID %s\n", id->name); + BLI_assert(!"Should never happen"); + break; + } +} + +void DepsgraphRelationBuilder::build_collection(LayerCollection *from_layer_collection, + Object *object, + Collection *collection) +{ + if (from_layer_collection != NULL) { + /* If we came from layer collection we don't go deeper, view layer + * builder takes care of going deeper. + * + * NOTE: Do early output before tagging build as done, so possbile + * subsequent builds from outside of the layer collection properly + * recurses into all the nested objects and collections. */ + return; + } + const bool group_done = built_map_.checkIsBuiltAndTag(collection); + OperationKey object_transform_final_key( + object != NULL ? &object->id : NULL, NodeType::TRANSFORM, OperationCode::TRANSFORM_FINAL); + ComponentKey duplicator_key(object != NULL ? &object->id : NULL, NodeType::DUPLI); + if (!group_done) { + LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { + build_object(NULL, cob->ob); + } + LISTBASE_FOREACH (CollectionChild *, child, &collection->children) { + build_collection(NULL, NULL, child->collection); + } + } + if (object != NULL) { + FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (collection, ob, graph_->mode) { + ComponentKey dupli_transform_key(&ob->id, NodeType::TRANSFORM); + add_relation(dupli_transform_key, object_transform_final_key, "Dupligroup"); + /* Hook to special component, to ensure proper visibility/evaluation + * optimizations. */ + add_relation(dupli_transform_key, duplicator_key, "Dupligroup"); + const NodeType dupli_geometry_component_type = geometry_tag_to_component(&ob->id); + if (dupli_geometry_component_type != NodeType::UNDEFINED) { + ComponentKey dupli_geometry_component_key(&ob->id, dupli_geometry_component_type); + add_relation(dupli_geometry_component_key, duplicator_key, "Dupligroup"); + } + } + FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; + } } void DepsgraphRelationBuilder::build_object(Base *base, Object *object) { - if (built_map_.checkIsBuiltAndTag(object)) { - if (base != NULL) { - build_object_flags(base, object); - } - return; - } - /* Object Transforms */ - OperationCode base_op = (object->parent) ? OperationCode::TRANSFORM_PARENT - : OperationCode::TRANSFORM_LOCAL; - OperationKey base_op_key(&object->id, NodeType::TRANSFORM, base_op); - OperationKey init_transform_key( - &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_INIT); - OperationKey local_transform_key( - &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_LOCAL); - OperationKey parent_transform_key( - &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_PARENT); - OperationKey final_transform_key( - &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_FINAL); - OperationKey ob_eval_key( - &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL); - add_relation(init_transform_key, local_transform_key, "Transform Init"); - /* Various flags, flushing from bases/collections. */ - build_object_flags(base, object); - /* Parenting. */ - if (object->parent != NULL) { - /* Make sure parent object's relations are built. */ - build_object(NULL, object->parent); - /* Parent relationship. */ - build_object_parent(object); - /* Local -> parent. */ - add_relation(local_transform_key, - parent_transform_key, - "ObLocal -> ObParent"); - } - /* Modifiers. */ - if (object->modifiers.first != NULL) { - BuilderWalkUserData data; - data.builder = this; - modifiers_foreachIDLink(object, modifier_walk, &data); - } - /* Grease Pencil Modifiers. */ - if (object->greasepencil_modifiers.first != NULL) { - BuilderWalkUserData data; - data.builder = this; - BKE_gpencil_modifiers_foreachIDLink(object, modifier_walk, &data); - } - /* Shader FX. */ - if (object->shader_fx.first != NULL) { - BuilderWalkUserData data; - data.builder = this; - BKE_shaderfx_foreachIDLink(object, modifier_walk, &data); - } - /* Constraints. */ - if (object->constraints.first != NULL) { - BuilderWalkUserData data; - data.builder = this; - BKE_constraints_id_loop(&object->constraints, constraint_walk, &data); - } - /* Object constraints. */ - OperationKey object_transform_simulation_init_key( - &object->id, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_SIMULATION_INIT); - if (object->constraints.first != NULL) { - OperationKey constraint_key(&object->id, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_CONSTRAINTS); - /* Constraint relations. */ - build_constraints(&object->id, - NodeType::TRANSFORM, - "", - &object->constraints, - NULL); - /* operation order */ - add_relation(base_op_key, constraint_key, "ObBase-> Constraint Stack"); - add_relation(constraint_key, final_transform_key, "ObConstraints -> Done"); - add_relation(constraint_key, ob_eval_key, "Constraint -> Transform Eval"); - add_relation(ob_eval_key, - object_transform_simulation_init_key, - "Transform Eval -> Simulation Init"); - add_relation(object_transform_simulation_init_key, - final_transform_key, - "Simulation -> Final Transform"); - } - else { - add_relation(base_op_key, ob_eval_key, "Eval"); - add_relation(ob_eval_key, - object_transform_simulation_init_key, - "Transform Eval -> Simulation Init"); - add_relation(object_transform_simulation_init_key, - final_transform_key, - "Simulation -> Final Transform"); - } - /* Animation data */ - build_animdata(&object->id); - /* Object data. */ - build_object_data(object); - /* Particle systems. */ - if (object->particlesystem.first != NULL) { - build_particle_systems(object); - } - /* Proxy object to copy from. */ - if (object->proxy_from != NULL) { - build_object(NULL, object->proxy_from); - ComponentKey ob_transform_key( - &object->proxy_from->id, NodeType::TRANSFORM); - ComponentKey proxy_transform_key(&object->id, NodeType::TRANSFORM); - add_relation(ob_transform_key, proxy_transform_key, "Proxy Transform"); - } - if (object->proxy_group != NULL) { - build_object(NULL, object->proxy_group); - OperationKey proxy_group_eval_key(&object->proxy_group->id, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_EVAL); - add_relation(proxy_group_eval_key, - final_transform_key, - "Proxy Group Transform"); - } - /* Object dupligroup. */ - if (object->instance_collection != NULL) { - build_collection(NULL, object, object->instance_collection); - } - /* Point caches. */ - build_object_pointcache(object); - /* Syncronization back to original object. */ - OperationKey synchronize_key(&object->id, - NodeType::SYNCHRONIZATION, - OperationCode::SYNCHRONIZE_TO_ORIGINAL); - add_relation( - final_transform_key, synchronize_key, "Synchronize to Original"); - /* Parameters. */ - build_parameters(&object->id); + if (built_map_.checkIsBuiltAndTag(object)) { + if (base != NULL) { + build_object_flags(base, object); + } + return; + } + /* Object Transforms */ + OperationCode base_op = (object->parent) ? OperationCode::TRANSFORM_PARENT : + OperationCode::TRANSFORM_LOCAL; + OperationKey base_op_key(&object->id, NodeType::TRANSFORM, base_op); + OperationKey init_transform_key(&object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_INIT); + OperationKey local_transform_key( + &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_LOCAL); + OperationKey parent_transform_key( + &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_PARENT); + OperationKey final_transform_key( + &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_FINAL); + OperationKey ob_eval_key(&object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL); + add_relation(init_transform_key, local_transform_key, "Transform Init"); + /* Various flags, flushing from bases/collections. */ + build_object_flags(base, object); + /* Parenting. */ + if (object->parent != NULL) { + /* Make sure parent object's relations are built. */ + build_object(NULL, object->parent); + /* Parent relationship. */ + build_object_parent(object); + /* Local -> parent. */ + add_relation(local_transform_key, parent_transform_key, "ObLocal -> ObParent"); + } + /* Modifiers. */ + if (object->modifiers.first != NULL) { + BuilderWalkUserData data; + data.builder = this; + modifiers_foreachIDLink(object, modifier_walk, &data); + } + /* Grease Pencil Modifiers. */ + if (object->greasepencil_modifiers.first != NULL) { + BuilderWalkUserData data; + data.builder = this; + BKE_gpencil_modifiers_foreachIDLink(object, modifier_walk, &data); + } + /* Shader FX. */ + if (object->shader_fx.first != NULL) { + BuilderWalkUserData data; + data.builder = this; + BKE_shaderfx_foreachIDLink(object, modifier_walk, &data); + } + /* Constraints. */ + if (object->constraints.first != NULL) { + BuilderWalkUserData data; + data.builder = this; + BKE_constraints_id_loop(&object->constraints, constraint_walk, &data); + } + /* Object constraints. */ + OperationKey object_transform_simulation_init_key( + &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_SIMULATION_INIT); + if (object->constraints.first != NULL) { + OperationKey constraint_key( + &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_CONSTRAINTS); + /* Constraint relations. */ + build_constraints(&object->id, NodeType::TRANSFORM, "", &object->constraints, NULL); + /* operation order */ + add_relation(base_op_key, constraint_key, "ObBase-> Constraint Stack"); + add_relation(constraint_key, final_transform_key, "ObConstraints -> Done"); + add_relation(constraint_key, ob_eval_key, "Constraint -> Transform Eval"); + add_relation( + ob_eval_key, object_transform_simulation_init_key, "Transform Eval -> Simulation Init"); + add_relation(object_transform_simulation_init_key, + final_transform_key, + "Simulation -> Final Transform"); + } + else { + add_relation(base_op_key, ob_eval_key, "Eval"); + add_relation( + ob_eval_key, object_transform_simulation_init_key, "Transform Eval -> Simulation Init"); + add_relation(object_transform_simulation_init_key, + final_transform_key, + "Simulation -> Final Transform"); + } + /* Animation data */ + build_animdata(&object->id); + /* Object data. */ + build_object_data(object); + /* Particle systems. */ + if (object->particlesystem.first != NULL) { + build_particle_systems(object); + } + /* Proxy object to copy from. */ + if (object->proxy_from != NULL) { + build_object(NULL, object->proxy_from); + ComponentKey ob_transform_key(&object->proxy_from->id, NodeType::TRANSFORM); + ComponentKey proxy_transform_key(&object->id, NodeType::TRANSFORM); + add_relation(ob_transform_key, proxy_transform_key, "Proxy Transform"); + } + if (object->proxy_group != NULL) { + build_object(NULL, object->proxy_group); + OperationKey proxy_group_eval_key( + &object->proxy_group->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL); + add_relation(proxy_group_eval_key, final_transform_key, "Proxy Group Transform"); + } + /* Object dupligroup. */ + if (object->instance_collection != NULL) { + build_collection(NULL, object, object->instance_collection); + } + /* Point caches. */ + build_object_pointcache(object); + /* Syncronization back to original object. */ + OperationKey synchronize_key( + &object->id, NodeType::SYNCHRONIZATION, OperationCode::SYNCHRONIZE_TO_ORIGINAL); + add_relation(final_transform_key, synchronize_key, "Synchronize to Original"); + /* Parameters. */ + build_parameters(&object->id); } void DepsgraphRelationBuilder::build_object_flags(Base *base, Object *object) { - if (base == NULL) { - return; - } - OperationKey view_layer_done_key(&scene_->id, - NodeType::LAYER_COLLECTIONS, - OperationCode::VIEW_LAYER_EVAL); - OperationKey object_flags_key(&object->id, - NodeType::OBJECT_FROM_LAYER, - OperationCode::OBJECT_BASE_FLAGS); - add_relation(view_layer_done_key, object_flags_key, "Base flags flush"); - /* Syncronization back to original object. */ - OperationKey synchronize_key(&object->id, - NodeType::SYNCHRONIZATION, - OperationCode::SYNCHRONIZE_TO_ORIGINAL); - add_relation( - object_flags_key, synchronize_key, "Synchronize to Original"); + if (base == NULL) { + return; + } + OperationKey view_layer_done_key( + &scene_->id, NodeType::LAYER_COLLECTIONS, OperationCode::VIEW_LAYER_EVAL); + OperationKey object_flags_key( + &object->id, NodeType::OBJECT_FROM_LAYER, OperationCode::OBJECT_BASE_FLAGS); + add_relation(view_layer_done_key, object_flags_key, "Base flags flush"); + /* Syncronization back to original object. */ + OperationKey synchronize_key( + &object->id, NodeType::SYNCHRONIZATION, OperationCode::SYNCHRONIZE_TO_ORIGINAL); + add_relation(object_flags_key, synchronize_key, "Synchronize to Original"); } void DepsgraphRelationBuilder::build_object_data(Object *object) { - if (object->data == NULL) { - return; - } - ID *obdata_id = (ID *)object->data; - /* Object data animation. */ - if (!built_map_.checkIsBuilt(obdata_id)) { - build_animdata(obdata_id); - } - /* type-specific data. */ - switch (object->type) { - case OB_MESH: - case OB_CURVE: - case OB_FONT: - case OB_SURF: - case OB_MBALL: - case OB_LATTICE: - case OB_GPENCIL: - { - build_object_data_geometry(object); - /* TODO(sergey): Only for until we support granular - * update of curves. */ - if (object->type == OB_FONT) { - Curve *curve = (Curve *)object->data; - if (curve->textoncurve) { - add_special_eval_flag(&curve->textoncurve->id, DAG_EVAL_NEED_CURVE_PATH); - } - } - break; - } - case OB_ARMATURE: - if (ID_IS_LINKED(object) && object->proxy_from != NULL) { - build_proxy_rig(object); - } - else { - build_rig(object); - } - break; - case OB_LAMP: - build_object_data_light(object); - break; - case OB_CAMERA: - build_object_data_camera(object); - break; - case OB_LIGHTPROBE: - build_object_data_lightprobe(object); - break; - case OB_SPEAKER: - build_object_data_speaker(object); - break; - } - Key *key = BKE_key_from_object(object); - if (key != NULL) { - ComponentKey geometry_key((ID *)object->data, NodeType::GEOMETRY); - ComponentKey key_key(&key->id, NodeType::GEOMETRY); - add_relation(key_key, geometry_key, "Shapekeys"); - build_nested_shapekey(&object->id, key); - } + if (object->data == NULL) { + return; + } + ID *obdata_id = (ID *)object->data; + /* Object data animation. */ + if (!built_map_.checkIsBuilt(obdata_id)) { + build_animdata(obdata_id); + } + /* type-specific data. */ + switch (object->type) { + case OB_MESH: + case OB_CURVE: + case OB_FONT: + case OB_SURF: + case OB_MBALL: + case OB_LATTICE: + case OB_GPENCIL: { + build_object_data_geometry(object); + /* TODO(sergey): Only for until we support granular + * update of curves. */ + if (object->type == OB_FONT) { + Curve *curve = (Curve *)object->data; + if (curve->textoncurve) { + add_special_eval_flag(&curve->textoncurve->id, DAG_EVAL_NEED_CURVE_PATH); + } + } + break; + } + case OB_ARMATURE: + if (ID_IS_LINKED(object) && object->proxy_from != NULL) { + build_proxy_rig(object); + } + else { + build_rig(object); + } + break; + case OB_LAMP: + build_object_data_light(object); + break; + case OB_CAMERA: + build_object_data_camera(object); + break; + case OB_LIGHTPROBE: + build_object_data_lightprobe(object); + break; + case OB_SPEAKER: + build_object_data_speaker(object); + break; + } + Key *key = BKE_key_from_object(object); + if (key != NULL) { + ComponentKey geometry_key((ID *)object->data, NodeType::GEOMETRY); + ComponentKey key_key(&key->id, NodeType::GEOMETRY); + add_relation(key_key, geometry_key, "Shapekeys"); + build_nested_shapekey(&object->id, key); + } } void DepsgraphRelationBuilder::build_object_data_camera(Object *object) { - Camera *camera = (Camera *)object->data; - build_camera(camera); - ComponentKey object_parameters_key(&object->id, NodeType::PARAMETERS); - ComponentKey camera_parameters_key(&camera->id, NodeType::PARAMETERS); - add_relation(camera_parameters_key, object_parameters_key, "Camera -> Object"); + Camera *camera = (Camera *)object->data; + build_camera(camera); + ComponentKey object_parameters_key(&object->id, NodeType::PARAMETERS); + ComponentKey camera_parameters_key(&camera->id, NodeType::PARAMETERS); + add_relation(camera_parameters_key, object_parameters_key, "Camera -> Object"); } void DepsgraphRelationBuilder::build_object_data_light(Object *object) { - Light *lamp = (Light *)object->data; - build_light(lamp); - ComponentKey lamp_parameters_key(&lamp->id, NodeType::PARAMETERS); - ComponentKey object_parameters_key(&object->id, NodeType::PARAMETERS); - add_relation(lamp_parameters_key, object_parameters_key, "Light -> Object"); + Light *lamp = (Light *)object->data; + build_light(lamp); + ComponentKey lamp_parameters_key(&lamp->id, NodeType::PARAMETERS); + ComponentKey object_parameters_key(&object->id, NodeType::PARAMETERS); + add_relation(lamp_parameters_key, object_parameters_key, "Light -> Object"); } void DepsgraphRelationBuilder::build_object_data_lightprobe(Object *object) { - LightProbe *probe = (LightProbe *)object->data; - build_lightprobe(probe); - OperationKey probe_key(&probe->id, - NodeType::PARAMETERS, - OperationCode::LIGHT_PROBE_EVAL); - OperationKey object_key(&object->id, - NodeType::PARAMETERS, - OperationCode::LIGHT_PROBE_EVAL); - add_relation(probe_key, object_key, "LightProbe Update"); + LightProbe *probe = (LightProbe *)object->data; + build_lightprobe(probe); + OperationKey probe_key(&probe->id, NodeType::PARAMETERS, OperationCode::LIGHT_PROBE_EVAL); + OperationKey object_key(&object->id, NodeType::PARAMETERS, OperationCode::LIGHT_PROBE_EVAL); + add_relation(probe_key, object_key, "LightProbe Update"); } void DepsgraphRelationBuilder::build_object_data_speaker(Object *object) { - Speaker *speaker = (Speaker *)object->data; - build_speaker(speaker); - OperationKey probe_key(&speaker->id, - NodeType::PARAMETERS, - OperationCode::SPEAKER_EVAL); - OperationKey object_key(&object->id, - NodeType::PARAMETERS, - OperationCode::SPEAKER_EVAL); - add_relation(probe_key, object_key, "Speaker Update"); + Speaker *speaker = (Speaker *)object->data; + build_speaker(speaker); + OperationKey probe_key(&speaker->id, NodeType::PARAMETERS, OperationCode::SPEAKER_EVAL); + OperationKey object_key(&object->id, NodeType::PARAMETERS, OperationCode::SPEAKER_EVAL); + add_relation(probe_key, object_key, "Speaker Update"); } void DepsgraphRelationBuilder::build_object_parent(Object *object) { - Object *parent = object->parent; - ID *parent_id = &object->parent->id; - ComponentKey ob_key(&object->id, NodeType::TRANSFORM); - /* Type-specific links/ */ - switch (object->partype) { - /* Armature Deform (Virtual Modifier) */ - case PARSKEL: - { - ComponentKey parent_key(parent_id, NodeType::TRANSFORM); - add_relation(parent_key, ob_key, "Armature Deform Parent"); - break; - } - - /* Vertex Parent */ - case PARVERT1: - case PARVERT3: - { - ComponentKey parent_key(parent_id, NodeType::GEOMETRY); - add_relation(parent_key, ob_key, "Vertex Parent"); - /* Original index is used for optimizations of lookups for subdiv - * only meshes. - * TODO(sergey): This optimization got lost at 2.8, so either verify - * we can get rid of this mask here, or bring the optimization - * back. */ - add_customdata_mask(object->parent, - DEGCustomDataMeshMasks::MaskVert(CD_MASK_ORIGINDEX) | - DEGCustomDataMeshMasks::MaskEdge(CD_MASK_ORIGINDEX) | - DEGCustomDataMeshMasks::MaskFace(CD_MASK_ORIGINDEX) | - DEGCustomDataMeshMasks::MaskPoly(CD_MASK_ORIGINDEX)); - ComponentKey transform_key(parent_id, NodeType::TRANSFORM); - add_relation(transform_key, ob_key, "Vertex Parent TFM"); - break; - } - - /* Bone Parent */ - case PARBONE: - { - ComponentKey parent_bone_key( - parent_id, NodeType::BONE, object->parsubstr); - OperationKey parent_transform_key(parent_id, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_FINAL); - add_relation(parent_bone_key, ob_key, "Bone Parent"); - add_relation(parent_transform_key, ob_key, "Armature Parent"); - break; - } - - default: - { - if (object->parent->type == OB_LATTICE) { - /* Lattice Deform Parent - Virtual Modifier. */ - ComponentKey parent_key(parent_id, NodeType::TRANSFORM); - ComponentKey geom_key(parent_id, NodeType::GEOMETRY); - add_relation(parent_key, ob_key, "Lattice Deform Parent"); - add_relation(geom_key, ob_key, "Lattice Deform Parent Geom"); - } - else if (object->parent->type == OB_CURVE) { - Curve *cu = (Curve *)object->parent->data; - - if (cu->flag & CU_PATH) { - /* Follow Path. */ - ComponentKey parent_key(parent_id, NodeType::GEOMETRY); - add_relation(parent_key, ob_key, "Curve Follow Parent"); - ComponentKey transform_key(parent_id, NodeType::TRANSFORM); - add_relation(transform_key, ob_key, "Curve Follow TFM"); - } - else { - /* Standard Parent. */ - ComponentKey parent_key(parent_id, NodeType::TRANSFORM); - add_relation(parent_key, ob_key, "Curve Parent"); - } - } - else { - /* Standard Parent. */ - ComponentKey parent_key(parent_id, NodeType::TRANSFORM); - add_relation(parent_key, ob_key, "Parent"); - } - break; - } - } - /* Metaballs are the odd balls here (no pun intended): they will request - * instance-list (formerly known as dupli-list) during evaluation. This is - * their way of interacting with all instanced surfaces, making a nice - * effect when is used form particle system. */ - if (object->type == OB_MBALL && parent->transflag & OB_DUPLI) { - ComponentKey parent_geometry_key(parent_id, NodeType::GEOMETRY); - /* NOTE: Metaballs are evaluating geometry only after their transform, - * so we onl;y hook up to transform channel here. */ - add_relation(parent_geometry_key, ob_key, "Parent"); - } - - /* Dupliverts uses original vertex index. */ - if (parent->transflag & OB_DUPLIVERTS) { - add_customdata_mask(parent, DEGCustomDataMeshMasks::MaskVert(CD_MASK_ORIGINDEX)); - } + Object *parent = object->parent; + ID *parent_id = &object->parent->id; + ComponentKey ob_key(&object->id, NodeType::TRANSFORM); + /* Type-specific links/ */ + switch (object->partype) { + /* Armature Deform (Virtual Modifier) */ + case PARSKEL: { + ComponentKey parent_key(parent_id, NodeType::TRANSFORM); + add_relation(parent_key, ob_key, "Armature Deform Parent"); + break; + } + + /* Vertex Parent */ + case PARVERT1: + case PARVERT3: { + ComponentKey parent_key(parent_id, NodeType::GEOMETRY); + add_relation(parent_key, ob_key, "Vertex Parent"); + /* Original index is used for optimizations of lookups for subdiv + * only meshes. + * TODO(sergey): This optimization got lost at 2.8, so either verify + * we can get rid of this mask here, or bring the optimization + * back. */ + add_customdata_mask(object->parent, + DEGCustomDataMeshMasks::MaskVert(CD_MASK_ORIGINDEX) | + DEGCustomDataMeshMasks::MaskEdge(CD_MASK_ORIGINDEX) | + DEGCustomDataMeshMasks::MaskFace(CD_MASK_ORIGINDEX) | + DEGCustomDataMeshMasks::MaskPoly(CD_MASK_ORIGINDEX)); + ComponentKey transform_key(parent_id, NodeType::TRANSFORM); + add_relation(transform_key, ob_key, "Vertex Parent TFM"); + break; + } + + /* Bone Parent */ + case PARBONE: { + ComponentKey parent_bone_key(parent_id, NodeType::BONE, object->parsubstr); + OperationKey parent_transform_key( + parent_id, NodeType::TRANSFORM, OperationCode::TRANSFORM_FINAL); + add_relation(parent_bone_key, ob_key, "Bone Parent"); + add_relation(parent_transform_key, ob_key, "Armature Parent"); + break; + } + + default: { + if (object->parent->type == OB_LATTICE) { + /* Lattice Deform Parent - Virtual Modifier. */ + ComponentKey parent_key(parent_id, NodeType::TRANSFORM); + ComponentKey geom_key(parent_id, NodeType::GEOMETRY); + add_relation(parent_key, ob_key, "Lattice Deform Parent"); + add_relation(geom_key, ob_key, "Lattice Deform Parent Geom"); + } + else if (object->parent->type == OB_CURVE) { + Curve *cu = (Curve *)object->parent->data; + + if (cu->flag & CU_PATH) { + /* Follow Path. */ + ComponentKey parent_key(parent_id, NodeType::GEOMETRY); + add_relation(parent_key, ob_key, "Curve Follow Parent"); + ComponentKey transform_key(parent_id, NodeType::TRANSFORM); + add_relation(transform_key, ob_key, "Curve Follow TFM"); + } + else { + /* Standard Parent. */ + ComponentKey parent_key(parent_id, NodeType::TRANSFORM); + add_relation(parent_key, ob_key, "Curve Parent"); + } + } + else { + /* Standard Parent. */ + ComponentKey parent_key(parent_id, NodeType::TRANSFORM); + add_relation(parent_key, ob_key, "Parent"); + } + break; + } + } + /* Metaballs are the odd balls here (no pun intended): they will request + * instance-list (formerly known as dupli-list) during evaluation. This is + * their way of interacting with all instanced surfaces, making a nice + * effect when is used form particle system. */ + if (object->type == OB_MBALL && parent->transflag & OB_DUPLI) { + ComponentKey parent_geometry_key(parent_id, NodeType::GEOMETRY); + /* NOTE: Metaballs are evaluating geometry only after their transform, + * so we onl;y hook up to transform channel here. */ + add_relation(parent_geometry_key, ob_key, "Parent"); + } + + /* Dupliverts uses original vertex index. */ + if (parent->transflag & OB_DUPLIVERTS) { + add_customdata_mask(parent, DEGCustomDataMeshMasks::MaskVert(CD_MASK_ORIGINDEX)); + } } void DepsgraphRelationBuilder::build_object_pointcache(Object *object) { - ComponentKey point_cache_key(&object->id, NodeType::POINT_CACHE); - /* Different point caches are affecting different aspects of life of the - * object. We keep track of those aspects and avoid duplicate relations. */ - enum { - FLAG_TRANSFORM = (1 << 0), - FLAG_GEOMETRY = (1 << 1), - FLAG_ALL = (FLAG_TRANSFORM | FLAG_GEOMETRY), - }; - ListBase ptcache_id_list; - BKE_ptcache_ids_from_object(&ptcache_id_list, object, scene_, 0); - int handled_components = 0; - LISTBASE_FOREACH (PTCacheID *, ptcache_id, &ptcache_id_list) { - /* Check which components needs the point cache. */ - int flag = -1; - if (ptcache_id->type == PTCACHE_TYPE_RIGIDBODY) { - flag = FLAG_TRANSFORM; - OperationKey transform_key( - &object->id, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_SIMULATION_INIT); - add_relation(point_cache_key, - transform_key, - "Point Cache -> Rigid Body"); - } - else { - flag = FLAG_GEOMETRY; - OperationKey geometry_key(&object->id, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL); - add_relation( - point_cache_key, geometry_key, "Point Cache -> Geometry"); - } - BLI_assert(flag != -1); - /* Tag that we did handle that component. */ - handled_components |= flag; - if (handled_components == FLAG_ALL) { - break; - } - } - /* Manual edits to any dependency (or self) should reset the point cache. */ - if (!BLI_listbase_is_empty(&ptcache_id_list)) { - OperationKey transform_eval_key( - &object->id, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_EVAL); - OperationKey geometry_init_key(&object->id, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL_INIT); - add_relation(transform_eval_key, - point_cache_key, - "Transform Simulation -> Point Cache", - RELATION_FLAG_FLUSH_USER_EDIT_ONLY); - add_relation(geometry_init_key, - point_cache_key, - "Geometry Init -> Point Cache", - RELATION_FLAG_FLUSH_USER_EDIT_ONLY); - } - BLI_freelistN(&ptcache_id_list); + ComponentKey point_cache_key(&object->id, NodeType::POINT_CACHE); + /* Different point caches are affecting different aspects of life of the + * object. We keep track of those aspects and avoid duplicate relations. */ + enum { + FLAG_TRANSFORM = (1 << 0), + FLAG_GEOMETRY = (1 << 1), + FLAG_ALL = (FLAG_TRANSFORM | FLAG_GEOMETRY), + }; + ListBase ptcache_id_list; + BKE_ptcache_ids_from_object(&ptcache_id_list, object, scene_, 0); + int handled_components = 0; + LISTBASE_FOREACH (PTCacheID *, ptcache_id, &ptcache_id_list) { + /* Check which components needs the point cache. */ + int flag = -1; + if (ptcache_id->type == PTCACHE_TYPE_RIGIDBODY) { + flag = FLAG_TRANSFORM; + OperationKey transform_key( + &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_SIMULATION_INIT); + add_relation(point_cache_key, transform_key, "Point Cache -> Rigid Body"); + } + else { + flag = FLAG_GEOMETRY; + OperationKey geometry_key(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); + add_relation(point_cache_key, geometry_key, "Point Cache -> Geometry"); + } + BLI_assert(flag != -1); + /* Tag that we did handle that component. */ + handled_components |= flag; + if (handled_components == FLAG_ALL) { + break; + } + } + /* Manual edits to any dependency (or self) should reset the point cache. */ + if (!BLI_listbase_is_empty(&ptcache_id_list)) { + OperationKey transform_eval_key( + &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL); + OperationKey geometry_init_key( + &object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT); + add_relation(transform_eval_key, + point_cache_key, + "Transform Simulation -> Point Cache", + RELATION_FLAG_FLUSH_USER_EDIT_ONLY); + add_relation(geometry_init_key, + point_cache_key, + "Geometry Init -> Point Cache", + RELATION_FLAG_FLUSH_USER_EDIT_ONLY); + } + BLI_freelistN(&ptcache_id_list); } void DepsgraphRelationBuilder::build_constraints(ID *id, @@ -1006,1069 +931,879 @@ void DepsgraphRelationBuilder::build_constraints(ID *id, ListBase *constraints, RootPChanMap *root_map) { - OperationKey constraint_op_key( - id, - component_type, - component_subdata, - (component_type == NodeType::BONE) - ? OperationCode::BONE_CONSTRAINTS - : OperationCode::TRANSFORM_CONSTRAINTS); - /* Add dependencies for each constraint in turn. */ - for (bConstraint *con = (bConstraint *)constraints->first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - /* Invalid constraint type. */ - if (cti == NULL) { - continue; - } - /* Special case for camera tracking -- it doesn't use targets to - * define relations. */ - /* TODO: we can now represent dependencies in a much richer manner, - * so review how this is done. */ - if (ELEM(cti->type, - CONSTRAINT_TYPE_FOLLOWTRACK, - CONSTRAINT_TYPE_CAMERASOLVER, - CONSTRAINT_TYPE_OBJECTSOLVER)) - { - bool depends_on_camera = false; - if (cti->type == CONSTRAINT_TYPE_FOLLOWTRACK) { - bFollowTrackConstraint *data = (bFollowTrackConstraint *)con->data; - if (((data->clip) || - (data->flag & FOLLOWTRACK_ACTIVECLIP)) && data->track[0]) - { - depends_on_camera = true; - } - if (data->depth_ob) { - ComponentKey depth_transform_key(&data->depth_ob->id, - NodeType::TRANSFORM); - ComponentKey depth_geometry_key(&data->depth_ob->id, - NodeType::GEOMETRY); - add_relation(depth_transform_key, constraint_op_key, cti->name); - add_relation(depth_geometry_key, constraint_op_key, cti->name); - } - } - else if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) { - depends_on_camera = true; - } - if (depends_on_camera && scene_->camera != NULL) { - ComponentKey camera_key(&scene_->camera->id, NodeType::TRANSFORM); - add_relation(camera_key, constraint_op_key, cti->name); - } - /* TODO(sergey): This is more a TimeSource -> MovieClip -> - * Constraint dependency chain. */ - TimeSourceKey time_src_key; - add_relation(time_src_key, constraint_op_key, "TimeSrc -> Animation"); - } - else if (cti->type == CONSTRAINT_TYPE_TRANSFORM_CACHE) { - /* TODO(kevin): This is more a TimeSource -> CacheFile -> Constraint - * dependency chain. */ - TimeSourceKey time_src_key; - add_relation(time_src_key, constraint_op_key, "TimeSrc -> Animation"); - bTransformCacheConstraint *data = (bTransformCacheConstraint *)con->data; - if (data->cache_file) { - ComponentKey cache_key(&data->cache_file->id, NodeType::CACHE); - add_relation(cache_key, constraint_op_key, cti->name); - } - } - else if (cti->get_constraint_targets) { - ListBase targets = {NULL, NULL}; - cti->get_constraint_targets(con, &targets); - LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) { - if (ct->tar == NULL) { - continue; - } - if (ELEM(con->type, - CONSTRAINT_TYPE_KINEMATIC, - CONSTRAINT_TYPE_SPLINEIK)) - { - /* Ignore IK constraints - these are handled separately - * (on pose level). */ - } - else if (ELEM(con->type, - CONSTRAINT_TYPE_FOLLOWPATH, - CONSTRAINT_TYPE_CLAMPTO)) - { - /* These constraints require path geometry data. */ - ComponentKey target_key(&ct->tar->id, NodeType::GEOMETRY); - add_relation(target_key, constraint_op_key, cti->name); - ComponentKey target_transform_key(&ct->tar->id, - NodeType::TRANSFORM); - add_relation(target_transform_key, constraint_op_key, cti->name); - } - else if ((ct->tar->type == OB_ARMATURE) && (ct->subtarget[0])) { - OperationCode opcode; - /* relation to bone */ - opcode = bone_target_opcode(&ct->tar->id, ct->subtarget, - id, component_subdata, root_map); - /* Armature constraint always wants the final position and chan_mat. */ - if (ELEM(con->type, CONSTRAINT_TYPE_ARMATURE)) { - opcode = OperationCode::BONE_DONE; - } - /* if needs bbone shape, reference the segment computation */ - if (BKE_constraint_target_uses_bbone(con, ct) && - bone_has_segments(ct->tar, ct->subtarget)) - { - opcode = OperationCode::BONE_SEGMENTS; - } - OperationKey target_key(&ct->tar->id, - NodeType::BONE, - ct->subtarget, - opcode); - add_relation(target_key, constraint_op_key, cti->name); - } - else if (ELEM(ct->tar->type, OB_MESH, OB_LATTICE) && - (ct->subtarget[0])) - { - /* Vertex group. */ - /* NOTE: Vertex group is likely to be used to get vertices - * in a world space. This requires to know both geometry - * and transformation of the target object. */ - ComponentKey target_transform_key( - &ct->tar->id, NodeType::TRANSFORM); - ComponentKey target_geometry_key( - &ct->tar->id, NodeType::GEOMETRY); - add_relation( - target_transform_key, constraint_op_key, cti->name); - add_relation( - target_geometry_key, constraint_op_key, cti->name); - add_customdata_mask(ct->tar, DEGCustomDataMeshMasks::MaskVert(CD_MASK_MDEFORMVERT)); - } - else if (con->type == CONSTRAINT_TYPE_SHRINKWRAP) { - bShrinkwrapConstraint *scon = (bShrinkwrapConstraint *) con->data; - - /* Constraints which requires the target object surface. */ - ComponentKey target_key(&ct->tar->id, NodeType::GEOMETRY); - add_relation(target_key, constraint_op_key, cti->name); - - /* Add dependency on normal layers if necessary. */ - if (ct->tar->type == OB_MESH && scon->shrinkType != MOD_SHRINKWRAP_NEAREST_VERTEX) { - bool track = (scon->flag & CON_SHRINKWRAP_TRACK_NORMAL) != 0; - if (track || BKE_shrinkwrap_needs_normals(scon->shrinkType, scon->shrinkMode)) { - add_customdata_mask(ct->tar, - DEGCustomDataMeshMasks::MaskVert(CD_MASK_NORMAL) | - DEGCustomDataMeshMasks::MaskLoop(CD_MASK_CUSTOMLOOPNORMAL)); - } - if (scon->shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) { - add_special_eval_flag(&ct->tar->id, DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY); - } - } - - /* NOTE: obdata eval now doesn't necessarily depend on the - * object's transform. */ - ComponentKey target_transform_key(&ct->tar->id, - NodeType::TRANSFORM); - add_relation(target_transform_key, constraint_op_key, cti->name); - } - else { - /* Standard object relation. */ - // TODO: loc vs rot vs scale? - if (&ct->tar->id == id) { - /* Constraint targeting own object: - * - This case is fine IFF we're dealing with a bone - * constraint pointing to its own armature. In that - * case, it's just transform -> bone. - * - If however it is a real self targeting case, just - * make it depend on the previous constraint (or the - * pre-constraint state). */ - if ((ct->tar->type == OB_ARMATURE) && - (component_type == NodeType::BONE)) - { - OperationKey target_key(&ct->tar->id, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_FINAL); - add_relation(target_key, constraint_op_key, cti->name); - } - else { - OperationKey target_key(&ct->tar->id, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_LOCAL); - add_relation(target_key, constraint_op_key, cti->name); - } - } - else { - /* Normal object dependency. */ - OperationKey target_key(&ct->tar->id, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_FINAL); - add_relation(target_key, constraint_op_key, cti->name); - } - } - /* Constraints which needs world's matrix for transform. - * TODO(sergey): More constraints here? */ - if (ELEM(con->type, - CONSTRAINT_TYPE_ROTLIKE, - CONSTRAINT_TYPE_SIZELIKE, - CONSTRAINT_TYPE_LOCLIKE, - CONSTRAINT_TYPE_TRANSLIKE)) - { - /* TODO(sergey): Add used space check. */ - ComponentKey target_transform_key(&ct->tar->id, - NodeType::TRANSFORM); - add_relation(target_transform_key, constraint_op_key, cti->name); - } - } - if (cti->flush_constraint_targets) { - cti->flush_constraint_targets(con, &targets, 1); - } - } - } + OperationKey constraint_op_key(id, + component_type, + component_subdata, + (component_type == NodeType::BONE) ? + OperationCode::BONE_CONSTRAINTS : + OperationCode::TRANSFORM_CONSTRAINTS); + /* Add dependencies for each constraint in turn. */ + for (bConstraint *con = (bConstraint *)constraints->first; con; con = con->next) { + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + /* Invalid constraint type. */ + if (cti == NULL) { + continue; + } + /* Special case for camera tracking -- it doesn't use targets to + * define relations. */ + /* TODO: we can now represent dependencies in a much richer manner, + * so review how this is done. */ + if (ELEM(cti->type, + CONSTRAINT_TYPE_FOLLOWTRACK, + CONSTRAINT_TYPE_CAMERASOLVER, + CONSTRAINT_TYPE_OBJECTSOLVER)) { + bool depends_on_camera = false; + if (cti->type == CONSTRAINT_TYPE_FOLLOWTRACK) { + bFollowTrackConstraint *data = (bFollowTrackConstraint *)con->data; + if (((data->clip) || (data->flag & FOLLOWTRACK_ACTIVECLIP)) && data->track[0]) { + depends_on_camera = true; + } + if (data->depth_ob) { + ComponentKey depth_transform_key(&data->depth_ob->id, NodeType::TRANSFORM); + ComponentKey depth_geometry_key(&data->depth_ob->id, NodeType::GEOMETRY); + add_relation(depth_transform_key, constraint_op_key, cti->name); + add_relation(depth_geometry_key, constraint_op_key, cti->name); + } + } + else if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) { + depends_on_camera = true; + } + if (depends_on_camera && scene_->camera != NULL) { + ComponentKey camera_key(&scene_->camera->id, NodeType::TRANSFORM); + add_relation(camera_key, constraint_op_key, cti->name); + } + /* TODO(sergey): This is more a TimeSource -> MovieClip -> + * Constraint dependency chain. */ + TimeSourceKey time_src_key; + add_relation(time_src_key, constraint_op_key, "TimeSrc -> Animation"); + } + else if (cti->type == CONSTRAINT_TYPE_TRANSFORM_CACHE) { + /* TODO(kevin): This is more a TimeSource -> CacheFile -> Constraint + * dependency chain. */ + TimeSourceKey time_src_key; + add_relation(time_src_key, constraint_op_key, "TimeSrc -> Animation"); + bTransformCacheConstraint *data = (bTransformCacheConstraint *)con->data; + if (data->cache_file) { + ComponentKey cache_key(&data->cache_file->id, NodeType::CACHE); + add_relation(cache_key, constraint_op_key, cti->name); + } + } + else if (cti->get_constraint_targets) { + ListBase targets = {NULL, NULL}; + cti->get_constraint_targets(con, &targets); + LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) { + if (ct->tar == NULL) { + continue; + } + if (ELEM(con->type, CONSTRAINT_TYPE_KINEMATIC, CONSTRAINT_TYPE_SPLINEIK)) { + /* Ignore IK constraints - these are handled separately + * (on pose level). */ + } + else if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO)) { + /* These constraints require path geometry data. */ + ComponentKey target_key(&ct->tar->id, NodeType::GEOMETRY); + add_relation(target_key, constraint_op_key, cti->name); + ComponentKey target_transform_key(&ct->tar->id, NodeType::TRANSFORM); + add_relation(target_transform_key, constraint_op_key, cti->name); + } + else if ((ct->tar->type == OB_ARMATURE) && (ct->subtarget[0])) { + OperationCode opcode; + /* relation to bone */ + opcode = bone_target_opcode( + &ct->tar->id, ct->subtarget, id, component_subdata, root_map); + /* Armature constraint always wants the final position and chan_mat. */ + if (ELEM(con->type, CONSTRAINT_TYPE_ARMATURE)) { + opcode = OperationCode::BONE_DONE; + } + /* if needs bbone shape, reference the segment computation */ + if (BKE_constraint_target_uses_bbone(con, ct) && + bone_has_segments(ct->tar, ct->subtarget)) { + opcode = OperationCode::BONE_SEGMENTS; + } + OperationKey target_key(&ct->tar->id, NodeType::BONE, ct->subtarget, opcode); + add_relation(target_key, constraint_op_key, cti->name); + } + else if (ELEM(ct->tar->type, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) { + /* Vertex group. */ + /* NOTE: Vertex group is likely to be used to get vertices + * in a world space. This requires to know both geometry + * and transformation of the target object. */ + ComponentKey target_transform_key(&ct->tar->id, NodeType::TRANSFORM); + ComponentKey target_geometry_key(&ct->tar->id, NodeType::GEOMETRY); + add_relation(target_transform_key, constraint_op_key, cti->name); + add_relation(target_geometry_key, constraint_op_key, cti->name); + add_customdata_mask(ct->tar, DEGCustomDataMeshMasks::MaskVert(CD_MASK_MDEFORMVERT)); + } + else if (con->type == CONSTRAINT_TYPE_SHRINKWRAP) { + bShrinkwrapConstraint *scon = (bShrinkwrapConstraint *)con->data; + + /* Constraints which requires the target object surface. */ + ComponentKey target_key(&ct->tar->id, NodeType::GEOMETRY); + add_relation(target_key, constraint_op_key, cti->name); + + /* Add dependency on normal layers if necessary. */ + if (ct->tar->type == OB_MESH && scon->shrinkType != MOD_SHRINKWRAP_NEAREST_VERTEX) { + bool track = (scon->flag & CON_SHRINKWRAP_TRACK_NORMAL) != 0; + if (track || BKE_shrinkwrap_needs_normals(scon->shrinkType, scon->shrinkMode)) { + add_customdata_mask(ct->tar, + DEGCustomDataMeshMasks::MaskVert(CD_MASK_NORMAL) | + DEGCustomDataMeshMasks::MaskLoop(CD_MASK_CUSTOMLOOPNORMAL)); + } + if (scon->shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) { + add_special_eval_flag(&ct->tar->id, DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY); + } + } + + /* NOTE: obdata eval now doesn't necessarily depend on the + * object's transform. */ + ComponentKey target_transform_key(&ct->tar->id, NodeType::TRANSFORM); + add_relation(target_transform_key, constraint_op_key, cti->name); + } + else { + /* Standard object relation. */ + // TODO: loc vs rot vs scale? + if (&ct->tar->id == id) { + /* Constraint targeting own object: + * - This case is fine IFF we're dealing with a bone + * constraint pointing to its own armature. In that + * case, it's just transform -> bone. + * - If however it is a real self targeting case, just + * make it depend on the previous constraint (or the + * pre-constraint state). */ + if ((ct->tar->type == OB_ARMATURE) && (component_type == NodeType::BONE)) { + OperationKey target_key( + &ct->tar->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_FINAL); + add_relation(target_key, constraint_op_key, cti->name); + } + else { + OperationKey target_key( + &ct->tar->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_LOCAL); + add_relation(target_key, constraint_op_key, cti->name); + } + } + else { + /* Normal object dependency. */ + OperationKey target_key( + &ct->tar->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_FINAL); + add_relation(target_key, constraint_op_key, cti->name); + } + } + /* Constraints which needs world's matrix for transform. + * TODO(sergey): More constraints here? */ + if (ELEM(con->type, + CONSTRAINT_TYPE_ROTLIKE, + CONSTRAINT_TYPE_SIZELIKE, + CONSTRAINT_TYPE_LOCLIKE, + CONSTRAINT_TYPE_TRANSLIKE)) { + /* TODO(sergey): Add used space check. */ + ComponentKey target_transform_key(&ct->tar->id, NodeType::TRANSFORM); + add_relation(target_transform_key, constraint_op_key, cti->name); + } + } + if (cti->flush_constraint_targets) { + cti->flush_constraint_targets(con, &targets, 1); + } + } + } } void DepsgraphRelationBuilder::build_animdata(ID *id) { - /* Images. */ - build_animation_images(id); - /* Animation curves and NLA. */ - build_animdata_curves(id); - /* Drivers. */ - build_animdata_drivers(id); + /* Images. */ + build_animation_images(id); + /* Animation curves and NLA. */ + build_animdata_curves(id); + /* Drivers. */ + build_animdata_drivers(id); } void DepsgraphRelationBuilder::build_animdata_curves(ID *id) { - AnimData *adt = BKE_animdata_from_id(id); - if (adt == NULL) { - return; - } - if (adt->action != NULL) { - build_action(adt->action); - } - if (adt->action == NULL && BLI_listbase_is_empty(&adt->nla_tracks)) { - return; - } - /* Ensure evaluation order from entry to exit. */ - OperationKey animation_entry_key( - id, NodeType::ANIMATION, OperationCode::ANIMATION_ENTRY); - OperationKey animation_eval_key( - id, NodeType::ANIMATION, OperationCode::ANIMATION_EVAL); - OperationKey animation_exit_key( - id, NodeType::ANIMATION, OperationCode::ANIMATION_EXIT); - add_relation(animation_entry_key, animation_eval_key, "Init -> Eval"); - add_relation(animation_eval_key, animation_exit_key, "Eval -> Exit"); - /* Wire up dependency from action. */ - ComponentKey adt_key(id, NodeType::ANIMATION); - /* Relation from action itself. */ - if (adt->action != NULL) { - ComponentKey action_key(&adt->action->id, NodeType::ANIMATION); - add_relation(action_key, adt_key, "Action -> Animation"); - } - /* Get source operations. */ - Node *node_from = get_node(adt_key); - BLI_assert(node_from != NULL); - if (node_from == NULL) { - return; - } - OperationNode *operation_from = node_from->get_exit_operation(); - BLI_assert(operation_from != NULL); - /* Build relations from animation operation to properties it changes. */ - if (adt->action != NULL) { - build_animdata_curves_targets( - id, adt_key, operation_from, &adt->action->curves); - } - LISTBASE_FOREACH(NlaTrack *, nlt, &adt->nla_tracks) { - build_animdata_nlastrip_targets( - id, adt_key, operation_from, &nlt->strips); - } -} - -void DepsgraphRelationBuilder::build_animdata_curves_targets( - ID *id, ComponentKey &adt_key, - OperationNode *operation_from, - ListBase *curves) -{ - /* Iterate over all curves and build relations. */ - PointerRNA id_ptr; - RNA_id_pointer_create(id, &id_ptr); - LISTBASE_FOREACH (FCurve *, fcu, curves) { - PointerRNA ptr; - PropertyRNA *prop; - int index; - if (!RNA_path_resolve_full( - &id_ptr, fcu->rna_path, &ptr, &prop, &index)) - { - continue; - } - Node *node_to = rna_node_query_.find_node( - &ptr, prop, RNAPointerSource::ENTRY); - if (node_to == NULL) { - continue; - } - OperationNode *operation_to = node_to->get_entry_operation(); - /* NOTE: Special case for bones, avoid relation from animation to - * each of the bones. Bone evaluation could only start from pose - * init anyway. */ - if (operation_to->opcode == OperationCode::BONE_LOCAL) { - OperationKey pose_init_key( - id, NodeType::EVAL_POSE, OperationCode::POSE_INIT); - add_relation(adt_key, - pose_init_key, - "Animation -> Prop", - RELATION_CHECK_BEFORE_ADD); - continue; - } - graph_->add_new_relation(operation_from, operation_to, - "Animation -> Prop", - RELATION_CHECK_BEFORE_ADD); - /* It is possible that animation is writing to a nested ID datablock, - * need to make sure animation is evaluated after target ID is copied. */ - const IDNode *id_node_from = operation_from->owner->owner; - const IDNode *id_node_to = operation_to->owner->owner; - if (id_node_from != id_node_to) { - ComponentKey cow_key(id_node_to->id_orig, NodeType::COPY_ON_WRITE); - add_relation(cow_key, - adt_key, - "Animated CoW -> Animation", - RELATION_CHECK_BEFORE_ADD); - } - } -} - -void DepsgraphRelationBuilder::build_animdata_nlastrip_targets( - ID *id, ComponentKey &adt_key, - OperationNode *operation_from, - ListBase *strips) -{ - LISTBASE_FOREACH (NlaStrip *, strip, strips) { - if (strip->act != NULL) { - build_action(strip->act); - - ComponentKey action_key(&strip->act->id, NodeType::ANIMATION); - add_relation(action_key, adt_key, "Action -> Animation"); - - build_animdata_curves_targets( - id, adt_key, operation_from, &strip->act->curves); - } - else if (strip->strips.first != NULL) { - build_animdata_nlastrip_targets( - id, adt_key, operation_from, &strip->strips); - } - } + AnimData *adt = BKE_animdata_from_id(id); + if (adt == NULL) { + return; + } + if (adt->action != NULL) { + build_action(adt->action); + } + if (adt->action == NULL && BLI_listbase_is_empty(&adt->nla_tracks)) { + return; + } + /* Ensure evaluation order from entry to exit. */ + OperationKey animation_entry_key(id, NodeType::ANIMATION, OperationCode::ANIMATION_ENTRY); + OperationKey animation_eval_key(id, NodeType::ANIMATION, OperationCode::ANIMATION_EVAL); + OperationKey animation_exit_key(id, NodeType::ANIMATION, OperationCode::ANIMATION_EXIT); + add_relation(animation_entry_key, animation_eval_key, "Init -> Eval"); + add_relation(animation_eval_key, animation_exit_key, "Eval -> Exit"); + /* Wire up dependency from action. */ + ComponentKey adt_key(id, NodeType::ANIMATION); + /* Relation from action itself. */ + if (adt->action != NULL) { + ComponentKey action_key(&adt->action->id, NodeType::ANIMATION); + add_relation(action_key, adt_key, "Action -> Animation"); + } + /* Get source operations. */ + Node *node_from = get_node(adt_key); + BLI_assert(node_from != NULL); + if (node_from == NULL) { + return; + } + OperationNode *operation_from = node_from->get_exit_operation(); + BLI_assert(operation_from != NULL); + /* Build relations from animation operation to properties it changes. */ + if (adt->action != NULL) { + build_animdata_curves_targets(id, adt_key, operation_from, &adt->action->curves); + } + LISTBASE_FOREACH (NlaTrack *, nlt, &adt->nla_tracks) { + build_animdata_nlastrip_targets(id, adt_key, operation_from, &nlt->strips); + } +} + +void DepsgraphRelationBuilder::build_animdata_curves_targets(ID *id, + ComponentKey &adt_key, + OperationNode *operation_from, + ListBase *curves) +{ + /* Iterate over all curves and build relations. */ + PointerRNA id_ptr; + RNA_id_pointer_create(id, &id_ptr); + LISTBASE_FOREACH (FCurve *, fcu, curves) { + PointerRNA ptr; + PropertyRNA *prop; + int index; + if (!RNA_path_resolve_full(&id_ptr, fcu->rna_path, &ptr, &prop, &index)) { + continue; + } + Node *node_to = rna_node_query_.find_node(&ptr, prop, RNAPointerSource::ENTRY); + if (node_to == NULL) { + continue; + } + OperationNode *operation_to = node_to->get_entry_operation(); + /* NOTE: Special case for bones, avoid relation from animation to + * each of the bones. Bone evaluation could only start from pose + * init anyway. */ + if (operation_to->opcode == OperationCode::BONE_LOCAL) { + OperationKey pose_init_key(id, NodeType::EVAL_POSE, OperationCode::POSE_INIT); + add_relation(adt_key, pose_init_key, "Animation -> Prop", RELATION_CHECK_BEFORE_ADD); + continue; + } + graph_->add_new_relation( + operation_from, operation_to, "Animation -> Prop", RELATION_CHECK_BEFORE_ADD); + /* It is possible that animation is writing to a nested ID datablock, + * need to make sure animation is evaluated after target ID is copied. */ + const IDNode *id_node_from = operation_from->owner->owner; + const IDNode *id_node_to = operation_to->owner->owner; + if (id_node_from != id_node_to) { + ComponentKey cow_key(id_node_to->id_orig, NodeType::COPY_ON_WRITE); + add_relation(cow_key, adt_key, "Animated CoW -> Animation", RELATION_CHECK_BEFORE_ADD); + } + } +} + +void DepsgraphRelationBuilder::build_animdata_nlastrip_targets(ID *id, + ComponentKey &adt_key, + OperationNode *operation_from, + ListBase *strips) +{ + LISTBASE_FOREACH (NlaStrip *, strip, strips) { + if (strip->act != NULL) { + build_action(strip->act); + + ComponentKey action_key(&strip->act->id, NodeType::ANIMATION); + add_relation(action_key, adt_key, "Action -> Animation"); + + build_animdata_curves_targets(id, adt_key, operation_from, &strip->act->curves); + } + else if (strip->strips.first != NULL) { + build_animdata_nlastrip_targets(id, adt_key, operation_from, &strip->strips); + } + } } void DepsgraphRelationBuilder::build_animdata_drivers(ID *id) { - AnimData *adt = BKE_animdata_from_id(id); - if (adt == NULL) { - return; - } - ComponentKey adt_key(id, NodeType::ANIMATION); - LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) { - OperationKey driver_key(id, - NodeType::PARAMETERS, - OperationCode::DRIVER, - fcu->rna_path ? fcu->rna_path : "", - fcu->array_index); - - /* create the driver's relations to targets */ - build_driver(id, fcu); - /* Special case for array drivers: we can not multithread them because - * of the way how they work internally: animation system will write the - * whole array back to RNA even when changing individual array value. - * - * Some tricky things here: - * - array_index is -1 for single channel drivers, meaning we only have - * to do some magic when array_index is not -1. - * - We do relation from next array index to a previous one, so we don't - * have to deal with array index 0. - * - * TODO(sergey): Avoid liner lookup somehow. */ - if (fcu->array_index > 0) { - FCurve *fcu_prev = NULL; - LISTBASE_FOREACH (FCurve *, fcu_candidate, &adt->drivers) { - /* Writing to different RNA paths is */ - const char *rna_path = fcu->rna_path ? fcu->rna_path : ""; - if (!STREQ(fcu_candidate->rna_path, rna_path)) { - continue; - } - /* We only do relation from previous fcurve to previous one. */ - if (fcu_candidate->array_index >= fcu->array_index) { - continue; - } - /* Choose fcurve with highest possible array index. */ - if (fcu_prev == NULL || - fcu_candidate->array_index > fcu_prev->array_index) - { - fcu_prev = fcu_candidate; - } - } - if (fcu_prev != NULL) { - OperationKey prev_driver_key(id, - NodeType::PARAMETERS, - OperationCode::DRIVER, - fcu_prev->rna_path ? fcu_prev->rna_path : "", - fcu_prev->array_index); - OperationKey driver_key(id, - NodeType::PARAMETERS, - OperationCode::DRIVER, - fcu->rna_path ? fcu->rna_path : "", - fcu->array_index); - add_relation(prev_driver_key, driver_key, "Driver Order"); - } - } - - /* prevent driver from occurring before own animation... */ - if (adt->action || adt->nla_tracks.first) { - add_relation(adt_key, driver_key, "AnimData Before Drivers"); - } - } + AnimData *adt = BKE_animdata_from_id(id); + if (adt == NULL) { + return; + } + ComponentKey adt_key(id, NodeType::ANIMATION); + LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) { + OperationKey driver_key(id, + NodeType::PARAMETERS, + OperationCode::DRIVER, + fcu->rna_path ? fcu->rna_path : "", + fcu->array_index); + + /* create the driver's relations to targets */ + build_driver(id, fcu); + /* Special case for array drivers: we can not multithread them because + * of the way how they work internally: animation system will write the + * whole array back to RNA even when changing individual array value. + * + * Some tricky things here: + * - array_index is -1 for single channel drivers, meaning we only have + * to do some magic when array_index is not -1. + * - We do relation from next array index to a previous one, so we don't + * have to deal with array index 0. + * + * TODO(sergey): Avoid liner lookup somehow. */ + if (fcu->array_index > 0) { + FCurve *fcu_prev = NULL; + LISTBASE_FOREACH (FCurve *, fcu_candidate, &adt->drivers) { + /* Writing to different RNA paths is */ + const char *rna_path = fcu->rna_path ? fcu->rna_path : ""; + if (!STREQ(fcu_candidate->rna_path, rna_path)) { + continue; + } + /* We only do relation from previous fcurve to previous one. */ + if (fcu_candidate->array_index >= fcu->array_index) { + continue; + } + /* Choose fcurve with highest possible array index. */ + if (fcu_prev == NULL || fcu_candidate->array_index > fcu_prev->array_index) { + fcu_prev = fcu_candidate; + } + } + if (fcu_prev != NULL) { + OperationKey prev_driver_key(id, + NodeType::PARAMETERS, + OperationCode::DRIVER, + fcu_prev->rna_path ? fcu_prev->rna_path : "", + fcu_prev->array_index); + OperationKey driver_key(id, + NodeType::PARAMETERS, + OperationCode::DRIVER, + fcu->rna_path ? fcu->rna_path : "", + fcu->array_index); + add_relation(prev_driver_key, driver_key, "Driver Order"); + } + } + + /* prevent driver from occurring before own animation... */ + if (adt->action || adt->nla_tracks.first) { + add_relation(adt_key, driver_key, "AnimData Before Drivers"); + } + } } void DepsgraphRelationBuilder::build_animation_images(ID *id) { - /* TODO: can we check for existance of node for performance? */ - if (BKE_image_user_id_has_animation(id)) { - OperationKey image_animation_key(id, - NodeType::ANIMATION, - OperationCode::IMAGE_ANIMATION); - TimeSourceKey time_src_key; - add_relation(time_src_key, image_animation_key, "TimeSrc -> Image Animation"); - } + /* TODO: can we check for existance of node for performance? */ + if (BKE_image_user_id_has_animation(id)) { + OperationKey image_animation_key(id, NodeType::ANIMATION, OperationCode::IMAGE_ANIMATION); + TimeSourceKey time_src_key; + add_relation(time_src_key, image_animation_key, "TimeSrc -> Image Animation"); + } } void DepsgraphRelationBuilder::build_action(bAction *action) { - if (built_map_.checkIsBuiltAndTag(action)) { - return; - } - TimeSourceKey time_src_key; - ComponentKey animation_key(&action->id, NodeType::ANIMATION); - add_relation(time_src_key, animation_key, "TimeSrc -> Animation"); + if (built_map_.checkIsBuiltAndTag(action)) { + return; + } + TimeSourceKey time_src_key; + ComponentKey animation_key(&action->id, NodeType::ANIMATION); + add_relation(time_src_key, animation_key, "TimeSrc -> Animation"); } void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) { - ChannelDriver *driver = fcu->driver; - OperationKey driver_key(id, - NodeType::PARAMETERS, - OperationCode::DRIVER, - fcu->rna_path ? fcu->rna_path : "", - fcu->array_index); - /* Driver -> data components (for interleaved evaluation - * bones/constraints/modifiers). */ - build_driver_data(id, fcu); - /* Loop over variables to get the target relationships. */ - build_driver_variables(id, fcu); - /* It's quite tricky to detect if the driver actually depends on time or - * not, so for now we'll be quite conservative here about optimization and - * consider all python drivers to be depending on time. */ - if ((driver->type == DRIVER_TYPE_PYTHON) && - python_driver_depends_on_time(driver)) - { - TimeSourceKey time_src_key; - add_relation(time_src_key, driver_key, "TimeSrc -> Driver"); - } + ChannelDriver *driver = fcu->driver; + OperationKey driver_key(id, + NodeType::PARAMETERS, + OperationCode::DRIVER, + fcu->rna_path ? fcu->rna_path : "", + fcu->array_index); + /* Driver -> data components (for interleaved evaluation + * bones/constraints/modifiers). */ + build_driver_data(id, fcu); + /* Loop over variables to get the target relationships. */ + build_driver_variables(id, fcu); + /* It's quite tricky to detect if the driver actually depends on time or + * not, so for now we'll be quite conservative here about optimization and + * consider all python drivers to be depending on time. */ + if ((driver->type == DRIVER_TYPE_PYTHON) && python_driver_depends_on_time(driver)) { + TimeSourceKey time_src_key; + add_relation(time_src_key, driver_key, "TimeSrc -> Driver"); + } } void DepsgraphRelationBuilder::build_driver_data(ID *id, FCurve *fcu) { - OperationKey driver_key(id, - NodeType::PARAMETERS, - OperationCode::DRIVER, - fcu->rna_path ? fcu->rna_path : "", - fcu->array_index); - const char *rna_path = fcu->rna_path ? fcu->rna_path : ""; - if (GS(id->name) == ID_AR && strstr(rna_path, "bones[")) { - /* Drivers on armature-level bone settings (i.e. bbone stuff), - * which will affect the evaluation of corresponding pose bones. */ - IDNode *arm_node = graph_->find_id_node(id); - char *bone_name = BLI_str_quoted_substrN(rna_path, "bones["); - if (arm_node != NULL && bone_name != NULL) { - /* Find objects which use this, and make their eval callbacks - * depend on this. */ - for (Relation *rel : arm_node->outlinks) { - IDNode *to_node = (IDNode *)rel->to; - /* We only care about objects with pose data which use this. */ - if (GS(to_node->id_orig->name) == ID_OB) { - Object *object = (Object *)to_node->id_orig; - // NOTE: object->pose may be NULL - bPoseChannel *pchan = BKE_pose_channel_find_name(object->pose, - bone_name); - if (pchan != NULL) { - OperationKey bone_key(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_LOCAL); - add_relation(driver_key, - bone_key, - "Arm Bone -> Driver -> Bone"); - } - } - } - /* Free temp data. */ - MEM_freeN(bone_name); - bone_name = NULL; - } - else { - fprintf(stderr, - "Couldn't find armature bone name for driver path - '%s'\n", - rna_path); - } - } - else if (rna_path != NULL && rna_path[0] != '\0') { - RNAPathKey property_entry_key(id, rna_path, RNAPointerSource::ENTRY); - if (RNA_pointer_is_null(&property_entry_key.ptr)) { - /* TODO(sergey): This would only mean that driver is broken. - * so we can't create relation anyway. However, we need to avoid - * adding drivers which are known to be buggy to a dependency - * graph, in order to save computational power. */ - return; - } - add_relation( - driver_key, property_entry_key, "Driver -> Driven Property"); - /* Similar to the case with f-curves, driver might drive a nested - * datablock, which means driver execution should wait for that - * datablock to be copied. */ - { - PointerRNA id_ptr; - PointerRNA ptr; - RNA_id_pointer_create(id, &id_ptr); - if (RNA_path_resolve_full(&id_ptr, fcu->rna_path, &ptr, NULL, NULL)) { - if (id_ptr.id.data != ptr.id.data) { - ComponentKey cow_key((ID *)ptr.id.data, - NodeType::COPY_ON_WRITE); - add_relation(cow_key, - driver_key, - "Driven CoW -> Driver", - RELATION_CHECK_BEFORE_ADD); - } - } - } - if (property_entry_key.prop != NULL && - RNA_property_is_idprop(property_entry_key.prop)) - { - RNAPathKey property_exit_key(id, rna_path, RNAPointerSource::EXIT); - OperationKey parameters_key(id, - NodeType::PARAMETERS, - OperationCode::PARAMETERS_EVAL); - add_relation(property_exit_key, - parameters_key, - "Driven Property -> Properties"); - } - } + OperationKey driver_key(id, + NodeType::PARAMETERS, + OperationCode::DRIVER, + fcu->rna_path ? fcu->rna_path : "", + fcu->array_index); + const char *rna_path = fcu->rna_path ? fcu->rna_path : ""; + if (GS(id->name) == ID_AR && strstr(rna_path, "bones[")) { + /* Drivers on armature-level bone settings (i.e. bbone stuff), + * which will affect the evaluation of corresponding pose bones. */ + IDNode *arm_node = graph_->find_id_node(id); + char *bone_name = BLI_str_quoted_substrN(rna_path, "bones["); + if (arm_node != NULL && bone_name != NULL) { + /* Find objects which use this, and make their eval callbacks + * depend on this. */ + for (Relation *rel : arm_node->outlinks) { + IDNode *to_node = (IDNode *)rel->to; + /* We only care about objects with pose data which use this. */ + if (GS(to_node->id_orig->name) == ID_OB) { + Object *object = (Object *)to_node->id_orig; + // NOTE: object->pose may be NULL + bPoseChannel *pchan = BKE_pose_channel_find_name(object->pose, bone_name); + if (pchan != NULL) { + OperationKey bone_key( + &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL); + add_relation(driver_key, bone_key, "Arm Bone -> Driver -> Bone"); + } + } + } + /* Free temp data. */ + MEM_freeN(bone_name); + bone_name = NULL; + } + else { + fprintf(stderr, "Couldn't find armature bone name for driver path - '%s'\n", rna_path); + } + } + else if (rna_path != NULL && rna_path[0] != '\0') { + RNAPathKey property_entry_key(id, rna_path, RNAPointerSource::ENTRY); + if (RNA_pointer_is_null(&property_entry_key.ptr)) { + /* TODO(sergey): This would only mean that driver is broken. + * so we can't create relation anyway. However, we need to avoid + * adding drivers which are known to be buggy to a dependency + * graph, in order to save computational power. */ + return; + } + add_relation(driver_key, property_entry_key, "Driver -> Driven Property"); + /* Similar to the case with f-curves, driver might drive a nested + * datablock, which means driver execution should wait for that + * datablock to be copied. */ + { + PointerRNA id_ptr; + PointerRNA ptr; + RNA_id_pointer_create(id, &id_ptr); + if (RNA_path_resolve_full(&id_ptr, fcu->rna_path, &ptr, NULL, NULL)) { + if (id_ptr.id.data != ptr.id.data) { + ComponentKey cow_key((ID *)ptr.id.data, NodeType::COPY_ON_WRITE); + add_relation(cow_key, driver_key, "Driven CoW -> Driver", RELATION_CHECK_BEFORE_ADD); + } + } + } + if (property_entry_key.prop != NULL && RNA_property_is_idprop(property_entry_key.prop)) { + RNAPathKey property_exit_key(id, rna_path, RNAPointerSource::EXIT); + OperationKey parameters_key(id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL); + add_relation(property_exit_key, parameters_key, "Driven Property -> Properties"); + } + } } void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu) { - ChannelDriver *driver = fcu->driver; - OperationKey driver_key(id, - NodeType::PARAMETERS, - OperationCode::DRIVER, - fcu->rna_path ? fcu->rna_path : "", - fcu->array_index); - const char *rna_path = fcu->rna_path ? fcu->rna_path : ""; - const RNAPathKey self_key(id, rna_path, RNAPointerSource::ENTRY); - LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) { - /* Only used targets. */ - DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar) - { - if (dtar->id == NULL) { - continue; - } - build_id(dtar->id); - build_driver_id_property(dtar->id, dtar->rna_path); - /* Initialize relations coming to proxy_from. */ - Object *proxy_from = NULL; - if ((GS(dtar->id->name) == ID_OB) && - (((Object *)dtar->id)->proxy_from != NULL)) - { - proxy_from = ((Object *)dtar->id)->proxy_from; - build_id(&proxy_from->id); - } - /* Special handling for directly-named bones. */ - if ((dtar->flag & DTAR_FLAG_STRUCT_REF) && - (((Object *)dtar->id)->type == OB_ARMATURE) && - (dtar->pchan_name[0])) - { - Object *object = (Object *)dtar->id; - bPoseChannel *target_pchan = - BKE_pose_channel_find_name(object->pose, - dtar->pchan_name); - if (target_pchan == NULL) { - continue; - } - OperationKey variable_key(dtar->id, - NodeType::BONE, - target_pchan->name, - OperationCode::BONE_DONE); - if (is_same_bone_dependency(variable_key, self_key)) { - continue; - } - add_relation(variable_key, driver_key, "Bone Target -> Driver"); - } - else if (dtar->flag & DTAR_FLAG_STRUCT_REF) { - /* Get node associated with the object's transforms. */ - if (dtar->id == id) { - /* Ignore input dependency if we're driving properties of - * the same ID, otherwise we'll be ending up in a cyclic - * dependency here. */ - continue; - } - OperationKey target_key(dtar->id, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_FINAL); - add_relation(target_key, driver_key, "Target -> Driver"); - } - else if (dtar->rna_path != NULL && dtar->rna_path[0] != '\0') { - RNAPathKey variable_exit_key( - dtar->id, dtar->rna_path, RNAPointerSource::EXIT); - if (RNA_pointer_is_null(&variable_exit_key.ptr)) { - continue; - } - if (is_same_bone_dependency(variable_exit_key, self_key) || - is_same_nodetree_node_dependency(variable_exit_key, self_key)) - { - continue; - } - add_relation(variable_exit_key, - driver_key, - "RNA Target -> Driver"); - if (proxy_from != NULL) { - RNAPathKey proxy_from_variable_key(&proxy_from->id, - dtar->rna_path, - RNAPointerSource::EXIT); - RNAPathKey variable_entry_key( - dtar->id, dtar->rna_path, RNAPointerSource::ENTRY); - add_relation(proxy_from_variable_key, - variable_entry_key, - "Proxy From -> Variable"); - } - } - else { - /* If rna_path is NULL, and DTAR_FLAG_STRUCT_REF isn't set, this - * is an incomplete target reference, so nothing to do here. */ - } - } - DRIVER_TARGETS_LOOPER_END; - } -} - -void DepsgraphRelationBuilder::build_driver_id_property(ID *id, - const char *rna_path) -{ - if (id == NULL || rna_path == NULL) { - return; - } - PointerRNA id_ptr, ptr; - PropertyRNA *prop; - RNA_id_pointer_create(id, &id_ptr); - if (!RNA_path_resolve_full(&id_ptr, rna_path, &ptr, &prop, NULL)) { - return; - } - if (prop == NULL) { - return; - } - if (!RNA_property_is_idprop(prop)) { - return; - } - const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop); - OperationKey id_property_key(id, - NodeType::PARAMETERS, - OperationCode::ID_PROPERTY, - prop_identifier); - OperationKey parameters_exit_key(id, - NodeType::PARAMETERS, - OperationCode::PARAMETERS_EXIT); - add_relation(id_property_key, - parameters_exit_key, - "ID Property -> Done", - RELATION_CHECK_BEFORE_ADD); + ChannelDriver *driver = fcu->driver; + OperationKey driver_key(id, + NodeType::PARAMETERS, + OperationCode::DRIVER, + fcu->rna_path ? fcu->rna_path : "", + fcu->array_index); + const char *rna_path = fcu->rna_path ? fcu->rna_path : ""; + const RNAPathKey self_key(id, rna_path, RNAPointerSource::ENTRY); + LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) { + /* Only used targets. */ + DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { + if (dtar->id == NULL) { + continue; + } + build_id(dtar->id); + build_driver_id_property(dtar->id, dtar->rna_path); + /* Initialize relations coming to proxy_from. */ + Object *proxy_from = NULL; + if ((GS(dtar->id->name) == ID_OB) && (((Object *)dtar->id)->proxy_from != NULL)) { + proxy_from = ((Object *)dtar->id)->proxy_from; + build_id(&proxy_from->id); + } + /* Special handling for directly-named bones. */ + if ((dtar->flag & DTAR_FLAG_STRUCT_REF) && (((Object *)dtar->id)->type == OB_ARMATURE) && + (dtar->pchan_name[0])) { + Object *object = (Object *)dtar->id; + bPoseChannel *target_pchan = BKE_pose_channel_find_name(object->pose, dtar->pchan_name); + if (target_pchan == NULL) { + continue; + } + OperationKey variable_key( + dtar->id, NodeType::BONE, target_pchan->name, OperationCode::BONE_DONE); + if (is_same_bone_dependency(variable_key, self_key)) { + continue; + } + add_relation(variable_key, driver_key, "Bone Target -> Driver"); + } + else if (dtar->flag & DTAR_FLAG_STRUCT_REF) { + /* Get node associated with the object's transforms. */ + if (dtar->id == id) { + /* Ignore input dependency if we're driving properties of + * the same ID, otherwise we'll be ending up in a cyclic + * dependency here. */ + continue; + } + OperationKey target_key(dtar->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_FINAL); + add_relation(target_key, driver_key, "Target -> Driver"); + } + else if (dtar->rna_path != NULL && dtar->rna_path[0] != '\0') { + RNAPathKey variable_exit_key(dtar->id, dtar->rna_path, RNAPointerSource::EXIT); + if (RNA_pointer_is_null(&variable_exit_key.ptr)) { + continue; + } + if (is_same_bone_dependency(variable_exit_key, self_key) || + is_same_nodetree_node_dependency(variable_exit_key, self_key)) { + continue; + } + add_relation(variable_exit_key, driver_key, "RNA Target -> Driver"); + if (proxy_from != NULL) { + RNAPathKey proxy_from_variable_key( + &proxy_from->id, dtar->rna_path, RNAPointerSource::EXIT); + RNAPathKey variable_entry_key(dtar->id, dtar->rna_path, RNAPointerSource::ENTRY); + add_relation(proxy_from_variable_key, variable_entry_key, "Proxy From -> Variable"); + } + } + else { + /* If rna_path is NULL, and DTAR_FLAG_STRUCT_REF isn't set, this + * is an incomplete target reference, so nothing to do here. */ + } + } + DRIVER_TARGETS_LOOPER_END; + } +} + +void DepsgraphRelationBuilder::build_driver_id_property(ID *id, const char *rna_path) +{ + if (id == NULL || rna_path == NULL) { + return; + } + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + RNA_id_pointer_create(id, &id_ptr); + if (!RNA_path_resolve_full(&id_ptr, rna_path, &ptr, &prop, NULL)) { + return; + } + if (prop == NULL) { + return; + } + if (!RNA_property_is_idprop(prop)) { + return; + } + const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop); + OperationKey id_property_key( + id, NodeType::PARAMETERS, OperationCode::ID_PROPERTY, prop_identifier); + OperationKey parameters_exit_key(id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EXIT); + add_relation( + id_property_key, parameters_exit_key, "ID Property -> Done", RELATION_CHECK_BEFORE_ADD); } void DepsgraphRelationBuilder::build_parameters(ID *id) { - OperationKey parameters_entry_key( - id, NodeType::PARAMETERS, OperationCode::PARAMETERS_ENTRY); - OperationKey parameters_eval_key( - id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL); - OperationKey parameters_exit_key( - id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EXIT); - add_relation( - parameters_entry_key, parameters_eval_key, "Entry -> Eval"); - add_relation( - parameters_eval_key, parameters_exit_key, "Entry -> Exit"); + OperationKey parameters_entry_key(id, NodeType::PARAMETERS, OperationCode::PARAMETERS_ENTRY); + OperationKey parameters_eval_key(id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL); + OperationKey parameters_exit_key(id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EXIT); + add_relation(parameters_entry_key, parameters_eval_key, "Entry -> Eval"); + add_relation(parameters_eval_key, parameters_exit_key, "Entry -> Exit"); } void DepsgraphRelationBuilder::build_world(World *world) { - if (built_map_.checkIsBuiltAndTag(world)) { - return; - } - /* animation */ - build_animdata(&world->id); - build_parameters(&world->id); - /* world's nodetree */ - if (world->nodetree != NULL) { - build_nodetree(world->nodetree); - OperationKey ntree_key(&world->nodetree->id, - NodeType::SHADING, - OperationCode::MATERIAL_UPDATE); - OperationKey world_key(&world->id, - NodeType::SHADING, - OperationCode::WORLD_UPDATE); - add_relation(ntree_key, world_key, "World's NTree"); - build_nested_nodetree(&world->id, world->nodetree); - } + if (built_map_.checkIsBuiltAndTag(world)) { + return; + } + /* animation */ + build_animdata(&world->id); + build_parameters(&world->id); + /* world's nodetree */ + if (world->nodetree != NULL) { + build_nodetree(world->nodetree); + OperationKey ntree_key( + &world->nodetree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE); + OperationKey world_key(&world->id, NodeType::SHADING, OperationCode::WORLD_UPDATE); + add_relation(ntree_key, world_key, "World's NTree"); + build_nested_nodetree(&world->id, world->nodetree); + } } void DepsgraphRelationBuilder::build_rigidbody(Scene *scene) { - RigidBodyWorld *rbw = scene->rigidbody_world; - OperationKey rb_init_key(&scene->id, - NodeType::TRANSFORM, - OperationCode::RIGIDBODY_REBUILD); - OperationKey rb_simulate_key(&scene->id, - NodeType::TRANSFORM, - OperationCode::RIGIDBODY_SIM); - /* Simulation depends on time. */ - TimeSourceKey time_src_key; - add_relation(time_src_key, rb_init_key, "TimeSrc -> Rigidbody Init"); - /* Simulation should always be run after initialization. */ - /* NOTE: It is possible in theory to have dependency cycle which involves - * this relation. We never want it to be killed. */ - add_relation(rb_init_key, - rb_simulate_key, - "Rigidbody [Init -> SimStep]", - RELATION_FLAG_GODMODE); - /* Effectors should be evaluated at the time simulation is being - * initialized. - * TODO(sergey): Verify that it indeed goes to initialization and not to a - * simulation. */ - ListBase *effector_relations = - build_effector_relations(graph_, rbw->effector_weights->group); - LISTBASE_FOREACH (EffectorRelation *, effector_relation, effector_relations) { - ComponentKey effector_transform_key( - &effector_relation->ob->id, NodeType::TRANSFORM); - add_relation(effector_transform_key, rb_init_key, "RigidBody Field"); - if (effector_relation->pd != NULL) { - const short shape = effector_relation->pd->shape; - if (ELEM(shape, PFIELD_SHAPE_SURFACE, PFIELD_SHAPE_POINTS)) { - ComponentKey effector_geometry_key( - &effector_relation->ob->id, NodeType::GEOMETRY); - add_relation( - effector_geometry_key, rb_init_key, "RigidBody Field"); - } - } - } - /* Objects. */ - if (rbw->group != NULL) { - build_collection(NULL, NULL, rbw->group); - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object) - { - if (object->type != OB_MESH) { - continue; - } - OperationKey rb_transform_copy_key( - &object->id, - NodeType::TRANSFORM, - OperationCode::RIGIDBODY_TRANSFORM_COPY); - /* Rigid body synchronization depends on the actual simulation. */ - add_relation(rb_simulate_key, - rb_transform_copy_key, - "Rigidbody Sim Eval -> RBO Sync"); - /* Simulation uses object transformation after parenting and solving - * contraints. */ - OperationKey object_transform_simulation_init_key( - &object->id, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_SIMULATION_INIT); - OperationKey object_transform_eval_key( - &object->id, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_EVAL); - add_relation(object_transform_simulation_init_key, - rb_simulate_key, - "Object Transform -> Rigidbody Sim Eval"); - /* Geometry must be known to create the rigid body. RBO_MESH_BASE - * uses the non-evaluated mesh, so then the evaluation is - * unnecessary. */ - if (object->rigidbody_object != NULL && - object->rigidbody_object->mesh_source != RBO_MESH_BASE) - { - /* NOTE: We prefer this relation to be never killed, to avoid - * access partially evaluated mesh from solver. */ - ComponentKey object_geometry_key( - &object->id, NodeType::GEOMETRY); - add_relation(object_geometry_key, - rb_simulate_key, - "Object Geom Eval -> Rigidbody Rebuild", - RELATION_FLAG_GODMODE); - } - /* Final transform is whetever solver gave to us. */ - OperationKey object_transform_final_key( - &object->id, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_FINAL); - add_relation(rb_transform_copy_key, - object_transform_final_key, - "Rigidbody Sync -> Transform Final"); - } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - } - /* Constraints. */ - if (rbw->constraints != NULL) { - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, object) - { - RigidBodyCon *rbc = object->rigidbody_constraint; - if (rbc == NULL || rbc->ob1 == NULL || rbc->ob2 == NULL) { - /* When either ob1 or ob2 is NULL, the constraint doesn't - * work. */ - continue; - } - /* Make sure indirectly linked objects are fully built. */ - build_object(NULL, object); - build_object(NULL, rbc->ob1); - build_object(NULL, rbc->ob2); - /* final result of the constraint object's transform controls how - * the constraint affects the physics sim for these objects. */ - ComponentKey trans_key(&object->id, NodeType::TRANSFORM); - OperationKey ob1_key(&rbc->ob1->id, - NodeType::TRANSFORM, - OperationCode::RIGIDBODY_TRANSFORM_COPY); - OperationKey ob2_key(&rbc->ob2->id, - NodeType::TRANSFORM, - OperationCode::RIGIDBODY_TRANSFORM_COPY); - /* Constrained-objects sync depends on the constraint-holder. */ - add_relation( - trans_key, ob1_key, "RigidBodyConstraint -> RBC.Object_1"); - add_relation( - trans_key, ob2_key, "RigidBodyConstraint -> RBC.Object_2"); - /* Ensure that sim depends on this constraint's transform. */ - add_relation(trans_key, - rb_simulate_key, - "RigidBodyConstraint Transform -> RB Simulation"); - } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - } + RigidBodyWorld *rbw = scene->rigidbody_world; + OperationKey rb_init_key(&scene->id, NodeType::TRANSFORM, OperationCode::RIGIDBODY_REBUILD); + OperationKey rb_simulate_key(&scene->id, NodeType::TRANSFORM, OperationCode::RIGIDBODY_SIM); + /* Simulation depends on time. */ + TimeSourceKey time_src_key; + add_relation(time_src_key, rb_init_key, "TimeSrc -> Rigidbody Init"); + /* Simulation should always be run after initialization. */ + /* NOTE: It is possible in theory to have dependency cycle which involves + * this relation. We never want it to be killed. */ + add_relation(rb_init_key, rb_simulate_key, "Rigidbody [Init -> SimStep]", RELATION_FLAG_GODMODE); + /* Effectors should be evaluated at the time simulation is being + * initialized. + * TODO(sergey): Verify that it indeed goes to initialization and not to a + * simulation. */ + ListBase *effector_relations = build_effector_relations(graph_, rbw->effector_weights->group); + LISTBASE_FOREACH (EffectorRelation *, effector_relation, effector_relations) { + ComponentKey effector_transform_key(&effector_relation->ob->id, NodeType::TRANSFORM); + add_relation(effector_transform_key, rb_init_key, "RigidBody Field"); + if (effector_relation->pd != NULL) { + const short shape = effector_relation->pd->shape; + if (ELEM(shape, PFIELD_SHAPE_SURFACE, PFIELD_SHAPE_POINTS)) { + ComponentKey effector_geometry_key(&effector_relation->ob->id, NodeType::GEOMETRY); + add_relation(effector_geometry_key, rb_init_key, "RigidBody Field"); + } + } + } + /* Objects. */ + if (rbw->group != NULL) { + build_collection(NULL, NULL, rbw->group); + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, object) { + if (object->type != OB_MESH) { + continue; + } + OperationKey rb_transform_copy_key( + &object->id, NodeType::TRANSFORM, OperationCode::RIGIDBODY_TRANSFORM_COPY); + /* Rigid body synchronization depends on the actual simulation. */ + add_relation(rb_simulate_key, rb_transform_copy_key, "Rigidbody Sim Eval -> RBO Sync"); + /* Simulation uses object transformation after parenting and solving + * contraints. */ + OperationKey object_transform_simulation_init_key( + &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_SIMULATION_INIT); + OperationKey object_transform_eval_key( + &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL); + add_relation(object_transform_simulation_init_key, + rb_simulate_key, + "Object Transform -> Rigidbody Sim Eval"); + /* Geometry must be known to create the rigid body. RBO_MESH_BASE + * uses the non-evaluated mesh, so then the evaluation is + * unnecessary. */ + if (object->rigidbody_object != NULL && + object->rigidbody_object->mesh_source != RBO_MESH_BASE) { + /* NOTE: We prefer this relation to be never killed, to avoid + * access partially evaluated mesh from solver. */ + ComponentKey object_geometry_key(&object->id, NodeType::GEOMETRY); + add_relation(object_geometry_key, + rb_simulate_key, + "Object Geom Eval -> Rigidbody Rebuild", + RELATION_FLAG_GODMODE); + } + /* Final transform is whetever solver gave to us. */ + OperationKey object_transform_final_key( + &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_FINAL); + add_relation( + rb_transform_copy_key, object_transform_final_key, "Rigidbody Sync -> Transform Final"); + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + } + /* Constraints. */ + if (rbw->constraints != NULL) { + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->constraints, object) { + RigidBodyCon *rbc = object->rigidbody_constraint; + if (rbc == NULL || rbc->ob1 == NULL || rbc->ob2 == NULL) { + /* When either ob1 or ob2 is NULL, the constraint doesn't + * work. */ + continue; + } + /* Make sure indirectly linked objects are fully built. */ + build_object(NULL, object); + build_object(NULL, rbc->ob1); + build_object(NULL, rbc->ob2); + /* final result of the constraint object's transform controls how + * the constraint affects the physics sim for these objects. */ + ComponentKey trans_key(&object->id, NodeType::TRANSFORM); + OperationKey ob1_key( + &rbc->ob1->id, NodeType::TRANSFORM, OperationCode::RIGIDBODY_TRANSFORM_COPY); + OperationKey ob2_key( + &rbc->ob2->id, NodeType::TRANSFORM, OperationCode::RIGIDBODY_TRANSFORM_COPY); + /* Constrained-objects sync depends on the constraint-holder. */ + add_relation(trans_key, ob1_key, "RigidBodyConstraint -> RBC.Object_1"); + add_relation(trans_key, ob2_key, "RigidBodyConstraint -> RBC.Object_2"); + /* Ensure that sim depends on this constraint's transform. */ + add_relation(trans_key, rb_simulate_key, "RigidBodyConstraint Transform -> RB Simulation"); + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + } } void DepsgraphRelationBuilder::build_particle_systems(Object *object) { - TimeSourceKey time_src_key; - OperationKey obdata_ubereval_key(&object->id, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL); - OperationKey eval_init_key(&object->id, - NodeType::PARTICLE_SYSTEM, - OperationCode::PARTICLE_SYSTEM_INIT); - OperationKey eval_done_key(&object->id, - NodeType::PARTICLE_SYSTEM, - OperationCode::PARTICLE_SYSTEM_DONE); - ComponentKey eval_key(&object->id, NodeType::PARTICLE_SYSTEM); - if (BKE_ptcache_object_has(scene_, object, 0)) { - ComponentKey point_cache_key(&object->id, NodeType::POINT_CACHE); - add_relation(eval_key, - point_cache_key, - "Particle Point Cache", - RELATION_FLAG_FLUSH_USER_EDIT_ONLY); - } - /* Particle systems. */ - LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) { - ParticleSettings *part = psys->part; - /* Build particle settings relations. - * NOTE: The call itself ensures settings are only build once. */ - build_particle_settings(part); - /* This particle system. */ - OperationKey psys_key(&object->id, - NodeType::PARTICLE_SYSTEM, - OperationCode::PARTICLE_SYSTEM_EVAL, - psys->name); - /* Update particle system when settings changes. */ - OperationKey particle_settings_key(&part->id, - NodeType::PARTICLE_SETTINGS, - OperationCode::PARTICLE_SETTINGS_EVAL); - add_relation(particle_settings_key, - eval_init_key, - "Particle Settings Change"); - add_relation(eval_init_key, psys_key, "Init -> PSys"); - add_relation(psys_key, eval_done_key, "PSys -> Done"); - /* TODO(sergey): Currently particle update is just a placeholder, - * hook it to the ubereval node so particle system is getting updated - * on playback. */ - add_relation(psys_key, obdata_ubereval_key, "PSys -> UberEval"); - /* Collisions. */ - if (part->type != PART_HAIR) { - add_particle_collision_relations(psys_key, - object, - part->collision_group, - "Particle Collision"); - } - else if ((psys->flag & PSYS_HAIR_DYNAMICS) && - psys->clmd != NULL && - psys->clmd->coll_parms != NULL) - { - add_particle_collision_relations(psys_key, - object, - psys->clmd->coll_parms->group, - "Hair Collision"); - } - /* Effectors. */ - add_particle_forcefield_relations(psys_key, - object, - psys, - part->effector_weights, - part->type == PART_HAIR, - "Particle Field"); - /* Boids .*/ - if (part->boids != NULL) { - LISTBASE_FOREACH (BoidState *, state, &part->boids->states) { - LISTBASE_FOREACH (BoidRule *, rule, &state->rules) { - Object *ruleob = NULL; - if (rule->type == eBoidRuleType_Avoid) { - ruleob = ((BoidRuleGoalAvoid *)rule)->ob; - } - else if (rule->type == eBoidRuleType_FollowLeader) { - ruleob = ((BoidRuleFollowLeader *)rule)->ob; - } - if (ruleob != NULL) { - ComponentKey ruleob_key(&ruleob->id, - NodeType::TRANSFORM); - add_relation(ruleob_key, psys_key, "Boid Rule"); - } - } - } - } - /* Keyed particle targets. */ - if (part->phystype == PART_PHYS_KEYED) { - LISTBASE_FOREACH (ParticleTarget *, particle_target, &psys->targets) { - if (particle_target->ob == NULL || - particle_target->ob == object) - { - continue; - } - /* Make sure target object is pulled into the graph. */ - build_object(NULL, particle_target->ob); - /* Use geometry component, since that's where particles are - * actually evaluated. */ - ComponentKey target_key(&particle_target->ob->id, - NodeType::GEOMETRY); - add_relation(target_key, psys_key, "Keyed Target"); - } - } - /* Visualization. */ - switch (part->ren_as) { - case PART_DRAW_OB: - if (part->instance_object != NULL) { - /* Make sure object's relations are all built. */ - build_object(NULL, part->instance_object); - /* Build relation for the particle visualization. */ - build_particle_system_visualization_object( - object, psys, part->instance_object); - } - break; - case PART_DRAW_GR: - if (part->instance_collection != NULL) { - build_collection(NULL, NULL, part->instance_collection); - LISTBASE_FOREACH (CollectionObject *, go, &part->instance_collection->gobject) { - build_particle_system_visualization_object( - object, psys, go->ob); - } - } - break; - } - } - /* Particle depends on the object transform, so that channel is to be ready - * first. */ - add_depends_on_transform_relation( - &object->id, obdata_ubereval_key, "Particle Eval"); + TimeSourceKey time_src_key; + OperationKey obdata_ubereval_key(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); + OperationKey eval_init_key( + &object->id, NodeType::PARTICLE_SYSTEM, OperationCode::PARTICLE_SYSTEM_INIT); + OperationKey eval_done_key( + &object->id, NodeType::PARTICLE_SYSTEM, OperationCode::PARTICLE_SYSTEM_DONE); + ComponentKey eval_key(&object->id, NodeType::PARTICLE_SYSTEM); + if (BKE_ptcache_object_has(scene_, object, 0)) { + ComponentKey point_cache_key(&object->id, NodeType::POINT_CACHE); + add_relation( + eval_key, point_cache_key, "Particle Point Cache", RELATION_FLAG_FLUSH_USER_EDIT_ONLY); + } + /* Particle systems. */ + LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) { + ParticleSettings *part = psys->part; + /* Build particle settings relations. + * NOTE: The call itself ensures settings are only build once. */ + build_particle_settings(part); + /* This particle system. */ + OperationKey psys_key( + &object->id, NodeType::PARTICLE_SYSTEM, OperationCode::PARTICLE_SYSTEM_EVAL, psys->name); + /* Update particle system when settings changes. */ + OperationKey particle_settings_key( + &part->id, NodeType::PARTICLE_SETTINGS, OperationCode::PARTICLE_SETTINGS_EVAL); + add_relation(particle_settings_key, eval_init_key, "Particle Settings Change"); + add_relation(eval_init_key, psys_key, "Init -> PSys"); + add_relation(psys_key, eval_done_key, "PSys -> Done"); + /* TODO(sergey): Currently particle update is just a placeholder, + * hook it to the ubereval node so particle system is getting updated + * on playback. */ + add_relation(psys_key, obdata_ubereval_key, "PSys -> UberEval"); + /* Collisions. */ + if (part->type != PART_HAIR) { + add_particle_collision_relations( + psys_key, object, part->collision_group, "Particle Collision"); + } + else if ((psys->flag & PSYS_HAIR_DYNAMICS) && psys->clmd != NULL && + psys->clmd->coll_parms != NULL) { + add_particle_collision_relations( + psys_key, object, psys->clmd->coll_parms->group, "Hair Collision"); + } + /* Effectors. */ + add_particle_forcefield_relations( + psys_key, object, psys, part->effector_weights, part->type == PART_HAIR, "Particle Field"); + /* Boids .*/ + if (part->boids != NULL) { + LISTBASE_FOREACH (BoidState *, state, &part->boids->states) { + LISTBASE_FOREACH (BoidRule *, rule, &state->rules) { + Object *ruleob = NULL; + if (rule->type == eBoidRuleType_Avoid) { + ruleob = ((BoidRuleGoalAvoid *)rule)->ob; + } + else if (rule->type == eBoidRuleType_FollowLeader) { + ruleob = ((BoidRuleFollowLeader *)rule)->ob; + } + if (ruleob != NULL) { + ComponentKey ruleob_key(&ruleob->id, NodeType::TRANSFORM); + add_relation(ruleob_key, psys_key, "Boid Rule"); + } + } + } + } + /* Keyed particle targets. */ + if (part->phystype == PART_PHYS_KEYED) { + LISTBASE_FOREACH (ParticleTarget *, particle_target, &psys->targets) { + if (particle_target->ob == NULL || particle_target->ob == object) { + continue; + } + /* Make sure target object is pulled into the graph. */ + build_object(NULL, particle_target->ob); + /* Use geometry component, since that's where particles are + * actually evaluated. */ + ComponentKey target_key(&particle_target->ob->id, NodeType::GEOMETRY); + add_relation(target_key, psys_key, "Keyed Target"); + } + } + /* Visualization. */ + switch (part->ren_as) { + case PART_DRAW_OB: + if (part->instance_object != NULL) { + /* Make sure object's relations are all built. */ + build_object(NULL, part->instance_object); + /* Build relation for the particle visualization. */ + build_particle_system_visualization_object(object, psys, part->instance_object); + } + break; + case PART_DRAW_GR: + if (part->instance_collection != NULL) { + build_collection(NULL, NULL, part->instance_collection); + LISTBASE_FOREACH (CollectionObject *, go, &part->instance_collection->gobject) { + build_particle_system_visualization_object(object, psys, go->ob); + } + } + break; + } + } + /* Particle depends on the object transform, so that channel is to be ready + * first. */ + add_depends_on_transform_relation(&object->id, obdata_ubereval_key, "Particle Eval"); } void DepsgraphRelationBuilder::build_particle_settings(ParticleSettings *part) { - if (built_map_.checkIsBuiltAndTag(part)) { - return; - } - /* Animation data relations. */ - build_animdata(&part->id); - build_parameters(&part->id); - OperationKey particle_settings_init_key(&part->id, - NodeType::PARTICLE_SETTINGS, - OperationCode::PARTICLE_SETTINGS_INIT); - OperationKey particle_settings_eval_key(&part->id, - NodeType::PARTICLE_SETTINGS, - OperationCode::PARTICLE_SETTINGS_EVAL); - OperationKey particle_settings_reset_key( - &part->id, - NodeType::PARTICLE_SETTINGS, - OperationCode::PARTICLE_SETTINGS_RESET); - add_relation(particle_settings_init_key, - particle_settings_eval_key, - "Particle Settings Init Order"); - add_relation(particle_settings_reset_key, - particle_settings_eval_key, - "Particle Settings Reset"); - /* Texture slots. */ - for (int mtex_index = 0; mtex_index < MAX_MTEX; ++mtex_index) { - MTex *mtex = part->mtex[mtex_index]; - if (mtex == NULL || mtex->tex == NULL) { - continue; - } - build_texture(mtex->tex); - ComponentKey texture_key(&mtex->tex->id, - NodeType::GENERIC_DATABLOCK); - add_relation(texture_key, - particle_settings_reset_key, - "Particle Texture", - RELATION_FLAG_FLUSH_USER_EDIT_ONLY); - /* TODO(sergey): Consider moving texture space handling to an own - * function. */ - if (mtex->texco == TEXCO_OBJECT && mtex->object != NULL) { - ComponentKey object_key(&mtex->object->id, NodeType::TRANSFORM); - add_relation(object_key, - particle_settings_eval_key, - "Particle Texture Space"); - } - } - if (check_id_has_anim_component(&part->id)) { - ComponentKey animation_key(&part->id, NodeType::ANIMATION); - add_relation(animation_key, - particle_settings_eval_key, - "Particle Settings Animation"); - } -} - -void DepsgraphRelationBuilder::build_particle_system_visualization_object( - Object *object, - ParticleSystem *psys, - Object *draw_object) -{ - OperationKey psys_key(&object->id, - NodeType::PARTICLE_SYSTEM, - OperationCode::PARTICLE_SYSTEM_EVAL, - psys->name); - OperationKey obdata_ubereval_key(&object->id, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL); - ComponentKey dup_ob_key(&draw_object->id, NodeType::TRANSFORM); - add_relation(dup_ob_key, psys_key, "Particle Object Visualization"); - if (draw_object->type == OB_MBALL) { - ComponentKey dup_geometry_key(&draw_object->id, NodeType::GEOMETRY); - add_relation(obdata_ubereval_key, - dup_geometry_key, - "Particle MBall Visualization"); - } + if (built_map_.checkIsBuiltAndTag(part)) { + return; + } + /* Animation data relations. */ + build_animdata(&part->id); + build_parameters(&part->id); + OperationKey particle_settings_init_key( + &part->id, NodeType::PARTICLE_SETTINGS, OperationCode::PARTICLE_SETTINGS_INIT); + OperationKey particle_settings_eval_key( + &part->id, NodeType::PARTICLE_SETTINGS, OperationCode::PARTICLE_SETTINGS_EVAL); + OperationKey particle_settings_reset_key( + &part->id, NodeType::PARTICLE_SETTINGS, OperationCode::PARTICLE_SETTINGS_RESET); + add_relation( + particle_settings_init_key, particle_settings_eval_key, "Particle Settings Init Order"); + add_relation(particle_settings_reset_key, particle_settings_eval_key, "Particle Settings Reset"); + /* Texture slots. */ + for (int mtex_index = 0; mtex_index < MAX_MTEX; ++mtex_index) { + MTex *mtex = part->mtex[mtex_index]; + if (mtex == NULL || mtex->tex == NULL) { + continue; + } + build_texture(mtex->tex); + ComponentKey texture_key(&mtex->tex->id, NodeType::GENERIC_DATABLOCK); + add_relation(texture_key, + particle_settings_reset_key, + "Particle Texture", + RELATION_FLAG_FLUSH_USER_EDIT_ONLY); + /* TODO(sergey): Consider moving texture space handling to an own + * function. */ + if (mtex->texco == TEXCO_OBJECT && mtex->object != NULL) { + ComponentKey object_key(&mtex->object->id, NodeType::TRANSFORM); + add_relation(object_key, particle_settings_eval_key, "Particle Texture Space"); + } + } + if (check_id_has_anim_component(&part->id)) { + ComponentKey animation_key(&part->id, NodeType::ANIMATION); + add_relation(animation_key, particle_settings_eval_key, "Particle Settings Animation"); + } +} + +void DepsgraphRelationBuilder::build_particle_system_visualization_object(Object *object, + ParticleSystem *psys, + Object *draw_object) +{ + OperationKey psys_key( + &object->id, NodeType::PARTICLE_SYSTEM, OperationCode::PARTICLE_SYSTEM_EVAL, psys->name); + OperationKey obdata_ubereval_key(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); + ComponentKey dup_ob_key(&draw_object->id, NodeType::TRANSFORM); + add_relation(dup_ob_key, psys_key, "Particle Object Visualization"); + if (draw_object->type == OB_MBALL) { + ComponentKey dup_geometry_key(&draw_object->id, NodeType::GEOMETRY); + add_relation(obdata_ubereval_key, dup_geometry_key, "Particle MBall Visualization"); + } } /* Shapekeys */ void DepsgraphRelationBuilder::build_shapekeys(Key *key) { - if (built_map_.checkIsBuiltAndTag(key)) { - return; - } - /* Attach animdata to geometry. */ - build_animdata(&key->id); - build_parameters(&key->id); - /* Connect all blocks properties to the final result evaluation. */ - ComponentKey geometry_key(&key->id, NodeType::GEOMETRY); - OperationKey parameters_eval_key(&key->id, - NodeType::PARAMETERS, - OperationCode::PARAMETERS_EVAL); - LISTBASE_FOREACH (KeyBlock *, key_block, &key->block) { - OperationKey key_block_key(&key->id, - NodeType::PARAMETERS, - OperationCode::PARAMETERS_EVAL, - key_block->name); - add_relation(key_block_key, geometry_key, "Key Block Properties"); - add_relation(key_block_key, parameters_eval_key, "Key Block Properties"); - } + if (built_map_.checkIsBuiltAndTag(key)) { + return; + } + /* Attach animdata to geometry. */ + build_animdata(&key->id); + build_parameters(&key->id); + /* Connect all blocks properties to the final result evaluation. */ + ComponentKey geometry_key(&key->id, NodeType::GEOMETRY); + OperationKey parameters_eval_key(&key->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL); + LISTBASE_FOREACH (KeyBlock *, key_block, &key->block) { + OperationKey key_block_key( + &key->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, key_block->name); + add_relation(key_block_key, geometry_key, "Key Block Properties"); + add_relation(key_block_key, parameters_eval_key, "Key Block Properties"); + } } /** @@ -2092,535 +1827,475 @@ void DepsgraphRelationBuilder::build_shapekeys(Key *key) * downstream re-evaluation of the individual instances of this geometry. */ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object) { - ID *obdata = (ID *)object->data; - /* Init operation of object-level geometry evaluation. */ - OperationKey geom_init_key(&object->id, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL_INIT); - /* Get nodes for result of obdata's evaluation, and geometry evaluation - * on object. */ - ComponentKey obdata_geom_key(obdata, NodeType::GEOMETRY); - ComponentKey geom_key(&object->id, NodeType::GEOMETRY); - /* Link components to each other. */ - add_relation(obdata_geom_key, geom_key, "Object Geometry Base Data"); - OperationKey obdata_ubereval_key(&object->id, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL); - /* Special case: modifiers evaluation queries scene for various things like - * data mask to be used. We add relation here to ensure object is never - * evaluated prior to Scene's CoW is ready. */ - OperationKey scene_key(&scene_->id, - NodeType::LAYER_COLLECTIONS, - OperationCode::VIEW_LAYER_EVAL); - Relation *rel = add_relation(scene_key, obdata_ubereval_key, "CoW Relation"); - rel->flag |= RELATION_FLAG_NO_FLUSH; - /* Modifiers */ - if (object->modifiers.first != NULL) { - ModifierUpdateDepsgraphContext ctx = {}; - ctx.scene = scene_; - ctx.object = object; - LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) { - const ModifierTypeInfo *mti = modifierType_getInfo((ModifierType)md->type); - if (mti->updateDepsgraph) { - DepsNodeHandle handle = create_node_handle(obdata_ubereval_key); - ctx.node = reinterpret_cast< ::DepsNodeHandle* >(&handle); - mti->updateDepsgraph(md, &ctx); - } - if (BKE_object_modifier_use_time(object, md)) { - TimeSourceKey time_src_key; - add_relation(time_src_key, obdata_ubereval_key, "Time Source"); - } - } - } - /* Grease Pencil Modifiers. */ - if (object->greasepencil_modifiers.first != NULL) { - ModifierUpdateDepsgraphContext ctx = {}; - ctx.scene = scene_; - ctx.object = object; - LISTBASE_FOREACH (GpencilModifierData *, md, &object->greasepencil_modifiers) { - const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo((GpencilModifierType)md->type); - if (mti->updateDepsgraph) { - DepsNodeHandle handle = create_node_handle(obdata_ubereval_key); - ctx.node = reinterpret_cast< ::DepsNodeHandle* >(&handle); - mti->updateDepsgraph(md, &ctx); - } - if (BKE_object_modifier_gpencil_use_time(object, md)) { - TimeSourceKey time_src_key; - add_relation(time_src_key, obdata_ubereval_key, "Time Source"); - } - } - } - /* Shader FX. */ - if (object->shader_fx.first != NULL) { - ModifierUpdateDepsgraphContext ctx = {}; - ctx.scene = scene_; - ctx.object = object; - LISTBASE_FOREACH (ShaderFxData *, fx, &object->shader_fx) { - const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo((ShaderFxType)fx->type); - if (fxi->updateDepsgraph) { - DepsNodeHandle handle = create_node_handle(obdata_ubereval_key); - ctx.node = reinterpret_cast< ::DepsNodeHandle* >(&handle); - fxi->updateDepsgraph(fx, &ctx); - } - if (BKE_object_shaderfx_use_time(object, fx)) { - TimeSourceKey time_src_key; - add_relation(time_src_key, obdata_ubereval_key, "Time Source"); - } - } - } - /* Materials. */ - if (object->totcol) { - for (int a = 1; a <= object->totcol; a++) { - Material *ma = give_current_material(object, a); - if (ma != NULL) { - build_material(ma); - - if (object->type == OB_MESH) { - OperationKey material_key(&ma->id, - NodeType::SHADING, - OperationCode::MATERIAL_UPDATE); - OperationKey shading_key(&object->id, - NodeType::SHADING, - OperationCode::SHADING); - add_relation(material_key, shading_key, "Material Update"); - } - } - } - } - /* Geometry collision. */ - if (ELEM(object->type, OB_MESH, OB_CURVE, OB_LATTICE)) { - // add geometry collider relations - } - /* Make sure uber update is the last in the dependencies. */ - if (object->type != OB_ARMATURE) { - /* Armatures does no longer require uber node. */ - OperationKey obdata_ubereval_key(&object->id, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL); - add_relation(geom_init_key, - obdata_ubereval_key, - "Object Geometry UberEval"); - if (object->totcol != 0 && object->type == OB_MESH) { - ComponentKey object_shading_key(&object->id, NodeType::SHADING); - Relation *rel = add_relation(obdata_ubereval_key, - object_shading_key, - "Object Geometry batch Update"); - rel->flag |= RELATION_FLAG_NO_FLUSH; - } - } - if (object->type == OB_MBALL) { - Object *mom = BKE_mball_basis_find(scene_, object); - ComponentKey mom_geom_key(&mom->id, NodeType::GEOMETRY); - /* motherball - mom depends on children! */ - if (mom == object) { - ComponentKey mom_transform_key(&mom->id, - NodeType::TRANSFORM); - add_relation(mom_transform_key, - mom_geom_key, - "Metaball Motherball Transform -> Geometry"); - } - else { - ComponentKey transform_key(&object->id, NodeType::TRANSFORM); - add_relation(geom_key, mom_geom_key, "Metaball Motherball"); - add_relation(transform_key, mom_geom_key, "Metaball Motherball"); - } - } - /* NOTE: This is compatibility code to support particle systems - * - * for viewport being properly rendered in final render mode. - * This relation is similar to what dag_object_time_update_flags() - * was doing for mesh objects with particle system. - * - * Ideally we need to get rid of this relation. */ - if (object_particles_depends_on_time(object)) { - TimeSourceKey time_key; - OperationKey obdata_ubereval_key(&object->id, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL); - add_relation(time_key, obdata_ubereval_key, "Legacy particle time"); - } - /* Object data datablock. */ - build_object_data_geometry_datablock((ID *)object->data); - Key *key = BKE_key_from_object(object); - if (key != NULL) { - if (key->adt != NULL) { - if (key->adt->action || key->adt->nla_tracks.first) { - ComponentKey obdata_key((ID *)object->data, - NodeType::GEOMETRY); - ComponentKey adt_key(&key->id, NodeType::ANIMATION); - add_relation(adt_key, obdata_key, "Animation"); - } - } - } - /* Syncronization back to original object. */ - ComponentKey final_geometry_jey(&object->id, NodeType::GEOMETRY); - OperationKey synchronize_key(&object->id, - NodeType::SYNCHRONIZATION, - OperationCode::SYNCHRONIZE_TO_ORIGINAL); - add_relation( - final_geometry_jey, synchronize_key, "Synchronize to Original"); + ID *obdata = (ID *)object->data; + /* Init operation of object-level geometry evaluation. */ + OperationKey geom_init_key(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT); + /* Get nodes for result of obdata's evaluation, and geometry evaluation + * on object. */ + ComponentKey obdata_geom_key(obdata, NodeType::GEOMETRY); + ComponentKey geom_key(&object->id, NodeType::GEOMETRY); + /* Link components to each other. */ + add_relation(obdata_geom_key, geom_key, "Object Geometry Base Data"); + OperationKey obdata_ubereval_key(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); + /* Special case: modifiers evaluation queries scene for various things like + * data mask to be used. We add relation here to ensure object is never + * evaluated prior to Scene's CoW is ready. */ + OperationKey scene_key(&scene_->id, NodeType::LAYER_COLLECTIONS, OperationCode::VIEW_LAYER_EVAL); + Relation *rel = add_relation(scene_key, obdata_ubereval_key, "CoW Relation"); + rel->flag |= RELATION_FLAG_NO_FLUSH; + /* Modifiers */ + if (object->modifiers.first != NULL) { + ModifierUpdateDepsgraphContext ctx = {}; + ctx.scene = scene_; + ctx.object = object; + LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) { + const ModifierTypeInfo *mti = modifierType_getInfo((ModifierType)md->type); + if (mti->updateDepsgraph) { + DepsNodeHandle handle = create_node_handle(obdata_ubereval_key); + ctx.node = reinterpret_cast<::DepsNodeHandle *>(&handle); + mti->updateDepsgraph(md, &ctx); + } + if (BKE_object_modifier_use_time(object, md)) { + TimeSourceKey time_src_key; + add_relation(time_src_key, obdata_ubereval_key, "Time Source"); + } + } + } + /* Grease Pencil Modifiers. */ + if (object->greasepencil_modifiers.first != NULL) { + ModifierUpdateDepsgraphContext ctx = {}; + ctx.scene = scene_; + ctx.object = object; + LISTBASE_FOREACH (GpencilModifierData *, md, &object->greasepencil_modifiers) { + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo( + (GpencilModifierType)md->type); + if (mti->updateDepsgraph) { + DepsNodeHandle handle = create_node_handle(obdata_ubereval_key); + ctx.node = reinterpret_cast<::DepsNodeHandle *>(&handle); + mti->updateDepsgraph(md, &ctx); + } + if (BKE_object_modifier_gpencil_use_time(object, md)) { + TimeSourceKey time_src_key; + add_relation(time_src_key, obdata_ubereval_key, "Time Source"); + } + } + } + /* Shader FX. */ + if (object->shader_fx.first != NULL) { + ModifierUpdateDepsgraphContext ctx = {}; + ctx.scene = scene_; + ctx.object = object; + LISTBASE_FOREACH (ShaderFxData *, fx, &object->shader_fx) { + const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo((ShaderFxType)fx->type); + if (fxi->updateDepsgraph) { + DepsNodeHandle handle = create_node_handle(obdata_ubereval_key); + ctx.node = reinterpret_cast<::DepsNodeHandle *>(&handle); + fxi->updateDepsgraph(fx, &ctx); + } + if (BKE_object_shaderfx_use_time(object, fx)) { + TimeSourceKey time_src_key; + add_relation(time_src_key, obdata_ubereval_key, "Time Source"); + } + } + } + /* Materials. */ + if (object->totcol) { + for (int a = 1; a <= object->totcol; a++) { + Material *ma = give_current_material(object, a); + if (ma != NULL) { + build_material(ma); + + if (object->type == OB_MESH) { + OperationKey material_key(&ma->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE); + OperationKey shading_key(&object->id, NodeType::SHADING, OperationCode::SHADING); + add_relation(material_key, shading_key, "Material Update"); + } + } + } + } + /* Geometry collision. */ + if (ELEM(object->type, OB_MESH, OB_CURVE, OB_LATTICE)) { + // add geometry collider relations + } + /* Make sure uber update is the last in the dependencies. */ + if (object->type != OB_ARMATURE) { + /* Armatures does no longer require uber node. */ + OperationKey obdata_ubereval_key( + &object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); + add_relation(geom_init_key, obdata_ubereval_key, "Object Geometry UberEval"); + if (object->totcol != 0 && object->type == OB_MESH) { + ComponentKey object_shading_key(&object->id, NodeType::SHADING); + Relation *rel = add_relation( + obdata_ubereval_key, object_shading_key, "Object Geometry batch Update"); + rel->flag |= RELATION_FLAG_NO_FLUSH; + } + } + if (object->type == OB_MBALL) { + Object *mom = BKE_mball_basis_find(scene_, object); + ComponentKey mom_geom_key(&mom->id, NodeType::GEOMETRY); + /* motherball - mom depends on children! */ + if (mom == object) { + ComponentKey mom_transform_key(&mom->id, NodeType::TRANSFORM); + add_relation(mom_transform_key, mom_geom_key, "Metaball Motherball Transform -> Geometry"); + } + else { + ComponentKey transform_key(&object->id, NodeType::TRANSFORM); + add_relation(geom_key, mom_geom_key, "Metaball Motherball"); + add_relation(transform_key, mom_geom_key, "Metaball Motherball"); + } + } + /* NOTE: This is compatibility code to support particle systems + * + * for viewport being properly rendered in final render mode. + * This relation is similar to what dag_object_time_update_flags() + * was doing for mesh objects with particle system. + * + * Ideally we need to get rid of this relation. */ + if (object_particles_depends_on_time(object)) { + TimeSourceKey time_key; + OperationKey obdata_ubereval_key( + &object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); + add_relation(time_key, obdata_ubereval_key, "Legacy particle time"); + } + /* Object data datablock. */ + build_object_data_geometry_datablock((ID *)object->data); + Key *key = BKE_key_from_object(object); + if (key != NULL) { + if (key->adt != NULL) { + if (key->adt->action || key->adt->nla_tracks.first) { + ComponentKey obdata_key((ID *)object->data, NodeType::GEOMETRY); + ComponentKey adt_key(&key->id, NodeType::ANIMATION); + add_relation(adt_key, obdata_key, "Animation"); + } + } + } + /* Syncronization back to original object. */ + ComponentKey final_geometry_jey(&object->id, NodeType::GEOMETRY); + OperationKey synchronize_key( + &object->id, NodeType::SYNCHRONIZATION, OperationCode::SYNCHRONIZE_TO_ORIGINAL); + add_relation(final_geometry_jey, synchronize_key, "Synchronize to Original"); } void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata) { - if (built_map_.checkIsBuiltAndTag(obdata)) { - return; - } - /* Animation. */ - build_animdata(obdata); - build_parameters(obdata); - /* ShapeKeys. */ - Key *key = BKE_key_from_id(obdata); - if (key != NULL) { - build_shapekeys(key); - } - /* Link object data evaluation node to exit operation. */ - OperationKey obdata_geom_eval_key( - obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); - OperationKey obdata_geom_done_key(obdata, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL_DONE); - add_relation(obdata_geom_eval_key, - obdata_geom_done_key, - "ObData Geom Eval Done"); - /* Type-specific links. */ - const ID_Type id_type = GS(obdata->name); - switch (id_type) { - case ID_ME: - break; - case ID_MB: - break; - case ID_CU: - { - Curve *cu = (Curve *)obdata; - if (cu->bevobj != NULL) { - ComponentKey bevob_geom_key( - &cu->bevobj->id, - NodeType::GEOMETRY); - add_relation( - bevob_geom_key, - obdata_geom_eval_key, - "Curve Bevel Geometry"); - ComponentKey bevob_key( - &cu->bevobj->id, - NodeType::TRANSFORM); - add_relation( - bevob_key, - obdata_geom_eval_key, - "Curve Bevel Transform"); - build_object(NULL, cu->bevobj); - } - if (cu->taperobj != NULL) { - ComponentKey taperob_key( - &cu->taperobj->id, - NodeType::GEOMETRY); - add_relation(taperob_key, obdata_geom_eval_key, "Curve Taper"); - build_object(NULL, cu->taperobj); - } - if (cu->textoncurve != NULL) { - ComponentKey textoncurve_key( - &cu->textoncurve->id, - NodeType::GEOMETRY); - add_relation( - textoncurve_key, - obdata_geom_eval_key, - "Text on Curve"); - build_object(NULL, cu->textoncurve); - } - break; - } - case ID_LT: - break; - case ID_GD: /* Grease Pencil */ - { - bGPdata *gpd = (bGPdata *)obdata; - - /* Geometry cache needs to be recalculated on frame change - * (e.g. to fix crashes after scrubbing the timeline when - * onion skinning is enabled, since the ghosts need to be - * re-added to the cache once scrubbing ends). */ - TimeSourceKey time_key; - ComponentKey geometry_key(obdata, NodeType::GEOMETRY); - add_relation(time_key, - geometry_key, - "GP Frame Change"); - - /* Geometry cache also needs to be recalculated when Material - * settings change (e.g. when fill.opacity changes on/off, - * we need to rebuild the bGPDstroke->triangles caches). */ - for (int i = 0; i < gpd->totcol; i++) { - Material *ma = gpd->mat[i]; - if ((ma != NULL) && (ma->gp_style != NULL)) { - OperationKey material_key(&ma->id, - NodeType::SHADING, - OperationCode::MATERIAL_UPDATE); - add_relation(material_key, - geometry_key, - "Material -> GP Data"); - } - } - break; - } - default: - BLI_assert(!"Should not happen"); - break; - } + if (built_map_.checkIsBuiltAndTag(obdata)) { + return; + } + /* Animation. */ + build_animdata(obdata); + build_parameters(obdata); + /* ShapeKeys. */ + Key *key = BKE_key_from_id(obdata); + if (key != NULL) { + build_shapekeys(key); + } + /* Link object data evaluation node to exit operation. */ + OperationKey obdata_geom_eval_key(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); + OperationKey obdata_geom_done_key(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_DONE); + add_relation(obdata_geom_eval_key, obdata_geom_done_key, "ObData Geom Eval Done"); + /* Type-specific links. */ + const ID_Type id_type = GS(obdata->name); + switch (id_type) { + case ID_ME: + break; + case ID_MB: + break; + case ID_CU: { + Curve *cu = (Curve *)obdata; + if (cu->bevobj != NULL) { + ComponentKey bevob_geom_key(&cu->bevobj->id, NodeType::GEOMETRY); + add_relation(bevob_geom_key, obdata_geom_eval_key, "Curve Bevel Geometry"); + ComponentKey bevob_key(&cu->bevobj->id, NodeType::TRANSFORM); + add_relation(bevob_key, obdata_geom_eval_key, "Curve Bevel Transform"); + build_object(NULL, cu->bevobj); + } + if (cu->taperobj != NULL) { + ComponentKey taperob_key(&cu->taperobj->id, NodeType::GEOMETRY); + add_relation(taperob_key, obdata_geom_eval_key, "Curve Taper"); + build_object(NULL, cu->taperobj); + } + if (cu->textoncurve != NULL) { + ComponentKey textoncurve_key(&cu->textoncurve->id, NodeType::GEOMETRY); + add_relation(textoncurve_key, obdata_geom_eval_key, "Text on Curve"); + build_object(NULL, cu->textoncurve); + } + break; + } + case ID_LT: + break; + case ID_GD: /* Grease Pencil */ + { + bGPdata *gpd = (bGPdata *)obdata; + + /* Geometry cache needs to be recalculated on frame change + * (e.g. to fix crashes after scrubbing the timeline when + * onion skinning is enabled, since the ghosts need to be + * re-added to the cache once scrubbing ends). */ + TimeSourceKey time_key; + ComponentKey geometry_key(obdata, NodeType::GEOMETRY); + add_relation(time_key, geometry_key, "GP Frame Change"); + + /* Geometry cache also needs to be recalculated when Material + * settings change (e.g. when fill.opacity changes on/off, + * we need to rebuild the bGPDstroke->triangles caches). */ + for (int i = 0; i < gpd->totcol; i++) { + Material *ma = gpd->mat[i]; + if ((ma != NULL) && (ma->gp_style != NULL)) { + OperationKey material_key(&ma->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE); + add_relation(material_key, geometry_key, "Material -> GP Data"); + } + } + break; + } + default: + BLI_assert(!"Should not happen"); + break; + } } void DepsgraphRelationBuilder::build_armature(bArmature *armature) { - if (built_map_.checkIsBuiltAndTag(armature)) { - return; - } - build_animdata(&armature->id); - build_parameters(&armature->id); + if (built_map_.checkIsBuiltAndTag(armature)) { + return; + } + build_animdata(&armature->id); + build_parameters(&armature->id); } void DepsgraphRelationBuilder::build_camera(Camera *camera) { - if (built_map_.checkIsBuiltAndTag(camera)) { - return; - } - build_parameters(&camera->id); - if (camera->dof_ob != NULL) { - ComponentKey camera_parameters_key(&camera->id, NodeType::PARAMETERS); - ComponentKey dof_ob_key(&camera->dof_ob->id, NodeType::TRANSFORM); - add_relation(dof_ob_key, camera_parameters_key, "Camera DOF"); - } + if (built_map_.checkIsBuiltAndTag(camera)) { + return; + } + build_parameters(&camera->id); + if (camera->dof_ob != NULL) { + ComponentKey camera_parameters_key(&camera->id, NodeType::PARAMETERS); + ComponentKey dof_ob_key(&camera->dof_ob->id, NodeType::TRANSFORM); + add_relation(dof_ob_key, camera_parameters_key, "Camera DOF"); + } } /* Lights */ void DepsgraphRelationBuilder::build_light(Light *lamp) { - if (built_map_.checkIsBuiltAndTag(lamp)) { - return; - } - build_parameters(&lamp->id); - /* light's nodetree */ - if (lamp->nodetree != NULL) { - build_nodetree(lamp->nodetree); - ComponentKey lamp_parameters_key(&lamp->id, NodeType::PARAMETERS); - ComponentKey nodetree_key(&lamp->nodetree->id, NodeType::SHADING); - add_relation(nodetree_key, lamp_parameters_key, "NTree->Light Parameters"); - build_nested_nodetree(&lamp->id, lamp->nodetree); - } + if (built_map_.checkIsBuiltAndTag(lamp)) { + return; + } + build_parameters(&lamp->id); + /* light's nodetree */ + if (lamp->nodetree != NULL) { + build_nodetree(lamp->nodetree); + ComponentKey lamp_parameters_key(&lamp->id, NodeType::PARAMETERS); + ComponentKey nodetree_key(&lamp->nodetree->id, NodeType::SHADING); + add_relation(nodetree_key, lamp_parameters_key, "NTree->Light Parameters"); + build_nested_nodetree(&lamp->id, lamp->nodetree); + } } void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree) { - if (ntree == NULL) { - return; - } - if (built_map_.checkIsBuiltAndTag(ntree)) { - return; - } - build_animdata(&ntree->id); - build_parameters(&ntree->id); - ComponentKey shading_key(&ntree->id, NodeType::SHADING); - /* nodetree's nodes... */ - LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) { - ID *id = bnode->id; - if (id == NULL) { - continue; - } - ID_Type id_type = GS(id->name); - if (id_type == ID_MA) { - build_material((Material *)bnode->id); - } - else if (id_type == ID_TE) { - build_texture((Tex *)bnode->id); - } - else if (id_type == ID_IM) { - build_image((Image *)bnode->id); - } - else if (id_type == ID_OB) { - build_object(NULL, (Object *)id); - } - else if (id_type == ID_SCE) { - /* Scenes are used by compositor trees, and handled by render - * pipeline. No need to build dependencies for them here. */ - } - else if (id_type == ID_TXT) { - /* Ignore script nodes. */ - } - else if (id_type == ID_MSK) { - build_mask((Mask *)id); - } - else if (id_type == ID_MC) { - build_movieclip((MovieClip *)id); - } - else if (ELEM(bnode->type, NODE_GROUP, NODE_CUSTOM_GROUP)) { - bNodeTree *group_ntree = (bNodeTree *)id; - build_nodetree(group_ntree); - ComponentKey group_shading_key(&group_ntree->id, - NodeType::SHADING); - add_relation(group_shading_key, shading_key, "Group Node"); - } - else { - BLI_assert(!"Unknown ID type used for node"); - } - } - - OperationKey shading_update_key(&ntree->id, - NodeType::SHADING, - OperationCode::MATERIAL_UPDATE); - OperationKey shading_parameters_key(&ntree->id, - NodeType::SHADING_PARAMETERS, - OperationCode::MATERIAL_UPDATE); - add_relation(shading_parameters_key, shading_update_key, "NTree Shading Parameters"); - - if (check_id_has_anim_component(&ntree->id)) { - ComponentKey animation_key(&ntree->id, NodeType::ANIMATION); - add_relation(animation_key, shading_parameters_key, "NTree Shading Parameters"); - } - ComponentKey parameters_key(&ntree->id, NodeType::PARAMETERS); - add_relation(parameters_key, shading_parameters_key, "NTree Shading Parameters"); + if (ntree == NULL) { + return; + } + if (built_map_.checkIsBuiltAndTag(ntree)) { + return; + } + build_animdata(&ntree->id); + build_parameters(&ntree->id); + ComponentKey shading_key(&ntree->id, NodeType::SHADING); + /* nodetree's nodes... */ + LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) { + ID *id = bnode->id; + if (id == NULL) { + continue; + } + ID_Type id_type = GS(id->name); + if (id_type == ID_MA) { + build_material((Material *)bnode->id); + } + else if (id_type == ID_TE) { + build_texture((Tex *)bnode->id); + } + else if (id_type == ID_IM) { + build_image((Image *)bnode->id); + } + else if (id_type == ID_OB) { + build_object(NULL, (Object *)id); + } + else if (id_type == ID_SCE) { + /* Scenes are used by compositor trees, and handled by render + * pipeline. No need to build dependencies for them here. */ + } + else if (id_type == ID_TXT) { + /* Ignore script nodes. */ + } + else if (id_type == ID_MSK) { + build_mask((Mask *)id); + } + else if (id_type == ID_MC) { + build_movieclip((MovieClip *)id); + } + else if (ELEM(bnode->type, NODE_GROUP, NODE_CUSTOM_GROUP)) { + bNodeTree *group_ntree = (bNodeTree *)id; + build_nodetree(group_ntree); + ComponentKey group_shading_key(&group_ntree->id, NodeType::SHADING); + add_relation(group_shading_key, shading_key, "Group Node"); + } + else { + BLI_assert(!"Unknown ID type used for node"); + } + } + + OperationKey shading_update_key(&ntree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE); + OperationKey shading_parameters_key( + &ntree->id, NodeType::SHADING_PARAMETERS, OperationCode::MATERIAL_UPDATE); + add_relation(shading_parameters_key, shading_update_key, "NTree Shading Parameters"); + + if (check_id_has_anim_component(&ntree->id)) { + ComponentKey animation_key(&ntree->id, NodeType::ANIMATION); + add_relation(animation_key, shading_parameters_key, "NTree Shading Parameters"); + } + ComponentKey parameters_key(&ntree->id, NodeType::PARAMETERS); + add_relation(parameters_key, shading_parameters_key, "NTree Shading Parameters"); } /* Recursively build graph for material */ void DepsgraphRelationBuilder::build_material(Material *material) { - if (built_map_.checkIsBuiltAndTag(material)) { - return; - } - /* animation */ - build_animdata(&material->id); - build_parameters(&material->id); - /* material's nodetree */ - if (material->nodetree != NULL) { - build_nodetree(material->nodetree); - OperationKey ntree_key(&material->nodetree->id, - NodeType::SHADING, - OperationCode::MATERIAL_UPDATE); - OperationKey material_key(&material->id, - NodeType::SHADING, - OperationCode::MATERIAL_UPDATE); - add_relation(ntree_key, material_key, "Material's NTree"); - build_nested_nodetree(&material->id, material->nodetree); - } + if (built_map_.checkIsBuiltAndTag(material)) { + return; + } + /* animation */ + build_animdata(&material->id); + build_parameters(&material->id); + /* material's nodetree */ + if (material->nodetree != NULL) { + build_nodetree(material->nodetree); + OperationKey ntree_key( + &material->nodetree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE); + OperationKey material_key(&material->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE); + add_relation(ntree_key, material_key, "Material's NTree"); + build_nested_nodetree(&material->id, material->nodetree); + } } /* Recursively build graph for texture */ void DepsgraphRelationBuilder::build_texture(Tex *texture) { - if (built_map_.checkIsBuiltAndTag(texture)) { - return; - } - /* texture itself */ - build_animdata(&texture->id); - build_parameters(&texture->id); - /* texture's nodetree */ - build_nodetree(texture->nodetree); - /* Special cases for different IDs which texture uses. */ - if (texture->type == TEX_IMAGE) { - if (texture->ima != NULL) { - build_image(texture->ima); - } - } - build_nested_nodetree(&texture->id, texture->nodetree); - if (check_id_has_anim_component(&texture->id)) { - ComponentKey animation_key(&texture->id, NodeType::ANIMATION); - ComponentKey datablock_key(&texture->id, - NodeType::GENERIC_DATABLOCK); - add_relation(animation_key, datablock_key, "Datablock Animation"); - } + if (built_map_.checkIsBuiltAndTag(texture)) { + return; + } + /* texture itself */ + build_animdata(&texture->id); + build_parameters(&texture->id); + /* texture's nodetree */ + build_nodetree(texture->nodetree); + /* Special cases for different IDs which texture uses. */ + if (texture->type == TEX_IMAGE) { + if (texture->ima != NULL) { + build_image(texture->ima); + } + } + build_nested_nodetree(&texture->id, texture->nodetree); + if (check_id_has_anim_component(&texture->id)) { + ComponentKey animation_key(&texture->id, NodeType::ANIMATION); + ComponentKey datablock_key(&texture->id, NodeType::GENERIC_DATABLOCK); + add_relation(animation_key, datablock_key, "Datablock Animation"); + } } void DepsgraphRelationBuilder::build_image(Image *image) { - if (built_map_.checkIsBuiltAndTag(image)) { - return; - } - build_parameters(&image->id); + if (built_map_.checkIsBuiltAndTag(image)) { + return; + } + build_parameters(&image->id); } void DepsgraphRelationBuilder::build_compositor(Scene *scene) { - /* For now, just a plain wrapper? */ - build_nodetree(scene->nodetree); + /* For now, just a plain wrapper? */ + build_nodetree(scene->nodetree); } void DepsgraphRelationBuilder::build_gpencil(bGPdata *gpd) { - if (built_map_.checkIsBuiltAndTag(gpd)) { - return; - } - /* animation */ - build_animdata(&gpd->id); - build_parameters(&gpd->id); + if (built_map_.checkIsBuiltAndTag(gpd)) { + return; + } + /* animation */ + build_animdata(&gpd->id); + build_parameters(&gpd->id); - // TODO: parent object (when that feature is implemented) + // TODO: parent object (when that feature is implemented) } void DepsgraphRelationBuilder::build_cachefile(CacheFile *cache_file) { - if (built_map_.checkIsBuiltAndTag(cache_file)) { - return; - } - /* Animation. */ - build_animdata(&cache_file->id); - build_parameters(&cache_file->id); - if (check_id_has_anim_component(&cache_file->id)) { - ComponentKey animation_key(&cache_file->id, NodeType::ANIMATION); - ComponentKey datablock_key(&cache_file->id, - NodeType::CACHE); - add_relation(animation_key, datablock_key, "Datablock Animation"); - } + if (built_map_.checkIsBuiltAndTag(cache_file)) { + return; + } + /* Animation. */ + build_animdata(&cache_file->id); + build_parameters(&cache_file->id); + if (check_id_has_anim_component(&cache_file->id)) { + ComponentKey animation_key(&cache_file->id, NodeType::ANIMATION); + ComponentKey datablock_key(&cache_file->id, NodeType::CACHE); + add_relation(animation_key, datablock_key, "Datablock Animation"); + } } void DepsgraphRelationBuilder::build_mask(Mask *mask) { - if (built_map_.checkIsBuiltAndTag(mask)) { - return; - } - ID *mask_id = &mask->id; - /* F-Curve animation. */ - build_animdata(mask_id); - build_parameters(mask_id); - /* Own mask animation. */ - OperationKey mask_animation_key(mask_id, - NodeType::ANIMATION, - OperationCode::MASK_ANIMATION); - TimeSourceKey time_src_key; - add_relation(time_src_key, mask_animation_key, "TimeSrc -> Mask Animation"); - /* Final mask evaluation. */ - ComponentKey parameters_key(mask_id, NodeType::PARAMETERS); - add_relation(mask_animation_key, parameters_key, "Mask Animation -> Mask Eval"); + if (built_map_.checkIsBuiltAndTag(mask)) { + return; + } + ID *mask_id = &mask->id; + /* F-Curve animation. */ + build_animdata(mask_id); + build_parameters(mask_id); + /* Own mask animation. */ + OperationKey mask_animation_key(mask_id, NodeType::ANIMATION, OperationCode::MASK_ANIMATION); + TimeSourceKey time_src_key; + add_relation(time_src_key, mask_animation_key, "TimeSrc -> Mask Animation"); + /* Final mask evaluation. */ + ComponentKey parameters_key(mask_id, NodeType::PARAMETERS); + add_relation(mask_animation_key, parameters_key, "Mask Animation -> Mask Eval"); } void DepsgraphRelationBuilder::build_movieclip(MovieClip *clip) { - if (built_map_.checkIsBuiltAndTag(clip)) { - return; - } - /* Animation. */ - build_animdata(&clip->id); - build_parameters(&clip->id); + if (built_map_.checkIsBuiltAndTag(clip)) { + return; + } + /* Animation. */ + build_animdata(&clip->id); + build_parameters(&clip->id); } void DepsgraphRelationBuilder::build_lightprobe(LightProbe *probe) { - if (built_map_.checkIsBuiltAndTag(probe)) { - return; - } - build_animdata(&probe->id); - build_parameters(&probe->id); + if (built_map_.checkIsBuiltAndTag(probe)) { + return; + } + build_animdata(&probe->id); + build_parameters(&probe->id); } void DepsgraphRelationBuilder::build_speaker(Speaker *speaker) { - if (built_map_.checkIsBuiltAndTag(speaker)) { - return; - } - build_animdata(&speaker->id); - build_parameters(&speaker->id); + if (built_map_.checkIsBuiltAndTag(speaker)) { + return; + } + build_animdata(&speaker->id); + build_parameters(&speaker->id); } void DepsgraphRelationBuilder::build_copy_on_write_relations() { - for (IDNode *id_node : graph_->id_nodes) { - build_copy_on_write_relations(id_node); - } + for (IDNode *id_node : graph_->id_nodes) { + build_copy_on_write_relations(id_node); + } } /* Nested datablocks (node trees, shape keys) requires special relation to @@ -2630,150 +2305,132 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations() */ void DepsgraphRelationBuilder::build_nested_datablock(ID *owner, ID *id) { - OperationKey owner_copy_on_write_key(owner, - NodeType::COPY_ON_WRITE, - OperationCode::COPY_ON_WRITE); - OperationKey id_copy_on_write_key(id, - NodeType::COPY_ON_WRITE, - OperationCode::COPY_ON_WRITE); - add_relation(id_copy_on_write_key, - owner_copy_on_write_key, - "Eval Order"); + OperationKey owner_copy_on_write_key( + owner, NodeType::COPY_ON_WRITE, OperationCode::COPY_ON_WRITE); + OperationKey id_copy_on_write_key(id, NodeType::COPY_ON_WRITE, OperationCode::COPY_ON_WRITE); + add_relation(id_copy_on_write_key, owner_copy_on_write_key, "Eval Order"); } -void DepsgraphRelationBuilder::build_nested_nodetree(ID *owner, - bNodeTree *ntree) +void DepsgraphRelationBuilder::build_nested_nodetree(ID *owner, bNodeTree *ntree) { - if (ntree == NULL) { - return; - } - build_nested_datablock(owner, &ntree->id); + if (ntree == NULL) { + return; + } + build_nested_datablock(owner, &ntree->id); } void DepsgraphRelationBuilder::build_nested_shapekey(ID *owner, Key *key) { - if (key == NULL) { - return; - } - build_nested_datablock(owner, &key->id); + if (key == NULL) { + return; + } + build_nested_datablock(owner, &key->id); } void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node) { - ID *id_orig = id_node->id_orig; - const ID_Type id_type = GS(id_orig->name); - TimeSourceKey time_source_key; - OperationKey copy_on_write_key(id_orig, - NodeType::COPY_ON_WRITE, - OperationCode::COPY_ON_WRITE); - /* XXX: This is a quick hack to make Alt-A to work. */ - // add_relation(time_source_key, copy_on_write_key, "Fluxgate capacitor hack"); - /* Resat of code is using rather low level trickery, so need to get some - * explicit pointers. */ - Node *node_cow = find_node(copy_on_write_key); - OperationNode *op_cow = node_cow->get_exit_operation(); - /* Plug any other components to this one. */ - GHASH_FOREACH_BEGIN(ComponentNode *, comp_node, id_node->components) - { - if (comp_node->type == NodeType::COPY_ON_WRITE) { - /* Copy-on-write component never depends on itself. */ - continue; - } - if (!comp_node->depends_on_cow()) { - /* Component explicitly requests to not add relation. */ - continue; - } - int rel_flag = (RELATION_FLAG_NO_FLUSH | RELATION_FLAG_GODMODE); - if (id_type == ID_ME && comp_node->type == NodeType::GEOMETRY) { - rel_flag &= ~RELATION_FLAG_NO_FLUSH; - } - /* Notes on exceptions: - * - Parameters component is where drivers are living. Changing any - * of the (custom) properties in the original datablock (even the - * ones which do not imply other component update) need to make - * sure drivers are properly updated. - * This way, for example, changing ID property will properly poke - * all drivers to be updated. - * - * - View layers have cached array of bases in them, which is not - * copied by copy-on-write, and not preserved. PROBABLY it is better - * to preserve that cache in copy-on-write, but for the time being - * we allow flush to layer collections component which will ensure - * that cached array fo bases exists and is up-to-date. */ - if (comp_node->type == NodeType::PARAMETERS || - comp_node->type == NodeType::LAYER_COLLECTIONS) - { - rel_flag &= ~RELATION_FLAG_NO_FLUSH; - } - /* All entry operations of each component should wait for a proper - * copy of ID. */ - OperationNode *op_entry = comp_node->get_entry_operation(); - if (op_entry != NULL) { - Relation *rel = graph_->add_new_relation( - op_cow, op_entry, "CoW Dependency"); - rel->flag |= rel_flag; - } - /* All dangling operations should also be executed after copy-on-write. */ - GHASH_FOREACH_BEGIN(OperationNode *, op_node, comp_node->operations_map) - { - if (op_node == op_entry) { - continue; - } - if (op_node->inlinks.size() == 0) { - Relation *rel = graph_->add_new_relation( - op_cow, op_node, "CoW Dependency"); - rel->flag |= rel_flag; - } - else { - bool has_same_comp_dependency = false; - for (Relation *rel_current : op_node->inlinks) { - if (rel_current->from->type != NodeType::OPERATION) { - continue; - } - OperationNode *op_node_from = - (OperationNode *)rel_current->from; - if (op_node_from->owner == op_node->owner) { - has_same_comp_dependency = true; - break; - } - } - if (!has_same_comp_dependency) { - Relation *rel = graph_->add_new_relation( - op_cow, op_node, "CoW Dependency"); - rel->flag |= rel_flag; - } - } - } - GHASH_FOREACH_END(); - /* NOTE: We currently ignore implicit relations to an external - * datablocks for copy-on-write operations. This means, for example, - * copy-on-write component of Object will not wait for copy-on-write - * component of it's Mesh. This is because pointers are all known - * already so remapping will happen all correct. And then If some object - * evaluation step needs geometry, it will have transitive dependency - * to Mesh copy-on-write already. */ - } - GHASH_FOREACH_END(); - /* TODO(sergey): This solves crash for now, but causes too many - * updates potentially. */ - if (GS(id_orig->name) == ID_OB) { - Object *object = (Object *)id_orig; - ID *object_data_id = (ID *)object->data; - if (object_data_id != NULL) { - if (deg_copy_on_write_is_needed(object_data_id)) { - OperationKey data_copy_on_write_key(object_data_id, - NodeType::COPY_ON_WRITE, - OperationCode::COPY_ON_WRITE); - add_relation(data_copy_on_write_key, - copy_on_write_key, - "Eval Order", - RELATION_FLAG_GODMODE); - } - } - else { - BLI_assert(object->type == OB_EMPTY); - } - } + ID *id_orig = id_node->id_orig; + const ID_Type id_type = GS(id_orig->name); + TimeSourceKey time_source_key; + OperationKey copy_on_write_key(id_orig, NodeType::COPY_ON_WRITE, OperationCode::COPY_ON_WRITE); + /* XXX: This is a quick hack to make Alt-A to work. */ + // add_relation(time_source_key, copy_on_write_key, "Fluxgate capacitor hack"); + /* Resat of code is using rather low level trickery, so need to get some + * explicit pointers. */ + Node *node_cow = find_node(copy_on_write_key); + OperationNode *op_cow = node_cow->get_exit_operation(); + /* Plug any other components to this one. */ + GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) { + if (comp_node->type == NodeType::COPY_ON_WRITE) { + /* Copy-on-write component never depends on itself. */ + continue; + } + if (!comp_node->depends_on_cow()) { + /* Component explicitly requests to not add relation. */ + continue; + } + int rel_flag = (RELATION_FLAG_NO_FLUSH | RELATION_FLAG_GODMODE); + if (id_type == ID_ME && comp_node->type == NodeType::GEOMETRY) { + rel_flag &= ~RELATION_FLAG_NO_FLUSH; + } + /* Notes on exceptions: + * - Parameters component is where drivers are living. Changing any + * of the (custom) properties in the original datablock (even the + * ones which do not imply other component update) need to make + * sure drivers are properly updated. + * This way, for example, changing ID property will properly poke + * all drivers to be updated. + * + * - View layers have cached array of bases in them, which is not + * copied by copy-on-write, and not preserved. PROBABLY it is better + * to preserve that cache in copy-on-write, but for the time being + * we allow flush to layer collections component which will ensure + * that cached array fo bases exists and is up-to-date. */ + if (comp_node->type == NodeType::PARAMETERS || + comp_node->type == NodeType::LAYER_COLLECTIONS) { + rel_flag &= ~RELATION_FLAG_NO_FLUSH; + } + /* All entry operations of each component should wait for a proper + * copy of ID. */ + OperationNode *op_entry = comp_node->get_entry_operation(); + if (op_entry != NULL) { + Relation *rel = graph_->add_new_relation(op_cow, op_entry, "CoW Dependency"); + rel->flag |= rel_flag; + } + /* All dangling operations should also be executed after copy-on-write. */ + GHASH_FOREACH_BEGIN (OperationNode *, op_node, comp_node->operations_map) { + if (op_node == op_entry) { + continue; + } + if (op_node->inlinks.size() == 0) { + Relation *rel = graph_->add_new_relation(op_cow, op_node, "CoW Dependency"); + rel->flag |= rel_flag; + } + else { + bool has_same_comp_dependency = false; + for (Relation *rel_current : op_node->inlinks) { + if (rel_current->from->type != NodeType::OPERATION) { + continue; + } + OperationNode *op_node_from = (OperationNode *)rel_current->from; + if (op_node_from->owner == op_node->owner) { + has_same_comp_dependency = true; + break; + } + } + if (!has_same_comp_dependency) { + Relation *rel = graph_->add_new_relation(op_cow, op_node, "CoW Dependency"); + rel->flag |= rel_flag; + } + } + } + GHASH_FOREACH_END(); + /* NOTE: We currently ignore implicit relations to an external + * datablocks for copy-on-write operations. This means, for example, + * copy-on-write component of Object will not wait for copy-on-write + * component of it's Mesh. This is because pointers are all known + * already so remapping will happen all correct. And then If some object + * evaluation step needs geometry, it will have transitive dependency + * to Mesh copy-on-write already. */ + } + GHASH_FOREACH_END(); + /* TODO(sergey): This solves crash for now, but causes too many + * updates potentially. */ + if (GS(id_orig->name) == ID_OB) { + Object *object = (Object *)id_orig; + ID *object_data_id = (ID *)object->data; + if (object_data_id != NULL) { + if (deg_copy_on_write_is_needed(object_data_id)) { + OperationKey data_copy_on_write_key( + object_data_id, NodeType::COPY_ON_WRITE, OperationCode::COPY_ON_WRITE); + add_relation( + data_copy_on_write_key, copy_on_write_key, "Eval Order", RELATION_FLAG_GODMODE); + } + } + else { + BLI_assert(object->type == OB_EMPTY); + } + } } /* **** ID traversal callbacks functions **** */ @@ -2783,12 +2440,12 @@ void DepsgraphRelationBuilder::modifier_walk(void *user_data, struct ID **idpoin, int /*cb_flag*/) { - BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; - ID *id = *idpoin; - if (id == NULL) { - return; - } - data->builder->build_id(id); + BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; + ID *id = *idpoin; + if (id == NULL) { + return; + } + data->builder->build_id(id); } void DepsgraphRelationBuilder::constraint_walk(bConstraint * /*con*/, @@ -2796,12 +2453,12 @@ void DepsgraphRelationBuilder::constraint_walk(bConstraint * /*con*/, bool /*is_reference*/, void *user_data) { - BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; - ID *id = *idpoin; - if (id == NULL) { - return; - } - data->builder->build_id(id); + BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; + ID *id = *idpoin; + if (id == NULL) { + return; + } + data->builder->build_id(id); } } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index 0a0f0e99865..5b2d34a270c 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -93,301 +93,268 @@ struct Relation; struct RootPChanMap; struct TimeSourceNode; -struct TimeSourceKey -{ - TimeSourceKey(); - TimeSourceKey(ID *id); +struct TimeSourceKey { + TimeSourceKey(); + TimeSourceKey(ID *id); - string identifier() const; + string identifier() const; - ID *id; + ID *id; }; -struct ComponentKey -{ - ComponentKey(); - ComponentKey(ID *id, NodeType type, const char *name = ""); +struct ComponentKey { + ComponentKey(); + ComponentKey(ID *id, NodeType type, const char *name = ""); - string identifier() const; + string identifier() const; - ID *id; - NodeType type; - const char *name; + ID *id; + NodeType type; + const char *name; }; -struct OperationKey -{ - OperationKey(); - OperationKey(ID *id, - NodeType component_type, - const char *name, - int name_tag = -1); - OperationKey(ID *id, - NodeType component_type, - const char *component_name, - const char *name, - int name_tag); - - OperationKey(ID *id, - NodeType component_type, - OperationCode opcode); - OperationKey(ID *id, - NodeType component_type, - const char *component_name, - OperationCode opcode); - - OperationKey(ID *id, - NodeType component_type, - OperationCode opcode, - const char *name, - int name_tag = -1); - OperationKey(ID *id, - NodeType component_type, - const char *component_name, - OperationCode opcode, - const char *name, - int name_tag = -1); - - string identifier() const; - - ID *id; - NodeType component_type; - const char *component_name; - OperationCode opcode; - const char *name; - int name_tag; +struct OperationKey { + OperationKey(); + OperationKey(ID *id, NodeType component_type, const char *name, int name_tag = -1); + OperationKey( + ID *id, NodeType component_type, const char *component_name, const char *name, int name_tag); + + OperationKey(ID *id, NodeType component_type, OperationCode opcode); + OperationKey(ID *id, NodeType component_type, const char *component_name, OperationCode opcode); + + OperationKey( + ID *id, NodeType component_type, OperationCode opcode, const char *name, int name_tag = -1); + OperationKey(ID *id, + NodeType component_type, + const char *component_name, + OperationCode opcode, + const char *name, + int name_tag = -1); + + string identifier() const; + + ID *id; + NodeType component_type; + const char *component_name; + OperationCode opcode; + const char *name; + int name_tag; }; -struct RNAPathKey -{ - RNAPathKey(ID *id, const char *path, RNAPointerSource source); - RNAPathKey(ID *id, - const PointerRNA &ptr, - PropertyRNA *prop, - RNAPointerSource source); +struct RNAPathKey { + RNAPathKey(ID *id, const char *path, RNAPointerSource source); + RNAPathKey(ID *id, const PointerRNA &ptr, PropertyRNA *prop, RNAPointerSource source); - string identifier() const; + string identifier() const; - ID *id; - PointerRNA ptr; - PropertyRNA *prop; - RNAPointerSource source; + ID *id; + PointerRNA ptr; + PropertyRNA *prop; + RNAPointerSource source; }; -class DepsgraphRelationBuilder : public DepsgraphBuilder -{ -public: - DepsgraphRelationBuilder(Main *bmain, Depsgraph *graph); - - void begin_build(); - - template - Relation *add_relation(const KeyFrom& key_from, - const KeyTo& key_to, - const char *description, - int flags = 0); - - template - Relation *add_relation(const TimeSourceKey& key_from, - const KeyTo& key_to, - const char *description, - int flags = 0); - - template - Relation *add_node_handle_relation(const KeyType& key_from, - const DepsNodeHandle *handle, - const char *description, - int flags = 0); - - template - Relation *add_depends_on_transform_relation(ID *id, - const KeyTo& key_to, - const char *description, - int flags = 0); - - /* Adds relation from proper transformation opertation to the modifier. - * Takes care of checking for possible physics solvers modifying position - * of this object. */ - void add_modifier_to_transform_relation(const DepsNodeHandle *handle, - const char *description); - - void add_customdata_mask(Object *object, - const DEGCustomDataMeshMasks &customdata_masks); - void add_special_eval_flag(ID *object, uint32_t flag); - - void build_id(ID *id); - void build_layer_collections(ListBase *lb); - void build_view_layer(Scene *scene, ViewLayer *view_layer); - void build_collection(LayerCollection *from_layer_collection, - Object *object, - Collection *collection); - void build_object(Base *base, Object *object); - void build_object_flags(Base *base, Object *object); - void build_object_data(Object *object); - void build_object_data_camera(Object *object); - void build_object_data_geometry(Object *object); - void build_object_data_geometry_datablock(ID *obdata); - void build_object_data_light(Object *object); - void build_object_data_lightprobe(Object *object); - void build_object_data_speaker(Object *object); - void build_object_parent(Object *object); - void build_object_pointcache(Object *object); - void build_constraints(ID *id, - NodeType component_type, - const char *component_subdata, - ListBase *constraints, - RootPChanMap *root_map); - void build_animdata(ID *id); - void build_animdata_curves(ID *id); - void build_animdata_curves_targets(ID *id, - ComponentKey &adt_key, - OperationNode *operation_from, - ListBase *curves); - void build_animdata_nlastrip_targets(ID *id, - ComponentKey &adt_key, - OperationNode *operation_from, - ListBase *strips); - void build_animdata_drivers(ID *id); - void build_animation_images(ID *id); - void build_action(bAction *action); - void build_driver(ID *id, FCurve *fcurve); - void build_driver_data(ID *id, FCurve *fcurve); - void build_driver_variables(ID *id, FCurve *fcurve); - void build_driver_id_property(ID *id, const char *rna_path); - void build_parameters(ID *id); - void build_world(World *world); - void build_rigidbody(Scene *scene); - void build_particle_systems(Object *object); - void build_particle_settings(ParticleSettings *part); - void build_particle_system_visualization_object(Object *object, - ParticleSystem *psys, - Object *draw_object); - void build_ik_pose(Object *object, - bPoseChannel *pchan, - bConstraint *con, - RootPChanMap *root_map); - void build_splineik_pose(Object *object, - bPoseChannel *pchan, - bConstraint *con, - RootPChanMap *root_map); - void build_rig(Object *object); - void build_proxy_rig(Object *object); - void build_shapekeys(Key *key); - void build_armature(bArmature *armature); - void build_camera(Camera *camera); - void build_light(Light *lamp); - void build_nodetree(bNodeTree *ntree); - void build_material(Material *ma); - void build_texture(Tex *tex); - void build_image(Image *image); - void build_compositor(Scene *scene); - void build_gpencil(bGPdata *gpd); - void build_cachefile(CacheFile *cache_file); - void build_mask(Mask *mask); - void build_movieclip(MovieClip *clip); - void build_lightprobe(LightProbe *probe); - void build_speaker(Speaker *speaker); - - void build_nested_datablock(ID *owner, ID *id); - void build_nested_nodetree(ID *owner, bNodeTree *ntree); - void build_nested_shapekey(ID *owner, Key *key); - - void add_particle_collision_relations(const OperationKey &key, - Object *object, - Collection *collection, - const char *name); - void add_particle_forcefield_relations(const OperationKey &key, - Object *object, - ParticleSystem *psys, - EffectorWeights *eff, - bool add_absorption, const char *name); - - void build_copy_on_write_relations(); - void build_copy_on_write_relations(IDNode *id_node); - - template - OperationNode *find_operation_node(const KeyType &key); - - Depsgraph *getGraph(); - -protected: - TimeSourceNode *get_node(const TimeSourceKey &key) const; - ComponentNode *get_node(const ComponentKey &key) const; - OperationNode *get_node(const OperationKey &key) const; - Node *get_node(const RNAPathKey &key); - - OperationNode *find_node(const OperationKey &key) const; - bool has_node(const OperationKey &key) const; - - Relation *add_time_relation(TimeSourceNode *timesrc, - Node *node_to, - const char *description, - int flags = 0); - Relation *add_operation_relation(OperationNode *node_from, - OperationNode *node_to, - const char *description, - int flags = 0); - - template - DepsNodeHandle create_node_handle(const KeyType& key, - const char *default_name = ""); - - /* TODO(sergey): All those is_same* functions are to be generalized. */ - - /* Check whether two keys corresponds to the same bone from same armature. - * - * This is used by drivers relations builder to avoid possible fake - * dependency cycle when one bone property drives another property of the - * same bone. */ - template - bool is_same_bone_dependency(const KeyFrom& key_from, const KeyTo& key_to); - - /* Similar to above, but used to check whether driver is using node from - * the same node tree as a driver variable. */ - template - bool is_same_nodetree_node_dependency(const KeyFrom& key_from, - const KeyTo& key_to); - -private: - struct BuilderWalkUserData { - DepsgraphRelationBuilder *builder; - }; - - static void modifier_walk(void *user_data, - struct Object *object, - struct ID **idpoin, - int cb_flag); - - static void constraint_walk(bConstraint *con, - ID **idpoin, - bool is_reference, - void *user_data); - - /* State which demotes currently built entities. */ - Scene *scene_; - - BuilderMap built_map_; - RNANodeQuery rna_node_query_; +class DepsgraphRelationBuilder : public DepsgraphBuilder { + public: + DepsgraphRelationBuilder(Main *bmain, Depsgraph *graph); + + void begin_build(); + + template + Relation *add_relation(const KeyFrom &key_from, + const KeyTo &key_to, + const char *description, + int flags = 0); + + template + Relation *add_relation(const TimeSourceKey &key_from, + const KeyTo &key_to, + const char *description, + int flags = 0); + + template + Relation *add_node_handle_relation(const KeyType &key_from, + const DepsNodeHandle *handle, + const char *description, + int flags = 0); + + template + Relation *add_depends_on_transform_relation(ID *id, + const KeyTo &key_to, + const char *description, + int flags = 0); + + /* Adds relation from proper transformation opertation to the modifier. + * Takes care of checking for possible physics solvers modifying position + * of this object. */ + void add_modifier_to_transform_relation(const DepsNodeHandle *handle, const char *description); + + void add_customdata_mask(Object *object, const DEGCustomDataMeshMasks &customdata_masks); + void add_special_eval_flag(ID *object, uint32_t flag); + + void build_id(ID *id); + void build_layer_collections(ListBase *lb); + void build_view_layer(Scene *scene, ViewLayer *view_layer); + void build_collection(LayerCollection *from_layer_collection, + Object *object, + Collection *collection); + void build_object(Base *base, Object *object); + void build_object_flags(Base *base, Object *object); + void build_object_data(Object *object); + void build_object_data_camera(Object *object); + void build_object_data_geometry(Object *object); + void build_object_data_geometry_datablock(ID *obdata); + void build_object_data_light(Object *object); + void build_object_data_lightprobe(Object *object); + void build_object_data_speaker(Object *object); + void build_object_parent(Object *object); + void build_object_pointcache(Object *object); + void build_constraints(ID *id, + NodeType component_type, + const char *component_subdata, + ListBase *constraints, + RootPChanMap *root_map); + void build_animdata(ID *id); + void build_animdata_curves(ID *id); + void build_animdata_curves_targets(ID *id, + ComponentKey &adt_key, + OperationNode *operation_from, + ListBase *curves); + void build_animdata_nlastrip_targets(ID *id, + ComponentKey &adt_key, + OperationNode *operation_from, + ListBase *strips); + void build_animdata_drivers(ID *id); + void build_animation_images(ID *id); + void build_action(bAction *action); + void build_driver(ID *id, FCurve *fcurve); + void build_driver_data(ID *id, FCurve *fcurve); + void build_driver_variables(ID *id, FCurve *fcurve); + void build_driver_id_property(ID *id, const char *rna_path); + void build_parameters(ID *id); + void build_world(World *world); + void build_rigidbody(Scene *scene); + void build_particle_systems(Object *object); + void build_particle_settings(ParticleSettings *part); + void build_particle_system_visualization_object(Object *object, + ParticleSystem *psys, + Object *draw_object); + void build_ik_pose(Object *object, + bPoseChannel *pchan, + bConstraint *con, + RootPChanMap *root_map); + void build_splineik_pose(Object *object, + bPoseChannel *pchan, + bConstraint *con, + RootPChanMap *root_map); + void build_rig(Object *object); + void build_proxy_rig(Object *object); + void build_shapekeys(Key *key); + void build_armature(bArmature *armature); + void build_camera(Camera *camera); + void build_light(Light *lamp); + void build_nodetree(bNodeTree *ntree); + void build_material(Material *ma); + void build_texture(Tex *tex); + void build_image(Image *image); + void build_compositor(Scene *scene); + void build_gpencil(bGPdata *gpd); + void build_cachefile(CacheFile *cache_file); + void build_mask(Mask *mask); + void build_movieclip(MovieClip *clip); + void build_lightprobe(LightProbe *probe); + void build_speaker(Speaker *speaker); + + void build_nested_datablock(ID *owner, ID *id); + void build_nested_nodetree(ID *owner, bNodeTree *ntree); + void build_nested_shapekey(ID *owner, Key *key); + + void add_particle_collision_relations(const OperationKey &key, + Object *object, + Collection *collection, + const char *name); + void add_particle_forcefield_relations(const OperationKey &key, + Object *object, + ParticleSystem *psys, + EffectorWeights *eff, + bool add_absorption, + const char *name); + + void build_copy_on_write_relations(); + void build_copy_on_write_relations(IDNode *id_node); + + template OperationNode *find_operation_node(const KeyType &key); + + Depsgraph *getGraph(); + + protected: + TimeSourceNode *get_node(const TimeSourceKey &key) const; + ComponentNode *get_node(const ComponentKey &key) const; + OperationNode *get_node(const OperationKey &key) const; + Node *get_node(const RNAPathKey &key); + + OperationNode *find_node(const OperationKey &key) const; + bool has_node(const OperationKey &key) const; + + Relation *add_time_relation(TimeSourceNode *timesrc, + Node *node_to, + const char *description, + int flags = 0); + Relation *add_operation_relation(OperationNode *node_from, + OperationNode *node_to, + const char *description, + int flags = 0); + + template + DepsNodeHandle create_node_handle(const KeyType &key, const char *default_name = ""); + + /* TODO(sergey): All those is_same* functions are to be generalized. */ + + /* Check whether two keys corresponds to the same bone from same armature. + * + * This is used by drivers relations builder to avoid possible fake + * dependency cycle when one bone property drives another property of the + * same bone. */ + template + bool is_same_bone_dependency(const KeyFrom &key_from, const KeyTo &key_to); + + /* Similar to above, but used to check whether driver is using node from + * the same node tree as a driver variable. */ + template + bool is_same_nodetree_node_dependency(const KeyFrom &key_from, const KeyTo &key_to); + + private: + struct BuilderWalkUserData { + DepsgraphRelationBuilder *builder; + }; + + static void modifier_walk(void *user_data, + struct Object *object, + struct ID **idpoin, + int cb_flag); + + static void constraint_walk(bConstraint *con, ID **idpoin, bool is_reference, void *user_data); + + /* State which demotes currently built entities. */ + Scene *scene_; + + BuilderMap built_map_; + RNANodeQuery rna_node_query_; }; -struct DepsNodeHandle -{ - DepsNodeHandle(DepsgraphRelationBuilder *builder, - OperationNode *node, - const char *default_name = "") - : builder(builder), - node(node), - default_name(default_name) - { - BLI_assert(node != NULL); - } - - DepsgraphRelationBuilder *builder; - OperationNode *node; - const char *default_name; +struct DepsNodeHandle { + DepsNodeHandle(DepsgraphRelationBuilder *builder, + OperationNode *node, + const char *default_name = "") + : builder(builder), node(node), default_name(default_name) + { + BLI_assert(node != NULL); + } + + DepsgraphRelationBuilder *builder; + OperationNode *node; + const char *default_name; }; } // namespace DEG - #include "intern/builder/deg_builder_relations_impl.h" diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h index 86a17ae4a47..4412fa3fca3 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h @@ -32,187 +32,189 @@ extern "C" { namespace DEG { -template -OperationNode *DepsgraphRelationBuilder::find_operation_node(const KeyType& key) +template +OperationNode *DepsgraphRelationBuilder::find_operation_node(const KeyType &key) { - Node *node = get_node(key); - return node != NULL ? node->get_exit_operation() : NULL; + Node *node = get_node(key); + return node != NULL ? node->get_exit_operation() : NULL; } -template +template Relation *DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from, const KeyTo &key_to, const char *description, int flags) { - Node *node_from = get_node(key_from); - Node *node_to = get_node(key_to); - OperationNode *op_from = node_from ? node_from->get_exit_operation() : NULL; - OperationNode *op_to = node_to ? node_to->get_entry_operation() : NULL; - if (op_from && op_to) { - return add_operation_relation(op_from, op_to, description, flags); - } - else { - if (!op_from) { - /* XXX TODO handle as error or report if needed */ - fprintf(stderr, "add_relation(%s) - Could not find op_from (%s)\n", - description, key_from.identifier().c_str()); - } - else { - fprintf(stderr, "add_relation(%s) - Failed, but op_from (%s) was ok\n", - description, key_from.identifier().c_str()); - } - if (!op_to) { - /* XXX TODO handle as error or report if needed */ - fprintf(stderr, "add_relation(%s) - Could not find op_to (%s)\n", - description, key_to.identifier().c_str()); - } - else { - fprintf(stderr, "add_relation(%s) - Failed, but op_to (%s) was ok\n", - description, key_to.identifier().c_str()); - } - } - return NULL; + Node *node_from = get_node(key_from); + Node *node_to = get_node(key_to); + OperationNode *op_from = node_from ? node_from->get_exit_operation() : NULL; + OperationNode *op_to = node_to ? node_to->get_entry_operation() : NULL; + if (op_from && op_to) { + return add_operation_relation(op_from, op_to, description, flags); + } + else { + if (!op_from) { + /* XXX TODO handle as error or report if needed */ + fprintf(stderr, + "add_relation(%s) - Could not find op_from (%s)\n", + description, + key_from.identifier().c_str()); + } + else { + fprintf(stderr, + "add_relation(%s) - Failed, but op_from (%s) was ok\n", + description, + key_from.identifier().c_str()); + } + if (!op_to) { + /* XXX TODO handle as error or report if needed */ + fprintf(stderr, + "add_relation(%s) - Could not find op_to (%s)\n", + description, + key_to.identifier().c_str()); + } + else { + fprintf(stderr, + "add_relation(%s) - Failed, but op_to (%s) was ok\n", + description, + key_to.identifier().c_str()); + } + } + return NULL; } -template -Relation *DepsgraphRelationBuilder::add_relation( - const TimeSourceKey &key_from, - const KeyTo &key_to, - const char *description, - int flags) +template +Relation *DepsgraphRelationBuilder::add_relation(const TimeSourceKey &key_from, + const KeyTo &key_to, + const char *description, + int flags) { - TimeSourceNode *time_from = get_node(key_from); - Node *node_to = get_node(key_to); - OperationNode *op_to = node_to ? node_to->get_entry_operation() : NULL; - if (time_from != NULL && op_to != NULL) { - return add_time_relation( - time_from, op_to, description, flags); - } - return NULL; + TimeSourceNode *time_from = get_node(key_from); + Node *node_to = get_node(key_to); + OperationNode *op_to = node_to ? node_to->get_entry_operation() : NULL; + if (time_from != NULL && op_to != NULL) { + return add_time_relation(time_from, op_to, description, flags); + } + return NULL; } -template -Relation *DepsgraphRelationBuilder::add_node_handle_relation( - const KeyType &key_from, - const DepsNodeHandle *handle, - const char *description, - int flags) +template +Relation *DepsgraphRelationBuilder::add_node_handle_relation(const KeyType &key_from, + const DepsNodeHandle *handle, + const char *description, + int flags) { - Node *node_from = get_node(key_from); - OperationNode *op_from = node_from ? node_from->get_exit_operation() : NULL; - OperationNode *op_to = handle->node->get_entry_operation(); - if (op_from != NULL && op_to != NULL) { - return add_operation_relation(op_from, op_to, description, flags); - } - else { - if (!op_from) { - fprintf(stderr, "add_node_handle_relation(%s) - Could not find op_from (%s)\n", - description, key_from.identifier().c_str()); - } - if (!op_to) { - fprintf(stderr, "add_node_handle_relation(%s) - Could not find op_to (%s)\n", - description, key_from.identifier().c_str()); - } - } - return NULL; + Node *node_from = get_node(key_from); + OperationNode *op_from = node_from ? node_from->get_exit_operation() : NULL; + OperationNode *op_to = handle->node->get_entry_operation(); + if (op_from != NULL && op_to != NULL) { + return add_operation_relation(op_from, op_to, description, flags); + } + else { + if (!op_from) { + fprintf(stderr, + "add_node_handle_relation(%s) - Could not find op_from (%s)\n", + description, + key_from.identifier().c_str()); + } + if (!op_to) { + fprintf(stderr, + "add_node_handle_relation(%s) - Could not find op_to (%s)\n", + description, + key_from.identifier().c_str()); + } + } + return NULL; } -template -Relation *DepsgraphRelationBuilder::add_depends_on_transform_relation( - ID *id, - const KeyTo& key_to, - const char *description, - int flags) +template +Relation *DepsgraphRelationBuilder::add_depends_on_transform_relation(ID *id, + const KeyTo &key_to, + const char *description, + int flags) { - if (GS(id->name) == ID_OB) { - Object *object = reinterpret_cast(id); - if (object->rigidbody_object != NULL) { - OperationKey transform_key(&object->id, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_EVAL); - return add_relation(transform_key, key_to, description, flags); - } - } - ComponentKey transform_key(id, NodeType::TRANSFORM); - return add_relation(transform_key, key_to, description, flags); + if (GS(id->name) == ID_OB) { + Object *object = reinterpret_cast(id); + if (object->rigidbody_object != NULL) { + OperationKey transform_key(&object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL); + return add_relation(transform_key, key_to, description, flags); + } + } + ComponentKey transform_key(id, NodeType::TRANSFORM); + return add_relation(transform_key, key_to, description, flags); } -template -DepsNodeHandle DepsgraphRelationBuilder::create_node_handle( - const KeyType &key, - const char *default_name) +template +DepsNodeHandle DepsgraphRelationBuilder::create_node_handle(const KeyType &key, + const char *default_name) { - return DepsNodeHandle(this, get_node(key), default_name); + return DepsNodeHandle(this, get_node(key), default_name); } /* Rig compatibility: we check if bone is using local transform as a variable * for driver on itself and ignore those relations to avoid "false-positive" * dependency cycles. */ -template -bool DepsgraphRelationBuilder::is_same_bone_dependency(const KeyFrom& key_from, - const KeyTo& key_to) +template +bool DepsgraphRelationBuilder::is_same_bone_dependency(const KeyFrom &key_from, + const KeyTo &key_to) { - /* Get operations for requested keys. */ - Node *node_from = get_node(key_from); - Node *node_to = get_node(key_to); - if (node_from == NULL || node_to == NULL) { - return false; - } - OperationNode *op_from = node_from->get_exit_operation(); - OperationNode *op_to = node_to->get_entry_operation(); - if (op_from == NULL || op_to == NULL) { - return false; - } - /* Different armatures, bone can't be the same. */ - if (op_from->owner->owner != op_to->owner->owner) { - return false; - } - /* We are only interested in relations like BONE_DONE -> BONE_LOCAL... */ - if (!(op_from->opcode == OperationCode::BONE_DONE && - op_to->opcode == OperationCode::BONE_LOCAL)) - { - return false; - } - /* ... BUT, we also need to check if it's same bone. */ - if (op_from->owner->name != op_to->owner->name) { - return false; - } - return true; + /* Get operations for requested keys. */ + Node *node_from = get_node(key_from); + Node *node_to = get_node(key_to); + if (node_from == NULL || node_to == NULL) { + return false; + } + OperationNode *op_from = node_from->get_exit_operation(); + OperationNode *op_to = node_to->get_entry_operation(); + if (op_from == NULL || op_to == NULL) { + return false; + } + /* Different armatures, bone can't be the same. */ + if (op_from->owner->owner != op_to->owner->owner) { + return false; + } + /* We are only interested in relations like BONE_DONE -> BONE_LOCAL... */ + if (!(op_from->opcode == OperationCode::BONE_DONE && + op_to->opcode == OperationCode::BONE_LOCAL)) { + return false; + } + /* ... BUT, we also need to check if it's same bone. */ + if (op_from->owner->name != op_to->owner->name) { + return false; + } + return true; } -template -bool DepsgraphRelationBuilder::is_same_nodetree_node_dependency( - const KeyFrom& key_from, - const KeyTo& key_to) +template +bool DepsgraphRelationBuilder::is_same_nodetree_node_dependency(const KeyFrom &key_from, + const KeyTo &key_to) { - /* Get operations for requested keys. */ - Node *node_from = get_node(key_from); - Node *node_to = get_node(key_to); - if (node_from == NULL || node_to == NULL) { - return false; - } - OperationNode *op_from = node_from->get_exit_operation(); - OperationNode *op_to = node_to->get_entry_operation(); - if (op_from == NULL || op_to == NULL) { - return false; - } - /* Check if this is actually a node tree. */ - if (GS(op_from->owner->owner->id_orig->name) != ID_NT) { - return false; - } - /* Different node trees. */ - if (op_from->owner->owner != op_to->owner->owner) { - return false; - } - /* We are only interested in relations like BONE_DONE -> BONE_LOCAL... */ - if (!(op_from->opcode == OperationCode::PARAMETERS_EVAL && - op_to->opcode == OperationCode::PARAMETERS_EVAL)) - { - return false; - } - return true; + /* Get operations for requested keys. */ + Node *node_from = get_node(key_from); + Node *node_to = get_node(key_to); + if (node_from == NULL || node_to == NULL) { + return false; + } + OperationNode *op_from = node_from->get_exit_operation(); + OperationNode *op_to = node_to->get_entry_operation(); + if (op_from == NULL || op_to == NULL) { + return false; + } + /* Check if this is actually a node tree. */ + if (GS(op_from->owner->owner->id_orig->name) != ID_NT) { + return false; + } + /* Different node trees. */ + if (op_from->owner->owner != op_to->owner->owner) { + return false; + } + /* We are only interested in relations like BONE_DONE -> BONE_LOCAL... */ + if (!(op_from->opcode == OperationCode::PARAMETERS_EVAL && + op_to->opcode == OperationCode::PARAMETERS_EVAL)) { + return false; + } + return true; } } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc index 22ff10d3b70..35af968d46e 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc @@ -30,100 +30,85 @@ namespace DEG { //////////////////////////////////////////////////////////////////////////////// // Time source. -TimeSourceKey::TimeSourceKey() - : id(NULL) +TimeSourceKey::TimeSourceKey() : id(NULL) { } -TimeSourceKey::TimeSourceKey(ID *id) - : id(id) +TimeSourceKey::TimeSourceKey(ID *id) : id(id) { } string TimeSourceKey::identifier() const { - return string("TimeSourceKey"); + return string("TimeSourceKey"); } //////////////////////////////////////////////////////////////////////////////// // Component. -ComponentKey::ComponentKey() - : id(NULL), - type(NodeType::UNDEFINED), - name("") +ComponentKey::ComponentKey() : id(NULL), type(NodeType::UNDEFINED), name("") { } ComponentKey::ComponentKey(ID *id, NodeType type, const char *name) - : id(id), - type(type), - name(name) + : id(id), type(type), name(name) { } string ComponentKey::identifier() const { - const char *idname = (id) ? id->name : ""; - string result = string("ComponentKey("); - result += idname; - result += ", " + string(nodeTypeAsString(type)); - if (name[0] != '\0') { - result += ", '" + string(name) + "'"; - } - result += ')'; - return result; + const char *idname = (id) ? id->name : ""; + string result = string("ComponentKey("); + result += idname; + result += ", " + string(nodeTypeAsString(type)); + if (name[0] != '\0') { + result += ", '" + string(name) + "'"; + } + result += ')'; + return result; } //////////////////////////////////////////////////////////////////////////////// // Operation. OperationKey::OperationKey() - : id(NULL), - component_type(NodeType::UNDEFINED), - component_name(""), - opcode(OperationCode::OPERATION), - name(""), - name_tag(-1) + : id(NULL), + component_type(NodeType::UNDEFINED), + component_name(""), + opcode(OperationCode::OPERATION), + name(""), + name_tag(-1) { } -OperationKey::OperationKey(ID *id, - NodeType component_type, - const char *name, - int name_tag) - : id(id), - component_type(component_type), - component_name(""), - opcode(OperationCode::OPERATION), - name(name), - name_tag(name_tag) +OperationKey::OperationKey(ID *id, NodeType component_type, const char *name, int name_tag) + : id(id), + component_type(component_type), + component_name(""), + opcode(OperationCode::OPERATION), + name(name), + name_tag(name_tag) { } -OperationKey::OperationKey(ID *id, - NodeType component_type, - const char *component_name, - const char *name, - int name_tag) - : id(id), - component_type(component_type), - component_name(component_name), - opcode(OperationCode::OPERATION), - name(name), - name_tag(name_tag) +OperationKey::OperationKey( + ID *id, NodeType component_type, const char *component_name, const char *name, int name_tag) + : id(id), + component_type(component_type), + component_name(component_name), + opcode(OperationCode::OPERATION), + name(name), + name_tag(name_tag) { } -OperationKey::OperationKey(ID *id, - NodeType component_type, - OperationCode opcode) - : id(id), - component_type(component_type), - component_name(""), - opcode(opcode), - name(""), - name_tag(-1) +OperationKey::OperationKey(ID *id, NodeType component_type, OperationCode opcode) + : id(id), + component_type(component_type), + component_name(""), + opcode(opcode), + name(""), + name_tag(-1) { } @@ -131,26 +116,23 @@ OperationKey::OperationKey(ID *id, NodeType component_type, const char *component_name, OperationCode opcode) - : id(id), - component_type(component_type), - component_name(component_name), - opcode(opcode), - name(""), - name_tag(-1) + : id(id), + component_type(component_type), + component_name(component_name), + opcode(opcode), + name(""), + name_tag(-1) { } -OperationKey::OperationKey(ID *id, - NodeType component_type, - OperationCode opcode, - const char *name, - int name_tag) - : id(id), - component_type(component_type), - component_name(""), - opcode(opcode), - name(name), - name_tag(name_tag) +OperationKey::OperationKey( + ID *id, NodeType component_type, OperationCode opcode, const char *name, int name_tag) + : id(id), + component_type(component_type), + component_name(""), + opcode(opcode), + name(name), + name_tag(name_tag) { } @@ -160,63 +142,54 @@ OperationKey::OperationKey(ID *id, OperationCode opcode, const char *name, int name_tag) - : id(id), - component_type(component_type), - component_name(component_name), - opcode(opcode), - name(name), - name_tag(name_tag) + : id(id), + component_type(component_type), + component_name(component_name), + opcode(opcode), + name(name), + name_tag(name_tag) { } string OperationKey::identifier() const { - string result = string("OperationKey("); - result += "type: " + string(nodeTypeAsString(component_type)); - result += ", component name: '" + string(component_name) + "'"; - result += ", operation code: " + string(operationCodeAsString(opcode)); - if (name[0] != '\0') { - result += ", '" + string(name) + "'"; - } - result += ")"; - return result; + string result = string("OperationKey("); + result += "type: " + string(nodeTypeAsString(component_type)); + result += ", component name: '" + string(component_name) + "'"; + result += ", operation code: " + string(operationCodeAsString(opcode)); + if (name[0] != '\0') { + result += ", '" + string(name) + "'"; + } + result += ")"; + return result; } //////////////////////////////////////////////////////////////////////////////// // RNA path. -RNAPathKey::RNAPathKey(ID *id, const char *path, RNAPointerSource source) - : id(id), - source(source) +RNAPathKey::RNAPathKey(ID *id, const char *path, RNAPointerSource source) : id(id), source(source) { - /* Create ID pointer for root of path lookup. */ - PointerRNA id_ptr; - RNA_id_pointer_create(id, &id_ptr); - /* Try to resolve path. */ - int index; - if (!RNA_path_resolve_full(&id_ptr, path, &ptr, &prop, &index)) { - ptr = PointerRNA_NULL; - prop = NULL; - } + /* Create ID pointer for root of path lookup. */ + PointerRNA id_ptr; + RNA_id_pointer_create(id, &id_ptr); + /* Try to resolve path. */ + int index; + if (!RNA_path_resolve_full(&id_ptr, path, &ptr, &prop, &index)) { + ptr = PointerRNA_NULL; + prop = NULL; + } } -RNAPathKey::RNAPathKey(ID *id, - const PointerRNA &ptr, - PropertyRNA *prop, - RNAPointerSource source) - : id(id), - ptr(ptr), - prop(prop), - source(source) +RNAPathKey::RNAPathKey(ID *id, const PointerRNA &ptr, PropertyRNA *prop, RNAPointerSource source) + : id(id), ptr(ptr), prop(prop), source(source) { } string RNAPathKey::identifier() const { - const char *id_name = (id) ? id->name : ""; - const char *prop_name = (prop) ? RNA_property_identifier(prop) : ""; - return string("RnaPathKey(") + "id: " + id_name + - ", prop: '" + prop_name + "')"; + const char *id_name = (id) ? id->name : ""; + const char *prop_name = (prop) ? RNA_property_identifier(prop) : ""; + return string("RnaPathKey(") + "id: " + id_name + ", prop: '" + prop_name + "')"; } } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc index 9d36e9495e3..1d222258449 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc @@ -27,7 +27,7 @@ #include #include -#include /* required for STREQ later on. */ +#include /* required for STREQ later on. */ #include "MEM_guardedalloc.h" @@ -67,166 +67,139 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *object, bConstraint *con, RootPChanMap *root_map) { - bKinematicConstraint *data = (bKinematicConstraint *)con->data; - /* Attach owner to IK Solver to. */ - bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data); - if (rootchan == NULL) { - return; - } - OperationKey pchan_local_key(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_LOCAL); - OperationKey init_ik_key( - &object->id, NodeType::EVAL_POSE, OperationCode::POSE_INIT_IK); - OperationKey solver_key(&object->id, - NodeType::EVAL_POSE, - rootchan->name, - OperationCode::POSE_IK_SOLVER); - OperationKey pose_cleanup_key( - &object->id, NodeType::EVAL_POSE, OperationCode::POSE_CLEANUP); - add_relation(pchan_local_key, init_ik_key, "IK Constraint -> Init IK Tree"); - add_relation(init_ik_key, solver_key, "Init IK -> IK Solver"); - /* Never cleanup before solver is run. */ - add_relation(solver_key, - pose_cleanup_key, - "IK Solver -> Cleanup", - RELATION_FLAG_GODMODE); - /* IK target */ - /* TODO(sergey): This should get handled as part of the constraint code. */ - if (data->tar != NULL) { - /* TODO(sergey): For until we'll store partial matrices in the - * depsgraph, we create dependency between target object and pose eval - * component. - * - * This way we ensuring the whole subtree is updated from scratch - * without need of intermediate matrices. This is an overkill, but good - * enough for testing IK solver. */ - ComponentKey pose_key(&object->id, NodeType::EVAL_POSE); - if ((data->tar->type == OB_ARMATURE) && (data->subtarget[0])) { - /* TODO(sergey): This is only for until granular update stores - * intermediate result. */ - if (data->tar != object) { - /* Different armature - can just read the results. */ - ComponentKey target_key( - &data->tar->id, NodeType::BONE, data->subtarget); - add_relation(target_key, pose_key, con->name); - } - else { - /* Same armature - we'll use the ready state only, just in case - * this bone is in the chain we're solving. */ - OperationKey target_key(&data->tar->id, - NodeType::BONE, - data->subtarget, - OperationCode::BONE_DONE); - add_relation(target_key, solver_key, con->name); - } - } - else if (data->subtarget[0] && - ELEM(data->tar->type, OB_MESH, OB_LATTICE)) - { - /* Vertex group target. */ - /* NOTE: for now, we don't need to represent vertex groups - * separately. */ - ComponentKey target_key(&data->tar->id, NodeType::GEOMETRY); - add_relation(target_key, solver_key, con->name); - add_customdata_mask(data->tar, DEGCustomDataMeshMasks::MaskVert(CD_MASK_MDEFORMVERT)); - } - else { - /* Standard Object Target. */ - ComponentKey target_key(&data->tar->id, NodeType::TRANSFORM); - add_relation(target_key, pose_key, con->name); - } - if (data->tar == object && data->subtarget[0]) { - /* Prevent target's constraints from linking to anything from same - * chain that it controls. */ - root_map->add_bone(data->subtarget, rootchan->name); - } - } - /* Pole Target. */ - /* TODO(sergey): This should get handled as part of the constraint code. */ - if (data->poletar != NULL) { - if ((data->poletar->type == OB_ARMATURE) && (data->polesubtarget[0])) { - ComponentKey target_key(&data->poletar->id, - NodeType::BONE, - data->polesubtarget); - add_relation(target_key, solver_key, con->name); - } - else if (data->polesubtarget[0] && - ELEM(data->poletar->type, OB_MESH, OB_LATTICE)) - { - /* Vertex group target. */ - /* NOTE: for now, we don't need to represent vertex groups - * separately. */ - ComponentKey target_key(&data->poletar->id, NodeType::GEOMETRY); - add_relation(target_key, solver_key, con->name); - add_customdata_mask(data->poletar, DEGCustomDataMeshMasks::MaskVert(CD_MASK_MDEFORMVERT)); - } - else { - ComponentKey target_key(&data->poletar->id, NodeType::TRANSFORM); - add_relation(target_key, solver_key, con->name); - } - } - DEG_DEBUG_PRINTF( - (::Depsgraph *)graph_, - BUILD, - "\nStarting IK Build: pchan = %s, target = (%s, %s), " - "segcount = %d\n", - pchan->name, data->tar ? data->tar->id.name : "NULL", - data->subtarget, data->rootbone); - bPoseChannel *parchan = pchan; - /* Exclude tip from chain if needed. */ - if (!(data->flag & CONSTRAINT_IK_TIP)) { - parchan = pchan->parent; - } - root_map->add_bone(parchan->name, rootchan->name); - OperationKey parchan_transforms_key(&object->id, NodeType::BONE, - parchan->name, OperationCode::BONE_READY); - add_relation(parchan_transforms_key, solver_key, "IK Solver Owner"); - /* Walk to the chain's root. */ - int segcount = 0; - while (parchan != NULL) { - /* Make IK-solver dependent on this bone's result, since it can only run - * after the standard results of the bone are know. Validate links step - * on the bone will ensure that users of this bone only grab the result - * with IK solver results. */ - if (parchan != pchan) { - OperationKey parent_key(&object->id, - NodeType::BONE, - parchan->name, - OperationCode::BONE_READY); - add_relation(parent_key, solver_key, "IK Chain Parent"); - OperationKey bone_done_key(&object->id, - NodeType::BONE, - parchan->name, - OperationCode::BONE_DONE); - add_relation(solver_key, bone_done_key, "IK Chain Result"); - } - else { - OperationKey final_transforms_key(&object->id, - NodeType::BONE, - parchan->name, - OperationCode::BONE_DONE); - add_relation(solver_key, final_transforms_key, "IK Solver Result"); - } - parchan->flag |= POSE_DONE; - root_map->add_bone(parchan->name, rootchan->name); - /* continue up chain, until we reach target number of items. */ - DEG_DEBUG_PRINTF((::Depsgraph *)graph_, - BUILD, - " %d = %s\n", - segcount, parchan->name); - /* TODO(sergey): This is an arbitrary value, which was just following - * old code convention. */ - segcount++; - if ((segcount == data->rootbone) || (segcount > 255)) { - break; - } - parchan = parchan->parent; - } - OperationKey pose_done_key( - &object->id, NodeType::EVAL_POSE, OperationCode::POSE_DONE); - add_relation(solver_key, pose_done_key, "PoseEval Result-Bone Link"); + bKinematicConstraint *data = (bKinematicConstraint *)con->data; + /* Attach owner to IK Solver to. */ + bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data); + if (rootchan == NULL) { + return; + } + OperationKey pchan_local_key( + &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL); + OperationKey init_ik_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_INIT_IK); + OperationKey solver_key( + &object->id, NodeType::EVAL_POSE, rootchan->name, OperationCode::POSE_IK_SOLVER); + OperationKey pose_cleanup_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_CLEANUP); + add_relation(pchan_local_key, init_ik_key, "IK Constraint -> Init IK Tree"); + add_relation(init_ik_key, solver_key, "Init IK -> IK Solver"); + /* Never cleanup before solver is run. */ + add_relation(solver_key, pose_cleanup_key, "IK Solver -> Cleanup", RELATION_FLAG_GODMODE); + /* IK target */ + /* TODO(sergey): This should get handled as part of the constraint code. */ + if (data->tar != NULL) { + /* TODO(sergey): For until we'll store partial matrices in the + * depsgraph, we create dependency between target object and pose eval + * component. + * + * This way we ensuring the whole subtree is updated from scratch + * without need of intermediate matrices. This is an overkill, but good + * enough for testing IK solver. */ + ComponentKey pose_key(&object->id, NodeType::EVAL_POSE); + if ((data->tar->type == OB_ARMATURE) && (data->subtarget[0])) { + /* TODO(sergey): This is only for until granular update stores + * intermediate result. */ + if (data->tar != object) { + /* Different armature - can just read the results. */ + ComponentKey target_key(&data->tar->id, NodeType::BONE, data->subtarget); + add_relation(target_key, pose_key, con->name); + } + else { + /* Same armature - we'll use the ready state only, just in case + * this bone is in the chain we're solving. */ + OperationKey target_key( + &data->tar->id, NodeType::BONE, data->subtarget, OperationCode::BONE_DONE); + add_relation(target_key, solver_key, con->name); + } + } + else if (data->subtarget[0] && ELEM(data->tar->type, OB_MESH, OB_LATTICE)) { + /* Vertex group target. */ + /* NOTE: for now, we don't need to represent vertex groups + * separately. */ + ComponentKey target_key(&data->tar->id, NodeType::GEOMETRY); + add_relation(target_key, solver_key, con->name); + add_customdata_mask(data->tar, DEGCustomDataMeshMasks::MaskVert(CD_MASK_MDEFORMVERT)); + } + else { + /* Standard Object Target. */ + ComponentKey target_key(&data->tar->id, NodeType::TRANSFORM); + add_relation(target_key, pose_key, con->name); + } + if (data->tar == object && data->subtarget[0]) { + /* Prevent target's constraints from linking to anything from same + * chain that it controls. */ + root_map->add_bone(data->subtarget, rootchan->name); + } + } + /* Pole Target. */ + /* TODO(sergey): This should get handled as part of the constraint code. */ + if (data->poletar != NULL) { + if ((data->poletar->type == OB_ARMATURE) && (data->polesubtarget[0])) { + ComponentKey target_key(&data->poletar->id, NodeType::BONE, data->polesubtarget); + add_relation(target_key, solver_key, con->name); + } + else if (data->polesubtarget[0] && ELEM(data->poletar->type, OB_MESH, OB_LATTICE)) { + /* Vertex group target. */ + /* NOTE: for now, we don't need to represent vertex groups + * separately. */ + ComponentKey target_key(&data->poletar->id, NodeType::GEOMETRY); + add_relation(target_key, solver_key, con->name); + add_customdata_mask(data->poletar, DEGCustomDataMeshMasks::MaskVert(CD_MASK_MDEFORMVERT)); + } + else { + ComponentKey target_key(&data->poletar->id, NodeType::TRANSFORM); + add_relation(target_key, solver_key, con->name); + } + } + DEG_DEBUG_PRINTF((::Depsgraph *)graph_, + BUILD, + "\nStarting IK Build: pchan = %s, target = (%s, %s), " + "segcount = %d\n", + pchan->name, + data->tar ? data->tar->id.name : "NULL", + data->subtarget, + data->rootbone); + bPoseChannel *parchan = pchan; + /* Exclude tip from chain if needed. */ + if (!(data->flag & CONSTRAINT_IK_TIP)) { + parchan = pchan->parent; + } + root_map->add_bone(parchan->name, rootchan->name); + OperationKey parchan_transforms_key( + &object->id, NodeType::BONE, parchan->name, OperationCode::BONE_READY); + add_relation(parchan_transforms_key, solver_key, "IK Solver Owner"); + /* Walk to the chain's root. */ + int segcount = 0; + while (parchan != NULL) { + /* Make IK-solver dependent on this bone's result, since it can only run + * after the standard results of the bone are know. Validate links step + * on the bone will ensure that users of this bone only grab the result + * with IK solver results. */ + if (parchan != pchan) { + OperationKey parent_key( + &object->id, NodeType::BONE, parchan->name, OperationCode::BONE_READY); + add_relation(parent_key, solver_key, "IK Chain Parent"); + OperationKey bone_done_key( + &object->id, NodeType::BONE, parchan->name, OperationCode::BONE_DONE); + add_relation(solver_key, bone_done_key, "IK Chain Result"); + } + else { + OperationKey final_transforms_key( + &object->id, NodeType::BONE, parchan->name, OperationCode::BONE_DONE); + add_relation(solver_key, final_transforms_key, "IK Solver Result"); + } + parchan->flag |= POSE_DONE; + root_map->add_bone(parchan->name, rootchan->name); + /* continue up chain, until we reach target number of items. */ + DEG_DEBUG_PRINTF((::Depsgraph *)graph_, BUILD, " %d = %s\n", segcount, parchan->name); + /* TODO(sergey): This is an arbitrary value, which was just following + * old code convention. */ + segcount++; + if ((segcount == data->rootbone) || (segcount > 255)) { + break; + } + parchan = parchan->parent; + } + OperationKey pose_done_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_DONE); + add_relation(solver_key, pose_done_key, "PoseEval Result-Bone Link"); } /* Spline IK Eval Steps */ @@ -235,375 +208,270 @@ void DepsgraphRelationBuilder::build_splineik_pose(Object *object, bConstraint *con, RootPChanMap *root_map) { - bSplineIKConstraint *data = (bSplineIKConstraint *)con->data; - bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data); - OperationKey transforms_key(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_READY); - OperationKey init_ik_key(&object->id, - NodeType::EVAL_POSE, - OperationCode::POSE_INIT_IK); - OperationKey solver_key(&object->id, - NodeType::EVAL_POSE, - rootchan->name, - OperationCode::POSE_SPLINE_IK_SOLVER); - OperationKey pose_cleanup_key( - &object->id, NodeType::EVAL_POSE, OperationCode::POSE_CLEANUP); - /* Solver depends on initialization. */ - add_relation(init_ik_key, solver_key, "Init IK -> IK Solver"); - /* Never cleanup before solver is run. */ - add_relation(solver_key, pose_cleanup_key, "IK Solver -> Cleanup"); - /* Attach owner to IK Solver. */ - add_relation(transforms_key, - solver_key, - "Spline IK Solver Owner", - RELATION_FLAG_GODMODE); - /* Attach path dependency to solver. */ - if (data->tar != NULL) { - ComponentKey target_geometry_key(&data->tar->id, NodeType::GEOMETRY); - add_relation(target_geometry_key, solver_key, "Curve.Path -> Spline IK"); - ComponentKey target_transform_key(&data->tar->id, NodeType::TRANSFORM); - add_relation(target_transform_key, solver_key, "Curve.Transform -> Spline IK"); - add_special_eval_flag(&data->tar->id, DAG_EVAL_NEED_CURVE_PATH); - } - pchan->flag |= POSE_DONE; - OperationKey final_transforms_key( - &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_DONE); - add_relation(solver_key, final_transforms_key, "Spline IK Result"); - root_map->add_bone(pchan->name, rootchan->name); - /* Walk to the chain's root/ */ - int segcount = 1; - for (bPoseChannel *parchan = pchan->parent; - parchan != NULL && segcount < data->chainlen; - parchan = parchan->parent, segcount++) - { - /* Make Spline IK solver dependent on this bone's result, since it can - * only run after the standard results of the bone are know. Validate - * links step on the bone will ensure that users of this bone only grab - * the result with IK solver results. */ - OperationKey parent_key(&object->id, - NodeType::BONE, - parchan->name, - OperationCode::BONE_READY); - add_relation(parent_key, solver_key, "Spline IK Solver Update"); - OperationKey bone_done_key(&object->id, - NodeType::BONE, - parchan->name, - OperationCode::BONE_DONE); - add_relation(solver_key, bone_done_key, "Spline IK Solver Result"); - parchan->flag |= POSE_DONE; - root_map->add_bone(parchan->name, rootchan->name); - } - OperationKey pose_done_key( - &object->id, NodeType::EVAL_POSE, OperationCode::POSE_DONE); - add_relation(solver_key, pose_done_key, "PoseEval Result-Bone Link"); + bSplineIKConstraint *data = (bSplineIKConstraint *)con->data; + bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data); + OperationKey transforms_key(&object->id, NodeType::BONE, pchan->name, OperationCode::BONE_READY); + OperationKey init_ik_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_INIT_IK); + OperationKey solver_key( + &object->id, NodeType::EVAL_POSE, rootchan->name, OperationCode::POSE_SPLINE_IK_SOLVER); + OperationKey pose_cleanup_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_CLEANUP); + /* Solver depends on initialization. */ + add_relation(init_ik_key, solver_key, "Init IK -> IK Solver"); + /* Never cleanup before solver is run. */ + add_relation(solver_key, pose_cleanup_key, "IK Solver -> Cleanup"); + /* Attach owner to IK Solver. */ + add_relation(transforms_key, solver_key, "Spline IK Solver Owner", RELATION_FLAG_GODMODE); + /* Attach path dependency to solver. */ + if (data->tar != NULL) { + ComponentKey target_geometry_key(&data->tar->id, NodeType::GEOMETRY); + add_relation(target_geometry_key, solver_key, "Curve.Path -> Spline IK"); + ComponentKey target_transform_key(&data->tar->id, NodeType::TRANSFORM); + add_relation(target_transform_key, solver_key, "Curve.Transform -> Spline IK"); + add_special_eval_flag(&data->tar->id, DAG_EVAL_NEED_CURVE_PATH); + } + pchan->flag |= POSE_DONE; + OperationKey final_transforms_key( + &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_DONE); + add_relation(solver_key, final_transforms_key, "Spline IK Result"); + root_map->add_bone(pchan->name, rootchan->name); + /* Walk to the chain's root/ */ + int segcount = 1; + for (bPoseChannel *parchan = pchan->parent; parchan != NULL && segcount < data->chainlen; + parchan = parchan->parent, segcount++) { + /* Make Spline IK solver dependent on this bone's result, since it can + * only run after the standard results of the bone are know. Validate + * links step on the bone will ensure that users of this bone only grab + * the result with IK solver results. */ + OperationKey parent_key(&object->id, NodeType::BONE, parchan->name, OperationCode::BONE_READY); + add_relation(parent_key, solver_key, "Spline IK Solver Update"); + OperationKey bone_done_key( + &object->id, NodeType::BONE, parchan->name, OperationCode::BONE_DONE); + add_relation(solver_key, bone_done_key, "Spline IK Solver Result"); + parchan->flag |= POSE_DONE; + root_map->add_bone(parchan->name, rootchan->name); + } + OperationKey pose_done_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_DONE); + add_relation(solver_key, pose_done_key, "PoseEval Result-Bone Link"); } /* Pose/Armature Bones Graph */ void DepsgraphRelationBuilder::build_rig(Object *object) { - /* Armature-Data */ - bArmature *armature = (bArmature *)object->data; - // TODO: selection status? - /* Attach links between pose operations. */ - ComponentKey local_transform(&object->id, NodeType::TRANSFORM); - OperationKey pose_init_key( - &object->id, NodeType::EVAL_POSE, OperationCode::POSE_INIT); - OperationKey pose_init_ik_key( - &object->id, NodeType::EVAL_POSE, OperationCode::POSE_INIT_IK); - OperationKey pose_cleanup_key( - &object->id, NodeType::EVAL_POSE, OperationCode::POSE_CLEANUP); - OperationKey pose_done_key( - &object->id, NodeType::EVAL_POSE, OperationCode::POSE_DONE); - add_relation( - local_transform, pose_init_key, "Local Transform -> Pose Init"); - add_relation(pose_init_key, pose_init_ik_key, "Pose Init -> Pose Init IK"); - add_relation( - pose_init_ik_key, pose_done_key, "Pose Init IK -> Pose Cleanup"); - /* Make sure pose is up-to-date with armature updates. */ - build_armature(armature); - OperationKey armature_key(&armature->id, - NodeType::PARAMETERS, - OperationCode::ARMATURE_EVAL); - add_relation(armature_key, pose_init_key, "Data dependency"); - /* Run cleanup even when there are no bones. */ - add_relation(pose_init_key, pose_cleanup_key, "Init -> Cleanup"); - /* IK Solvers. - * - * - These require separate processing steps are pose-level to be executed - * between chains of bones (i.e. once the base transforms of a bunch of - * bones is done). - * - * - We build relations for these before the dependencies between operations - * in the same component as it is necessary to check whether such bones - * are in the same IK chain (or else we get weird issues with either - * in-chain references, or with bones being parented to IK'd bones). - * - * Unsolved Issues: - * - Care is needed to ensure that multi-headed trees work out the same as - * in ik-tree building - * - Animated chain-lengths are a problem. */ - RootPChanMap root_map; - bool pose_depends_on_local_transform = false; - LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { - LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) { - switch (con->type) { - case CONSTRAINT_TYPE_KINEMATIC: - build_ik_pose(object, pchan, con, &root_map); - pose_depends_on_local_transform = true; - break; - case CONSTRAINT_TYPE_SPLINEIK: - build_splineik_pose(object, pchan, con, &root_map); - pose_depends_on_local_transform = true; - break; - /* Constraints which needs world's matrix for transform. - * TODO(sergey): More constraints here? */ - case CONSTRAINT_TYPE_ROTLIKE: - case CONSTRAINT_TYPE_SIZELIKE: - case CONSTRAINT_TYPE_LOCLIKE: - case CONSTRAINT_TYPE_TRANSLIKE: - /* TODO(sergey): Add used space check. */ - pose_depends_on_local_transform = true; - break; - default: - break; - } - } - } - // root_map.print_debug(); - if (pose_depends_on_local_transform) { - /* TODO(sergey): Once partial updates are possible use relation between - * object transform and solver itself in it's build function. */ - ComponentKey pose_key(&object->id, NodeType::EVAL_POSE); - ComponentKey local_transform_key(&object->id, NodeType::TRANSFORM); - add_relation(local_transform_key, pose_key, "Local Transforms"); - } - /* Links between operations for each bone. */ - LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { - OperationKey bone_local_key(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_LOCAL); - OperationKey bone_pose_key(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_POSE_PARENT); - OperationKey bone_ready_key(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_READY); - OperationKey bone_done_key(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_DONE); - pchan->flag &= ~POSE_DONE; - /* Pose init to bone local. */ - add_relation(pose_init_key, - bone_local_key, - "Pose Init - Bone Local", - RELATION_FLAG_GODMODE); - /* Local to pose parenting operation. */ - add_relation(bone_local_key, bone_pose_key, "Bone Local - Bone Pose"); - /* Parent relation. */ - if (pchan->parent != NULL) { - OperationCode parent_key_opcode; - /* NOTE: this difference in handling allows us to prevent lockups - * while ensuring correct poses for separate chains. */ - if (root_map.has_common_root(pchan->name, pchan->parent->name)) { - parent_key_opcode = OperationCode::BONE_READY; - } - else { - parent_key_opcode = OperationCode::BONE_DONE; - } + /* Armature-Data */ + bArmature *armature = (bArmature *)object->data; + // TODO: selection status? + /* Attach links between pose operations. */ + ComponentKey local_transform(&object->id, NodeType::TRANSFORM); + OperationKey pose_init_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_INIT); + OperationKey pose_init_ik_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_INIT_IK); + OperationKey pose_cleanup_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_CLEANUP); + OperationKey pose_done_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_DONE); + add_relation(local_transform, pose_init_key, "Local Transform -> Pose Init"); + add_relation(pose_init_key, pose_init_ik_key, "Pose Init -> Pose Init IK"); + add_relation(pose_init_ik_key, pose_done_key, "Pose Init IK -> Pose Cleanup"); + /* Make sure pose is up-to-date with armature updates. */ + build_armature(armature); + OperationKey armature_key(&armature->id, NodeType::PARAMETERS, OperationCode::ARMATURE_EVAL); + add_relation(armature_key, pose_init_key, "Data dependency"); + /* Run cleanup even when there are no bones. */ + add_relation(pose_init_key, pose_cleanup_key, "Init -> Cleanup"); + /* IK Solvers. + * + * - These require separate processing steps are pose-level to be executed + * between chains of bones (i.e. once the base transforms of a bunch of + * bones is done). + * + * - We build relations for these before the dependencies between operations + * in the same component as it is necessary to check whether such bones + * are in the same IK chain (or else we get weird issues with either + * in-chain references, or with bones being parented to IK'd bones). + * + * Unsolved Issues: + * - Care is needed to ensure that multi-headed trees work out the same as + * in ik-tree building + * - Animated chain-lengths are a problem. */ + RootPChanMap root_map; + bool pose_depends_on_local_transform = false; + LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { + LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) { + switch (con->type) { + case CONSTRAINT_TYPE_KINEMATIC: + build_ik_pose(object, pchan, con, &root_map); + pose_depends_on_local_transform = true; + break; + case CONSTRAINT_TYPE_SPLINEIK: + build_splineik_pose(object, pchan, con, &root_map); + pose_depends_on_local_transform = true; + break; + /* Constraints which needs world's matrix for transform. + * TODO(sergey): More constraints here? */ + case CONSTRAINT_TYPE_ROTLIKE: + case CONSTRAINT_TYPE_SIZELIKE: + case CONSTRAINT_TYPE_LOCLIKE: + case CONSTRAINT_TYPE_TRANSLIKE: + /* TODO(sergey): Add used space check. */ + pose_depends_on_local_transform = true; + break; + default: + break; + } + } + } + // root_map.print_debug(); + if (pose_depends_on_local_transform) { + /* TODO(sergey): Once partial updates are possible use relation between + * object transform and solver itself in it's build function. */ + ComponentKey pose_key(&object->id, NodeType::EVAL_POSE); + ComponentKey local_transform_key(&object->id, NodeType::TRANSFORM); + add_relation(local_transform_key, pose_key, "Local Transforms"); + } + /* Links between operations for each bone. */ + LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { + OperationKey bone_local_key( + &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL); + OperationKey bone_pose_key( + &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_POSE_PARENT); + OperationKey bone_ready_key( + &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_READY); + OperationKey bone_done_key(&object->id, NodeType::BONE, pchan->name, OperationCode::BONE_DONE); + pchan->flag &= ~POSE_DONE; + /* Pose init to bone local. */ + add_relation(pose_init_key, bone_local_key, "Pose Init - Bone Local", RELATION_FLAG_GODMODE); + /* Local to pose parenting operation. */ + add_relation(bone_local_key, bone_pose_key, "Bone Local - Bone Pose"); + /* Parent relation. */ + if (pchan->parent != NULL) { + OperationCode parent_key_opcode; + /* NOTE: this difference in handling allows us to prevent lockups + * while ensuring correct poses for separate chains. */ + if (root_map.has_common_root(pchan->name, pchan->parent->name)) { + parent_key_opcode = OperationCode::BONE_READY; + } + else { + parent_key_opcode = OperationCode::BONE_DONE; + } - OperationKey parent_key(&object->id, - NodeType::BONE, - pchan->parent->name, - parent_key_opcode); - add_relation( - parent_key, bone_pose_key, "Parent Bone -> Child Bone"); - } - /* Build constraints. */ - if (pchan->constraints.first != NULL) { - /* Build relations for indirectly linked objects. */ - BuilderWalkUserData data; - data.builder = this; - BKE_constraints_id_loop( - &pchan->constraints, constraint_walk, &data); - /* Constraints stack and constraint dependencies. */ - build_constraints(&object->id, - NodeType::BONE, - pchan->name, - &pchan->constraints, - &root_map); - /* Pose -> constraints. */ - OperationKey constraints_key(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_CONSTRAINTS); - add_relation(bone_pose_key, constraints_key, "Pose -> Constraints Stack"); - add_relation(bone_local_key, constraints_key, "Local -> Constraints Stack"); - /* Constraints -> ready/ */ - /* TODO(sergey): When constraint stack is exploded, this step should - * occur before the first IK solver. */ - add_relation( - constraints_key, bone_ready_key, "Constraints -> Ready"); - } - else { - /* Pose -> Ready */ - add_relation(bone_pose_key, bone_ready_key, "Pose -> Ready"); - } - /* Bone ready -> Bone done. - * NOTE: For bones without IK, this is all that's needed. - * For IK chains however, an additional rel is created from IK - * to done, with transitive reduction removing this one. */ - add_relation(bone_ready_key, bone_done_key, "Ready -> Done"); - /* B-Bone shape is the real final step after Done if present. */ - if (pchan->bone != NULL && pchan->bone->segments > 1) { - OperationKey bone_segments_key(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_SEGMENTS); - /* B-Bone shape depends on the final position of the bone. */ - add_relation(bone_done_key, - bone_segments_key, - "Done -> B-Bone Segments"); - /* B-Bone shape depends on final position of handle bones. */ - bPoseChannel *prev, *next; - BKE_pchan_bbone_handles_get(pchan, &prev, &next); - if (prev) { - OperationKey prev_key(&object->id, - NodeType::BONE, - prev->name, - OperationCode::BONE_DONE); - add_relation(prev_key, - bone_segments_key, - "Prev Handle -> B-Bone Segments"); - } - if (next) { - OperationKey next_key(&object->id, - NodeType::BONE, - next->name, - OperationCode::BONE_DONE); - add_relation(next_key, - bone_segments_key, - "Next Handle -> B-Bone Segments"); - } - /* Pose requires the B-Bone shape. */ - add_relation(bone_segments_key, - pose_done_key, - "PoseEval Result-Bone Link", - RELATION_FLAG_GODMODE); - add_relation(bone_segments_key, - pose_cleanup_key, - "Cleanup dependency"); - } - else { - /* Assume that all bones must be done for the pose to be ready - * (for deformers). */ - add_relation(bone_done_key, - pose_done_key, - "PoseEval Result-Bone Link"); + OperationKey parent_key(&object->id, NodeType::BONE, pchan->parent->name, parent_key_opcode); + add_relation(parent_key, bone_pose_key, "Parent Bone -> Child Bone"); + } + /* Build constraints. */ + if (pchan->constraints.first != NULL) { + /* Build relations for indirectly linked objects. */ + BuilderWalkUserData data; + data.builder = this; + BKE_constraints_id_loop(&pchan->constraints, constraint_walk, &data); + /* Constraints stack and constraint dependencies. */ + build_constraints(&object->id, NodeType::BONE, pchan->name, &pchan->constraints, &root_map); + /* Pose -> constraints. */ + OperationKey constraints_key( + &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_CONSTRAINTS); + add_relation(bone_pose_key, constraints_key, "Pose -> Constraints Stack"); + add_relation(bone_local_key, constraints_key, "Local -> Constraints Stack"); + /* Constraints -> ready/ */ + /* TODO(sergey): When constraint stack is exploded, this step should + * occur before the first IK solver. */ + add_relation(constraints_key, bone_ready_key, "Constraints -> Ready"); + } + else { + /* Pose -> Ready */ + add_relation(bone_pose_key, bone_ready_key, "Pose -> Ready"); + } + /* Bone ready -> Bone done. + * NOTE: For bones without IK, this is all that's needed. + * For IK chains however, an additional rel is created from IK + * to done, with transitive reduction removing this one. */ + add_relation(bone_ready_key, bone_done_key, "Ready -> Done"); + /* B-Bone shape is the real final step after Done if present. */ + if (pchan->bone != NULL && pchan->bone->segments > 1) { + OperationKey bone_segments_key( + &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_SEGMENTS); + /* B-Bone shape depends on the final position of the bone. */ + add_relation(bone_done_key, bone_segments_key, "Done -> B-Bone Segments"); + /* B-Bone shape depends on final position of handle bones. */ + bPoseChannel *prev, *next; + BKE_pchan_bbone_handles_get(pchan, &prev, &next); + if (prev) { + OperationKey prev_key(&object->id, NodeType::BONE, prev->name, OperationCode::BONE_DONE); + add_relation(prev_key, bone_segments_key, "Prev Handle -> B-Bone Segments"); + } + if (next) { + OperationKey next_key(&object->id, NodeType::BONE, next->name, OperationCode::BONE_DONE); + add_relation(next_key, bone_segments_key, "Next Handle -> B-Bone Segments"); + } + /* Pose requires the B-Bone shape. */ + add_relation( + bone_segments_key, pose_done_key, "PoseEval Result-Bone Link", RELATION_FLAG_GODMODE); + add_relation(bone_segments_key, pose_cleanup_key, "Cleanup dependency"); + } + else { + /* Assume that all bones must be done for the pose to be ready + * (for deformers). */ + add_relation(bone_done_key, pose_done_key, "PoseEval Result-Bone Link"); - /* Bones must be traversed before cleanup. */ - add_relation(bone_done_key, - pose_cleanup_key, - "Done -> Cleanup"); + /* Bones must be traversed before cleanup. */ + add_relation(bone_done_key, pose_cleanup_key, "Done -> Cleanup"); - add_relation(bone_ready_key, - pose_cleanup_key, - "Ready -> Cleanup"); - } - /* Custom shape. */ - if (pchan->custom != NULL) { - build_object(NULL, pchan->custom); - } - } + add_relation(bone_ready_key, pose_cleanup_key, "Ready -> Cleanup"); + } + /* Custom shape. */ + if (pchan->custom != NULL) { + build_object(NULL, pchan->custom); + } + } } void DepsgraphRelationBuilder::build_proxy_rig(Object *object) { - bArmature *armature = (bArmature *)object->data; - Object *proxy_from = object->proxy_from; - build_armature(armature); - OperationKey pose_init_key(&object->id, - NodeType::EVAL_POSE, - OperationCode::POSE_INIT); - OperationKey pose_done_key(&object->id, - NodeType::EVAL_POSE, - OperationCode::POSE_DONE); - OperationKey pose_cleanup_key(&object->id, - NodeType::EVAL_POSE, - OperationCode::POSE_CLEANUP); - LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { - OperationKey bone_local_key(&object->id, - NodeType::BONE, pchan->name, - OperationCode::BONE_LOCAL); - OperationKey bone_ready_key(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_READY); - OperationKey bone_done_key(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_DONE); - OperationKey from_bone_done_key(&proxy_from->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_DONE); - add_relation(pose_init_key, bone_local_key, "Pose Init -> Bone Local"); - add_relation(bone_local_key, bone_ready_key, "Local -> Ready"); - add_relation(bone_ready_key, bone_done_key, "Ready -> Done"); - add_relation( - bone_done_key, pose_cleanup_key, "Bone Done -> Pose Cleanup"); - add_relation(bone_done_key, - pose_done_key, - "Bone Done -> Pose Done", - RELATION_FLAG_GODMODE); - /* Make sure bone in the proxy is not done before it's FROM is done. */ - if (pchan->bone && pchan->bone->segments > 1) { - OperationKey from_bone_segments_key(&proxy_from->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_SEGMENTS); - add_relation(from_bone_segments_key, - bone_done_key, - "Bone Segments -> Bone Done", - RELATION_FLAG_GODMODE); - } - else { - add_relation(from_bone_done_key, - bone_done_key, - "Bone Done -> Bone Done"); - } + bArmature *armature = (bArmature *)object->data; + Object *proxy_from = object->proxy_from; + build_armature(armature); + OperationKey pose_init_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_INIT); + OperationKey pose_done_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_DONE); + OperationKey pose_cleanup_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_CLEANUP); + LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { + OperationKey bone_local_key( + &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL); + OperationKey bone_ready_key( + &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_READY); + OperationKey bone_done_key(&object->id, NodeType::BONE, pchan->name, OperationCode::BONE_DONE); + OperationKey from_bone_done_key( + &proxy_from->id, NodeType::BONE, pchan->name, OperationCode::BONE_DONE); + add_relation(pose_init_key, bone_local_key, "Pose Init -> Bone Local"); + add_relation(bone_local_key, bone_ready_key, "Local -> Ready"); + add_relation(bone_ready_key, bone_done_key, "Ready -> Done"); + add_relation(bone_done_key, pose_cleanup_key, "Bone Done -> Pose Cleanup"); + add_relation(bone_done_key, pose_done_key, "Bone Done -> Pose Done", RELATION_FLAG_GODMODE); + /* Make sure bone in the proxy is not done before it's FROM is done. */ + if (pchan->bone && pchan->bone->segments > 1) { + OperationKey from_bone_segments_key( + &proxy_from->id, NodeType::BONE, pchan->name, OperationCode::BONE_SEGMENTS); + add_relation(from_bone_segments_key, + bone_done_key, + "Bone Segments -> Bone Done", + RELATION_FLAG_GODMODE); + } + else { + add_relation(from_bone_done_key, bone_done_key, "Bone Done -> Bone Done"); + } - /* Parent relation: even though the proxy bone itself doesn't need - * the parent bone, some users expect the parent to be ready if the - * bone itself is (e.g. for computing the local space matrix). - */ - if (pchan->parent != NULL) { - OperationKey parent_key(&object->id, - NodeType::BONE, - pchan->parent->name, - OperationCode::BONE_DONE); - add_relation(parent_key, bone_done_key, "Parent Bone -> Child Bone"); - } + /* Parent relation: even though the proxy bone itself doesn't need + * the parent bone, some users expect the parent to be ready if the + * bone itself is (e.g. for computing the local space matrix). + */ + if (pchan->parent != NULL) { + OperationKey parent_key( + &object->id, NodeType::BONE, pchan->parent->name, OperationCode::BONE_DONE); + add_relation(parent_key, bone_done_key, "Parent Bone -> Child Bone"); + } - if (pchan->prop != NULL) { - OperationKey bone_parameters(&object->id, - NodeType::PARAMETERS, - OperationCode::PARAMETERS_EVAL, - pchan->name); - OperationKey from_bone_parameters(&proxy_from->id, - NodeType::PARAMETERS, - OperationCode::PARAMETERS_EVAL, - pchan->name); - add_relation(from_bone_parameters, - bone_parameters, - "Proxy Bone Parameters"); - } - } + if (pchan->prop != NULL) { + OperationKey bone_parameters( + &object->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, pchan->name); + OperationKey from_bone_parameters( + &proxy_from->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, pchan->name); + add_relation(from_bone_parameters, bone_parameters, "Proxy Bone Parameters"); + } + } } } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc index 622bb4a8a02..a325544e046 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc @@ -27,7 +27,7 @@ #include #include -#include /* required for STREQ later on. */ +#include /* required for STREQ later on. */ #include "MEM_guardedalloc.h" @@ -61,78 +61,78 @@ namespace DEG { void DepsgraphRelationBuilder::build_layer_collections(ListBase *lb) { - const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT) ? - COLLECTION_RESTRICT_VIEW : COLLECTION_RESTRICT_RENDER; - - for (LayerCollection *lc = (LayerCollection *)lb->first; lc; lc = lc->next) { - if ((lc->collection->flag & restrict_flag)) { - continue; - } - if ((lc->flag & LAYER_COLLECTION_EXCLUDE) == 0) { - build_collection(lc, NULL, lc->collection); - } - build_layer_collections(&lc->layer_collections); - } + const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT) ? COLLECTION_RESTRICT_VIEW : + COLLECTION_RESTRICT_RENDER; + + for (LayerCollection *lc = (LayerCollection *)lb->first; lc; lc = lc->next) { + if ((lc->collection->flag & restrict_flag)) { + continue; + } + if ((lc->flag & LAYER_COLLECTION_EXCLUDE) == 0) { + build_collection(lc, NULL, lc->collection); + } + build_layer_collections(&lc->layer_collections); + } } void DepsgraphRelationBuilder::build_view_layer(Scene *scene, ViewLayer *view_layer) { - /* Setup currently building context. */ - scene_ = scene; - /* Scene objects. */ - /* NOTE: Nodes builder requires us to pass CoW base because it's being - * passed to the evaluation functions. During relations builder we only - * do NULL-pointer check of the base, so it's fine to pass original one. */ - LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { - if (need_pull_base_into_graph(base)) { - build_object(base, base->object); - } - } - - build_layer_collections(&view_layer->layer_collections); - - if (scene->camera != NULL) { - build_object(NULL, scene->camera); - } - /* Rigidbody. */ - if (scene->rigidbody_world != NULL) { - build_rigidbody(scene); - } - /* Scene's animation and drivers. */ - if (scene->adt != NULL) { - build_animdata(&scene->id); - } - /* World. */ - if (scene->world != NULL) { - build_world(scene->world); - } - /* Compositor nodes. */ - if (scene->nodetree != NULL) { - build_compositor(scene); - } - /* Masks. */ - LISTBASE_FOREACH (Mask *, mask, &bmain_->masks) { - build_mask(mask); - } - /* Movie clips. */ - LISTBASE_FOREACH (MovieClip *, clip, &bmain_->movieclips) { - build_movieclip(clip); - } - /* Material override. */ - if (view_layer->mat_override != NULL) { - build_material(view_layer->mat_override); - } - /* Freestyle collections. */ - LISTBASE_FOREACH (FreestyleLineSet *, fls, &view_layer->freestyle_config.linesets) { - if (fls->group != NULL) { - build_collection(NULL, NULL, fls->group); - } - } - /* Build all set scenes. */ - if (scene->set != NULL) { - ViewLayer *set_view_layer = BKE_view_layer_default_render(scene->set); - build_view_layer(scene->set, set_view_layer); - } + /* Setup currently building context. */ + scene_ = scene; + /* Scene objects. */ + /* NOTE: Nodes builder requires us to pass CoW base because it's being + * passed to the evaluation functions. During relations builder we only + * do NULL-pointer check of the base, so it's fine to pass original one. */ + LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { + if (need_pull_base_into_graph(base)) { + build_object(base, base->object); + } + } + + build_layer_collections(&view_layer->layer_collections); + + if (scene->camera != NULL) { + build_object(NULL, scene->camera); + } + /* Rigidbody. */ + if (scene->rigidbody_world != NULL) { + build_rigidbody(scene); + } + /* Scene's animation and drivers. */ + if (scene->adt != NULL) { + build_animdata(&scene->id); + } + /* World. */ + if (scene->world != NULL) { + build_world(scene->world); + } + /* Compositor nodes. */ + if (scene->nodetree != NULL) { + build_compositor(scene); + } + /* Masks. */ + LISTBASE_FOREACH (Mask *, mask, &bmain_->masks) { + build_mask(mask); + } + /* Movie clips. */ + LISTBASE_FOREACH (MovieClip *, clip, &bmain_->movieclips) { + build_movieclip(clip); + } + /* Material override. */ + if (view_layer->mat_override != NULL) { + build_material(view_layer->mat_override); + } + /* Freestyle collections. */ + LISTBASE_FOREACH (FreestyleLineSet *, fls, &view_layer->freestyle_config.linesets) { + if (fls->group != NULL) { + build_collection(NULL, NULL, fls->group); + } + } + /* Build all set scenes. */ + if (scene->set != NULL) { + ViewLayer *set_view_layer = BKE_view_layer_default_render(scene->set); + build_view_layer(scene->set, set_view_layer); + } } } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc index c8c6cc75418..810d3ee3f66 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc @@ -55,74 +55,67 @@ namespace DEG { /* ********************************* ID Data ******************************** */ class RNANodeQueryIDData { -public: - explicit RNANodeQueryIDData(const ID *id) - : id_(id), - contraint_to_pchan_map_(NULL) { - } + public: + explicit RNANodeQueryIDData(const ID *id) : id_(id), contraint_to_pchan_map_(NULL) + { + } - ~RNANodeQueryIDData() { - if (contraint_to_pchan_map_ != NULL) { - BLI_ghash_free(contraint_to_pchan_map_, NULL, NULL); - } - } + ~RNANodeQueryIDData() + { + if (contraint_to_pchan_map_ != NULL) { + BLI_ghash_free(contraint_to_pchan_map_, NULL, NULL); + } + } - const bPoseChannel *get_pchan_for_constraint(const bConstraint *constraint) - { - ensure_constraint_to_pchan_map(); - return static_cast( - BLI_ghash_lookup(contraint_to_pchan_map_, constraint)); - } + const bPoseChannel *get_pchan_for_constraint(const bConstraint *constraint) + { + ensure_constraint_to_pchan_map(); + return static_cast(BLI_ghash_lookup(contraint_to_pchan_map_, constraint)); + } - void ensure_constraint_to_pchan_map() - { - if (contraint_to_pchan_map_ != NULL) { - return; - } - BLI_assert(GS(id_->name) == ID_OB); - const Object *object = reinterpret_cast(id_); - contraint_to_pchan_map_ = - BLI_ghash_ptr_new("id data pchan constraint map"); - if (object->pose != NULL) { - LISTBASE_FOREACH ( - const bPoseChannel *, pchan, &object->pose->chanbase) - { - LISTBASE_FOREACH ( - const bConstraint *, constraint, &pchan->constraints) - { - BLI_ghash_insert(contraint_to_pchan_map_, - const_cast(constraint), - const_cast(pchan)); - } - } - } - } + void ensure_constraint_to_pchan_map() + { + if (contraint_to_pchan_map_ != NULL) { + return; + } + BLI_assert(GS(id_->name) == ID_OB); + const Object *object = reinterpret_cast(id_); + contraint_to_pchan_map_ = BLI_ghash_ptr_new("id data pchan constraint map"); + if (object->pose != NULL) { + LISTBASE_FOREACH (const bPoseChannel *, pchan, &object->pose->chanbase) { + LISTBASE_FOREACH (const bConstraint *, constraint, &pchan->constraints) { + BLI_ghash_insert(contraint_to_pchan_map_, + const_cast(constraint), + const_cast(pchan)); + } + } + } + } -protected: - /* ID this data corresponds to. */ - const ID *id_; + protected: + /* ID this data corresponds to. */ + const ID *id_; - /* indexed by bConstraint*, returns pose channel which contains that - * constraint. */ - GHash *contraint_to_pchan_map_; + /* indexed by bConstraint*, returns pose channel which contains that + * constraint. */ + GHash *contraint_to_pchan_map_; }; /* ***************************** Node Identifier **************************** */ RNANodeIdentifier::RNANodeIdentifier() - : id(NULL), - type(NodeType::UNDEFINED), - component_name(""), - operation_code(OperationCode::OPERATION), - operation_name(), - operation_name_tag(-1) + : id(NULL), + type(NodeType::UNDEFINED), + component_name(""), + operation_code(OperationCode::OPERATION), + operation_name(), + operation_name_tag(-1) { } bool RNANodeIdentifier::is_valid() const { - return id != NULL && - type != NodeType::UNDEFINED; + return id != NULL && type != NodeType::UNDEFINED; } /* ********************************** Query ********************************* */ @@ -131,264 +124,244 @@ namespace { void ghash_id_data_free_func(void *value) { - RNANodeQueryIDData *id_data = static_cast(value); - OBJECT_GUARDED_DELETE(id_data, RNANodeQueryIDData); + RNANodeQueryIDData *id_data = static_cast(value); + OBJECT_GUARDED_DELETE(id_data, RNANodeQueryIDData); } } // namespace RNANodeQuery::RNANodeQuery(Depsgraph *depsgraph) - : depsgraph_(depsgraph), - id_data_map_(BLI_ghash_ptr_new("rna node query id data hash")) + : depsgraph_(depsgraph), id_data_map_(BLI_ghash_ptr_new("rna node query id data hash")) { } RNANodeQuery::~RNANodeQuery() { - BLI_ghash_free(id_data_map_, NULL, ghash_id_data_free_func); + BLI_ghash_free(id_data_map_, NULL, ghash_id_data_free_func); } Node *RNANodeQuery::find_node(const PointerRNA *ptr, const PropertyRNA *prop, RNAPointerSource source) { - const RNANodeIdentifier node_identifier = construct_node_identifier( - ptr, prop, source); - if (!node_identifier.is_valid()) { - return NULL; - } - IDNode *id_node = depsgraph_->find_id_node(node_identifier.id); - if (id_node == NULL) { - return NULL; - } - ComponentNode *comp_node = id_node->find_component( - node_identifier.type, node_identifier.component_name); - if (comp_node == NULL) { - return NULL; - } - if (node_identifier.operation_code == OperationCode::OPERATION) { - return comp_node; - } - return comp_node->find_operation(node_identifier.operation_code, - node_identifier.operation_name, - node_identifier.operation_name_tag); + const RNANodeIdentifier node_identifier = construct_node_identifier(ptr, prop, source); + if (!node_identifier.is_valid()) { + return NULL; + } + IDNode *id_node = depsgraph_->find_id_node(node_identifier.id); + if (id_node == NULL) { + return NULL; + } + ComponentNode *comp_node = id_node->find_component(node_identifier.type, + node_identifier.component_name); + if (comp_node == NULL) { + return NULL; + } + if (node_identifier.operation_code == OperationCode::OPERATION) { + return comp_node; + } + return comp_node->find_operation(node_identifier.operation_code, + node_identifier.operation_name, + node_identifier.operation_name_tag); } -RNANodeIdentifier RNANodeQuery::construct_node_identifier( - const PointerRNA *ptr, - const PropertyRNA *prop, - RNAPointerSource source) +RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr, + const PropertyRNA *prop, + RNAPointerSource source) { - RNANodeIdentifier node_identifier; - if (ptr->type == NULL) { - return node_identifier; - } - /* Set default values for returns. */ - node_identifier.id = static_cast(ptr->id.data); - node_identifier.component_name = ""; - node_identifier.operation_code = OperationCode::OPERATION; - node_identifier.operation_name = ""; - node_identifier.operation_name_tag = -1; - /* Handling of commonly known scenarios. */ - if (ptr->type == &RNA_PoseBone) { - const bPoseChannel *pchan = - static_cast(ptr->data); - if (prop != NULL && RNA_property_is_idprop(prop)) { - node_identifier.type = NodeType::PARAMETERS; - node_identifier.operation_code = OperationCode::ID_PROPERTY; - node_identifier.operation_name = - RNA_property_identifier( - reinterpret_cast(prop)); - node_identifier.operation_name_tag = -1; - } - else { - /* Bone - generally, we just want the bone component. */ - node_identifier.type = NodeType::BONE; - node_identifier.component_name = pchan->name; - /* But B-Bone properties should connect to the actual operation. */ - if (!ELEM(NULL, pchan->bone, prop) && pchan->bone->segments > 1 && - STRPREFIX(RNA_property_identifier(prop), "bbone_")) - { - node_identifier.operation_code = OperationCode::BONE_SEGMENTS; - } - } - return node_identifier; - } - else if (ptr->type == &RNA_Bone) { - const Bone *bone = static_cast(ptr->data); - /* Armature-level bone, but it ends up going to bone component - * anyway. */ - // NOTE: the ID in this case will end up being bArmature. - node_identifier.type = NodeType::BONE; - node_identifier.component_name = bone->name; - return node_identifier; - } - else if (RNA_struct_is_a(ptr->type, &RNA_Constraint)) { - const Object *object = static_cast(ptr->id.data); - const bConstraint *constraint = - static_cast(ptr->data); - RNANodeQueryIDData *id_data = ensure_id_data(&object->id); - /* Check whether is object or bone constraint. */ - /* NOTE: Currently none of the area can address transform of an object - * at a given constraint, but for rigging one might use constraint - * influence to be used to drive some corrective shape keys or so. */ - const bPoseChannel *pchan = - id_data->get_pchan_for_constraint(constraint); - if (pchan == NULL) { - node_identifier.type = NodeType::TRANSFORM; - node_identifier.operation_code = OperationCode::TRANSFORM_LOCAL; - } - else { - node_identifier.type = NodeType::BONE; - node_identifier.operation_code = OperationCode::BONE_LOCAL; - node_identifier.component_name = pchan->name; - } - return node_identifier; - } - else if (ELEM(ptr->type, &RNA_ConstraintTarget, &RNA_ConstraintTargetBone)) { - Object *object = (Object *)ptr->id.data; - bConstraintTarget *tgt = (bConstraintTarget *)ptr->data; - /* Check whether is object or bone constraint. */ - bPoseChannel *pchan = NULL; - bConstraint *con = BKE_constraint_find_from_target(object, tgt, &pchan); - if (con != NULL) { - if (pchan != NULL) { - node_identifier.type = NodeType::BONE; - node_identifier.operation_code = OperationCode::BONE_LOCAL; - node_identifier.component_name = pchan->name; - } - else { - node_identifier.type = NodeType::TRANSFORM; - node_identifier.operation_code = OperationCode::TRANSFORM_LOCAL; - } - return node_identifier; - } - } - else if (RNA_struct_is_a(ptr->type, &RNA_Modifier)) { - /* When modifier is used as FROM operation this is likely referencing to - * the property (for example, modifier's influence). - * But when it's used as TO operation, this is geometry component. */ - switch (source) { - case RNAPointerSource::ENTRY: - node_identifier.type = NodeType::GEOMETRY; - break; - case RNAPointerSource::EXIT: - node_identifier.type = NodeType::PARAMETERS; - node_identifier.operation_code = OperationCode::PARAMETERS_EVAL; - break; - } - return node_identifier; - } - else if (ptr->type == &RNA_Object) { - /* Transforms props? */ - if (prop != NULL) { - const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop); - /* TODO(sergey): How to optimize this? */ - if (strstr(prop_identifier, "location") || - strstr(prop_identifier, "rotation") || - strstr(prop_identifier, "scale") || - strstr(prop_identifier, "matrix_")) - { - node_identifier.type = NodeType::TRANSFORM; - return node_identifier; - } - else if (strstr(prop_identifier, "data")) { - /* We access object.data, most likely a geometry. - * Might be a bone tho. */ - node_identifier.type = NodeType::GEOMETRY; - return node_identifier; - } - else if (STREQ(prop_identifier, "hide_viewport") || - STREQ(prop_identifier, "hide_render")) - { - node_identifier.type = NodeType::OBJECT_FROM_LAYER; - return node_identifier; - } - } - } - else if (ptr->type == &RNA_ShapeKey) { - KeyBlock *key_block = static_cast(ptr->data); - node_identifier.id = static_cast(ptr->id.data); - node_identifier.type = NodeType::PARAMETERS; - node_identifier.operation_code = OperationCode::PARAMETERS_EVAL; - node_identifier.operation_name = key_block->name; - return node_identifier; - } - else if (ptr->type == &RNA_Key) { - node_identifier.id = static_cast(ptr->id.data); - node_identifier.type = NodeType::GEOMETRY; - return node_identifier; - } - else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) { - const Sequence *seq = static_cast(ptr->data); - /* Sequencer strip */ - node_identifier.type = NodeType::SEQUENCER; - node_identifier.component_name = seq->name; - return node_identifier; - } - else if (RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) { - node_identifier.type = NodeType::SHADING; - return node_identifier; - } - else if (RNA_struct_is_a(ptr->type, &RNA_ShaderNode)) { - node_identifier.type = NodeType::SHADING; - return node_identifier; - } - else if (ELEM(ptr->type, &RNA_Curve, &RNA_TextCurve)) { - node_identifier.id = (ID *)ptr->id.data; - node_identifier.type = NodeType::GEOMETRY; - return node_identifier; - } - else if (ELEM(ptr->type, &RNA_BezierSplinePoint, &RNA_SplinePoint)) { - node_identifier.id = (ID *)ptr->id.data; - node_identifier.type = NodeType::GEOMETRY; - return node_identifier; - } - else if (RNA_struct_is_a(ptr->type, &RNA_ImageUser)) { - if (GS(node_identifier.id->name) == ID_NT) { - node_identifier.type = NodeType::ANIMATION; - node_identifier.operation_code = OperationCode::IMAGE_ANIMATION; - return node_identifier; - } - } - else if (ELEM(ptr->type, &RNA_MeshVertex, - &RNA_MeshEdge, - &RNA_MeshLoop, - &RNA_MeshPolygon)) - { - node_identifier.type = NodeType::GEOMETRY; - return node_identifier; - } - if (prop != NULL) { - /* All unknown data effectively falls under "parameter evaluation". */ - if (RNA_property_is_idprop(prop)) { - node_identifier.type = NodeType::PARAMETERS; - node_identifier.operation_code = OperationCode::ID_PROPERTY; - node_identifier.operation_name = - RNA_property_identifier((PropertyRNA *)prop); - node_identifier.operation_name_tag = -1; - } - else { - node_identifier.type = NodeType::PARAMETERS; - node_identifier.operation_code = OperationCode::PARAMETERS_EVAL; - node_identifier.operation_name = ""; - node_identifier.operation_name_tag = -1; - } - return node_identifier; - } - return node_identifier; + RNANodeIdentifier node_identifier; + if (ptr->type == NULL) { + return node_identifier; + } + /* Set default values for returns. */ + node_identifier.id = static_cast(ptr->id.data); + node_identifier.component_name = ""; + node_identifier.operation_code = OperationCode::OPERATION; + node_identifier.operation_name = ""; + node_identifier.operation_name_tag = -1; + /* Handling of commonly known scenarios. */ + if (ptr->type == &RNA_PoseBone) { + const bPoseChannel *pchan = static_cast(ptr->data); + if (prop != NULL && RNA_property_is_idprop(prop)) { + node_identifier.type = NodeType::PARAMETERS; + node_identifier.operation_code = OperationCode::ID_PROPERTY; + node_identifier.operation_name = RNA_property_identifier( + reinterpret_cast(prop)); + node_identifier.operation_name_tag = -1; + } + else { + /* Bone - generally, we just want the bone component. */ + node_identifier.type = NodeType::BONE; + node_identifier.component_name = pchan->name; + /* But B-Bone properties should connect to the actual operation. */ + if (!ELEM(NULL, pchan->bone, prop) && pchan->bone->segments > 1 && + STRPREFIX(RNA_property_identifier(prop), "bbone_")) { + node_identifier.operation_code = OperationCode::BONE_SEGMENTS; + } + } + return node_identifier; + } + else if (ptr->type == &RNA_Bone) { + const Bone *bone = static_cast(ptr->data); + /* Armature-level bone, but it ends up going to bone component + * anyway. */ + // NOTE: the ID in this case will end up being bArmature. + node_identifier.type = NodeType::BONE; + node_identifier.component_name = bone->name; + return node_identifier; + } + else if (RNA_struct_is_a(ptr->type, &RNA_Constraint)) { + const Object *object = static_cast(ptr->id.data); + const bConstraint *constraint = static_cast(ptr->data); + RNANodeQueryIDData *id_data = ensure_id_data(&object->id); + /* Check whether is object or bone constraint. */ + /* NOTE: Currently none of the area can address transform of an object + * at a given constraint, but for rigging one might use constraint + * influence to be used to drive some corrective shape keys or so. */ + const bPoseChannel *pchan = id_data->get_pchan_for_constraint(constraint); + if (pchan == NULL) { + node_identifier.type = NodeType::TRANSFORM; + node_identifier.operation_code = OperationCode::TRANSFORM_LOCAL; + } + else { + node_identifier.type = NodeType::BONE; + node_identifier.operation_code = OperationCode::BONE_LOCAL; + node_identifier.component_name = pchan->name; + } + return node_identifier; + } + else if (ELEM(ptr->type, &RNA_ConstraintTarget, &RNA_ConstraintTargetBone)) { + Object *object = (Object *)ptr->id.data; + bConstraintTarget *tgt = (bConstraintTarget *)ptr->data; + /* Check whether is object or bone constraint. */ + bPoseChannel *pchan = NULL; + bConstraint *con = BKE_constraint_find_from_target(object, tgt, &pchan); + if (con != NULL) { + if (pchan != NULL) { + node_identifier.type = NodeType::BONE; + node_identifier.operation_code = OperationCode::BONE_LOCAL; + node_identifier.component_name = pchan->name; + } + else { + node_identifier.type = NodeType::TRANSFORM; + node_identifier.operation_code = OperationCode::TRANSFORM_LOCAL; + } + return node_identifier; + } + } + else if (RNA_struct_is_a(ptr->type, &RNA_Modifier)) { + /* When modifier is used as FROM operation this is likely referencing to + * the property (for example, modifier's influence). + * But when it's used as TO operation, this is geometry component. */ + switch (source) { + case RNAPointerSource::ENTRY: + node_identifier.type = NodeType::GEOMETRY; + break; + case RNAPointerSource::EXIT: + node_identifier.type = NodeType::PARAMETERS; + node_identifier.operation_code = OperationCode::PARAMETERS_EVAL; + break; + } + return node_identifier; + } + else if (ptr->type == &RNA_Object) { + /* Transforms props? */ + if (prop != NULL) { + const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop); + /* TODO(sergey): How to optimize this? */ + if (strstr(prop_identifier, "location") || strstr(prop_identifier, "rotation") || + strstr(prop_identifier, "scale") || strstr(prop_identifier, "matrix_")) { + node_identifier.type = NodeType::TRANSFORM; + return node_identifier; + } + else if (strstr(prop_identifier, "data")) { + /* We access object.data, most likely a geometry. + * Might be a bone tho. */ + node_identifier.type = NodeType::GEOMETRY; + return node_identifier; + } + else if (STREQ(prop_identifier, "hide_viewport") || STREQ(prop_identifier, "hide_render")) { + node_identifier.type = NodeType::OBJECT_FROM_LAYER; + return node_identifier; + } + } + } + else if (ptr->type == &RNA_ShapeKey) { + KeyBlock *key_block = static_cast(ptr->data); + node_identifier.id = static_cast(ptr->id.data); + node_identifier.type = NodeType::PARAMETERS; + node_identifier.operation_code = OperationCode::PARAMETERS_EVAL; + node_identifier.operation_name = key_block->name; + return node_identifier; + } + else if (ptr->type == &RNA_Key) { + node_identifier.id = static_cast(ptr->id.data); + node_identifier.type = NodeType::GEOMETRY; + return node_identifier; + } + else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) { + const Sequence *seq = static_cast(ptr->data); + /* Sequencer strip */ + node_identifier.type = NodeType::SEQUENCER; + node_identifier.component_name = seq->name; + return node_identifier; + } + else if (RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) { + node_identifier.type = NodeType::SHADING; + return node_identifier; + } + else if (RNA_struct_is_a(ptr->type, &RNA_ShaderNode)) { + node_identifier.type = NodeType::SHADING; + return node_identifier; + } + else if (ELEM(ptr->type, &RNA_Curve, &RNA_TextCurve)) { + node_identifier.id = (ID *)ptr->id.data; + node_identifier.type = NodeType::GEOMETRY; + return node_identifier; + } + else if (ELEM(ptr->type, &RNA_BezierSplinePoint, &RNA_SplinePoint)) { + node_identifier.id = (ID *)ptr->id.data; + node_identifier.type = NodeType::GEOMETRY; + return node_identifier; + } + else if (RNA_struct_is_a(ptr->type, &RNA_ImageUser)) { + if (GS(node_identifier.id->name) == ID_NT) { + node_identifier.type = NodeType::ANIMATION; + node_identifier.operation_code = OperationCode::IMAGE_ANIMATION; + return node_identifier; + } + } + else if (ELEM(ptr->type, &RNA_MeshVertex, &RNA_MeshEdge, &RNA_MeshLoop, &RNA_MeshPolygon)) { + node_identifier.type = NodeType::GEOMETRY; + return node_identifier; + } + if (prop != NULL) { + /* All unknown data effectively falls under "parameter evaluation". */ + if (RNA_property_is_idprop(prop)) { + node_identifier.type = NodeType::PARAMETERS; + node_identifier.operation_code = OperationCode::ID_PROPERTY; + node_identifier.operation_name = RNA_property_identifier((PropertyRNA *)prop); + node_identifier.operation_name_tag = -1; + } + else { + node_identifier.type = NodeType::PARAMETERS; + node_identifier.operation_code = OperationCode::PARAMETERS_EVAL; + node_identifier.operation_name = ""; + node_identifier.operation_name_tag = -1; + } + return node_identifier; + } + return node_identifier; } RNANodeQueryIDData *RNANodeQuery::ensure_id_data(const ID *id) { - RNANodeQueryIDData **id_data_ptr; - if (!BLI_ghash_ensure_p(id_data_map_, - const_cast(id), - reinterpret_cast(&id_data_ptr))) - { - *id_data_ptr = OBJECT_GUARDED_NEW(RNANodeQueryIDData, id); - } - return *id_data_ptr; + RNANodeQueryIDData **id_data_ptr; + if (!BLI_ghash_ensure_p( + id_data_map_, const_cast(id), reinterpret_cast(&id_data_ptr))) { + *id_data_ptr = OBJECT_GUARDED_NEW(RNANodeQueryIDData, id); + } + return *id_data_ptr; } } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.h b/source/blender/depsgraph/intern/builder/deg_builder_rna.h index 5e121476087..e8dbd7fb523 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_rna.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.h @@ -41,58 +41,56 @@ class RNANodeQueryIDData; * interested in a result of the given property or whether we are linking some * dependency to that property. */ enum class RNAPointerSource { - /* Query will return pointer to an entry operation of component which is - * responsible for evaluation of the given property. */ - ENTRY, - /* Query will return pointer to an exit operation of component which is - * responsible for evaluation of the given property. - * More precisely, it will return operation at which the property is known - * to be evaluated. */ - EXIT, + /* Query will return pointer to an entry operation of component which is + * responsible for evaluation of the given property. */ + ENTRY, + /* Query will return pointer to an exit operation of component which is + * responsible for evaluation of the given property. + * More precisely, it will return operation at which the property is known + * to be evaluated. */ + EXIT, }; /* A helper structure which wraps all fields needed to find a node inside of * the dependency graph. */ class RNANodeIdentifier { -public: - RNANodeIdentifier(); - - /* Check whether this identifier is valid and usable. */ - bool is_valid() const; - - ID *id; - NodeType type; - const char *component_name; - OperationCode operation_code; - const char *operation_name; - int operation_name_tag; + public: + RNANodeIdentifier(); + + /* Check whether this identifier is valid and usable. */ + bool is_valid() const; + + ID *id; + NodeType type; + const char *component_name; + OperationCode operation_code; + const char *operation_name; + int operation_name_tag; }; /* Helper class which performs optimized lookups of a node within a given * dependency graph which satisfies given RNA pointer or RAN path. */ class RNANodeQuery { -public: - RNANodeQuery(Depsgraph *depsgraph); - ~RNANodeQuery(); + public: + RNANodeQuery(Depsgraph *depsgraph); + ~RNANodeQuery(); - Node *find_node(const PointerRNA *ptr, - const PropertyRNA *prop, - RNAPointerSource source); + Node *find_node(const PointerRNA *ptr, const PropertyRNA *prop, RNAPointerSource source); -protected: - Depsgraph *depsgraph_; + protected: + Depsgraph *depsgraph_; - /* Indexed by an ID, returns RNANodeQueryIDData associated with that ID. */ - GHash *id_data_map_; + /* Indexed by an ID, returns RNANodeQueryIDData associated with that ID. */ + GHash *id_data_map_; - /* Construct identifier of the node which correspods given configuration - * of RNA property. */ - RNANodeIdentifier construct_node_identifier(const PointerRNA *ptr, - const PropertyRNA *prop, - RNAPointerSource source); + /* Construct identifier of the node which correspods given configuration + * of RNA property. */ + RNANodeIdentifier construct_node_identifier(const PointerRNA *ptr, + const PropertyRNA *prop, + RNAPointerSource source); - /* Make sure ID data exists for the given ID, and returns it. */ - RNANodeQueryIDData *ensure_id_data(const ID *id); + /* Make sure ID data exists for the given ID, and returns it. */ + RNANodeQueryIDData *ensure_id_data(const ID *id); }; } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc index 2aa716fc87c..3e5e96d30ff 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc @@ -50,63 +50,61 @@ namespace DEG { */ enum { - OP_VISITED = 1, - OP_REACHABLE = 2, + OP_VISITED = 1, + OP_REACHABLE = 2, }; static void deg_graph_tag_paths_recursive(Node *node) { - if (node->custom_flags & OP_VISITED) { - return; - } - node->custom_flags |= OP_VISITED; - for (Relation *rel : node->inlinks) { - deg_graph_tag_paths_recursive(rel->from); - /* Do this only in inlinks loop, so the target node does not get - * flagged. */ - rel->from->custom_flags |= OP_REACHABLE; - } + if (node->custom_flags & OP_VISITED) { + return; + } + node->custom_flags |= OP_VISITED; + for (Relation *rel : node->inlinks) { + deg_graph_tag_paths_recursive(rel->from); + /* Do this only in inlinks loop, so the target node does not get + * flagged. */ + rel->from->custom_flags |= OP_REACHABLE; + } } void deg_graph_transitive_reduction(Depsgraph *graph) { - int num_removed_relations = 0; - for (OperationNode *target : graph->operations) { - /* Clear tags. */ - for (OperationNode *node : graph->operations) { - node->custom_flags = 0; - } - /* Mark nodes from which we can reach the target - * start with children, so the target node and direct children are not - * flagged. */ - target->custom_flags |= OP_VISITED; - for (Relation *rel : target->inlinks) { - deg_graph_tag_paths_recursive(rel->from); - } - /* Remove redundant paths to the target. */ - for (Node::Relations::const_iterator it_rel = target->inlinks.begin(); - it_rel != target->inlinks.end(); - ) - { - Relation *rel = *it_rel; - if (rel->from->type == NodeType::TIMESOURCE) { - /* HACK: time source nodes don't get "custom_flags" flag - * set/cleared. */ - /* TODO: there will be other types in future, so iterators above - * need modifying. */ - ++it_rel; - } - else if (rel->from->custom_flags & OP_REACHABLE) { - rel->unlink(); - OBJECT_GUARDED_DELETE(rel, Relation); - ++num_removed_relations; - } - else { - ++it_rel; - } - } - } - DEG_DEBUG_PRINTF((::Depsgraph *)graph, BUILD, "Removed %d relations\n", num_removed_relations); + int num_removed_relations = 0; + for (OperationNode *target : graph->operations) { + /* Clear tags. */ + for (OperationNode *node : graph->operations) { + node->custom_flags = 0; + } + /* Mark nodes from which we can reach the target + * start with children, so the target node and direct children are not + * flagged. */ + target->custom_flags |= OP_VISITED; + for (Relation *rel : target->inlinks) { + deg_graph_tag_paths_recursive(rel->from); + } + /* Remove redundant paths to the target. */ + for (Node::Relations::const_iterator it_rel = target->inlinks.begin(); + it_rel != target->inlinks.end();) { + Relation *rel = *it_rel; + if (rel->from->type == NodeType::TIMESOURCE) { + /* HACK: time source nodes don't get "custom_flags" flag + * set/cleared. */ + /* TODO: there will be other types in future, so iterators above + * need modifying. */ + ++it_rel; + } + else if (rel->from->custom_flags & OP_REACHABLE) { + rel->unlink(); + OBJECT_GUARDED_DELETE(rel, Relation); + ++num_removed_relations; + } + else { + ++it_rel; + } + } + } + DEG_DEBUG_PRINTF((::Depsgraph *)graph, BUILD, "Removed %d relations\n", num_removed_relations); } } // namespace DEG diff --git a/source/blender/depsgraph/intern/debug/deg_debug.cc b/source/blender/depsgraph/intern/debug/deg_debug.cc index a6c4b59e7df..b811f11f721 100644 --- a/source/blender/depsgraph/intern/debug/deg_debug.cc +++ b/source/blender/depsgraph/intern/debug/deg_debug.cc @@ -34,27 +34,27 @@ namespace DEG { bool terminal_do_color(void) { - return (G.debug & G_DEBUG_DEPSGRAPH_PRETTY) != 0; + return (G.debug & G_DEBUG_DEPSGRAPH_PRETTY) != 0; } string color_for_pointer(const void *pointer) { - if (!terminal_do_color()) { - return ""; - } - int r, g, b; - BLI_hash_pointer_to_color(pointer, &r, &g, &b); - char buffer[64]; - BLI_snprintf(buffer, sizeof(buffer), TRUECOLOR_ANSI_COLOR_FORMAT, r, g, b); - return string(buffer); + if (!terminal_do_color()) { + return ""; + } + int r, g, b; + BLI_hash_pointer_to_color(pointer, &r, &g, &b); + char buffer[64]; + BLI_snprintf(buffer, sizeof(buffer), TRUECOLOR_ANSI_COLOR_FORMAT, r, g, b); + return string(buffer); } string color_end(void) { - if (!terminal_do_color()) { - return ""; - } - return string(TRUECOLOR_ANSI_COLOR_FINISH); + if (!terminal_do_color()) { + return ""; + } + return string(TRUECOLOR_ANSI_COLOR_FINISH); } } // namespace DEG diff --git a/source/blender/depsgraph/intern/debug/deg_debug.h b/source/blender/depsgraph/intern/debug/deg_debug.h index 1cdcba9b8fd..3e4da644641 100644 --- a/source/blender/depsgraph/intern/debug/deg_debug.h +++ b/source/blender/depsgraph/intern/debug/deg_debug.h @@ -32,25 +32,25 @@ namespace DEG { #define DEG_DEBUG_PRINTF(depsgraph, type, ...) \ - do { \ - if (DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_ ## type) { \ - DEG_debug_print_begin(depsgraph); \ - fprintf(stdout, __VA_ARGS__); \ - } \ - } while (0) + do { \ + if (DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_##type) { \ + DEG_debug_print_begin(depsgraph); \ + fprintf(stdout, __VA_ARGS__); \ + } \ + } while (0) #define DEG_GLOBAL_DEBUG_PRINTF(type, ...) \ - do { \ - if (G.debug & G_DEBUG_DEPSGRAPH_ ## type) { \ - fprintf(stdout, __VA_ARGS__); \ - } \ - } while (0) - -#define DEG_ERROR_PRINTF(...) \ - do { \ - fprintf(stderr, __VA_ARGS__); \ - fflush(stderr); \ - } while (0) + do { \ + if (G.debug & G_DEBUG_DEPSGRAPH_##type) { \ + fprintf(stdout, __VA_ARGS__); \ + } \ + } while (0) + +#define DEG_ERROR_PRINTF(...) \ + do { \ + fprintf(stderr, __VA_ARGS__); \ + fflush(stderr); \ + } while (0) bool terminal_do_color(void); string color_for_pointer(const void *pointer); diff --git a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc index 34f68528059..abd3b398cb7 100644 --- a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc +++ b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc @@ -30,7 +30,7 @@ extern "C" { #include "DNA_listBase.h" -} /* extern "C" */ +} /* extern "C" */ #include "DEG_depsgraph.h" #include "DEG_depsgraph_debug.h" @@ -60,547 +60,546 @@ static float deg_debug_graphviz_node_label_size = 14.0f; static const int deg_debug_max_colors = 12; #ifdef COLOR_SCHEME_NODE_TYPE static const char *deg_debug_colors[] = { - "#a6cee3", "#1f78b4", "#b2df8a", - "#33a02c", "#fb9a99", "#e31a1c", - "#fdbf6f", "#ff7f00", "#cab2d6", - "#6a3d9a", "#ffff99", "#b15928", + "#a6cee3", + "#1f78b4", + "#b2df8a", + "#33a02c", + "#fb9a99", + "#e31a1c", + "#fdbf6f", + "#ff7f00", + "#cab2d6", + "#6a3d9a", + "#ffff99", + "#b15928", "#ff00ff", }; #endif static const char *deg_debug_colors_light[] = { - "#8dd3c7", "#ffffb3", "#bebada", - "#fb8072", "#80b1d3", "#fdb462", - "#b3de69", "#fccde5", "#d9d9d9", - "#bc80bd", "#ccebc5", "#ffed6f", + "#8dd3c7", + "#ffffb3", + "#bebada", + "#fb8072", + "#80b1d3", + "#fdb462", + "#b3de69", + "#fccde5", + "#d9d9d9", + "#bc80bd", + "#ccebc5", + "#ffed6f", "#ff00ff", }; #ifdef COLOR_SCHEME_NODE_TYPE static const int deg_debug_node_type_color_map[][2] = { - {NodeType::TIMESOURCE, 0}, - {NodeType::ID_REF, 1}, + {NodeType::TIMESOURCE, 0}, + {NodeType::ID_REF, 1}, /* Outer Types */ - {NodeType::PARAMETERS, 2}, - {NodeType::PROXY, 3}, - {NodeType::ANIMATION, 4}, - {NodeType::TRANSFORM, 5}, - {NodeType::GEOMETRY, 6}, - {NodeType::SEQUENCER, 7}, - {NodeType::SHADING, 8}, + {NodeType::PARAMETERS, 2}, + {NodeType::PROXY, 3}, + {NodeType::ANIMATION, 4}, + {NodeType::TRANSFORM, 5}, + {NodeType::GEOMETRY, 6}, + {NodeType::SEQUENCER, 7}, + {NodeType::SHADING, 8}, {NodeType::SHADING_PARAMETERS, 9}, - {NodeType::CACHE, 10}, - {NodeType::POINT_CACHE, 11}, - {NodeType::LAYER_COLLECTIONS, 12}, - {NodeType::COPY_ON_WRITE, 13}, - {-1, 0}, + {NodeType::CACHE, 10}, + {NodeType::POINT_CACHE, 11}, + {NodeType::LAYER_COLLECTIONS, 12}, + {NodeType::COPY_ON_WRITE, 13}, + {-1, 0}, }; #endif static int deg_debug_node_color_index(const Node *node) { #ifdef COLOR_SCHEME_NODE_CLASS - /* Some special types. */ - switch (node->type) { - case NodeType::ID_REF: - return 5; - case NodeType::OPERATION: - { - OperationNode *op_node = (OperationNode *)node; - if (op_node->is_noop()) - return 8; - break; - } - - default: - break; - } - /* Do others based on class. */ - switch (node->get_class()) { - case NodeClass::OPERATION: - return 4; - case NodeClass::COMPONENT: - return 1; - default: - return 9; - } + /* Some special types. */ + switch (node->type) { + case NodeType::ID_REF: + return 5; + case NodeType::OPERATION: { + OperationNode *op_node = (OperationNode *)node; + if (op_node->is_noop()) + return 8; + break; + } + + default: + break; + } + /* Do others based on class. */ + switch (node->get_class()) { + case NodeClass::OPERATION: + return 4; + case NodeClass::COMPONENT: + return 1; + default: + return 9; + } #endif #ifdef COLOR_SCHEME_NODE_TYPE - const int (*pair)[2]; - for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) { - if ((*pair)[0] == node->type) { - return (*pair)[1]; - } - } - return -1; + const int(*pair)[2]; + for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) { + if ((*pair)[0] == node->type) { + return (*pair)[1]; + } + } + return -1; #endif } struct DebugContext { - FILE *file; - bool show_tags; + FILE *file; + bool show_tags; }; -static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...) ATTR_PRINTF_FORMAT(2, 3); +static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...) + ATTR_PRINTF_FORMAT(2, 3); static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...) { - va_list args; - va_start(args, fmt); - vfprintf(ctx.file, fmt, args); - va_end(args); + va_list args; + va_start(args, fmt); + vfprintf(ctx.file, fmt, args); + va_end(args); } static void deg_debug_graphviz_legend_color(const DebugContext &ctx, const char *name, const char *color) { - deg_debug_fprintf(ctx, ""); - deg_debug_fprintf(ctx, "%s", name); - deg_debug_fprintf(ctx, "", color); - deg_debug_fprintf(ctx, "" NL); + deg_debug_fprintf(ctx, ""); + deg_debug_fprintf(ctx, "%s", name); + deg_debug_fprintf(ctx, "", color); + deg_debug_fprintf(ctx, "" NL); } static void deg_debug_graphviz_legend(const DebugContext &ctx) { - deg_debug_fprintf(ctx, "{" NL); - deg_debug_fprintf(ctx, "rank = sink;" NL); - deg_debug_fprintf(ctx, "Legend [shape=none, margin=0, label=<" NL); - deg_debug_fprintf(ctx, " " NL); - deg_debug_fprintf(ctx, "" NL); + deg_debug_fprintf(ctx, "{" NL); + deg_debug_fprintf(ctx, "rank = sink;" NL); + deg_debug_fprintf(ctx, "Legend [shape=none, margin=0, label=<" NL); + deg_debug_fprintf( + ctx, "
Legend
" NL); + deg_debug_fprintf(ctx, "" NL); #ifdef COLOR_SCHEME_NODE_CLASS - const char **colors = deg_debug_colors_light; - deg_debug_graphviz_legend_color(ctx, "Operation", colors[4]); - deg_debug_graphviz_legend_color(ctx, "Component", colors[1]); - deg_debug_graphviz_legend_color(ctx, "ID Node", colors[5]); - deg_debug_graphviz_legend_color(ctx, "NOOP", colors[8]); + const char **colors = deg_debug_colors_light; + deg_debug_graphviz_legend_color(ctx, "Operation", colors[4]); + deg_debug_graphviz_legend_color(ctx, "Component", colors[1]); + deg_debug_graphviz_legend_color(ctx, "ID Node", colors[5]); + deg_debug_graphviz_legend_color(ctx, "NOOP", colors[8]); #endif #ifdef COLOR_SCHEME_NODE_TYPE - const int (*pair)[2]; - for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) { - DepsNodeFactory *nti = type_get_factory((NodeType)(*pair)[0]); - deg_debug_graphviz_legend_color(ctx, - nti->tname().c_str(), - deg_debug_colors_light[(*pair)[1] % deg_debug_max_colors]); - } + const int(*pair)[2]; + for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) { + DepsNodeFactory *nti = type_get_factory((NodeType)(*pair)[0]); + deg_debug_graphviz_legend_color( + ctx, nti->tname().c_str(), deg_debug_colors_light[(*pair)[1] % deg_debug_max_colors]); + } #endif - deg_debug_fprintf(ctx, "
Legend
" NL); - deg_debug_fprintf(ctx, ">" NL); - deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname); - deg_debug_fprintf(ctx, "];" NL); - deg_debug_fprintf(ctx, "}" NL); + deg_debug_fprintf(ctx, "" NL); + deg_debug_fprintf(ctx, ">" NL); + deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname); + deg_debug_fprintf(ctx, "];" NL); + deg_debug_fprintf(ctx, "}" NL); } -static void deg_debug_graphviz_node_color(const DebugContext &ctx, - const Node *node) +static void deg_debug_graphviz_node_color(const DebugContext &ctx, const Node *node) { - const char *color_default = "black"; - const char *color_modified = "orangered4"; - const char *color_update = "dodgerblue3"; - const char *color = color_default; - if (ctx.show_tags) { - if (node->get_class() == NodeClass::OPERATION) { - OperationNode *op_node = (OperationNode *)node; - if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) { - color = color_modified; - } - else if (op_node->flag & DEPSOP_FLAG_NEEDS_UPDATE) { - color = color_update; - } - } - } - deg_debug_fprintf(ctx, "\"%s\"", color); + const char *color_default = "black"; + const char *color_modified = "orangered4"; + const char *color_update = "dodgerblue3"; + const char *color = color_default; + if (ctx.show_tags) { + if (node->get_class() == NodeClass::OPERATION) { + OperationNode *op_node = (OperationNode *)node; + if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) { + color = color_modified; + } + else if (op_node->flag & DEPSOP_FLAG_NEEDS_UPDATE) { + color = color_update; + } + } + } + deg_debug_fprintf(ctx, "\"%s\"", color); } -static void deg_debug_graphviz_node_penwidth(const DebugContext &ctx, - const Node *node) +static void deg_debug_graphviz_node_penwidth(const DebugContext &ctx, const Node *node) { - float penwidth_default = 1.0f; - float penwidth_modified = 4.0f; - float penwidth_update = 4.0f; - float penwidth = penwidth_default; - if (ctx.show_tags) { - if (node->get_class() == NodeClass::OPERATION) { - OperationNode *op_node = (OperationNode *)node; - if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) { - penwidth = penwidth_modified; - } - else if (op_node->flag & DEPSOP_FLAG_NEEDS_UPDATE) { - penwidth = penwidth_update; - } - } - } - deg_debug_fprintf(ctx, "\"%f\"", penwidth); + float penwidth_default = 1.0f; + float penwidth_modified = 4.0f; + float penwidth_update = 4.0f; + float penwidth = penwidth_default; + if (ctx.show_tags) { + if (node->get_class() == NodeClass::OPERATION) { + OperationNode *op_node = (OperationNode *)node; + if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) { + penwidth = penwidth_modified; + } + else if (op_node->flag & DEPSOP_FLAG_NEEDS_UPDATE) { + penwidth = penwidth_update; + } + } + } + deg_debug_fprintf(ctx, "\"%f\"", penwidth); } -static void deg_debug_graphviz_node_fillcolor(const DebugContext &ctx, - const Node *node) +static void deg_debug_graphviz_node_fillcolor(const DebugContext &ctx, const Node *node) { - const char *defaultcolor = "gainsboro"; - int color_index = deg_debug_node_color_index(node); - const char *fillcolor = color_index < 0 ? defaultcolor : deg_debug_colors_light[color_index % deg_debug_max_colors]; - deg_debug_fprintf(ctx, "\"%s\"", fillcolor); + const char *defaultcolor = "gainsboro"; + int color_index = deg_debug_node_color_index(node); + const char *fillcolor = color_index < 0 ? + defaultcolor : + deg_debug_colors_light[color_index % deg_debug_max_colors]; + deg_debug_fprintf(ctx, "\"%s\"", fillcolor); } -static void deg_debug_graphviz_relation_color(const DebugContext &ctx, - const Relation *rel) +static void deg_debug_graphviz_relation_color(const DebugContext &ctx, const Relation *rel) { - const char *color_default = "black"; - const char *color_cyclic = "red4"; /* The color of crime scene. */ - const char *color_godmode = "blue4"; /* The color of beautiful sky. */ - const char *color = color_default; - if (rel->flag & RELATION_FLAG_CYCLIC) { - color = color_cyclic; - } - else if (rel->flag & RELATION_FLAG_GODMODE) { - color = color_godmode; - } - deg_debug_fprintf(ctx, "%s", color); + const char *color_default = "black"; + const char *color_cyclic = "red4"; /* The color of crime scene. */ + const char *color_godmode = "blue4"; /* The color of beautiful sky. */ + const char *color = color_default; + if (rel->flag & RELATION_FLAG_CYCLIC) { + color = color_cyclic; + } + else if (rel->flag & RELATION_FLAG_GODMODE) { + color = color_godmode; + } + deg_debug_fprintf(ctx, "%s", color); } -static void deg_debug_graphviz_relation_style(const DebugContext &ctx, - const Relation *rel) +static void deg_debug_graphviz_relation_style(const DebugContext &ctx, const Relation *rel) { - const char *style_default = "solid"; - const char *style_no_flush = "dashed"; - const char *style_flush_user_only = "dotted"; - const char *style = style_default; - if (rel->flag & RELATION_FLAG_NO_FLUSH) { - style = style_no_flush; - } - if (rel->flag & RELATION_FLAG_FLUSH_USER_EDIT_ONLY) { - style = style_flush_user_only; - } - deg_debug_fprintf(ctx, "%s", style); + const char *style_default = "solid"; + const char *style_no_flush = "dashed"; + const char *style_flush_user_only = "dotted"; + const char *style = style_default; + if (rel->flag & RELATION_FLAG_NO_FLUSH) { + style = style_no_flush; + } + if (rel->flag & RELATION_FLAG_FLUSH_USER_EDIT_ONLY) { + style = style_flush_user_only; + } + deg_debug_fprintf(ctx, "%s", style); } -static void deg_debug_graphviz_relation_arrowhead(const DebugContext &ctx, - const Relation *rel) +static void deg_debug_graphviz_relation_arrowhead(const DebugContext &ctx, const Relation *rel) { - const char *shape_default = "normal"; - const char *shape_no_cow = "box"; - const char *shape = shape_default; - if (rel->from->get_class() == NodeClass::OPERATION && - rel->to->get_class() == NodeClass::OPERATION) - { - OperationNode *op_from = (OperationNode *)rel->from; - OperationNode *op_to = (OperationNode *)rel->to; - if (op_from->owner->type == NodeType::COPY_ON_WRITE && - !op_to->owner->need_tag_cow_before_update()) - { - shape = shape_no_cow; - } - } - deg_debug_fprintf(ctx, "%s", shape); + const char *shape_default = "normal"; + const char *shape_no_cow = "box"; + const char *shape = shape_default; + if (rel->from->get_class() == NodeClass::OPERATION && + rel->to->get_class() == NodeClass::OPERATION) { + OperationNode *op_from = (OperationNode *)rel->from; + OperationNode *op_to = (OperationNode *)rel->to; + if (op_from->owner->type == NodeType::COPY_ON_WRITE && + !op_to->owner->need_tag_cow_before_update()) { + shape = shape_no_cow; + } + } + deg_debug_fprintf(ctx, "%s", shape); } static void deg_debug_graphviz_node_style(const DebugContext &ctx, const Node *node) { - const char *base_style = "filled"; /* default style */ - if (ctx.show_tags) { - if (node->get_class() == NodeClass::OPERATION) { - OperationNode *op_node = (OperationNode *)node; - if (op_node->flag & (DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE)) { - base_style = "striped"; - } - } - } - switch (node->get_class()) { - case NodeClass::GENERIC: - deg_debug_fprintf(ctx, "\"%s\"", base_style); - break; - case NodeClass::COMPONENT: - deg_debug_fprintf(ctx, "\"%s\"", base_style); - break; - case NodeClass::OPERATION: - deg_debug_fprintf(ctx, "\"%s,rounded\"", base_style); - break; - } + const char *base_style = "filled"; /* default style */ + if (ctx.show_tags) { + if (node->get_class() == NodeClass::OPERATION) { + OperationNode *op_node = (OperationNode *)node; + if (op_node->flag & (DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE)) { + base_style = "striped"; + } + } + } + switch (node->get_class()) { + case NodeClass::GENERIC: + deg_debug_fprintf(ctx, "\"%s\"", base_style); + break; + case NodeClass::COMPONENT: + deg_debug_fprintf(ctx, "\"%s\"", base_style); + break; + case NodeClass::OPERATION: + deg_debug_fprintf(ctx, "\"%s,rounded\"", base_style); + break; + } } -static void deg_debug_graphviz_node_single(const DebugContext &ctx, - const Node *node) +static void deg_debug_graphviz_node_single(const DebugContext &ctx, const Node *node) { - const char *shape = "box"; - string name = node->identifier(); - deg_debug_fprintf(ctx, "// %s\n", name.c_str()); - deg_debug_fprintf(ctx, "\"node_%p\"", node); - deg_debug_fprintf(ctx, "["); -// deg_debug_fprintf(ctx, "label=<%s>", name); - deg_debug_fprintf(ctx, "label=<%s>", name.c_str()); - deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname); - deg_debug_fprintf(ctx, ",fontsize=%f", deg_debug_graphviz_node_label_size); - deg_debug_fprintf(ctx, ",shape=%s", shape); - deg_debug_fprintf(ctx, ",style="); deg_debug_graphviz_node_style(ctx, node); - deg_debug_fprintf(ctx, ",color="); deg_debug_graphviz_node_color(ctx, node); - deg_debug_fprintf(ctx, ",fillcolor="); deg_debug_graphviz_node_fillcolor(ctx, node); - deg_debug_fprintf(ctx, ",penwidth="); deg_debug_graphviz_node_penwidth(ctx, node); - deg_debug_fprintf(ctx, "];" NL); - deg_debug_fprintf(ctx, NL); + const char *shape = "box"; + string name = node->identifier(); + deg_debug_fprintf(ctx, "// %s\n", name.c_str()); + deg_debug_fprintf(ctx, "\"node_%p\"", node); + deg_debug_fprintf(ctx, "["); + // deg_debug_fprintf(ctx, "label=<%s>", name); + deg_debug_fprintf(ctx, "label=<%s>", name.c_str()); + deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname); + deg_debug_fprintf(ctx, ",fontsize=%f", deg_debug_graphviz_node_label_size); + deg_debug_fprintf(ctx, ",shape=%s", shape); + deg_debug_fprintf(ctx, ",style="); + deg_debug_graphviz_node_style(ctx, node); + deg_debug_fprintf(ctx, ",color="); + deg_debug_graphviz_node_color(ctx, node); + deg_debug_fprintf(ctx, ",fillcolor="); + deg_debug_graphviz_node_fillcolor(ctx, node); + deg_debug_fprintf(ctx, ",penwidth="); + deg_debug_graphviz_node_penwidth(ctx, node); + deg_debug_fprintf(ctx, "];" NL); + deg_debug_fprintf(ctx, NL); } -static void deg_debug_graphviz_node_cluster_begin(const DebugContext &ctx, - const Node *node) +static void deg_debug_graphviz_node_cluster_begin(const DebugContext &ctx, const Node *node) { - string name = node->identifier(); - deg_debug_fprintf(ctx, "// %s\n", name.c_str()); - deg_debug_fprintf(ctx, "subgraph \"cluster_%p\" {" NL, node); -// deg_debug_fprintf(ctx, "label=<%s>;" NL, name); - deg_debug_fprintf(ctx, "label=<%s>;" NL, name.c_str()); - deg_debug_fprintf(ctx, "fontname=\"%s\";" NL, deg_debug_graphviz_fontname); - deg_debug_fprintf(ctx, "fontsize=%f;" NL, deg_debug_graphviz_node_label_size); - deg_debug_fprintf(ctx, "margin=\"%d\";" NL, 16); - deg_debug_fprintf(ctx, "style="); deg_debug_graphviz_node_style(ctx, node); deg_debug_fprintf(ctx, ";" NL); - deg_debug_fprintf(ctx, "color="); deg_debug_graphviz_node_color(ctx, node); deg_debug_fprintf(ctx, ";" NL); - deg_debug_fprintf(ctx, "fillcolor="); deg_debug_graphviz_node_fillcolor(ctx, node); deg_debug_fprintf(ctx, ";" NL); - deg_debug_fprintf(ctx, "penwidth="); deg_debug_graphviz_node_penwidth(ctx, node); deg_debug_fprintf(ctx, ";" NL); - /* dummy node, so we can add edges between clusters */ - deg_debug_fprintf(ctx, "\"node_%p\"", node); - deg_debug_fprintf(ctx, "["); - deg_debug_fprintf(ctx, "shape=%s", "point"); - deg_debug_fprintf(ctx, ",style=%s", "invis"); - deg_debug_fprintf(ctx, "];" NL); - deg_debug_fprintf(ctx, NL); + string name = node->identifier(); + deg_debug_fprintf(ctx, "// %s\n", name.c_str()); + deg_debug_fprintf(ctx, "subgraph \"cluster_%p\" {" NL, node); + // deg_debug_fprintf(ctx, "label=<%s>;" NL, name); + deg_debug_fprintf(ctx, "label=<%s>;" NL, name.c_str()); + deg_debug_fprintf(ctx, "fontname=\"%s\";" NL, deg_debug_graphviz_fontname); + deg_debug_fprintf(ctx, "fontsize=%f;" NL, deg_debug_graphviz_node_label_size); + deg_debug_fprintf(ctx, "margin=\"%d\";" NL, 16); + deg_debug_fprintf(ctx, "style="); + deg_debug_graphviz_node_style(ctx, node); + deg_debug_fprintf(ctx, ";" NL); + deg_debug_fprintf(ctx, "color="); + deg_debug_graphviz_node_color(ctx, node); + deg_debug_fprintf(ctx, ";" NL); + deg_debug_fprintf(ctx, "fillcolor="); + deg_debug_graphviz_node_fillcolor(ctx, node); + deg_debug_fprintf(ctx, ";" NL); + deg_debug_fprintf(ctx, "penwidth="); + deg_debug_graphviz_node_penwidth(ctx, node); + deg_debug_fprintf(ctx, ";" NL); + /* dummy node, so we can add edges between clusters */ + deg_debug_fprintf(ctx, "\"node_%p\"", node); + deg_debug_fprintf(ctx, "["); + deg_debug_fprintf(ctx, "shape=%s", "point"); + deg_debug_fprintf(ctx, ",style=%s", "invis"); + deg_debug_fprintf(ctx, "];" NL); + deg_debug_fprintf(ctx, NL); } static void deg_debug_graphviz_node_cluster_end(const DebugContext &ctx) { - deg_debug_fprintf(ctx, "}" NL); - deg_debug_fprintf(ctx, NL); + deg_debug_fprintf(ctx, "}" NL); + deg_debug_fprintf(ctx, NL); } -static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx, - const Depsgraph *graph); -static void deg_debug_graphviz_graph_relations(const DebugContext &ctx, - const Depsgraph *graph); +static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx, const Depsgraph *graph); +static void deg_debug_graphviz_graph_relations(const DebugContext &ctx, const Depsgraph *graph); -static void deg_debug_graphviz_node(const DebugContext &ctx, - const Node *node) +static void deg_debug_graphviz_node(const DebugContext &ctx, const Node *node) { - switch (node->type) { - case NodeType::ID_REF: - { - const IDNode *id_node = (const IDNode *)node; - if (BLI_ghash_len(id_node->components) == 0) { - deg_debug_graphviz_node_single(ctx, node); - } - else { - deg_debug_graphviz_node_cluster_begin(ctx, node); - GHASH_FOREACH_BEGIN(const ComponentNode *, comp, id_node->components) - { - deg_debug_graphviz_node(ctx, comp); - } - GHASH_FOREACH_END(); - deg_debug_graphviz_node_cluster_end(ctx); - } - break; - } - case NodeType::PARAMETERS: - case NodeType::ANIMATION: - case NodeType::TRANSFORM: - case NodeType::PROXY: - case NodeType::GEOMETRY: - case NodeType::SEQUENCER: - case NodeType::EVAL_POSE: - case NodeType::BONE: - case NodeType::SHADING: - case NodeType::SHADING_PARAMETERS: - case NodeType::CACHE: - case NodeType::POINT_CACHE: - case NodeType::LAYER_COLLECTIONS: - case NodeType::PARTICLE_SYSTEM: - case NodeType::PARTICLE_SETTINGS: - case NodeType::COPY_ON_WRITE: - case NodeType::OBJECT_FROM_LAYER: - case NodeType::BATCH_CACHE: - case NodeType::DUPLI: - case NodeType::SYNCHRONIZATION: - case NodeType::GENERIC_DATABLOCK: - { - ComponentNode *comp_node = (ComponentNode *)node; - if (!comp_node->operations.empty()) { - deg_debug_graphviz_node_cluster_begin(ctx, node); - for (Node *op_node : comp_node->operations) { - deg_debug_graphviz_node(ctx, op_node); - } - deg_debug_graphviz_node_cluster_end(ctx); - } - else { - deg_debug_graphviz_node_single(ctx, node); - } - break; - } - case NodeType::UNDEFINED: - case NodeType::TIMESOURCE: - case NodeType::OPERATION: - deg_debug_graphviz_node_single(ctx, node); - break; - case NodeType::NUM_TYPES: - break; - } + switch (node->type) { + case NodeType::ID_REF: { + const IDNode *id_node = (const IDNode *)node; + if (BLI_ghash_len(id_node->components) == 0) { + deg_debug_graphviz_node_single(ctx, node); + } + else { + deg_debug_graphviz_node_cluster_begin(ctx, node); + GHASH_FOREACH_BEGIN (const ComponentNode *, comp, id_node->components) { + deg_debug_graphviz_node(ctx, comp); + } + GHASH_FOREACH_END(); + deg_debug_graphviz_node_cluster_end(ctx); + } + break; + } + case NodeType::PARAMETERS: + case NodeType::ANIMATION: + case NodeType::TRANSFORM: + case NodeType::PROXY: + case NodeType::GEOMETRY: + case NodeType::SEQUENCER: + case NodeType::EVAL_POSE: + case NodeType::BONE: + case NodeType::SHADING: + case NodeType::SHADING_PARAMETERS: + case NodeType::CACHE: + case NodeType::POINT_CACHE: + case NodeType::LAYER_COLLECTIONS: + case NodeType::PARTICLE_SYSTEM: + case NodeType::PARTICLE_SETTINGS: + case NodeType::COPY_ON_WRITE: + case NodeType::OBJECT_FROM_LAYER: + case NodeType::BATCH_CACHE: + case NodeType::DUPLI: + case NodeType::SYNCHRONIZATION: + case NodeType::GENERIC_DATABLOCK: { + ComponentNode *comp_node = (ComponentNode *)node; + if (!comp_node->operations.empty()) { + deg_debug_graphviz_node_cluster_begin(ctx, node); + for (Node *op_node : comp_node->operations) { + deg_debug_graphviz_node(ctx, op_node); + } + deg_debug_graphviz_node_cluster_end(ctx); + } + else { + deg_debug_graphviz_node_single(ctx, node); + } + break; + } + case NodeType::UNDEFINED: + case NodeType::TIMESOURCE: + case NodeType::OPERATION: + deg_debug_graphviz_node_single(ctx, node); + break; + case NodeType::NUM_TYPES: + break; + } } static bool deg_debug_graphviz_is_cluster(const Node *node) { - switch (node->type) { - case NodeType::ID_REF: - { - const IDNode *id_node = (const IDNode *)node; - return BLI_ghash_len(id_node->components) > 0; - } - case NodeType::PARAMETERS: - case NodeType::ANIMATION: - case NodeType::TRANSFORM: - case NodeType::PROXY: - case NodeType::GEOMETRY: - case NodeType::SEQUENCER: - case NodeType::EVAL_POSE: - case NodeType::BONE: - { - ComponentNode *comp_node = (ComponentNode *)node; - return !comp_node->operations.empty(); - } - default: - return false; - } + switch (node->type) { + case NodeType::ID_REF: { + const IDNode *id_node = (const IDNode *)node; + return BLI_ghash_len(id_node->components) > 0; + } + case NodeType::PARAMETERS: + case NodeType::ANIMATION: + case NodeType::TRANSFORM: + case NodeType::PROXY: + case NodeType::GEOMETRY: + case NodeType::SEQUENCER: + case NodeType::EVAL_POSE: + case NodeType::BONE: { + ComponentNode *comp_node = (ComponentNode *)node; + return !comp_node->operations.empty(); + } + default: + return false; + } } -static bool deg_debug_graphviz_is_owner(const Node *node, - const Node *other) +static bool deg_debug_graphviz_is_owner(const Node *node, const Node *other) { - switch (node->get_class()) { - case NodeClass::COMPONENT: - { - ComponentNode *comp_node = (ComponentNode *)node; - if (comp_node->owner == other) - return true; - break; - } - case NodeClass::OPERATION: - { - OperationNode *op_node = (OperationNode *)node; - if (op_node->owner == other) - return true; - else if (op_node->owner->owner == other) - return true; - break; - } - default: break; - } - return false; + switch (node->get_class()) { + case NodeClass::COMPONENT: { + ComponentNode *comp_node = (ComponentNode *)node; + if (comp_node->owner == other) + return true; + break; + } + case NodeClass::OPERATION: { + OperationNode *op_node = (OperationNode *)node; + if (op_node->owner == other) + return true; + else if (op_node->owner->owner == other) + return true; + break; + } + default: + break; + } + return false; } -static void deg_debug_graphviz_node_relations(const DebugContext &ctx, - const Node *node) +static void deg_debug_graphviz_node_relations(const DebugContext &ctx, const Node *node) { - for (Relation *rel : node->inlinks) { - float penwidth = 2.0f; - - const Node *tail = rel->to; /* same as node */ - const Node *head = rel->from; - deg_debug_fprintf(ctx, "// %s -> %s\n", - head->identifier().c_str(), - tail->identifier().c_str()); - deg_debug_fprintf(ctx, "\"node_%p\"", head); - deg_debug_fprintf(ctx, " -> "); - deg_debug_fprintf(ctx, "\"node_%p\"", tail); - - deg_debug_fprintf(ctx, "["); - /* Note: without label an id seem necessary to avoid bugs in graphviz/dot */ - deg_debug_fprintf(ctx, "id=\"%s\"", rel->name); - // deg_debug_fprintf(ctx, "label=\"%s\"", rel->name); - deg_debug_fprintf(ctx, ",color="); - deg_debug_graphviz_relation_color(ctx, rel); - deg_debug_fprintf(ctx, ",style="); - deg_debug_graphviz_relation_style(ctx, rel); - deg_debug_fprintf(ctx, ",arrowhead="); - deg_debug_graphviz_relation_arrowhead(ctx, rel); - deg_debug_fprintf(ctx, ",penwidth=\"%f\"", penwidth); - /* NOTE: edge from node to own cluster is not possible and gives graphviz - * warning, avoid this here by just linking directly to the invisible - * placeholder node. */ - if (deg_debug_graphviz_is_cluster(tail) && - !deg_debug_graphviz_is_owner(head, tail)) - { - deg_debug_fprintf(ctx, ",ltail=\"cluster_%p\"", tail); - } - if (deg_debug_graphviz_is_cluster(head) && - !deg_debug_graphviz_is_owner(tail, head)) - { - deg_debug_fprintf(ctx, ",lhead=\"cluster_%p\"", head); - } - deg_debug_fprintf(ctx, "];" NL); - deg_debug_fprintf(ctx, NL); - } + for (Relation *rel : node->inlinks) { + float penwidth = 2.0f; + + const Node *tail = rel->to; /* same as node */ + const Node *head = rel->from; + deg_debug_fprintf( + ctx, "// %s -> %s\n", head->identifier().c_str(), tail->identifier().c_str()); + deg_debug_fprintf(ctx, "\"node_%p\"", head); + deg_debug_fprintf(ctx, " -> "); + deg_debug_fprintf(ctx, "\"node_%p\"", tail); + + deg_debug_fprintf(ctx, "["); + /* Note: without label an id seem necessary to avoid bugs in graphviz/dot */ + deg_debug_fprintf(ctx, "id=\"%s\"", rel->name); + // deg_debug_fprintf(ctx, "label=\"%s\"", rel->name); + deg_debug_fprintf(ctx, ",color="); + deg_debug_graphviz_relation_color(ctx, rel); + deg_debug_fprintf(ctx, ",style="); + deg_debug_graphviz_relation_style(ctx, rel); + deg_debug_fprintf(ctx, ",arrowhead="); + deg_debug_graphviz_relation_arrowhead(ctx, rel); + deg_debug_fprintf(ctx, ",penwidth=\"%f\"", penwidth); + /* NOTE: edge from node to own cluster is not possible and gives graphviz + * warning, avoid this here by just linking directly to the invisible + * placeholder node. */ + if (deg_debug_graphviz_is_cluster(tail) && !deg_debug_graphviz_is_owner(head, tail)) { + deg_debug_fprintf(ctx, ",ltail=\"cluster_%p\"", tail); + } + if (deg_debug_graphviz_is_cluster(head) && !deg_debug_graphviz_is_owner(tail, head)) { + deg_debug_fprintf(ctx, ",lhead=\"cluster_%p\"", head); + } + deg_debug_fprintf(ctx, "];" NL); + deg_debug_fprintf(ctx, NL); + } } -static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx, - const Depsgraph *graph) +static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx, const Depsgraph *graph) { - for (Node *node : graph->id_nodes) { - deg_debug_graphviz_node(ctx, node); - } - TimeSourceNode *time_source = graph->find_time_source(); - if (time_source != NULL) { - deg_debug_graphviz_node(ctx, time_source); - } + for (Node *node : graph->id_nodes) { + deg_debug_graphviz_node(ctx, node); + } + TimeSourceNode *time_source = graph->find_time_source(); + if (time_source != NULL) { + deg_debug_graphviz_node(ctx, time_source); + } } -static void deg_debug_graphviz_graph_relations(const DebugContext &ctx, - const Depsgraph *graph) +static void deg_debug_graphviz_graph_relations(const DebugContext &ctx, const Depsgraph *graph) { - for (IDNode *id_node : graph->id_nodes) { - GHASH_FOREACH_BEGIN(ComponentNode *, comp_node, id_node->components) - { - for (OperationNode *op_node : comp_node->operations) { - deg_debug_graphviz_node_relations(ctx, op_node); - } - } - GHASH_FOREACH_END(); - } - - TimeSourceNode *time_source = graph->find_time_source(); - if (time_source != NULL) { - deg_debug_graphviz_node_relations(ctx, time_source); - } + for (IDNode *id_node : graph->id_nodes) { + GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) { + for (OperationNode *op_node : comp_node->operations) { + deg_debug_graphviz_node_relations(ctx, op_node); + } + } + GHASH_FOREACH_END(); + } + + TimeSourceNode *time_source = graph->find_time_source(); + if (time_source != NULL) { + deg_debug_graphviz_node_relations(ctx, time_source); + } } } // namespace DEG -void DEG_debug_relations_graphviz(const Depsgraph *graph, - FILE *f, - const char *label) +void DEG_debug_relations_graphviz(const Depsgraph *graph, FILE *f, const char *label) { - if (!graph) { - return; - } + if (!graph) { + return; + } - const DEG::Depsgraph *deg_graph = reinterpret_cast(graph); + const DEG::Depsgraph *deg_graph = reinterpret_cast(graph); - DEG::DebugContext ctx; - ctx.file = f; + DEG::DebugContext ctx; + ctx.file = f; - DEG::deg_debug_fprintf(ctx, "digraph depgraph {" NL); - DEG::deg_debug_fprintf(ctx, "rankdir=LR;" NL); - DEG::deg_debug_fprintf(ctx, "graph ["); - DEG::deg_debug_fprintf(ctx, "compound=true"); - DEG::deg_debug_fprintf(ctx, ",labelloc=\"t\""); - DEG::deg_debug_fprintf(ctx, ",fontsize=%f", DEG::deg_debug_graphviz_graph_label_size); - DEG::deg_debug_fprintf(ctx, ",fontname=\"%s\"", DEG::deg_debug_graphviz_fontname); - DEG::deg_debug_fprintf(ctx, ",label=\"%s\"", label); - DEG::deg_debug_fprintf(ctx, ",splines=ortho"); - DEG::deg_debug_fprintf(ctx, ",overlap=scalexy"); // XXX: only when using neato - DEG::deg_debug_fprintf(ctx, "];" NL); + DEG::deg_debug_fprintf(ctx, "digraph depgraph {" NL); + DEG::deg_debug_fprintf(ctx, "rankdir=LR;" NL); + DEG::deg_debug_fprintf(ctx, "graph ["); + DEG::deg_debug_fprintf(ctx, "compound=true"); + DEG::deg_debug_fprintf(ctx, ",labelloc=\"t\""); + DEG::deg_debug_fprintf(ctx, ",fontsize=%f", DEG::deg_debug_graphviz_graph_label_size); + DEG::deg_debug_fprintf(ctx, ",fontname=\"%s\"", DEG::deg_debug_graphviz_fontname); + DEG::deg_debug_fprintf(ctx, ",label=\"%s\"", label); + DEG::deg_debug_fprintf(ctx, ",splines=ortho"); + DEG::deg_debug_fprintf(ctx, ",overlap=scalexy"); // XXX: only when using neato + DEG::deg_debug_fprintf(ctx, "];" NL); - DEG::deg_debug_graphviz_graph_nodes(ctx, deg_graph); - DEG::deg_debug_graphviz_graph_relations(ctx, deg_graph); + DEG::deg_debug_graphviz_graph_nodes(ctx, deg_graph); + DEG::deg_debug_graphviz_graph_relations(ctx, deg_graph); - DEG::deg_debug_graphviz_legend(ctx); + DEG::deg_debug_graphviz_legend(ctx); - DEG::deg_debug_fprintf(ctx, "}" NL); + DEG::deg_debug_fprintf(ctx, "}" NL); } #undef NL diff --git a/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc b/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc index 41b22c0c23a..b4cf30685a2 100644 --- a/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc +++ b/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc @@ -42,112 +42,110 @@ namespace DEG { namespace { struct DebugContext { - FILE *file; - const Depsgraph *graph; - const char *label; - const char *output_filename; + FILE *file; + const Depsgraph *graph; + const char *label; + const char *output_filename; }; struct StatsEntry { - const IDNode *id_node; - double time; + const IDNode *id_node; + double time; }; /* TODO(sergey): De-duplicate with graphviz relation debugger. */ -static void deg_debug_fprintf(const DebugContext &ctx, - const char *fmt, - ...) ATTR_PRINTF_FORMAT(2, 3); +static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...) + ATTR_PRINTF_FORMAT(2, 3); static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...) { - va_list args; - va_start(args, fmt); - vfprintf(ctx.file, fmt, args); - va_end(args); + va_list args; + va_start(args, fmt); + vfprintf(ctx.file, fmt, args); + va_end(args); } -BLI_INLINE double get_node_time(const DebugContext& /*ctx*/, - const Node *node) +BLI_INLINE double get_node_time(const DebugContext & /*ctx*/, const Node *node) { - // TODO(sergey): Figure out a nice way to define which exact time - // we want to show. - return node->stats.current_time; + // TODO(sergey): Figure out a nice way to define which exact time + // we want to show. + return node->stats.current_time; } -bool stat_entry_comparator(const StatsEntry& a, const StatsEntry& b) +bool stat_entry_comparator(const StatsEntry &a, const StatsEntry &b) { - return a.time > b.time; + return a.time > b.time; } -string gnuplotify_id_code(const string& name) +string gnuplotify_id_code(const string &name) { - return string("") + name[0] + name[1]; + return string("") + name[0] + name[1]; } -string gnuplotify_name(const string& name) +string gnuplotify_name(const string &name) { - string result = ""; - const int length = name.length(); - for (int i = 0; i < length; ++i) { - const char ch = name[i]; - if (ch == '_') { - result += "\\\\\\"; - } - result += ch; - } - return result; + string result = ""; + const int length = name.length(); + for (int i = 0; i < length; ++i) { + const char ch = name[i]; + if (ch == '_') { + result += "\\\\\\"; + } + result += ch; + } + return result; } -void write_stats_data(const DebugContext& ctx) +void write_stats_data(const DebugContext &ctx) { - // Fill in array of all stats which are to be displayed. - vector stats; - stats.reserve(ctx.graph->id_nodes.size()); - for (const IDNode *id_node : ctx.graph->id_nodes) { - const double time = get_node_time(ctx, id_node); - if (time == 0.0) { - continue; - } - StatsEntry entry; - entry.id_node = id_node; - entry.time = time; - stats.push_back(entry); - } - // Sort the data. - std::sort(stats.begin(), stats.end(), stat_entry_comparator); - // We limit number of entries, otherwise things become unreadable. - stats.resize(min_ii(stats.size(), 32)); - std::reverse(stats.begin(), stats.end()); - // Print data to the file stream. - deg_debug_fprintf(ctx, "$data << EOD" NL); - for (const StatsEntry& entry : stats) { - deg_debug_fprintf( - ctx, "\"[%s] %s\",%f" NL, - gnuplotify_id_code(entry.id_node->id_orig->name).c_str(), - gnuplotify_name(entry.id_node->id_orig->name + 2).c_str(), - entry.time); - } - deg_debug_fprintf(ctx, "EOD" NL); + // Fill in array of all stats which are to be displayed. + vector stats; + stats.reserve(ctx.graph->id_nodes.size()); + for (const IDNode *id_node : ctx.graph->id_nodes) { + const double time = get_node_time(ctx, id_node); + if (time == 0.0) { + continue; + } + StatsEntry entry; + entry.id_node = id_node; + entry.time = time; + stats.push_back(entry); + } + // Sort the data. + std::sort(stats.begin(), stats.end(), stat_entry_comparator); + // We limit number of entries, otherwise things become unreadable. + stats.resize(min_ii(stats.size(), 32)); + std::reverse(stats.begin(), stats.end()); + // Print data to the file stream. + deg_debug_fprintf(ctx, "$data << EOD" NL); + for (const StatsEntry &entry : stats) { + deg_debug_fprintf(ctx, + "\"[%s] %s\",%f" NL, + gnuplotify_id_code(entry.id_node->id_orig->name).c_str(), + gnuplotify_name(entry.id_node->id_orig->name + 2).c_str(), + entry.time); + } + deg_debug_fprintf(ctx, "EOD" NL); } -void deg_debug_stats_gnuplot(const DebugContext& ctx) +void deg_debug_stats_gnuplot(const DebugContext &ctx) { - // Data itself. - write_stats_data(ctx); - // Optional label. - if (ctx.label && ctx.label[0]) { - deg_debug_fprintf(ctx, "set title \"%s\"" NL, ctx.label); - } - // Rest of the commands. - // TODO(sergey): Need to decide on the resolution somehow. - deg_debug_fprintf(ctx, "set terminal pngcairo size 1920,1080" NL); - deg_debug_fprintf(ctx, "set output \"%s\"" NL, ctx.output_filename); - deg_debug_fprintf(ctx, "set grid" NL); - deg_debug_fprintf(ctx, "set datafile separator ','" NL); - deg_debug_fprintf(ctx, "set style fill solid" NL); - deg_debug_fprintf(ctx, "plot \"$data\" using " \ - "($2*0.5):0:($2*0.5):(0.2):yticlabels(1) " - "with boxxyerrorbars t '' lt rgb \"#406090\"" NL); - + // Data itself. + write_stats_data(ctx); + // Optional label. + if (ctx.label && ctx.label[0]) { + deg_debug_fprintf(ctx, "set title \"%s\"" NL, ctx.label); + } + // Rest of the commands. + // TODO(sergey): Need to decide on the resolution somehow. + deg_debug_fprintf(ctx, "set terminal pngcairo size 1920,1080" NL); + deg_debug_fprintf(ctx, "set output \"%s\"" NL, ctx.output_filename); + deg_debug_fprintf(ctx, "set grid" NL); + deg_debug_fprintf(ctx, "set datafile separator ','" NL); + deg_debug_fprintf(ctx, "set style fill solid" NL); + deg_debug_fprintf(ctx, + "plot \"$data\" using " + "($2*0.5):0:($2*0.5):(0.2):yticlabels(1) " + "with boxxyerrorbars t '' lt rgb \"#406090\"" NL); } } // namespace @@ -158,13 +156,13 @@ void DEG_debug_stats_gnuplot(const Depsgraph *depsgraph, const char *label, const char *output_filename) { - if (depsgraph == NULL) { - return; - } - DEG::DebugContext ctx; - ctx.file = f; - ctx.graph = (DEG::Depsgraph *)depsgraph; - ctx.label = label; - ctx.output_filename = output_filename; - DEG::deg_debug_stats_gnuplot(ctx); + if (depsgraph == NULL) { + return; + } + DEG::DebugContext ctx; + ctx.file = f; + ctx.graph = (DEG::Depsgraph *)depsgraph; + ctx.label = label; + ctx.output_filename = output_filename; + DEG::deg_debug_stats_gnuplot(ctx); } diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc index 43bdba55360..e2a9dde1eea 100644 --- a/source/blender/depsgraph/intern/depsgraph.cc +++ b/source/blender/depsgraph/intern/depsgraph.cc @@ -59,206 +59,195 @@ extern "C" { namespace DEG { /* TODO(sergey): Find a better place for this. */ -template -static void remove_from_vector(vector *vector, const T& value) +template static void remove_from_vector(vector *vector, const T &value) { - vector->erase(std::remove(vector->begin(), vector->end(), value), - vector->end()); + vector->erase(std::remove(vector->begin(), vector->end(), value), vector->end()); } -Depsgraph::Depsgraph(Scene *scene, - ViewLayer *view_layer, - eEvaluationMode mode) - : time_source(NULL), - need_update(true), - scene(scene), - view_layer(view_layer), - mode(mode), - ctime(BKE_scene_frame_get(scene)), - scene_cow(NULL), - is_active(false), - debug_is_evaluating(false) +Depsgraph::Depsgraph(Scene *scene, ViewLayer *view_layer, eEvaluationMode mode) + : time_source(NULL), + need_update(true), + scene(scene), + view_layer(view_layer), + mode(mode), + ctime(BKE_scene_frame_get(scene)), + scene_cow(NULL), + is_active(false), + debug_is_evaluating(false) { - BLI_spin_init(&lock); - id_hash = BLI_ghash_ptr_new("Depsgraph id hash"); - entry_tags = BLI_gset_ptr_new("Depsgraph entry_tags"); - debug_flags = G.debug; - memset(id_type_updated, 0, sizeof(id_type_updated)); - memset(physics_relations, 0, sizeof(physics_relations)); + BLI_spin_init(&lock); + id_hash = BLI_ghash_ptr_new("Depsgraph id hash"); + entry_tags = BLI_gset_ptr_new("Depsgraph entry_tags"); + debug_flags = G.debug; + memset(id_type_updated, 0, sizeof(id_type_updated)); + memset(physics_relations, 0, sizeof(physics_relations)); } Depsgraph::~Depsgraph() { - clear_id_nodes(); - BLI_ghash_free(id_hash, NULL, NULL); - BLI_gset_free(entry_tags, NULL); - if (time_source != NULL) { - OBJECT_GUARDED_DELETE(time_source, TimeSourceNode); - } - BLI_spin_end(&lock); + clear_id_nodes(); + BLI_ghash_free(id_hash, NULL, NULL); + BLI_gset_free(entry_tags, NULL); + if (time_source != NULL) { + OBJECT_GUARDED_DELETE(time_source, TimeSourceNode); + } + BLI_spin_end(&lock); } /* Node Management ---------------------------- */ TimeSourceNode *Depsgraph::add_time_source() { - if (time_source == NULL) { - DepsNodeFactory *factory = type_get_factory(NodeType::TIMESOURCE); - time_source = (TimeSourceNode *)factory->create_node(NULL, "", "Time Source"); - } - return time_source; + if (time_source == NULL) { + DepsNodeFactory *factory = type_get_factory(NodeType::TIMESOURCE); + time_source = (TimeSourceNode *)factory->create_node(NULL, "", "Time Source"); + } + return time_source; } TimeSourceNode *Depsgraph::find_time_source() const { - return time_source; + return time_source; } IDNode *Depsgraph::find_id_node(const ID *id) const { - return reinterpret_cast(BLI_ghash_lookup(id_hash, id)); + return reinterpret_cast(BLI_ghash_lookup(id_hash, id)); } IDNode *Depsgraph::add_id_node(ID *id, ID *id_cow_hint) { - BLI_assert((id->tag & LIB_TAG_COPIED_ON_WRITE) == 0); - IDNode *id_node = find_id_node(id); - if (!id_node) { - DepsNodeFactory *factory = type_get_factory(NodeType::ID_REF); - id_node = (IDNode *)factory->create_node(id, "", id->name); - id_node->init_copy_on_write(id_cow_hint); - /* Register node in ID hash. - * - * NOTE: We address ID nodes by the original ID pointer they are - * referencing to. */ - BLI_ghash_insert(id_hash, id, id_node); - id_nodes.push_back(id_node); - } - return id_node; + BLI_assert((id->tag & LIB_TAG_COPIED_ON_WRITE) == 0); + IDNode *id_node = find_id_node(id); + if (!id_node) { + DepsNodeFactory *factory = type_get_factory(NodeType::ID_REF); + id_node = (IDNode *)factory->create_node(id, "", id->name); + id_node->init_copy_on_write(id_cow_hint); + /* Register node in ID hash. + * + * NOTE: We address ID nodes by the original ID pointer they are + * referencing to. */ + BLI_ghash_insert(id_hash, id, id_node); + id_nodes.push_back(id_node); + } + return id_node; } -void Depsgraph::clear_id_nodes_conditional(const std::function & filter) +void Depsgraph::clear_id_nodes_conditional(const std::function &filter) { - for (IDNode *id_node : id_nodes) { - if (id_node->id_cow == NULL) { - /* This means builder "stole" ownership of the copy-on-written - * datablock for her own dirty needs. */ - continue; - } - if (!deg_copy_on_write_is_expanded(id_node->id_cow)) { - continue; - } - const ID_Type id_type = GS(id_node->id_cow->name); - if (filter(id_type)) { - id_node->destroy(); - } - } + for (IDNode *id_node : id_nodes) { + if (id_node->id_cow == NULL) { + /* This means builder "stole" ownership of the copy-on-written + * datablock for her own dirty needs. */ + continue; + } + if (!deg_copy_on_write_is_expanded(id_node->id_cow)) { + continue; + } + const ID_Type id_type = GS(id_node->id_cow->name); + if (filter(id_type)) { + id_node->destroy(); + } + } } void Depsgraph::clear_id_nodes() { - /* Free memory used by ID nodes. */ - - /* Stupid workaround to ensure we free IDs in a proper order. */ - clear_id_nodes_conditional([](ID_Type id_type) { return id_type == ID_SCE; }); - clear_id_nodes_conditional([](ID_Type id_type) { return id_type != ID_PA; }); - - for (IDNode *id_node : id_nodes) { - OBJECT_GUARDED_DELETE(id_node, IDNode); - } - /* Clear containers. */ - BLI_ghash_clear(id_hash, NULL, NULL); - id_nodes.clear(); - /* Clear physics relation caches. */ - clear_physics_relations(this); + /* Free memory used by ID nodes. */ + + /* Stupid workaround to ensure we free IDs in a proper order. */ + clear_id_nodes_conditional([](ID_Type id_type) { return id_type == ID_SCE; }); + clear_id_nodes_conditional([](ID_Type id_type) { return id_type != ID_PA; }); + + for (IDNode *id_node : id_nodes) { + OBJECT_GUARDED_DELETE(id_node, IDNode); + } + /* Clear containers. */ + BLI_ghash_clear(id_hash, NULL, NULL); + id_nodes.clear(); + /* Clear physics relation caches. */ + clear_physics_relations(this); } /* Add new relation between two nodes */ -Relation *Depsgraph::add_new_relation(Node *from, Node *to, - const char *description, - int flags) +Relation *Depsgraph::add_new_relation(Node *from, Node *to, const char *description, int flags) { - Relation *rel = NULL; - if (flags & RELATION_CHECK_BEFORE_ADD) { - rel = check_nodes_connected(from, to, description); - } - if (rel != NULL) { - rel->flag |= flags; - return rel; - } + Relation *rel = NULL; + if (flags & RELATION_CHECK_BEFORE_ADD) { + rel = check_nodes_connected(from, to, description); + } + if (rel != NULL) { + rel->flag |= flags; + return rel; + } #ifndef NDEBUG - if (from->type == NodeType::OPERATION && - to->type == NodeType::OPERATION) - { - OperationNode *operation_from = static_cast(from); - OperationNode *operation_to = static_cast(to); - BLI_assert(operation_to->owner->type != NodeType::COPY_ON_WRITE || - operation_from->owner->type == NodeType::COPY_ON_WRITE); - } + if (from->type == NodeType::OPERATION && to->type == NodeType::OPERATION) { + OperationNode *operation_from = static_cast(from); + OperationNode *operation_to = static_cast(to); + BLI_assert(operation_to->owner->type != NodeType::COPY_ON_WRITE || + operation_from->owner->type == NodeType::COPY_ON_WRITE); + } #endif - /* Create new relation, and add it to the graph. */ - rel = OBJECT_GUARDED_NEW(Relation, from, to, description); - rel->flag |= flags; - return rel; + /* Create new relation, and add it to the graph. */ + rel = OBJECT_GUARDED_NEW(Relation, from, to, description); + rel->flag |= flags; + return rel; } Relation *Depsgraph::check_nodes_connected(const Node *from, const Node *to, const char *description) { - for (Relation *rel : from->outlinks) { - BLI_assert(rel->from == from); - if (rel->to != to) { - continue; - } - if (description != NULL && !STREQ(rel->name, description)) { - continue; - } - return rel; - } - return NULL; + for (Relation *rel : from->outlinks) { + BLI_assert(rel->from == from); + if (rel->to != to) { + continue; + } + if (description != NULL && !STREQ(rel->name, description)) { + continue; + } + return rel; + } + return NULL; } /* ************************ */ /* Relationships Management */ Relation::Relation(Node *from, Node *to, const char *description) - : from(from), - to(to), - name(description), - flag(0) + : from(from), to(to), name(description), flag(0) { - /* Hook it up to the nodes which use it. - * - * NOTE: We register relation in the nodes which this link connects to here - * in constructor but we don't unregister it in the destructor. - * - * Reasoning: - * - * - Destructor is currently used on global graph destruction, so there's no - * real need in avoiding dangling pointers, all the memory is to be freed - * anyway. - * - * - Unregistering relation is not a cheap operation, so better to have it - * as an explicit call if we need this. */ - from->outlinks.push_back(this); - to->inlinks.push_back(this); + /* Hook it up to the nodes which use it. + * + * NOTE: We register relation in the nodes which this link connects to here + * in constructor but we don't unregister it in the destructor. + * + * Reasoning: + * + * - Destructor is currently used on global graph destruction, so there's no + * real need in avoiding dangling pointers, all the memory is to be freed + * anyway. + * + * - Unregistering relation is not a cheap operation, so better to have it + * as an explicit call if we need this. */ + from->outlinks.push_back(this); + to->inlinks.push_back(this); } Relation::~Relation() { - /* Sanity check. */ - BLI_assert(from != NULL && to != NULL); + /* Sanity check. */ + BLI_assert(from != NULL && to != NULL); } void Relation::unlink() { - /* Sanity check. */ - BLI_assert(from != NULL && to != NULL); - remove_from_vector(&from->outlinks, this); - remove_from_vector(&to->inlinks, this); + /* Sanity check. */ + BLI_assert(from != NULL && to != NULL); + remove_from_vector(&from->outlinks, this); + remove_from_vector(&to->inlinks, this); } /* Low level tagging -------------------------------------- */ @@ -266,50 +255,50 @@ void Relation::unlink() /* Tag a specific node as needing updates. */ void Depsgraph::add_entry_tag(OperationNode *node) { - /* Sanity check. */ - if (node == NULL) { - return; - } - /* Add to graph-level set of directly modified nodes to start searching - * from. - * NOTE: this is necessary since we have several thousand nodes to play - * with. */ - BLI_gset_insert(entry_tags, node); + /* Sanity check. */ + if (node == NULL) { + return; + } + /* Add to graph-level set of directly modified nodes to start searching + * from. + * NOTE: this is necessary since we have several thousand nodes to play + * with. */ + BLI_gset_insert(entry_tags, node); } void Depsgraph::clear_all_nodes() { - clear_id_nodes(); - if (time_source != NULL) { - OBJECT_GUARDED_DELETE(time_source, TimeSourceNode); - time_source = NULL; - } + clear_id_nodes(); + if (time_source != NULL) { + OBJECT_GUARDED_DELETE(time_source, TimeSourceNode); + time_source = NULL; + } } ID *Depsgraph::get_cow_id(const ID *id_orig) const { - IDNode *id_node = find_id_node(id_orig); - if (id_node == NULL) { - /* This function is used from places where we expect ID to be either - * already a copy-on-write version or have a corresponding copy-on-write - * version. - * - * We try to enforce that in debug builds, for for release we play a bit - * safer game here. */ - if ((id_orig->tag & LIB_TAG_COPIED_ON_WRITE) == 0) { - /* TODO(sergey): This is nice sanity check to have, but it fails - * in following situations: - * - * - Material has link to texture, which is not needed by new - * shading system and hence can be ignored at construction. - * - Object or mesh has material at a slot which is not used (for - * example, object has material slot by materials are set to - * object data). */ - // BLI_assert(!"Request for non-existing copy-on-write ID"); - } - return (ID *)id_orig; - } - return id_node->id_cow; + IDNode *id_node = find_id_node(id_orig); + if (id_node == NULL) { + /* This function is used from places where we expect ID to be either + * already a copy-on-write version or have a corresponding copy-on-write + * version. + * + * We try to enforce that in debug builds, for for release we play a bit + * safer game here. */ + if ((id_orig->tag & LIB_TAG_COPIED_ON_WRITE) == 0) { + /* TODO(sergey): This is nice sanity check to have, but it fails + * in following situations: + * + * - Material has link to texture, which is not needed by new + * shading system and hence can be ignored at construction. + * - Object or mesh has material at a slot which is not used (for + * example, object has material slot by materials are set to + * object data). */ + // BLI_assert(!"Request for non-existing copy-on-write ID"); + } + return (ID *)id_orig; + } + return id_node->id_cow; } } // namespace DEG @@ -318,48 +307,42 @@ ID *Depsgraph::get_cow_id(const ID *id_orig) const /* Public Graph API */ /* Initialize a new Depsgraph */ -Depsgraph *DEG_graph_new(Scene *scene, - ViewLayer *view_layer, - eEvaluationMode mode) +Depsgraph *DEG_graph_new(Scene *scene, ViewLayer *view_layer, eEvaluationMode mode) { - DEG::Depsgraph *deg_depsgraph = OBJECT_GUARDED_NEW(DEG::Depsgraph, - scene, - view_layer, - mode); - return reinterpret_cast(deg_depsgraph); + DEG::Depsgraph *deg_depsgraph = OBJECT_GUARDED_NEW(DEG::Depsgraph, scene, view_layer, mode); + return reinterpret_cast(deg_depsgraph); } /* Free graph's contents and graph itself */ void DEG_graph_free(Depsgraph *graph) { - using DEG::Depsgraph; - DEG::Depsgraph *deg_depsgraph = reinterpret_cast(graph); - OBJECT_GUARDED_DELETE(deg_depsgraph, Depsgraph); + using DEG::Depsgraph; + DEG::Depsgraph *deg_depsgraph = reinterpret_cast(graph); + OBJECT_GUARDED_DELETE(deg_depsgraph, Depsgraph); } bool DEG_is_active(const struct Depsgraph *depsgraph) { - if (depsgraph == NULL) { - /* Happens for such cases as work object in what_does_obaction(), - * and sine render pipeline parts. Shouldn't really be accepting - * NULL depsgraph, but is quite hard to get proper one in those - * cases. */ - return false; - } - const DEG::Depsgraph *deg_graph = - reinterpret_cast(depsgraph); - return deg_graph->is_active; + if (depsgraph == NULL) { + /* Happens for such cases as work object in what_does_obaction(), + * and sine render pipeline parts. Shouldn't really be accepting + * NULL depsgraph, but is quite hard to get proper one in those + * cases. */ + return false; + } + const DEG::Depsgraph *deg_graph = reinterpret_cast(depsgraph); + return deg_graph->is_active; } void DEG_make_active(struct Depsgraph *depsgraph) { - DEG::Depsgraph *deg_graph = reinterpret_cast(depsgraph); - deg_graph->is_active = true; - /* TODO(sergey): Copy data from evaluated state to original. */ + DEG::Depsgraph *deg_graph = reinterpret_cast(depsgraph); + deg_graph->is_active = true; + /* TODO(sergey): Copy data from evaluated state to original. */ } void DEG_make_inactive(struct Depsgraph *depsgraph) { - DEG::Depsgraph *deg_graph = reinterpret_cast(depsgraph); - deg_graph->is_active = false; + DEG::Depsgraph *deg_graph = reinterpret_cast(depsgraph); + deg_graph->is_active = false; } diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h index de01969e963..2dcbb6b5574 100644 --- a/source/blender/depsgraph/intern/depsgraph.h +++ b/source/blender/depsgraph/intern/depsgraph.h @@ -35,7 +35,7 @@ #include "BKE_main.h" /* for MAX_LIBARRAY */ -#include "BLI_threads.h" /* for SpinLock */ +#include "BLI_threads.h" /* for SpinLock */ #include "DEG_depsgraph.h" #include "DEG_depsgraph_physics.h" @@ -63,34 +63,34 @@ struct TimeSourceNode; /* Settings/Tags on Relationship. * NOTE: Is a bitmask, allowing accumulation. */ enum RelationFlag { - /* "cyclic" link - when detecting cycles, this relationship was the one - * which triggers a cyclic relationship to exist in the graph. */ - RELATION_FLAG_CYCLIC = (1 << 0), - /* Update flush will not go through this relation. */ - RELATION_FLAG_NO_FLUSH = (1 << 1), - /* Only flush along the relation is update comes from a node which was - * affected by user input. */ - RELATION_FLAG_FLUSH_USER_EDIT_ONLY = (1 << 2), - /* The relation can not be killed by the cyclic dependencies solver. */ - RELATION_FLAG_GODMODE = (1 << 4), - /* Relation will check existance before being added. */ - RELATION_CHECK_BEFORE_ADD = (1 << 5), + /* "cyclic" link - when detecting cycles, this relationship was the one + * which triggers a cyclic relationship to exist in the graph. */ + RELATION_FLAG_CYCLIC = (1 << 0), + /* Update flush will not go through this relation. */ + RELATION_FLAG_NO_FLUSH = (1 << 1), + /* Only flush along the relation is update comes from a node which was + * affected by user input. */ + RELATION_FLAG_FLUSH_USER_EDIT_ONLY = (1 << 2), + /* The relation can not be killed by the cyclic dependencies solver. */ + RELATION_FLAG_GODMODE = (1 << 4), + /* Relation will check existance before being added. */ + RELATION_CHECK_BEFORE_ADD = (1 << 5), }; /* B depends on A (A -> B) */ struct Relation { - Relation(Node *from, Node *to, const char *description); - ~Relation(); + Relation(Node *from, Node *to, const char *description); + ~Relation(); - void unlink(); + void unlink(); - /* the nodes in the relationship (since this is shared between the nodes) */ - Node *from; /* A */ - Node *to; /* B */ + /* the nodes in the relationship (since this is shared between the nodes) */ + Node *from; /* A */ + Node *to; /* B */ - /* relationship attributes */ - const char *name; /* label for debugging */ - int flag; /* Bitmask of RelationFlag) */ + /* relationship attributes */ + const char *name; /* label for debugging */ + int flag; /* Bitmask of RelationFlag) */ }; /* ********* */ @@ -98,112 +98,105 @@ struct Relation { /* Dependency Graph object */ struct Depsgraph { - // TODO(sergey): Go away from C++ container and use some native BLI. - typedef vector OperationNodes; - typedef vector IDDepsNodes; + // TODO(sergey): Go away from C++ container and use some native BLI. + typedef vector OperationNodes; + typedef vector IDDepsNodes; - Depsgraph(Scene *scene, - ViewLayer *view_layer, - eEvaluationMode mode); - ~Depsgraph(); + Depsgraph(Scene *scene, ViewLayer *view_layer, eEvaluationMode mode); + ~Depsgraph(); - TimeSourceNode *add_time_source(); - TimeSourceNode *find_time_source() const; + TimeSourceNode *add_time_source(); + TimeSourceNode *find_time_source() const; - IDNode *find_id_node(const ID *id) const; - IDNode *add_id_node(ID *id, ID *id_cow_hint = NULL); - void clear_id_nodes(); - void clear_id_nodes_conditional(const std::function & filter); + IDNode *find_id_node(const ID *id) const; + IDNode *add_id_node(ID *id, ID *id_cow_hint = NULL); + void clear_id_nodes(); + void clear_id_nodes_conditional(const std::function &filter); - /* Add new relationship between two nodes. */ - Relation *add_new_relation(Node *from, - Node *to, - const char *description, - int flags = 0); + /* Add new relationship between two nodes. */ + Relation *add_new_relation(Node *from, Node *to, const char *description, int flags = 0); - /* Check whether two nodes are connected by relation with given - * description. Description might be NULL to check ANY relation between - * given nodes. */ - Relation *check_nodes_connected(const Node *from, - const Node *to, - const char *description); + /* Check whether two nodes are connected by relation with given + * description. Description might be NULL to check ANY relation between + * given nodes. */ + Relation *check_nodes_connected(const Node *from, const Node *to, const char *description); - /* Tag a specific node as needing updates. */ - void add_entry_tag(OperationNode *node); + /* Tag a specific node as needing updates. */ + void add_entry_tag(OperationNode *node); - /* Clear storage used by all nodes. */ - void clear_all_nodes(); + /* Clear storage used by all nodes. */ + void clear_all_nodes(); - /* Copy-on-Write Functionality ........ */ + /* Copy-on-Write Functionality ........ */ - /* For given original ID get ID which is created by CoW system. */ - ID *get_cow_id(const ID *id_orig) const; + /* For given original ID get ID which is created by CoW system. */ + ID *get_cow_id(const ID *id_orig) const; - /* Core Graph Functionality ........... */ + /* Core Graph Functionality ........... */ - /* mapping from ID blocks to nodes representing these - * blocks, used for quick lookups. */ - GHash *id_hash; + /* mapping from ID blocks to nodes representing these + * blocks, used for quick lookups. */ + GHash *id_hash; - /* Ordered list of ID nodes, order matches ID allocation order. - * Used for faster iteration, especially for areas which are critical to - * keep exact order of iteration. */ - IDDepsNodes id_nodes; + /* Ordered list of ID nodes, order matches ID allocation order. + * Used for faster iteration, especially for areas which are critical to + * keep exact order of iteration. */ + IDDepsNodes id_nodes; - /* Top-level time source node. */ - TimeSourceNode *time_source; + /* Top-level time source node. */ + TimeSourceNode *time_source; - /* Indicates whether relations needs to be updated. */ - bool need_update; + /* Indicates whether relations needs to be updated. */ + bool need_update; - /* Indicates which ID types were updated. */ - char id_type_updated[MAX_LIBARRAY]; + /* Indicates which ID types were updated. */ + char id_type_updated[MAX_LIBARRAY]; - /* Quick-Access Temp Data ............. */ + /* Quick-Access Temp Data ............. */ - /* Nodes which have been tagged as "directly modified". */ - GSet *entry_tags; + /* Nodes which have been tagged as "directly modified". */ + GSet *entry_tags; - /* Convenience Data ................... */ + /* Convenience Data ................... */ - /* XXX: should be collected after building (if actually needed?) */ - /* All operation nodes, sorted in order of single-thread traversal order. */ - OperationNodes operations; + /* XXX: should be collected after building (if actually needed?) */ + /* All operation nodes, sorted in order of single-thread traversal order. */ + OperationNodes operations; - /* Spin lock for threading-critical operations. - * Mainly used by graph evaluation. */ - SpinLock lock; + /* Spin lock for threading-critical operations. + * Mainly used by graph evaluation. */ + SpinLock lock; - /* Scene, layer, mode this dependency graph is built for. */ - Scene *scene; - ViewLayer *view_layer; - eEvaluationMode mode; + /* Scene, layer, mode this dependency graph is built for. */ + Scene *scene; + ViewLayer *view_layer; + eEvaluationMode mode; - /* Time at which dependency graph is being or was last evaluated. */ - float ctime; + /* Time at which dependency graph is being or was last evaluated. */ + float ctime; - /* Evaluated version of datablocks we access a lot. - * Stored here to save us form doing hash lookup. */ - Scene *scene_cow; + /* Evaluated version of datablocks we access a lot. + * Stored here to save us form doing hash lookup. */ + Scene *scene_cow; - /* Active dependency graph is a dependency graph which is used by the - * currently active window. When dependency graph is active, it is allowed - * for evaluation functions to write animation f-curve result, drivers - * result and other selective things (object matrix?) to original object. - * - * This way we simplify operators, which don't need to worry about where - * to read stuff from. */ - bool is_active; + /* Active dependency graph is a dependency graph which is used by the + * currently active window. When dependency graph is active, it is allowed + * for evaluation functions to write animation f-curve result, drivers + * result and other selective things (object matrix?) to original object. + * + * This way we simplify operators, which don't need to worry about where + * to read stuff from. */ + bool is_active; - /* NOTE: Corresponds to G_DEBUG_DEPSGRAPH_* flags. */ - int debug_flags; - string debug_name; + /* NOTE: Corresponds to G_DEBUG_DEPSGRAPH_* flags. */ + int debug_flags; + string debug_name; - bool debug_is_evaluating; + bool debug_is_evaluating; - /* Cached list of colliders/effectors for collections and the scene - * created along with relations, for fast lookup during evaluation. */ - GHash *physics_relations[DEG_PHYSICS_RELATIONS_NUM]; + /* Cached list of colliders/effectors for collections and the scene + * created along with relations, for fast lookup during evaluation. */ + GHash *physics_relations[DEG_PHYSICS_RELATIONS_NUM]; }; } // namespace DEG diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc index 3cec2b45ea4..e4c84264960 100644 --- a/source/blender/depsgraph/intern/depsgraph_build.cc +++ b/source/blender/depsgraph/intern/depsgraph_build.cc @@ -63,37 +63,47 @@ extern "C" { /* ****************** */ /* External Build API */ -static DEG::NodeType deg_build_scene_component_type( - eDepsSceneComponentType component) +static DEG::NodeType deg_build_scene_component_type(eDepsSceneComponentType component) { - switch (component) { - case DEG_SCENE_COMP_PARAMETERS: return DEG::NodeType::PARAMETERS; - case DEG_SCENE_COMP_ANIMATION: return DEG::NodeType::ANIMATION; - case DEG_SCENE_COMP_SEQUENCER: return DEG::NodeType::SEQUENCER; - } - return DEG::NodeType::UNDEFINED; + switch (component) { + case DEG_SCENE_COMP_PARAMETERS: + return DEG::NodeType::PARAMETERS; + case DEG_SCENE_COMP_ANIMATION: + return DEG::NodeType::ANIMATION; + case DEG_SCENE_COMP_SEQUENCER: + return DEG::NodeType::SEQUENCER; + } + return DEG::NodeType::UNDEFINED; } -static DEG::NodeType deg_build_object_component_type( - eDepsObjectComponentType component) +static DEG::NodeType deg_build_object_component_type(eDepsObjectComponentType component) { - switch (component) { - case DEG_OB_COMP_PARAMETERS: return DEG::NodeType::PARAMETERS; - case DEG_OB_COMP_PROXY: return DEG::NodeType::PROXY; - case DEG_OB_COMP_ANIMATION: return DEG::NodeType::ANIMATION; - case DEG_OB_COMP_TRANSFORM: return DEG::NodeType::TRANSFORM; - case DEG_OB_COMP_GEOMETRY: return DEG::NodeType::GEOMETRY; - case DEG_OB_COMP_EVAL_POSE: return DEG::NodeType::EVAL_POSE; - case DEG_OB_COMP_BONE: return DEG::NodeType::BONE; - case DEG_OB_COMP_SHADING: return DEG::NodeType::SHADING; - case DEG_OB_COMP_CACHE: return DEG::NodeType::CACHE; - } - return DEG::NodeType::UNDEFINED; + switch (component) { + case DEG_OB_COMP_PARAMETERS: + return DEG::NodeType::PARAMETERS; + case DEG_OB_COMP_PROXY: + return DEG::NodeType::PROXY; + case DEG_OB_COMP_ANIMATION: + return DEG::NodeType::ANIMATION; + case DEG_OB_COMP_TRANSFORM: + return DEG::NodeType::TRANSFORM; + case DEG_OB_COMP_GEOMETRY: + return DEG::NodeType::GEOMETRY; + case DEG_OB_COMP_EVAL_POSE: + return DEG::NodeType::EVAL_POSE; + case DEG_OB_COMP_BONE: + return DEG::NodeType::BONE; + case DEG_OB_COMP_SHADING: + return DEG::NodeType::SHADING; + case DEG_OB_COMP_CACHE: + return DEG::NodeType::CACHE; + } + return DEG::NodeType::UNDEFINED; } static DEG::DepsNodeHandle *get_node_handle(DepsNodeHandle *node_handle) { - return reinterpret_cast(node_handle); + return reinterpret_cast(node_handle); } void DEG_add_scene_relation(DepsNodeHandle *node_handle, @@ -101,12 +111,10 @@ void DEG_add_scene_relation(DepsNodeHandle *node_handle, eDepsSceneComponentType component, const char *description) { - DEG::NodeType type = deg_build_scene_component_type(component); - DEG::ComponentKey comp_key(&scene->id, type); - DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); - deg_node_handle->builder->add_node_handle_relation(comp_key, - deg_node_handle, - description); + DEG::NodeType type = deg_build_scene_component_type(component); + DEG::ComponentKey comp_key(&scene->id, type); + DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); + deg_node_handle->builder->add_node_handle_relation(comp_key, deg_node_handle, description); } void DEG_add_object_relation(DepsNodeHandle *node_handle, @@ -114,12 +122,10 @@ void DEG_add_object_relation(DepsNodeHandle *node_handle, eDepsObjectComponentType component, const char *description) { - DEG::NodeType type = deg_build_object_component_type(component); - DEG::ComponentKey comp_key(&object->id, type); - DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); - deg_node_handle->builder->add_node_handle_relation(comp_key, - deg_node_handle, - description); + DEG::NodeType type = deg_build_object_component_type(component); + DEG::ComponentKey comp_key(&object->id, type); + DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); + deg_node_handle->builder->add_node_handle_relation(comp_key, deg_node_handle, description); } void DEG_add_object_cache_relation(DepsNodeHandle *node_handle, @@ -127,12 +133,10 @@ void DEG_add_object_cache_relation(DepsNodeHandle *node_handle, eDepsObjectComponentType component, const char *description) { - DEG::NodeType type = deg_build_object_component_type(component); - DEG::ComponentKey comp_key(&cache_file->id, type); - DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); - deg_node_handle->builder->add_node_handle_relation(comp_key, - deg_node_handle, - description); + DEG::NodeType type = deg_build_object_component_type(component); + DEG::ComponentKey comp_key(&cache_file->id, type); + DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); + deg_node_handle->builder->add_node_handle_relation(comp_key, deg_node_handle, description); } void DEG_add_bone_relation(DepsNodeHandle *node_handle, @@ -141,12 +145,10 @@ void DEG_add_bone_relation(DepsNodeHandle *node_handle, eDepsObjectComponentType component, const char *description) { - DEG::NodeType type = deg_build_object_component_type(component); - DEG::ComponentKey comp_key(&object->id, type, bone_name); - DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); - deg_node_handle->builder->add_node_handle_relation(comp_key, - deg_node_handle, - description); + DEG::NodeType type = deg_build_object_component_type(component); + DEG::ComponentKey comp_key(&object->id, type, bone_name); + DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); + deg_node_handle->builder->add_node_handle_relation(comp_key, deg_node_handle, description); } void DEG_add_object_pointcache_relation(struct DepsNodeHandle *node_handle, @@ -154,82 +156,66 @@ void DEG_add_object_pointcache_relation(struct DepsNodeHandle *node_handle, eDepsObjectComponentType component, const char *description) { - DEG::NodeType type = deg_build_object_component_type(component); - DEG::ComponentKey comp_key(&object->id, type); - DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); - DEG::DepsgraphRelationBuilder *relation_builder = deg_node_handle->builder; - /* Add relation from source to the node handle. */ - relation_builder->add_node_handle_relation( - comp_key, deg_node_handle, description); - /* Node deduct point cache component and connect source to it. */ - ID *id = DEG_get_id_from_handle(node_handle); - DEG::ComponentKey point_cache_key(id, DEG::NodeType::POINT_CACHE); - DEG::Relation *rel = relation_builder->add_relation( - comp_key, point_cache_key, "Point Cache"); - if (rel != NULL) { - rel->flag |= DEG::RELATION_FLAG_FLUSH_USER_EDIT_ONLY; - } - else { - fprintf(stderr, - "Error in point cache relation from %s to ^%s.\n", - object->id.name, - id->name); - } + DEG::NodeType type = deg_build_object_component_type(component); + DEG::ComponentKey comp_key(&object->id, type); + DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); + DEG::DepsgraphRelationBuilder *relation_builder = deg_node_handle->builder; + /* Add relation from source to the node handle. */ + relation_builder->add_node_handle_relation(comp_key, deg_node_handle, description); + /* Node deduct point cache component and connect source to it. */ + ID *id = DEG_get_id_from_handle(node_handle); + DEG::ComponentKey point_cache_key(id, DEG::NodeType::POINT_CACHE); + DEG::Relation *rel = relation_builder->add_relation(comp_key, point_cache_key, "Point Cache"); + if (rel != NULL) { + rel->flag |= DEG::RELATION_FLAG_FLUSH_USER_EDIT_ONLY; + } + else { + fprintf(stderr, "Error in point cache relation from %s to ^%s.\n", object->id.name, id->name); + } } void DEG_add_generic_id_relation(struct DepsNodeHandle *node_handle, struct ID *id, const char *description) { - DEG::OperationKey operation_key( - id, - DEG::NodeType::GENERIC_DATABLOCK, - DEG::OperationCode::GENERIC_DATABLOCK_UPDATE); - DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); - deg_node_handle->builder->add_node_handle_relation(operation_key, - deg_node_handle, - description); + DEG::OperationKey operation_key( + id, DEG::NodeType::GENERIC_DATABLOCK, DEG::OperationCode::GENERIC_DATABLOCK_UPDATE); + DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); + deg_node_handle->builder->add_node_handle_relation(operation_key, deg_node_handle, description); } -void DEG_add_modifier_to_transform_relation( - struct DepsNodeHandle *node_handle, - const char *description) +void DEG_add_modifier_to_transform_relation(struct DepsNodeHandle *node_handle, + const char *description) { - DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); - deg_node_handle->builder->add_modifier_to_transform_relation( - deg_node_handle, - description); + DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); + deg_node_handle->builder->add_modifier_to_transform_relation(deg_node_handle, description); } -void DEG_add_special_eval_flag(struct DepsNodeHandle *node_handle, - ID *id, - uint32_t flag) +void DEG_add_special_eval_flag(struct DepsNodeHandle *node_handle, ID *id, uint32_t flag) { - DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); - deg_node_handle->builder->add_special_eval_flag(id, flag); + DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); + deg_node_handle->builder->add_special_eval_flag(id, flag); } void DEG_add_customdata_mask(struct DepsNodeHandle *node_handle, struct Object *object, const CustomData_MeshMasks *masks) { - DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); - deg_node_handle->builder->add_customdata_mask( - object, - DEG::DEGCustomDataMeshMasks(masks)); + DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); + deg_node_handle->builder->add_customdata_mask(object, DEG::DEGCustomDataMeshMasks(masks)); } struct ID *DEG_get_id_from_handle(struct DepsNodeHandle *node_handle) { - DEG::DepsNodeHandle *deg_handle = get_node_handle(node_handle); - return deg_handle->node->owner->owner->id_orig; + DEG::DepsNodeHandle *deg_handle = get_node_handle(node_handle); + return deg_handle->node->owner->owner->id_orig; } struct Depsgraph *DEG_get_graph_from_handle(struct DepsNodeHandle *node_handle) { - DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); - DEG::DepsgraphRelationBuilder *relation_builder = deg_node_handle->builder; - return reinterpret_cast(relation_builder->getGraph()); + DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); + DEG::DepsgraphRelationBuilder *relation_builder = deg_node_handle->builder; + return reinterpret_cast(relation_builder->getGraph()); } /* ******************** */ @@ -239,106 +225,97 @@ struct Depsgraph *DEG_get_graph_from_handle(struct DepsNodeHandle *node_handle) * graph container. */ void DEG_graph_build_from_view_layer(Depsgraph *graph, - Main *bmain, - Scene *scene, - ViewLayer *view_layer) + Main *bmain, + Scene *scene, + ViewLayer *view_layer) { - double start_time = 0.0; - if (G.debug & (G_DEBUG_DEPSGRAPH_BUILD | G_DEBUG_DEPSGRAPH_TIME)) { - start_time = PIL_check_seconds_timer(); - } - DEG::Depsgraph *deg_graph = reinterpret_cast(graph); - /* Perform sanity checks. */ - BLI_assert(BLI_findindex(&scene->view_layers, view_layer) != -1); - BLI_assert(deg_graph->scene == scene); - BLI_assert(deg_graph->view_layer == view_layer); - /* Generate all the nodes in the graph first */ - DEG::DepsgraphNodeBuilder node_builder(bmain, deg_graph); - node_builder.begin_build(); - node_builder.build_view_layer(scene, - view_layer, - DEG::DEG_ID_LINKED_DIRECTLY); - node_builder.end_build(); - /* Hook up relationships between operations - to determine evaluation - * order. */ - DEG::DepsgraphRelationBuilder relation_builder(bmain, deg_graph); - relation_builder.begin_build(); - relation_builder.build_view_layer(scene, view_layer); - relation_builder.build_copy_on_write_relations(); - /* Detect and solve cycles. */ - DEG::deg_graph_detect_cycles(deg_graph); - /* Simplify the graph by removing redundant relations (to optimize - * traversal later). */ - /* TODO: it would be useful to have an option to disable this in cases where - * it is causing trouble. */ - if (G.debug_value == 799) { - DEG::deg_graph_transitive_reduction(deg_graph); - } - /* Store pointers to commonly used valuated datablocks. */ - deg_graph->scene_cow = (Scene *)deg_graph->get_cow_id(°_graph->scene->id); - /* Flush visibility layer and re-schedule nodes for update. */ - DEG::deg_graph_build_finalize(bmain, deg_graph); - DEG_graph_on_visible_update(bmain, graph); + double start_time = 0.0; + if (G.debug & (G_DEBUG_DEPSGRAPH_BUILD | G_DEBUG_DEPSGRAPH_TIME)) { + start_time = PIL_check_seconds_timer(); + } + DEG::Depsgraph *deg_graph = reinterpret_cast(graph); + /* Perform sanity checks. */ + BLI_assert(BLI_findindex(&scene->view_layers, view_layer) != -1); + BLI_assert(deg_graph->scene == scene); + BLI_assert(deg_graph->view_layer == view_layer); + /* Generate all the nodes in the graph first */ + DEG::DepsgraphNodeBuilder node_builder(bmain, deg_graph); + node_builder.begin_build(); + node_builder.build_view_layer(scene, view_layer, DEG::DEG_ID_LINKED_DIRECTLY); + node_builder.end_build(); + /* Hook up relationships between operations - to determine evaluation + * order. */ + DEG::DepsgraphRelationBuilder relation_builder(bmain, deg_graph); + relation_builder.begin_build(); + relation_builder.build_view_layer(scene, view_layer); + relation_builder.build_copy_on_write_relations(); + /* Detect and solve cycles. */ + DEG::deg_graph_detect_cycles(deg_graph); + /* Simplify the graph by removing redundant relations (to optimize + * traversal later). */ + /* TODO: it would be useful to have an option to disable this in cases where + * it is causing trouble. */ + if (G.debug_value == 799) { + DEG::deg_graph_transitive_reduction(deg_graph); + } + /* Store pointers to commonly used valuated datablocks. */ + deg_graph->scene_cow = (Scene *)deg_graph->get_cow_id(°_graph->scene->id); + /* Flush visibility layer and re-schedule nodes for update. */ + DEG::deg_graph_build_finalize(bmain, deg_graph); + DEG_graph_on_visible_update(bmain, graph); #if 0 - if (!DEG_debug_consistency_check(deg_graph)) { - printf("Consistency validation failed, ABORTING!\n"); - abort(); - } + if (!DEG_debug_consistency_check(deg_graph)) { + printf("Consistency validation failed, ABORTING!\n"); + abort(); + } #endif - /* Relations are up to date. */ - deg_graph->need_update = false; - /* Finish statistics. */ - if (G.debug & (G_DEBUG_DEPSGRAPH_BUILD | G_DEBUG_DEPSGRAPH_TIME)) { - printf("Depsgraph built in %f seconds.\n", - PIL_check_seconds_timer() - start_time); - } + /* Relations are up to date. */ + deg_graph->need_update = false; + /* Finish statistics. */ + if (G.debug & (G_DEBUG_DEPSGRAPH_BUILD | G_DEBUG_DEPSGRAPH_TIME)) { + printf("Depsgraph built in %f seconds.\n", PIL_check_seconds_timer() - start_time); + } } /* Tag graph relations for update. */ void DEG_graph_tag_relations_update(Depsgraph *graph) { - DEG_DEBUG_PRINTF(graph, TAG, "%s: Tagging relations for update.\n", __func__); - DEG::Depsgraph *deg_graph = reinterpret_cast(graph); - deg_graph->need_update = true; - /* NOTE: When relations are updated, it's quite possible that - * we've got new bases in the scene. This means, we need to - * re-create flat array of bases in view layer. - * - * TODO(sergey): Try to make it so we don't flush updates - * to the whole depsgraph. */ - DEG::IDNode *id_node = deg_graph->find_id_node(°_graph->scene->id); - if (id_node != NULL) { - id_node->tag_update(deg_graph, DEG::DEG_UPDATE_SOURCE_RELATIONS); - } + DEG_DEBUG_PRINTF(graph, TAG, "%s: Tagging relations for update.\n", __func__); + DEG::Depsgraph *deg_graph = reinterpret_cast(graph); + deg_graph->need_update = true; + /* NOTE: When relations are updated, it's quite possible that + * we've got new bases in the scene. This means, we need to + * re-create flat array of bases in view layer. + * + * TODO(sergey): Try to make it so we don't flush updates + * to the whole depsgraph. */ + DEG::IDNode *id_node = deg_graph->find_id_node(°_graph->scene->id); + if (id_node != NULL) { + id_node->tag_update(deg_graph, DEG::DEG_UPDATE_SOURCE_RELATIONS); + } } /* Create or update relations in the specified graph. */ -void DEG_graph_relations_update(Depsgraph *graph, - Main *bmain, - Scene *scene, - ViewLayer *view_layer) +void DEG_graph_relations_update(Depsgraph *graph, Main *bmain, Scene *scene, ViewLayer *view_layer) { - DEG::Depsgraph *deg_graph = (DEG::Depsgraph *)graph; - if (!deg_graph->need_update) { - /* Graph is up to date, nothing to do. */ - return; - } - DEG_graph_build_from_view_layer(graph, bmain, scene, view_layer); + DEG::Depsgraph *deg_graph = (DEG::Depsgraph *)graph; + if (!deg_graph->need_update) { + /* Graph is up to date, nothing to do. */ + return; + } + DEG_graph_build_from_view_layer(graph, bmain, scene, view_layer); } /* Tag all relations for update. */ void DEG_relations_tag_update(Main *bmain) { - DEG_GLOBAL_DEBUG_PRINTF(TAG, "%s: Tagging relations for update.\n", __func__); - LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { - LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { - Depsgraph *depsgraph = - (Depsgraph *)BKE_scene_get_depsgraph(scene, - view_layer, - false); - if (depsgraph != NULL) { - DEG_graph_tag_relations_update(depsgraph); - } - } - } + DEG_GLOBAL_DEBUG_PRINTF(TAG, "%s: Tagging relations for update.\n", __func__); + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { + Depsgraph *depsgraph = (Depsgraph *)BKE_scene_get_depsgraph(scene, view_layer, false); + if (depsgraph != NULL) { + DEG_graph_tag_relations_update(depsgraph); + } + } + } } diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc index 67450d1350f..e795bed144d 100644 --- a/source/blender/depsgraph/intern/depsgraph_debug.cc +++ b/source/blender/depsgraph/intern/depsgraph_debug.cc @@ -28,7 +28,7 @@ extern "C" { #include "DNA_scene_types.h" -} /* extern "C" */ +} /* extern "C" */ #include "DNA_object_types.h" @@ -46,49 +46,44 @@ extern "C" { void DEG_debug_flags_set(Depsgraph *depsgraph, int flags) { - DEG::Depsgraph *deg_graph = - reinterpret_cast(depsgraph); - deg_graph->debug_flags = flags; + DEG::Depsgraph *deg_graph = reinterpret_cast(depsgraph); + deg_graph->debug_flags = flags; } int DEG_debug_flags_get(const Depsgraph *depsgraph) { - const DEG::Depsgraph *deg_graph = - reinterpret_cast(depsgraph); - return deg_graph->debug_flags; + const DEG::Depsgraph *deg_graph = reinterpret_cast(depsgraph); + return deg_graph->debug_flags; } void DEG_debug_name_set(struct Depsgraph *depsgraph, const char *name) { - DEG::Depsgraph *deg_graph = - reinterpret_cast(depsgraph); - deg_graph->debug_name = name; + DEG::Depsgraph *deg_graph = reinterpret_cast(depsgraph); + deg_graph->debug_name = name; } const char *DEG_debug_name_get(struct Depsgraph *depsgraph) { - const DEG::Depsgraph *deg_graph = - reinterpret_cast(depsgraph); - return deg_graph->debug_name.c_str(); + const DEG::Depsgraph *deg_graph = reinterpret_cast(depsgraph); + return deg_graph->debug_name.c_str(); } -bool DEG_debug_compare(const struct Depsgraph *graph1, - const struct Depsgraph *graph2) +bool DEG_debug_compare(const struct Depsgraph *graph1, const struct Depsgraph *graph2) { - BLI_assert(graph1 != NULL); - BLI_assert(graph2 != NULL); - const DEG::Depsgraph *deg_graph1 = reinterpret_cast(graph1); - const DEG::Depsgraph *deg_graph2 = reinterpret_cast(graph2); - if (deg_graph1->operations.size() != deg_graph2->operations.size()) { - return false; - } - /* TODO(sergey): Currently we only do real stupid check, - * which is fast but which isn't 100% reliable. - * - * Would be cool to make it more robust, but it's good enough - * for now. Also, proper graph check is actually NP-complex - * problem. */ - return true; + BLI_assert(graph1 != NULL); + BLI_assert(graph2 != NULL); + const DEG::Depsgraph *deg_graph1 = reinterpret_cast(graph1); + const DEG::Depsgraph *deg_graph2 = reinterpret_cast(graph2); + if (deg_graph1->operations.size() != deg_graph2->operations.size()) { + return false; + } + /* TODO(sergey): Currently we only do real stupid check, + * which is fast but which isn't 100% reliable. + * + * Would be cool to make it more robust, but it's good enough + * for now. Also, proper graph check is actually NP-complex + * problem. */ + return true; } bool DEG_debug_graph_relations_validate(Depsgraph *graph, @@ -96,105 +91,107 @@ bool DEG_debug_graph_relations_validate(Depsgraph *graph, Scene *scene, ViewLayer *view_layer) { - Depsgraph *temp_depsgraph = DEG_graph_new(scene, view_layer, DEG_get_mode(graph)); - bool valid = true; - DEG_graph_build_from_view_layer(temp_depsgraph, bmain, scene, view_layer); - if (!DEG_debug_compare(temp_depsgraph, graph)) { - fprintf(stderr, "ERROR! Depsgraph wasn't tagged for update when it should have!\n"); - BLI_assert(!"This should not happen!"); - valid = false; - } - DEG_graph_free(temp_depsgraph); - return valid; + Depsgraph *temp_depsgraph = DEG_graph_new(scene, view_layer, DEG_get_mode(graph)); + bool valid = true; + DEG_graph_build_from_view_layer(temp_depsgraph, bmain, scene, view_layer); + if (!DEG_debug_compare(temp_depsgraph, graph)) { + fprintf(stderr, "ERROR! Depsgraph wasn't tagged for update when it should have!\n"); + BLI_assert(!"This should not happen!"); + valid = false; + } + DEG_graph_free(temp_depsgraph); + return valid; } bool DEG_debug_consistency_check(Depsgraph *graph) { - const DEG::Depsgraph *deg_graph = - reinterpret_cast(graph); - /* Validate links exists in both directions. */ - for (DEG::OperationNode *node : deg_graph->operations) { - for (DEG::Relation *rel : node->outlinks) { - int counter1 = 0; - for (DEG::Relation *tmp_rel : node->outlinks) { - if (tmp_rel == rel) { - ++counter1; - } - } - int counter2 = 0; - for (DEG::Relation *tmp_rel : rel->to->inlinks) { - if (tmp_rel == rel) { - ++counter2; - } - } - if (counter1 != counter2) { - printf("Relation exists in outgoing direction but not in " - "incoming (%d vs. %d).\n", - counter1, counter2); - return false; - } - } - } - - for (DEG::OperationNode *node : deg_graph->operations) { - for (DEG::Relation *rel : node->inlinks) { - int counter1 = 0; - for (DEG::Relation *tmp_rel : node->inlinks) { - if (tmp_rel == rel) { - ++counter1; - } - } - int counter2 = 0; - for (DEG::Relation *tmp_rel : rel->from->outlinks) { - if (tmp_rel == rel) { - ++counter2; - } - } - if (counter1 != counter2) { - printf("Relation exists in incoming direction but not in outcoming (%d vs. %d).\n", - counter1, counter2); - } - } - } - - /* Validate node valency calculated in both directions. */ - for (DEG::OperationNode *node : deg_graph->operations) { - node->num_links_pending = 0; - node->custom_flags = 0; - } - - for (DEG::OperationNode *node : deg_graph->operations) { - if (node->custom_flags) { - printf("Node %s is twice in the operations!\n", - node->identifier().c_str()); - return false; - } - for (DEG::Relation *rel : node->outlinks) { - if (rel->to->type == DEG::NodeType::OPERATION) { - DEG::OperationNode *to = (DEG::OperationNode *)rel->to; - BLI_assert(to->num_links_pending < to->inlinks.size()); - ++to->num_links_pending; - } - } - node->custom_flags = 1; - } - - for (DEG::OperationNode *node : deg_graph->operations) { - int num_links_pending = 0; - for (DEG::Relation *rel : node->inlinks) { - if (rel->from->type == DEG::NodeType::OPERATION) { - ++num_links_pending; - } - } - if (node->num_links_pending != num_links_pending) { - printf("Valency mismatch: %s, %u != %d\n", - node->identifier().c_str(), - node->num_links_pending, num_links_pending); - printf("Number of inlinks: %d\n", (int)node->inlinks.size()); - return false; - } - } - return true; + const DEG::Depsgraph *deg_graph = reinterpret_cast(graph); + /* Validate links exists in both directions. */ + for (DEG::OperationNode *node : deg_graph->operations) { + for (DEG::Relation *rel : node->outlinks) { + int counter1 = 0; + for (DEG::Relation *tmp_rel : node->outlinks) { + if (tmp_rel == rel) { + ++counter1; + } + } + int counter2 = 0; + for (DEG::Relation *tmp_rel : rel->to->inlinks) { + if (tmp_rel == rel) { + ++counter2; + } + } + if (counter1 != counter2) { + printf( + "Relation exists in outgoing direction but not in " + "incoming (%d vs. %d).\n", + counter1, + counter2); + return false; + } + } + } + + for (DEG::OperationNode *node : deg_graph->operations) { + for (DEG::Relation *rel : node->inlinks) { + int counter1 = 0; + for (DEG::Relation *tmp_rel : node->inlinks) { + if (tmp_rel == rel) { + ++counter1; + } + } + int counter2 = 0; + for (DEG::Relation *tmp_rel : rel->from->outlinks) { + if (tmp_rel == rel) { + ++counter2; + } + } + if (counter1 != counter2) { + printf("Relation exists in incoming direction but not in outcoming (%d vs. %d).\n", + counter1, + counter2); + } + } + } + + /* Validate node valency calculated in both directions. */ + for (DEG::OperationNode *node : deg_graph->operations) { + node->num_links_pending = 0; + node->custom_flags = 0; + } + + for (DEG::OperationNode *node : deg_graph->operations) { + if (node->custom_flags) { + printf("Node %s is twice in the operations!\n", node->identifier().c_str()); + return false; + } + for (DEG::Relation *rel : node->outlinks) { + if (rel->to->type == DEG::NodeType::OPERATION) { + DEG::OperationNode *to = (DEG::OperationNode *)rel->to; + BLI_assert(to->num_links_pending < to->inlinks.size()); + ++to->num_links_pending; + } + } + node->custom_flags = 1; + } + + for (DEG::OperationNode *node : deg_graph->operations) { + int num_links_pending = 0; + for (DEG::Relation *rel : node->inlinks) { + if (rel->from->type == DEG::NodeType::OPERATION) { + ++num_links_pending; + } + } + if (node->num_links_pending != num_links_pending) { + printf("Valency mismatch: %s, %u != %d\n", + node->identifier().c_str(), + node->num_links_pending, + num_links_pending); + printf("Number of inlinks: %d\n", (int)node->inlinks.size()); + return false; + } + } + return true; } /* ------------------------------------------------ */ @@ -205,65 +202,66 @@ bool DEG_debug_consistency_check(Depsgraph *graph) * \param[out] r_operations The number of operation nodes in the graph * \param[out] r_relations The number of relations between (executable) nodes in the graph */ -void DEG_stats_simple(const Depsgraph *graph, size_t *r_outer, - size_t *r_operations, size_t *r_relations) +void DEG_stats_simple(const Depsgraph *graph, + size_t *r_outer, + size_t *r_operations, + size_t *r_relations) { - const DEG::Depsgraph *deg_graph = reinterpret_cast(graph); - - /* number of operations */ - if (r_operations) { - /* All operations should be in this list, allowing us to count the total - * number of nodes. */ - *r_operations = deg_graph->operations.size(); - } - - /* Count number of outer nodes and/or relations between these. */ - if (r_outer || r_relations) { - size_t tot_outer = 0; - size_t tot_rels = 0; - - for (DEG::IDNode *id_node : deg_graph->id_nodes) { - tot_outer++; - GHASH_FOREACH_BEGIN(DEG::ComponentNode *, comp_node, id_node->components) - { - tot_outer++; - for (DEG::OperationNode *op_node : comp_node->operations) { - tot_rels += op_node->inlinks.size(); - } - } - GHASH_FOREACH_END(); - } - - DEG::TimeSourceNode *time_source = deg_graph->find_time_source(); - if (time_source != NULL) { - tot_rels += time_source->inlinks.size(); - } - - if (r_relations) *r_relations = tot_rels; - if (r_outer) *r_outer = tot_outer; - } + const DEG::Depsgraph *deg_graph = reinterpret_cast(graph); + + /* number of operations */ + if (r_operations) { + /* All operations should be in this list, allowing us to count the total + * number of nodes. */ + *r_operations = deg_graph->operations.size(); + } + + /* Count number of outer nodes and/or relations between these. */ + if (r_outer || r_relations) { + size_t tot_outer = 0; + size_t tot_rels = 0; + + for (DEG::IDNode *id_node : deg_graph->id_nodes) { + tot_outer++; + GHASH_FOREACH_BEGIN (DEG::ComponentNode *, comp_node, id_node->components) { + tot_outer++; + for (DEG::OperationNode *op_node : comp_node->operations) { + tot_rels += op_node->inlinks.size(); + } + } + GHASH_FOREACH_END(); + } + + DEG::TimeSourceNode *time_source = deg_graph->find_time_source(); + if (time_source != NULL) { + tot_rels += time_source->inlinks.size(); + } + + if (r_relations) + *r_relations = tot_rels; + if (r_outer) + *r_outer = tot_outer; + } } bool DEG_debug_is_evaluating(struct Depsgraph *depsgraph) { - DEG::Depsgraph *deg_graph = - reinterpret_cast(depsgraph); - return deg_graph->debug_is_evaluating; + DEG::Depsgraph *deg_graph = reinterpret_cast(depsgraph); + return deg_graph->debug_is_evaluating; } static DEG::string depsgraph_name_for_logging(struct Depsgraph *depsgraph) { - const char *name = DEG_debug_name_get(depsgraph); - if (name[0] == '\0') { - return ""; - } - return "[" + DEG::string(name) + "]: "; + const char *name = DEG_debug_name_get(depsgraph); + if (name[0] == '\0') { + return ""; + } + return "[" + DEG::string(name) + "]: "; } void DEG_debug_print_begin(struct Depsgraph *depsgraph) { - fprintf(stdout, "%s", - depsgraph_name_for_logging(depsgraph).c_str()); + fprintf(stdout, "%s", depsgraph_name_for_logging(depsgraph).c_str()); } void DEG_debug_print_eval(struct Depsgraph *depsgraph, @@ -271,18 +269,18 @@ void DEG_debug_print_eval(struct Depsgraph *depsgraph, const char *object_name, const void *object_address) { - if ((DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_EVAL) == 0) { - return; - } - fprintf(stdout, - "%s%s on %s %s(%p)%s\n", - depsgraph_name_for_logging(depsgraph).c_str(), - function_name, - object_name, - DEG::color_for_pointer(object_address).c_str(), - object_address, - DEG::color_end().c_str()); - fflush(stdout); + if ((DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_EVAL) == 0) { + return; + } + fprintf(stdout, + "%s%s on %s %s(%p)%s\n", + depsgraph_name_for_logging(depsgraph).c_str(), + function_name, + object_name, + DEG::color_for_pointer(object_address).c_str(), + object_address, + DEG::color_end().c_str()); + fflush(stdout); } void DEG_debug_print_eval_subdata(struct Depsgraph *depsgraph, @@ -293,23 +291,23 @@ void DEG_debug_print_eval_subdata(struct Depsgraph *depsgraph, const char *subdata_name, const void *subdata_address) { - if ((DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_EVAL) == 0) { - return; - } - fprintf(stdout, - "%s%s on %s %s(%p)%s %s %s %s(%p)%s\n", - depsgraph_name_for_logging(depsgraph).c_str(), - function_name, - object_name, - DEG::color_for_pointer(object_address).c_str(), - object_address, - DEG::color_end().c_str(), - subdata_comment, - subdata_name, - DEG::color_for_pointer(subdata_address).c_str(), - subdata_address, - DEG::color_end().c_str()); - fflush(stdout); + if ((DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_EVAL) == 0) { + return; + } + fprintf(stdout, + "%s%s on %s %s(%p)%s %s %s %s(%p)%s\n", + depsgraph_name_for_logging(depsgraph).c_str(), + function_name, + object_name, + DEG::color_for_pointer(object_address).c_str(), + object_address, + DEG::color_end().c_str(), + subdata_comment, + subdata_name, + DEG::color_for_pointer(subdata_address).c_str(), + subdata_address, + DEG::color_end().c_str()); + fflush(stdout); } void DEG_debug_print_eval_subdata_index(struct Depsgraph *depsgraph, @@ -321,24 +319,24 @@ void DEG_debug_print_eval_subdata_index(struct Depsgraph *depsgraph, const void *subdata_address, const int subdata_index) { - if ((DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_EVAL) == 0) { - return; - } - fprintf(stdout, - "%s%s on %s %s(%p)%s %s %s[%d] %s(%p)%s\n", - depsgraph_name_for_logging(depsgraph).c_str(), - function_name, - object_name, - DEG::color_for_pointer(object_address).c_str(), - object_address, - DEG::color_end().c_str(), - subdata_comment, - subdata_name, - subdata_index, - DEG::color_for_pointer(subdata_address).c_str(), - subdata_address, - DEG::color_end().c_str()); - fflush(stdout); + if ((DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_EVAL) == 0) { + return; + } + fprintf(stdout, + "%s%s on %s %s(%p)%s %s %s[%d] %s(%p)%s\n", + depsgraph_name_for_logging(depsgraph).c_str(), + function_name, + object_name, + DEG::color_for_pointer(object_address).c_str(), + object_address, + DEG::color_end().c_str(), + subdata_comment, + subdata_name, + subdata_index, + DEG::color_for_pointer(subdata_address).c_str(), + subdata_address, + DEG::color_end().c_str()); + fflush(stdout); } void DEG_debug_print_eval_parent_typed(struct Depsgraph *depsgraph, @@ -349,23 +347,23 @@ void DEG_debug_print_eval_parent_typed(struct Depsgraph *depsgraph, const char *parent_name, const void *parent_address) { - if ((DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_EVAL) == 0) { - return; - } - fprintf(stdout, - "%s%s on %s %s(%p) [%s] %s %s %s(%p)%s\n", - depsgraph_name_for_logging(depsgraph).c_str(), - function_name, - object_name, - DEG::color_for_pointer(object_address).c_str(), - object_address, - DEG::color_end().c_str(), - parent_comment, - parent_name, - DEG::color_for_pointer(parent_address).c_str(), - parent_address, - DEG::color_end().c_str()); - fflush(stdout); + if ((DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_EVAL) == 0) { + return; + } + fprintf(stdout, + "%s%s on %s %s(%p) [%s] %s %s %s(%p)%s\n", + depsgraph_name_for_logging(depsgraph).c_str(), + function_name, + object_name, + DEG::color_for_pointer(object_address).c_str(), + object_address, + DEG::color_end().c_str(), + parent_comment, + parent_name, + DEG::color_for_pointer(parent_address).c_str(), + parent_address, + DEG::color_end().c_str()); + fflush(stdout); } void DEG_debug_print_eval_time(struct Depsgraph *depsgraph, @@ -374,17 +372,17 @@ void DEG_debug_print_eval_time(struct Depsgraph *depsgraph, const void *object_address, float time) { - if ((DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_EVAL) == 0) { - return; - } - fprintf(stdout, - "%s%s on %s %s(%p)%s at time %f\n", - depsgraph_name_for_logging(depsgraph).c_str(), - function_name, - object_name, - DEG::color_for_pointer(object_address).c_str(), - object_address, - DEG::color_end().c_str(), - time); - fflush(stdout); + if ((DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_EVAL) == 0) { + return; + } + fprintf(stdout, + "%s%s on %s %s(%p)%s at time %f\n", + depsgraph_name_for_logging(depsgraph).c_str(), + function_name, + object_name, + DEG::color_for_pointer(object_address).c_str(), + object_address, + DEG::color_end().c_str(), + time); + fflush(stdout); } diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc index 30370c5ac15..6f3262174b4 100644 --- a/source/blender/depsgraph/intern/depsgraph_eval.cc +++ b/source/blender/depsgraph/intern/depsgraph_eval.cc @@ -51,40 +51,38 @@ extern "C" { /* Evaluate all nodes tagged for updating. */ void DEG_evaluate_on_refresh(Depsgraph *graph) { - DEG::Depsgraph *deg_graph = reinterpret_cast(graph); - deg_graph->ctime = BKE_scene_frame_get(deg_graph->scene); - /* Update time on primary timesource. */ - DEG::TimeSourceNode *tsrc = deg_graph->find_time_source(); - tsrc->cfra = deg_graph->ctime; - /* Update time in scene. */ - if (deg_graph->scene_cow) { - BKE_scene_frame_set(deg_graph->scene_cow, deg_graph->ctime); - } - DEG::deg_evaluate_on_refresh(deg_graph); + DEG::Depsgraph *deg_graph = reinterpret_cast(graph); + deg_graph->ctime = BKE_scene_frame_get(deg_graph->scene); + /* Update time on primary timesource. */ + DEG::TimeSourceNode *tsrc = deg_graph->find_time_source(); + tsrc->cfra = deg_graph->ctime; + /* Update time in scene. */ + if (deg_graph->scene_cow) { + BKE_scene_frame_set(deg_graph->scene_cow, deg_graph->ctime); + } + DEG::deg_evaluate_on_refresh(deg_graph); } /* Frame-change happened for root scene that graph belongs to. */ -void DEG_evaluate_on_framechange(Main *bmain, - Depsgraph *graph, - float ctime) +void DEG_evaluate_on_framechange(Main *bmain, Depsgraph *graph, float ctime) { - DEG::Depsgraph *deg_graph = reinterpret_cast(graph); - deg_graph->ctime = ctime; - /* Update time on primary timesource. */ - DEG::TimeSourceNode *tsrc = deg_graph->find_time_source(); - tsrc->cfra = ctime; - tsrc->tag_update(deg_graph, DEG::DEG_UPDATE_SOURCE_TIME); - DEG::deg_graph_flush_updates(bmain, deg_graph); - /* Update time in scene. */ - if (deg_graph->scene_cow) { - BKE_scene_frame_set(deg_graph->scene_cow, deg_graph->ctime); - } - /* Perform recalculation updates. */ - DEG::deg_evaluate_on_refresh(deg_graph); + DEG::Depsgraph *deg_graph = reinterpret_cast(graph); + deg_graph->ctime = ctime; + /* Update time on primary timesource. */ + DEG::TimeSourceNode *tsrc = deg_graph->find_time_source(); + tsrc->cfra = ctime; + tsrc->tag_update(deg_graph, DEG::DEG_UPDATE_SOURCE_TIME); + DEG::deg_graph_flush_updates(bmain, deg_graph); + /* Update time in scene. */ + if (deg_graph->scene_cow) { + BKE_scene_frame_set(deg_graph->scene_cow, deg_graph->ctime); + } + /* Perform recalculation updates. */ + DEG::deg_evaluate_on_refresh(deg_graph); } bool DEG_needs_eval(Depsgraph *graph) { - DEG::Depsgraph *deg_graph = reinterpret_cast(graph); - return BLI_gset_len(deg_graph->entry_tags) != 0; + DEG::Depsgraph *deg_graph = reinterpret_cast(graph); + return BLI_gset_len(deg_graph->entry_tags) != 0; } diff --git a/source/blender/depsgraph/intern/depsgraph_physics.cc b/source/blender/depsgraph/intern/depsgraph_physics.cc index 02265ba0e7a..3f81e49b170 100644 --- a/source/blender/depsgraph/intern/depsgraph_physics.cc +++ b/source/blender/depsgraph/intern/depsgraph_physics.cc @@ -49,51 +49,44 @@ extern "C" { /*************************** Evaluation Query API *****************************/ -static ePhysicsRelationType modifier_to_relation_type( - unsigned int modifier_type) +static ePhysicsRelationType modifier_to_relation_type(unsigned int modifier_type) { - switch (modifier_type) { - case eModifierType_Collision: - return DEG_PHYSICS_COLLISION; - case eModifierType_Smoke: - return DEG_PHYSICS_SMOKE_COLLISION; - case eModifierType_DynamicPaint: - return DEG_PHYSICS_DYNAMIC_BRUSH; - } - - BLI_assert(!"Unknown collision modifier type"); - return DEG_PHYSICS_RELATIONS_NUM; + switch (modifier_type) { + case eModifierType_Collision: + return DEG_PHYSICS_COLLISION; + case eModifierType_Smoke: + return DEG_PHYSICS_SMOKE_COLLISION; + case eModifierType_DynamicPaint: + return DEG_PHYSICS_DYNAMIC_BRUSH; + } + + BLI_assert(!"Unknown collision modifier type"); + return DEG_PHYSICS_RELATIONS_NUM; } -ListBase *DEG_get_effector_relations(const Depsgraph *graph, - Collection *collection) +ListBase *DEG_get_effector_relations(const Depsgraph *graph, Collection *collection) { - const DEG::Depsgraph *deg_graph = - reinterpret_cast(graph); - if (deg_graph->physics_relations[DEG_PHYSICS_EFFECTOR] == NULL) { - return NULL; - } - - ID *collection_orig = DEG_get_original_id(&collection->id); - return (ListBase *)BLI_ghash_lookup( - deg_graph->physics_relations[DEG_PHYSICS_EFFECTOR], - collection_orig); + const DEG::Depsgraph *deg_graph = reinterpret_cast(graph); + if (deg_graph->physics_relations[DEG_PHYSICS_EFFECTOR] == NULL) { + return NULL; + } + + ID *collection_orig = DEG_get_original_id(&collection->id); + return (ListBase *)BLI_ghash_lookup(deg_graph->physics_relations[DEG_PHYSICS_EFFECTOR], + collection_orig); } ListBase *DEG_get_collision_relations(const Depsgraph *graph, Collection *collection, unsigned int modifier_type) { - const DEG::Depsgraph *deg_graph = - reinterpret_cast(graph); - const ePhysicsRelationType type = modifier_to_relation_type(modifier_type); - if (deg_graph->physics_relations[type] == NULL) { - return NULL; - } - ID *collection_orig = DEG_get_original_id(&collection->id); - return (ListBase *)BLI_ghash_lookup( - deg_graph->physics_relations[type], - collection_orig); + const DEG::Depsgraph *deg_graph = reinterpret_cast(graph); + const ePhysicsRelationType type = modifier_to_relation_type(modifier_type); + if (deg_graph->physics_relations[type] == NULL) { + return NULL; + } + ID *collection_orig = DEG_get_original_id(&collection->id); + return (ListBase *)BLI_ghash_lookup(deg_graph->physics_relations[type], collection_orig); } /********************** Depsgraph Building API ************************/ @@ -105,26 +98,20 @@ void DEG_add_collision_relations(DepsNodeHandle *handle, DEG_CollobjFilterFunction filter_function, const char *name) { - Depsgraph *depsgraph = DEG_get_graph_from_handle(handle); - DEG::Depsgraph *deg_graph = (DEG::Depsgraph *)depsgraph; - ListBase *relations = build_collision_relations( - deg_graph, collection, modifier_type); - LISTBASE_FOREACH (CollisionRelation *, relation, relations) { - Object *ob1 = relation->ob; - if (ob1 == object) { - continue; - } - if (filter_function == NULL || - filter_function( - ob1, - modifiers_findByType(ob1, (ModifierType)modifier_type))) - { - DEG_add_object_pointcache_relation( - handle, ob1, DEG_OB_COMP_TRANSFORM, name); - DEG_add_object_pointcache_relation( - handle, ob1, DEG_OB_COMP_GEOMETRY, name); - } - } + Depsgraph *depsgraph = DEG_get_graph_from_handle(handle); + DEG::Depsgraph *deg_graph = (DEG::Depsgraph *)depsgraph; + ListBase *relations = build_collision_relations(deg_graph, collection, modifier_type); + LISTBASE_FOREACH (CollisionRelation *, relation, relations) { + Object *ob1 = relation->ob; + if (ob1 == object) { + continue; + } + if (filter_function == NULL || + filter_function(ob1, modifiers_findByType(ob1, (ModifierType)modifier_type))) { + DEG_add_object_pointcache_relation(handle, ob1, DEG_OB_COMP_TRANSFORM, name); + DEG_add_object_pointcache_relation(handle, ob1, DEG_OB_COMP_GEOMETRY, name); + } + } } void DEG_add_forcefield_relations(DepsNodeHandle *handle, @@ -134,144 +121,119 @@ void DEG_add_forcefield_relations(DepsNodeHandle *handle, int skip_forcefield, const char *name) { - Depsgraph *depsgraph = DEG_get_graph_from_handle(handle); - DEG::Depsgraph *deg_graph = (DEG::Depsgraph *)depsgraph; - ListBase *relations = - build_effector_relations(deg_graph, effector_weights->group); - LISTBASE_FOREACH (EffectorRelation *, relation, relations) { - if (relation->ob == object) { - continue; - } - if (relation->pd->forcefield == skip_forcefield) { - continue; - } - - /* Relation to forcefield object, optionally including geometry. - * Use special point cache relations for automatic cache clearing. */ - DEG_add_object_pointcache_relation( - handle, relation->ob, DEG_OB_COMP_TRANSFORM, name); - - if (relation->psys || - ELEM(relation->pd->shape, PFIELD_SHAPE_SURFACE, PFIELD_SHAPE_POINTS) || - relation->pd->forcefield == PFIELD_GUIDE) - { - /* TODO(sergey): Consider going more granular with more dedicated - * particle system operation. */ - DEG_add_object_pointcache_relation( - handle, relation->ob, DEG_OB_COMP_GEOMETRY, name); - } - - /* Smoke flow relations. */ - if (relation->pd->forcefield == PFIELD_SMOKEFLOW && - relation->pd->f_source != NULL) - { - DEG_add_object_pointcache_relation(handle, - relation->pd->f_source, - DEG_OB_COMP_TRANSFORM, - "Smoke Force Domain"); - DEG_add_object_pointcache_relation(handle, - relation->pd->f_source, - DEG_OB_COMP_GEOMETRY, - "Smoke Force Domain"); - } - - /* Absorption forces need collision relation. */ - if (add_absorption && (relation->pd->flag & PFIELD_VISIBILITY)) { - DEG_add_collision_relations(handle, - object, - NULL, - eModifierType_Collision, - NULL, - "Force Absorption"); - } - } + Depsgraph *depsgraph = DEG_get_graph_from_handle(handle); + DEG::Depsgraph *deg_graph = (DEG::Depsgraph *)depsgraph; + ListBase *relations = build_effector_relations(deg_graph, effector_weights->group); + LISTBASE_FOREACH (EffectorRelation *, relation, relations) { + if (relation->ob == object) { + continue; + } + if (relation->pd->forcefield == skip_forcefield) { + continue; + } + + /* Relation to forcefield object, optionally including geometry. + * Use special point cache relations for automatic cache clearing. */ + DEG_add_object_pointcache_relation(handle, relation->ob, DEG_OB_COMP_TRANSFORM, name); + + if (relation->psys || ELEM(relation->pd->shape, PFIELD_SHAPE_SURFACE, PFIELD_SHAPE_POINTS) || + relation->pd->forcefield == PFIELD_GUIDE) { + /* TODO(sergey): Consider going more granular with more dedicated + * particle system operation. */ + DEG_add_object_pointcache_relation(handle, relation->ob, DEG_OB_COMP_GEOMETRY, name); + } + + /* Smoke flow relations. */ + if (relation->pd->forcefield == PFIELD_SMOKEFLOW && relation->pd->f_source != NULL) { + DEG_add_object_pointcache_relation( + handle, relation->pd->f_source, DEG_OB_COMP_TRANSFORM, "Smoke Force Domain"); + DEG_add_object_pointcache_relation( + handle, relation->pd->f_source, DEG_OB_COMP_GEOMETRY, "Smoke Force Domain"); + } + + /* Absorption forces need collision relation. */ + if (add_absorption && (relation->pd->flag & PFIELD_VISIBILITY)) { + DEG_add_collision_relations( + handle, object, NULL, eModifierType_Collision, NULL, "Force Absorption"); + } + } } /******************************** Internal API ********************************/ -namespace DEG -{ +namespace DEG { ListBase *build_effector_relations(Depsgraph *graph, Collection *collection) { - GHash *hash = graph->physics_relations[DEG_PHYSICS_EFFECTOR]; - if (hash == NULL) { - graph->physics_relations[DEG_PHYSICS_EFFECTOR] = - BLI_ghash_ptr_new("Depsgraph physics relations hash"); - hash = graph->physics_relations[DEG_PHYSICS_EFFECTOR]; - } - ListBase *relations = - reinterpret_cast(BLI_ghash_lookup(hash, collection)); - if (relations == NULL) { - ::Depsgraph *depsgraph = reinterpret_cast<::Depsgraph*>(graph); - relations = BKE_effector_relations_create( - depsgraph, graph->view_layer, collection); - BLI_ghash_insert(hash, &collection->id, relations); - } - return relations; + GHash *hash = graph->physics_relations[DEG_PHYSICS_EFFECTOR]; + if (hash == NULL) { + graph->physics_relations[DEG_PHYSICS_EFFECTOR] = BLI_ghash_ptr_new( + "Depsgraph physics relations hash"); + hash = graph->physics_relations[DEG_PHYSICS_EFFECTOR]; + } + ListBase *relations = reinterpret_cast(BLI_ghash_lookup(hash, collection)); + if (relations == NULL) { + ::Depsgraph *depsgraph = reinterpret_cast<::Depsgraph *>(graph); + relations = BKE_effector_relations_create(depsgraph, graph->view_layer, collection); + BLI_ghash_insert(hash, &collection->id, relations); + } + return relations; } ListBase *build_collision_relations(Depsgraph *graph, Collection *collection, unsigned int modifier_type) { - const ePhysicsRelationType type = modifier_to_relation_type(modifier_type); - GHash *hash = graph->physics_relations[type]; - if (hash == NULL) { - graph->physics_relations[type] = - BLI_ghash_ptr_new("Depsgraph physics relations hash"); - hash = graph->physics_relations[type]; - } - ListBase *relations = - reinterpret_cast(BLI_ghash_lookup(hash, collection)); - if (relations == NULL) { - ::Depsgraph *depsgraph = reinterpret_cast<::Depsgraph*>(graph); - relations = BKE_collision_relations_create( - depsgraph, collection, modifier_type); - BLI_ghash_insert(hash, &collection->id, relations); - } - return relations; + const ePhysicsRelationType type = modifier_to_relation_type(modifier_type); + GHash *hash = graph->physics_relations[type]; + if (hash == NULL) { + graph->physics_relations[type] = BLI_ghash_ptr_new("Depsgraph physics relations hash"); + hash = graph->physics_relations[type]; + } + ListBase *relations = reinterpret_cast(BLI_ghash_lookup(hash, collection)); + if (relations == NULL) { + ::Depsgraph *depsgraph = reinterpret_cast<::Depsgraph *>(graph); + relations = BKE_collision_relations_create(depsgraph, collection, modifier_type); + BLI_ghash_insert(hash, &collection->id, relations); + } + return relations; } namespace { void free_effector_relations(void *value) { - BKE_effector_relations_free(reinterpret_cast(value)); + BKE_effector_relations_free(reinterpret_cast(value)); } void free_collision_relations(void *value) { - BKE_collision_relations_free(reinterpret_cast(value)); + BKE_collision_relations_free(reinterpret_cast(value)); } } // namespace void clear_physics_relations(Depsgraph *graph) { - for (int i = 0; i < DEG_PHYSICS_RELATIONS_NUM; i++) { - if (graph->physics_relations[i]) { - const ePhysicsRelationType type = (ePhysicsRelationType)i; - - switch (type) { - case DEG_PHYSICS_EFFECTOR: - BLI_ghash_free(graph->physics_relations[i], - NULL, - free_effector_relations); - break; - case DEG_PHYSICS_COLLISION: - case DEG_PHYSICS_SMOKE_COLLISION: - case DEG_PHYSICS_DYNAMIC_BRUSH: - BLI_ghash_free(graph->physics_relations[i], - NULL, - free_collision_relations); - break; - case DEG_PHYSICS_RELATIONS_NUM: - break; - } - graph->physics_relations[i] = NULL; - } - } + for (int i = 0; i < DEG_PHYSICS_RELATIONS_NUM; i++) { + if (graph->physics_relations[i]) { + const ePhysicsRelationType type = (ePhysicsRelationType)i; + + switch (type) { + case DEG_PHYSICS_EFFECTOR: + BLI_ghash_free(graph->physics_relations[i], NULL, free_effector_relations); + break; + case DEG_PHYSICS_COLLISION: + case DEG_PHYSICS_SMOKE_COLLISION: + case DEG_PHYSICS_DYNAMIC_BRUSH: + BLI_ghash_free(graph->physics_relations[i], NULL, free_collision_relations); + break; + case DEG_PHYSICS_RELATIONS_NUM: + break; + } + graph->physics_relations[i] = NULL; + } + } } -} +} // namespace DEG diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc index 3b7f19e9916..a653366a588 100644 --- a/source/blender/depsgraph/intern/depsgraph_query.cc +++ b/source/blender/depsgraph/intern/depsgraph_query.cc @@ -26,7 +26,7 @@ #include "MEM_guardedalloc.h" extern "C" { -#include // XXX: memcpy +#include // XXX: memcpy #include "BLI_utildefines.h" #include "BKE_customdata.h" @@ -34,7 +34,7 @@ extern "C" { #include "BKE_main.h" #include "BLI_listbase.h" -#include "BKE_action.h" // XXX: BKE_pose_channel_from_name +#include "BKE_action.h" // XXX: BKE_pose_channel_from_name } /* extern "C" */ #include "DNA_object_types.h" @@ -51,211 +51,215 @@ extern "C" { struct Scene *DEG_get_input_scene(const Depsgraph *graph) { - const DEG::Depsgraph *deg_graph = reinterpret_cast(graph); - return deg_graph->scene; + const DEG::Depsgraph *deg_graph = reinterpret_cast(graph); + return deg_graph->scene; } struct ViewLayer *DEG_get_input_view_layer(const Depsgraph *graph) { - const DEG::Depsgraph *deg_graph = reinterpret_cast(graph); - return deg_graph->view_layer; + const DEG::Depsgraph *deg_graph = reinterpret_cast(graph); + return deg_graph->view_layer; } eEvaluationMode DEG_get_mode(const Depsgraph *graph) { - const DEG::Depsgraph *deg_graph = reinterpret_cast(graph); - return deg_graph->mode; + const DEG::Depsgraph *deg_graph = reinterpret_cast(graph); + return deg_graph->mode; } float DEG_get_ctime(const Depsgraph *graph) { - const DEG::Depsgraph *deg_graph = reinterpret_cast(graph); - return deg_graph->ctime; + const DEG::Depsgraph *deg_graph = reinterpret_cast(graph); + return deg_graph->ctime; } - bool DEG_id_type_updated(const Depsgraph *graph, short id_type) { - const DEG::Depsgraph *deg_graph = reinterpret_cast(graph); - return deg_graph->id_type_updated[BKE_idcode_to_index(id_type)] != 0; + const DEG::Depsgraph *deg_graph = reinterpret_cast(graph); + return deg_graph->id_type_updated[BKE_idcode_to_index(id_type)] != 0; } bool DEG_id_type_any_updated(const Depsgraph *graph) { - const DEG::Depsgraph *deg_graph = reinterpret_cast(graph); + const DEG::Depsgraph *deg_graph = reinterpret_cast(graph); - /* Loop over all ID types. */ - for (int id_type_index = 0; id_type_index < MAX_LIBARRAY; id_type_index++) { - if (deg_graph->id_type_updated[id_type_index]) { - return true; - } - } + /* Loop over all ID types. */ + for (int id_type_index = 0; id_type_index < MAX_LIBARRAY; id_type_index++) { + if (deg_graph->id_type_updated[id_type_index]) { + return true; + } + } - return false; + return false; } uint32_t DEG_get_eval_flags_for_id(const Depsgraph *graph, ID *id) { - if (graph == NULL) { - /* Happens when converting objects to mesh from a python script - * after modifying scene graph. - * - * Currently harmless because it's only called for temporary - * objects which are out of the DAG anyway. */ - return 0; - } + if (graph == NULL) { + /* Happens when converting objects to mesh from a python script + * after modifying scene graph. + * + * Currently harmless because it's only called for temporary + * objects which are out of the DAG anyway. */ + return 0; + } - const DEG::Depsgraph *deg_graph = reinterpret_cast(graph); - const DEG::IDNode *id_node = deg_graph->find_id_node(DEG_get_original_id(id)); - if (id_node == NULL) { - /* TODO(sergey): Does it mean we need to check set scene? */ - return 0; - } + const DEG::Depsgraph *deg_graph = reinterpret_cast(graph); + const DEG::IDNode *id_node = deg_graph->find_id_node(DEG_get_original_id(id)); + if (id_node == NULL) { + /* TODO(sergey): Does it mean we need to check set scene? */ + return 0; + } - return id_node->eval_flags; + return id_node->eval_flags; } -void DEG_get_customdata_mask_for_object(const Depsgraph *graph, Object *ob, CustomData_MeshMasks *r_mask) +void DEG_get_customdata_mask_for_object(const Depsgraph *graph, + Object *ob, + CustomData_MeshMasks *r_mask) { - if (graph == NULL) { - /* Happens when converting objects to mesh from a python script - * after modifying scene graph. - * - * Currently harmless because it's only called for temporary - * objects which are out of the DAG anyway. */ - return; - } + if (graph == NULL) { + /* Happens when converting objects to mesh from a python script + * after modifying scene graph. + * + * Currently harmless because it's only called for temporary + * objects which are out of the DAG anyway. */ + return; + } - const DEG::Depsgraph *deg_graph = reinterpret_cast(graph); - const DEG::IDNode *id_node = deg_graph->find_id_node(DEG_get_original_id(&ob->id)); - if (id_node == NULL) { - /* TODO(sergey): Does it mean we need to check set scene? */ - return; - } + const DEG::Depsgraph *deg_graph = reinterpret_cast(graph); + const DEG::IDNode *id_node = deg_graph->find_id_node(DEG_get_original_id(&ob->id)); + if (id_node == NULL) { + /* TODO(sergey): Does it mean we need to check set scene? */ + return; + } - r_mask->vmask |= id_node->customdata_masks.vert_mask; - r_mask->emask |= id_node->customdata_masks.edge_mask; - r_mask->fmask |= id_node->customdata_masks.face_mask; - r_mask->lmask |= id_node->customdata_masks.loop_mask; - r_mask->pmask |= id_node->customdata_masks.poly_mask; + r_mask->vmask |= id_node->customdata_masks.vert_mask; + r_mask->emask |= id_node->customdata_masks.edge_mask; + r_mask->fmask |= id_node->customdata_masks.face_mask; + r_mask->lmask |= id_node->customdata_masks.loop_mask; + r_mask->pmask |= id_node->customdata_masks.poly_mask; } Scene *DEG_get_evaluated_scene(const Depsgraph *graph) { - const DEG::Depsgraph *deg_graph = - reinterpret_cast(graph); - Scene *scene_cow = deg_graph->scene_cow; - /* TODO(sergey): Shall we expand datablock here? Or is it OK to assume - * that calleer is OK with just a pointer in case scene is not updated - * yet? */ - BLI_assert(scene_cow != NULL && DEG::deg_copy_on_write_is_expanded(&scene_cow->id)); - return scene_cow; + const DEG::Depsgraph *deg_graph = reinterpret_cast(graph); + Scene *scene_cow = deg_graph->scene_cow; + /* TODO(sergey): Shall we expand datablock here? Or is it OK to assume + * that calleer is OK with just a pointer in case scene is not updated + * yet? */ + BLI_assert(scene_cow != NULL && DEG::deg_copy_on_write_is_expanded(&scene_cow->id)); + return scene_cow; } ViewLayer *DEG_get_evaluated_view_layer(const Depsgraph *graph) { - const DEG::Depsgraph *deg_graph = - reinterpret_cast(graph); - Scene *scene_cow = DEG_get_evaluated_scene(graph); - if (scene_cow == NULL) { - return NULL; /* Happens with new, not-yet-built/evaluated graphes. */ - } - /* Do name-based lookup. */ - /* TODO(sergey): Can this be optimized? */ - ViewLayer *view_layer_orig = deg_graph->view_layer; - ViewLayer *view_layer_cow = - (ViewLayer *)BLI_findstring(&scene_cow->view_layers, - view_layer_orig->name, - offsetof(ViewLayer, name)); - BLI_assert(view_layer_cow != NULL); - return view_layer_cow; + const DEG::Depsgraph *deg_graph = reinterpret_cast(graph); + Scene *scene_cow = DEG_get_evaluated_scene(graph); + if (scene_cow == NULL) { + return NULL; /* Happens with new, not-yet-built/evaluated graphes. */ + } + /* Do name-based lookup. */ + /* TODO(sergey): Can this be optimized? */ + ViewLayer *view_layer_orig = deg_graph->view_layer; + ViewLayer *view_layer_cow = (ViewLayer *)BLI_findstring( + &scene_cow->view_layers, view_layer_orig->name, offsetof(ViewLayer, name)); + BLI_assert(view_layer_cow != NULL); + return view_layer_cow; } Object *DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object) { - return (Object *)DEG_get_evaluated_id(depsgraph, &object->id); + return (Object *)DEG_get_evaluated_id(depsgraph, &object->id); } ID *DEG_get_evaluated_id(const Depsgraph *depsgraph, ID *id) { - if (id == NULL) { - return NULL; - } - /* TODO(sergey): This is a duplicate of Depsgraph::get_cow_id(), - * but here we never do assert, since we don't know nature of the - * incoming ID datablock. */ - const DEG::Depsgraph *deg_graph = (const DEG::Depsgraph *)depsgraph; - const DEG::IDNode *id_node = deg_graph->find_id_node(id); - if (id_node == NULL) { - return id; - } - return id_node->id_cow; + if (id == NULL) { + return NULL; + } + /* TODO(sergey): This is a duplicate of Depsgraph::get_cow_id(), + * but here we never do assert, since we don't know nature of the + * incoming ID datablock. */ + const DEG::Depsgraph *deg_graph = (const DEG::Depsgraph *)depsgraph; + const DEG::IDNode *id_node = deg_graph->find_id_node(id); + if (id_node == NULL) { + return id; + } + return id_node->id_cow; } /* Get evaluated version of data pointed to by RNA pointer */ -void DEG_get_evaluated_rna_pointer(const Depsgraph *depsgraph, PointerRNA *ptr, PointerRNA *r_ptr_eval) +void DEG_get_evaluated_rna_pointer(const Depsgraph *depsgraph, + PointerRNA *ptr, + PointerRNA *r_ptr_eval) { - if ((ptr == NULL) || (r_ptr_eval == NULL)) { - return; - } - ID *orig_id = (ID *)ptr->id.data; - ID *cow_id = DEG_get_evaluated_id(depsgraph, orig_id); - if (ptr->id.data == ptr->data) { - /* For ID pointers, it's easy... */ - r_ptr_eval->id.data = (void *)cow_id; - r_ptr_eval->data = (void *)cow_id; - r_ptr_eval->type = ptr->type; - } - else if (ptr->type == &RNA_PoseBone) { - /* HACK: Since bone keyframing is quite commonly used, - * speed things up for this case by doing a special lookup - * for bones */ - const Object *ob_eval = (Object *)cow_id; - bPoseChannel *pchan = (bPoseChannel *)ptr->data; - const bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name); - r_ptr_eval->id.data = (void *)cow_id; - r_ptr_eval->data = (void *)pchan_eval; - r_ptr_eval->type = ptr->type; - } - else { - /* For everything else, try to get RNA Path of the BMain-pointer, - * then use that to look up what the COW-domain one should be - * given the COW ID pointer as the new lookup point */ - /* TODO: Find a faster alternative, or implement support for other - * common types too above (e.g. modifiers) */ - char *path = RNA_path_from_ID_to_struct(ptr); - if (path) { - PointerRNA cow_id_ptr; - RNA_id_pointer_create(cow_id, &cow_id_ptr); - if (!RNA_path_resolve(&cow_id_ptr, path, r_ptr_eval, NULL)) { - /* Couldn't find COW copy of data */ - fprintf(stderr, - "%s: Couldn't resolve RNA path ('%s') relative to COW ID (%p) for '%s'\n", - __func__, path, (void *)cow_id, orig_id->name); - } - } - else { - /* Path resolution failed - XXX: Hide this behind a debug flag */ - fprintf(stderr, - "%s: Couldn't get RNA path for %s relative to %s\n", - __func__, RNA_struct_identifier(ptr->type), orig_id->name); - } - } + if ((ptr == NULL) || (r_ptr_eval == NULL)) { + return; + } + ID *orig_id = (ID *)ptr->id.data; + ID *cow_id = DEG_get_evaluated_id(depsgraph, orig_id); + if (ptr->id.data == ptr->data) { + /* For ID pointers, it's easy... */ + r_ptr_eval->id.data = (void *)cow_id; + r_ptr_eval->data = (void *)cow_id; + r_ptr_eval->type = ptr->type; + } + else if (ptr->type == &RNA_PoseBone) { + /* HACK: Since bone keyframing is quite commonly used, + * speed things up for this case by doing a special lookup + * for bones */ + const Object *ob_eval = (Object *)cow_id; + bPoseChannel *pchan = (bPoseChannel *)ptr->data; + const bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name); + r_ptr_eval->id.data = (void *)cow_id; + r_ptr_eval->data = (void *)pchan_eval; + r_ptr_eval->type = ptr->type; + } + else { + /* For everything else, try to get RNA Path of the BMain-pointer, + * then use that to look up what the COW-domain one should be + * given the COW ID pointer as the new lookup point */ + /* TODO: Find a faster alternative, or implement support for other + * common types too above (e.g. modifiers) */ + char *path = RNA_path_from_ID_to_struct(ptr); + if (path) { + PointerRNA cow_id_ptr; + RNA_id_pointer_create(cow_id, &cow_id_ptr); + if (!RNA_path_resolve(&cow_id_ptr, path, r_ptr_eval, NULL)) { + /* Couldn't find COW copy of data */ + fprintf(stderr, + "%s: Couldn't resolve RNA path ('%s') relative to COW ID (%p) for '%s'\n", + __func__, + path, + (void *)cow_id, + orig_id->name); + } + } + else { + /* Path resolution failed - XXX: Hide this behind a debug flag */ + fprintf(stderr, + "%s: Couldn't get RNA path for %s relative to %s\n", + __func__, + RNA_struct_identifier(ptr->type), + orig_id->name); + } + } } Object *DEG_get_original_object(Object *object) { - return (Object *)DEG_get_original_id(&object->id); + return (Object *)DEG_get_original_id(&object->id); } ID *DEG_get_original_id(ID *id) { - if (id == NULL) { - return NULL; - } - if (id->orig_id == NULL) { - return id; - } - BLI_assert((id->tag & LIB_TAG_COPIED_ON_WRITE) != 0); - return (ID *)id->orig_id; + if (id == NULL) { + return NULL; + } + if (id->orig_id == NULL) { + return id; + } + BLI_assert((id->tag & LIB_TAG_COPIED_ON_WRITE) != 0); + return (ID *)id->orig_id; } diff --git a/source/blender/depsgraph/intern/depsgraph_query_filter.cc b/source/blender/depsgraph/intern/depsgraph_query_filter.cc index dbfc488d44e..987e9330d35 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_filter.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_filter.cc @@ -26,7 +26,7 @@ #include "MEM_guardedalloc.h" extern "C" { -#include // XXX: memcpy +#include // XXX: memcpy #include "BLI_utildefines.h" #include "BKE_idcode.h" @@ -34,7 +34,7 @@ extern "C" { #include "BLI_listbase.h" #include "BLI_ghash.h" -#include "BKE_action.h" // XXX: BKE_pose_channel_from_name +#include "BKE_action.h" // XXX: BKE_pose_channel_from_name } /* extern "C" */ #include "DNA_object_types.h" @@ -56,7 +56,6 @@ extern "C" { #include "intern/node/deg_node_id.h" #include "intern/node/deg_node_operation.h" - /* *************************************************** */ /* Graph Filtering Internals */ @@ -64,8 +63,8 @@ namespace DEG { /* UserData for deg_add_retained_id_cb */ struct RetainedIdUserData { - DEG_FilterQuery *query; - GSet *set; + DEG_FilterQuery *query; + GSet *set; }; /* Helper for DEG_foreach_ancestor_id() @@ -73,8 +72,8 @@ struct RetainedIdUserData { */ static void deg_add_retained_id_cb(ID *id, void *user_data) { - RetainedIdUserData *data = (RetainedIdUserData *)user_data; - BLI_gset_add(data->set, (void *)id); + RetainedIdUserData *data = (RetainedIdUserData *)user_data; + BLI_gset_add(data->set, (void *)id); } /* ------------------------------------------- */ @@ -83,92 +82,87 @@ static void deg_add_retained_id_cb(ID *id, void *user_data) /* TODO: Make this part of OperationNode? */ static void deg_unlink_opnode(Depsgraph *graph, OperationNode *op_node) { - vector all_links; - - /* Collect all inlinks to this operation */ - for (Relation *rel : op_node->inlinks) { - all_links.push_back(rel); - } - /* Collect all outlinks from this operation */ - for (Relation *rel : op_node->outlinks) { - all_links.push_back(rel); - } - - /* Delete all collected relations */ - for (Relation *rel : all_links) { - rel->unlink(); - OBJECT_GUARDED_DELETE(rel, Relation); - } - - /* Remove from entry tags */ - if (BLI_gset_haskey(graph->entry_tags, op_node)) { - BLI_gset_remove(graph->entry_tags, op_node, NULL); - } + vector all_links; + + /* Collect all inlinks to this operation */ + for (Relation *rel : op_node->inlinks) { + all_links.push_back(rel); + } + /* Collect all outlinks from this operation */ + for (Relation *rel : op_node->outlinks) { + all_links.push_back(rel); + } + + /* Delete all collected relations */ + for (Relation *rel : all_links) { + rel->unlink(); + OBJECT_GUARDED_DELETE(rel, Relation); + } + + /* Remove from entry tags */ + if (BLI_gset_haskey(graph->entry_tags, op_node)) { + BLI_gset_remove(graph->entry_tags, op_node, NULL); + } } /* Remove every ID Node (and its associated subnodes, COW data) */ static void deg_filter_remove_unwanted_ids(Depsgraph *graph, GSet *retained_ids) { - /* 1) First pass over ID nodes + their operations - * - Identify and tag ID's (via "custom_flags = 1") to be removed - * - Remove all links to/from operations that will be removed. */ - for (IDNode *id_node : graph->id_nodes) { - id_node->custom_flags = !BLI_gset_haskey(retained_ids, (void *)id_node->id_orig); - if (id_node->custom_flags) { - GHASH_FOREACH_BEGIN(ComponentNode *, comp_node, id_node->components) - { - for (OperationNode *op_node : comp_node->operations) { - deg_unlink_opnode(graph, op_node); - } - } - GHASH_FOREACH_END(); - } - } - - /* 2) Remove unwanted operations from graph->operations */ - for (Depsgraph::OperationNodes::iterator it_opnode = graph->operations.begin(); - it_opnode != graph->operations.end(); - ) - { - OperationNode *op_node = *it_opnode; - IDNode *id_node = op_node->owner->owner; - if (id_node->custom_flags) { - it_opnode = graph->operations.erase(it_opnode); - } - else { - ++it_opnode; - } - } - - /* Free ID nodes that are no longer wanted - * - * This is loosely based on Depsgraph::clear_id_nodes(). - * However, we don't worry about the conditional freeing for physics - * stuff, since it's rarely needed currently. */ - for (Depsgraph::IDDepsNodes::iterator it_id = graph->id_nodes.begin(); - it_id != graph->id_nodes.end(); - ) - { - IDNode *id_node = *it_id; - ID *id = id_node->id_orig; - - if (id_node->custom_flags) { - /* Destroy node data, then remove from collections, and free */ - id_node->destroy(); - - BLI_ghash_remove(graph->id_hash, id, NULL, NULL); - it_id = graph->id_nodes.erase(it_id); - - OBJECT_GUARDED_DELETE(id_node, IDNode); - } - else { - /* This node has not been marked for deletion. Increment iterator */ - ++it_id; - } - } + /* 1) First pass over ID nodes + their operations + * - Identify and tag ID's (via "custom_flags = 1") to be removed + * - Remove all links to/from operations that will be removed. */ + for (IDNode *id_node : graph->id_nodes) { + id_node->custom_flags = !BLI_gset_haskey(retained_ids, (void *)id_node->id_orig); + if (id_node->custom_flags) { + GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) { + for (OperationNode *op_node : comp_node->operations) { + deg_unlink_opnode(graph, op_node); + } + } + GHASH_FOREACH_END(); + } + } + + /* 2) Remove unwanted operations from graph->operations */ + for (Depsgraph::OperationNodes::iterator it_opnode = graph->operations.begin(); + it_opnode != graph->operations.end();) { + OperationNode *op_node = *it_opnode; + IDNode *id_node = op_node->owner->owner; + if (id_node->custom_flags) { + it_opnode = graph->operations.erase(it_opnode); + } + else { + ++it_opnode; + } + } + + /* Free ID nodes that are no longer wanted + * + * This is loosely based on Depsgraph::clear_id_nodes(). + * However, we don't worry about the conditional freeing for physics + * stuff, since it's rarely needed currently. */ + for (Depsgraph::IDDepsNodes::iterator it_id = graph->id_nodes.begin(); + it_id != graph->id_nodes.end();) { + IDNode *id_node = *it_id; + ID *id = id_node->id_orig; + + if (id_node->custom_flags) { + /* Destroy node data, then remove from collections, and free */ + id_node->destroy(); + + BLI_ghash_remove(graph->id_hash, id, NULL, NULL); + it_id = graph->id_nodes.erase(it_id); + + OBJECT_GUARDED_DELETE(id_node, IDNode); + } + else { + /* This node has not been marked for deletion. Increment iterator */ + ++it_id; + } + } } -} //namespace DEG +} //namespace DEG /* *************************************************** */ /* Graph Filtering API */ @@ -179,67 +173,71 @@ static void deg_filter_remove_unwanted_ids(Depsgraph *graph, GSet *retained_ids) */ Depsgraph *DEG_graph_filter(const Depsgraph *graph_src, Main *bmain, DEG_FilterQuery *query) { - const DEG::Depsgraph *deg_graph_src = reinterpret_cast(graph_src); - if (deg_graph_src == NULL) { - return NULL; - } - - /* Construct a full new depsgraph based on the one we got */ - /* TODO: Improve the builders to not add any ID nodes we don't need later (e.g. ProxyBuilder?) */ - Depsgraph *graph_new = DEG_graph_new(deg_graph_src->scene, - deg_graph_src->view_layer, - deg_graph_src->mode); - DEG_graph_build_from_view_layer(graph_new, - bmain, - deg_graph_src->scene, - deg_graph_src->view_layer); - - /* Build a set of all the id's we want to keep */ - GSet *retained_ids = BLI_gset_ptr_new(__func__); - DEG::RetainedIdUserData retained_id_data = {query, retained_ids}; - - LISTBASE_FOREACH (DEG_FilterTarget *, target, &query->targets) { - /* Target Itself */ - BLI_gset_add(retained_ids, (void *)target->id); - - /* Target's Ancestors (i.e. things it depends on) */ - DEG_foreach_ancestor_ID(graph_new, - target->id, - DEG::deg_add_retained_id_cb, - &retained_id_data); - } - - /* Remove everything we don't want to keep around anymore */ - DEG::Depsgraph *deg_graph_new = reinterpret_cast(graph_new); - if (BLI_gset_len(retained_ids) > 0) { - DEG::deg_filter_remove_unwanted_ids(deg_graph_new, retained_ids); - } - // TODO: query->LOD filters - - /* Free temp data */ - BLI_gset_free(retained_ids, NULL); - retained_ids = NULL; - - /* Print Stats */ - // XXX: Hide behind debug flags - size_t s_outer, s_operations, s_relations; - size_t s_ids = deg_graph_src->id_nodes.size(); - unsigned int s_idh = BLI_ghash_len(deg_graph_src->id_hash); - - size_t n_outer, n_operations, n_relations; - size_t n_ids = deg_graph_new->id_nodes.size(); - unsigned int n_idh = BLI_ghash_len(deg_graph_new->id_hash); - - DEG_stats_simple(graph_src, &s_outer, &s_operations, &s_relations); - DEG_stats_simple(graph_new, &n_outer, &n_operations, &n_relations); - - printf("%s: src = (ID's: %zu (%u), Out: %zu, Op: %zu, Rel: %zu)\n", - __func__, s_ids, s_idh, s_outer, s_operations, s_relations); - printf("%s: new = (ID's: %zu (%u), Out: %zu, Op: %zu, Rel: %zu)\n", - __func__, n_ids, n_idh, n_outer, n_operations, n_relations); - - /* Return this new graph instance */ - return graph_new; + const DEG::Depsgraph *deg_graph_src = reinterpret_cast(graph_src); + if (deg_graph_src == NULL) { + return NULL; + } + + /* Construct a full new depsgraph based on the one we got */ + /* TODO: Improve the builders to not add any ID nodes we don't need later (e.g. ProxyBuilder?) */ + Depsgraph *graph_new = DEG_graph_new( + deg_graph_src->scene, deg_graph_src->view_layer, deg_graph_src->mode); + DEG_graph_build_from_view_layer( + graph_new, bmain, deg_graph_src->scene, deg_graph_src->view_layer); + + /* Build a set of all the id's we want to keep */ + GSet *retained_ids = BLI_gset_ptr_new(__func__); + DEG::RetainedIdUserData retained_id_data = {query, retained_ids}; + + LISTBASE_FOREACH (DEG_FilterTarget *, target, &query->targets) { + /* Target Itself */ + BLI_gset_add(retained_ids, (void *)target->id); + + /* Target's Ancestors (i.e. things it depends on) */ + DEG_foreach_ancestor_ID(graph_new, target->id, DEG::deg_add_retained_id_cb, &retained_id_data); + } + + /* Remove everything we don't want to keep around anymore */ + DEG::Depsgraph *deg_graph_new = reinterpret_cast(graph_new); + if (BLI_gset_len(retained_ids) > 0) { + DEG::deg_filter_remove_unwanted_ids(deg_graph_new, retained_ids); + } + // TODO: query->LOD filters + + /* Free temp data */ + BLI_gset_free(retained_ids, NULL); + retained_ids = NULL; + + /* Print Stats */ + // XXX: Hide behind debug flags + size_t s_outer, s_operations, s_relations; + size_t s_ids = deg_graph_src->id_nodes.size(); + unsigned int s_idh = BLI_ghash_len(deg_graph_src->id_hash); + + size_t n_outer, n_operations, n_relations; + size_t n_ids = deg_graph_new->id_nodes.size(); + unsigned int n_idh = BLI_ghash_len(deg_graph_new->id_hash); + + DEG_stats_simple(graph_src, &s_outer, &s_operations, &s_relations); + DEG_stats_simple(graph_new, &n_outer, &n_operations, &n_relations); + + printf("%s: src = (ID's: %zu (%u), Out: %zu, Op: %zu, Rel: %zu)\n", + __func__, + s_ids, + s_idh, + s_outer, + s_operations, + s_relations); + printf("%s: new = (ID's: %zu (%u), Out: %zu, Op: %zu, Rel: %zu)\n", + __func__, + n_ids, + n_idh, + n_outer, + n_operations, + n_relations); + + /* Return this new graph instance */ + return graph_new; } /* *************************************************** */ diff --git a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc index a2ca4be5e33..717793d60f1 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc @@ -51,17 +51,17 @@ namespace DEG { typedef std::deque TraversalQueue; enum { - DEG_NODE_VISITED = (1 << 0), + DEG_NODE_VISITED = (1 << 0), }; static void deg_foreach_clear_flags(const Depsgraph *graph) { - for (OperationNode *op_node : graph->operations) { - op_node->scheduled = false; - } - for (IDNode *id_node : graph->id_nodes) { - id_node->custom_flags = 0; - } + for (OperationNode *op_node : graph->operations) { + op_node->scheduled = false; + } + for (IDNode *id_node : graph->id_nodes) { + id_node->custom_flags = 0; + } } static void deg_foreach_dependent_ID(const Depsgraph *graph, @@ -69,165 +69,161 @@ static void deg_foreach_dependent_ID(const Depsgraph *graph, DEGForeachIDCallback callback, void *user_data) { - /* Start with getting ID node from the graph. */ - IDNode *target_id_node = graph->find_id_node(id); - if (target_id_node == NULL) { - /* TODO(sergey): Shall we inform or assert here about attempt to start - * iterating over non-existing ID? */ - return; - } - /* Make sure all runtime flags are ready and clear. */ - deg_foreach_clear_flags(graph); - /* Start with scheduling all operations from ID node. */ - TraversalQueue queue; - GHASH_FOREACH_BEGIN(ComponentNode *, comp_node, target_id_node->components) - { - for (OperationNode *op_node : comp_node->operations) { - queue.push_back(op_node); - op_node->scheduled = true; - } - } - GHASH_FOREACH_END(); - target_id_node->custom_flags |= DEG_NODE_VISITED; - /* Process the queue. */ - while (!queue.empty()) { - /* get next operation node to process. */ - OperationNode *op_node = queue.front(); - queue.pop_front(); - for (;;) { - /* Check whether we need to inform callee about corresponding ID node. */ - ComponentNode *comp_node = op_node->owner; - IDNode *id_node = comp_node->owner; - if ((id_node->custom_flags & DEG_NODE_VISITED) == 0) { - /* TODO(sergey): Is it orig or CoW? */ - callback(id_node->id_orig, user_data); - id_node->custom_flags |= DEG_NODE_VISITED; - } - /* Schedule outgoing operation nodes. */ - if (op_node->outlinks.size() == 1) { - OperationNode *to_node = (OperationNode *)op_node->outlinks[0]->to; - if (to_node->scheduled == false) { - to_node->scheduled = true; - op_node = to_node; - } - else { - break; - } - } - else { - for (Relation *rel : op_node->outlinks) { - OperationNode *to_node = (OperationNode *)rel->to; - if (to_node->scheduled == false) { - queue.push_front(to_node); - to_node->scheduled = true; - } - } - break; - } - } - } + /* Start with getting ID node from the graph. */ + IDNode *target_id_node = graph->find_id_node(id); + if (target_id_node == NULL) { + /* TODO(sergey): Shall we inform or assert here about attempt to start + * iterating over non-existing ID? */ + return; + } + /* Make sure all runtime flags are ready and clear. */ + deg_foreach_clear_flags(graph); + /* Start with scheduling all operations from ID node. */ + TraversalQueue queue; + GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, target_id_node->components) { + for (OperationNode *op_node : comp_node->operations) { + queue.push_back(op_node); + op_node->scheduled = true; + } + } + GHASH_FOREACH_END(); + target_id_node->custom_flags |= DEG_NODE_VISITED; + /* Process the queue. */ + while (!queue.empty()) { + /* get next operation node to process. */ + OperationNode *op_node = queue.front(); + queue.pop_front(); + for (;;) { + /* Check whether we need to inform callee about corresponding ID node. */ + ComponentNode *comp_node = op_node->owner; + IDNode *id_node = comp_node->owner; + if ((id_node->custom_flags & DEG_NODE_VISITED) == 0) { + /* TODO(sergey): Is it orig or CoW? */ + callback(id_node->id_orig, user_data); + id_node->custom_flags |= DEG_NODE_VISITED; + } + /* Schedule outgoing operation nodes. */ + if (op_node->outlinks.size() == 1) { + OperationNode *to_node = (OperationNode *)op_node->outlinks[0]->to; + if (to_node->scheduled == false) { + to_node->scheduled = true; + op_node = to_node; + } + else { + break; + } + } + else { + for (Relation *rel : op_node->outlinks) { + OperationNode *to_node = (OperationNode *)rel->to; + if (to_node->scheduled == false) { + queue.push_front(to_node); + to_node->scheduled = true; + } + } + break; + } + } + } } static void deg_foreach_ancestor_ID(const Depsgraph *graph, - const ID *id, - DEGForeachIDCallback callback, - void *user_data) + const ID *id, + DEGForeachIDCallback callback, + void *user_data) { - /* Start with getting ID node from the graph. */ - IDNode *target_id_node = graph->find_id_node(id); - if (target_id_node == NULL) { - /* TODO(sergey): Shall we inform or assert here about attempt to start - * iterating over non-existing ID? */ - return; - } - /* Make sure all runtime flags are ready and clear. */ - deg_foreach_clear_flags(graph); - /* Start with scheduling all operations from ID node. */ - TraversalQueue queue; - GHASH_FOREACH_BEGIN(ComponentNode *, comp_node, target_id_node->components) - { - for (OperationNode *op_node : comp_node->operations) { - queue.push_back(op_node); - op_node->scheduled = true; - } - } - GHASH_FOREACH_END(); - target_id_node->custom_flags |= DEG_NODE_VISITED; - /* Process the queue. */ - while (!queue.empty()) { - /* get next operation node to process. */ - OperationNode *op_node = queue.front(); - queue.pop_front(); - for (;;) { - /* Check whether we need to inform callee about corresponding ID node. */ - ComponentNode *comp_node = op_node->owner; - IDNode *id_node = comp_node->owner; - if ((id_node->custom_flags & DEG_NODE_VISITED) == 0) { - /* TODO(sergey): Is it orig or CoW? */ - callback(id_node->id_orig, user_data); - id_node->custom_flags |= DEG_NODE_VISITED; - } - /* Schedule incoming operation nodes. */ - if (op_node->inlinks.size() == 1) { - Node *from = op_node->inlinks[0]->from; - if (from->get_class() == NodeClass::OPERATION) { - OperationNode *from_node = (OperationNode *)from; - if (from_node->scheduled == false) { - from_node->scheduled = true; - op_node = from_node; - } - else { - break; - } - } - } - else { - for (Relation *rel : op_node->inlinks) { - Node *from = rel->from; - if (from->get_class() == NodeClass::OPERATION) { - OperationNode *from_node = (OperationNode *)from; - if (from_node->scheduled == false) { - queue.push_front(from_node); - from_node->scheduled = true; - } - } - } - break; - } - } - } + /* Start with getting ID node from the graph. */ + IDNode *target_id_node = graph->find_id_node(id); + if (target_id_node == NULL) { + /* TODO(sergey): Shall we inform or assert here about attempt to start + * iterating over non-existing ID? */ + return; + } + /* Make sure all runtime flags are ready and clear. */ + deg_foreach_clear_flags(graph); + /* Start with scheduling all operations from ID node. */ + TraversalQueue queue; + GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, target_id_node->components) { + for (OperationNode *op_node : comp_node->operations) { + queue.push_back(op_node); + op_node->scheduled = true; + } + } + GHASH_FOREACH_END(); + target_id_node->custom_flags |= DEG_NODE_VISITED; + /* Process the queue. */ + while (!queue.empty()) { + /* get next operation node to process. */ + OperationNode *op_node = queue.front(); + queue.pop_front(); + for (;;) { + /* Check whether we need to inform callee about corresponding ID node. */ + ComponentNode *comp_node = op_node->owner; + IDNode *id_node = comp_node->owner; + if ((id_node->custom_flags & DEG_NODE_VISITED) == 0) { + /* TODO(sergey): Is it orig or CoW? */ + callback(id_node->id_orig, user_data); + id_node->custom_flags |= DEG_NODE_VISITED; + } + /* Schedule incoming operation nodes. */ + if (op_node->inlinks.size() == 1) { + Node *from = op_node->inlinks[0]->from; + if (from->get_class() == NodeClass::OPERATION) { + OperationNode *from_node = (OperationNode *)from; + if (from_node->scheduled == false) { + from_node->scheduled = true; + op_node = from_node; + } + else { + break; + } + } + } + else { + for (Relation *rel : op_node->inlinks) { + Node *from = rel->from; + if (from->get_class() == NodeClass::OPERATION) { + OperationNode *from_node = (OperationNode *)from; + if (from_node->scheduled == false) { + queue.push_front(from_node); + from_node->scheduled = true; + } + } + } + break; + } + } + } } static void deg_foreach_id(const Depsgraph *depsgraph, - DEGForeachIDCallback callback, void *user_data) + DEGForeachIDCallback callback, + void *user_data) { - for (const IDNode *id_node : depsgraph->id_nodes) { - callback(id_node->id_orig, user_data); - } + for (const IDNode *id_node : depsgraph->id_nodes) { + callback(id_node->id_orig, user_data); + } } } // namespace DEG void DEG_foreach_dependent_ID(const Depsgraph *depsgraph, const ID *id, - DEGForeachIDCallback callback, void *user_data) + DEGForeachIDCallback callback, + void *user_data) { - DEG::deg_foreach_dependent_ID((const DEG::Depsgraph *)depsgraph, - id, - callback, user_data); + DEG::deg_foreach_dependent_ID((const DEG::Depsgraph *)depsgraph, id, callback, user_data); } void DEG_foreach_ancestor_ID(const Depsgraph *depsgraph, const ID *id, - DEGForeachIDCallback callback, void *user_data) + DEGForeachIDCallback callback, + void *user_data) { - DEG::deg_foreach_ancestor_ID((const DEG::Depsgraph *)depsgraph, - id, - callback, user_data); + DEG::deg_foreach_ancestor_ID((const DEG::Depsgraph *)depsgraph, id, callback, user_data); } -void DEG_foreach_ID(const Depsgraph *depsgraph, - DEGForeachIDCallback callback, void *user_data) +void DEG_foreach_ID(const Depsgraph *depsgraph, DEGForeachIDCallback callback, void *user_data) { - DEG::deg_foreach_id((const DEG::Depsgraph *)depsgraph, callback, user_data); + DEG::deg_foreach_id((const DEG::Depsgraph *)depsgraph, callback, user_data); } diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc index 2dfffe92368..d3bf27747c0 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc @@ -67,315 +67,309 @@ namespace { void deg_invalidate_iterator_work_data(DEGObjectIterData *data) { #ifdef INVALIDATE_WORK_DATA - BLI_assert(data != NULL); - memset(&data->temp_dupli_object, 0xff, sizeof(data->temp_dupli_object)); + BLI_assert(data != NULL); + memset(&data->temp_dupli_object, 0xff, sizeof(data->temp_dupli_object)); #else - (void) data; + (void)data; #endif } void verify_id_properties_freed(DEGObjectIterData *data) { - if (data->dupli_object_current == NULL) { - // We didn't enter duplication yet, so we can't have any dangling - // pointers. - return; - } - const Object *dupli_object = data->dupli_object_current->ob; - Object *temp_dupli_object = &data->temp_dupli_object; - if (temp_dupli_object->id.properties == NULL) { - // No ID properties in temp datablock -- no leak is possible. - return; - } - if (temp_dupli_object->id.properties == dupli_object->id.properties) { - // Temp copy of object did not modify ID properties. - return; - } - // Free memory which is owned by temporary storage which is about to - // get overwritten. - IDP_FreeProperty(temp_dupli_object->id.properties); - MEM_freeN(temp_dupli_object->id.properties); - temp_dupli_object->id.properties = NULL; + if (data->dupli_object_current == NULL) { + // We didn't enter duplication yet, so we can't have any dangling + // pointers. + return; + } + const Object *dupli_object = data->dupli_object_current->ob; + Object *temp_dupli_object = &data->temp_dupli_object; + if (temp_dupli_object->id.properties == NULL) { + // No ID properties in temp datablock -- no leak is possible. + return; + } + if (temp_dupli_object->id.properties == dupli_object->id.properties) { + // Temp copy of object did not modify ID properties. + return; + } + // Free memory which is owned by temporary storage which is about to + // get overwritten. + IDP_FreeProperty(temp_dupli_object->id.properties); + MEM_freeN(temp_dupli_object->id.properties); + temp_dupli_object->id.properties = NULL; } static bool deg_object_hide_original(eEvaluationMode eval_mode, Object *ob, DupliObject *dob) { - /* Automatic hiding if this object is being instanced on verts/faces/frames - * by its parent. Ideally this should not be needed, but due to the wrong - * dependency direction in the data design there is no way to keep the object - * visible otherwise. The better solution eventually would be for objects - * to specify which object they instance, instead of through parenting. */ - if (eval_mode == DAG_EVAL_RENDER || dob) { - const int hide_original_types = OB_DUPLIVERTS | OB_DUPLIFACES; - - if (!dob || !(dob->type & hide_original_types)) { - if (ob->parent && (ob->parent->transflag & hide_original_types)) { - return true; - } - } - } - - return false; + /* Automatic hiding if this object is being instanced on verts/faces/frames + * by its parent. Ideally this should not be needed, but due to the wrong + * dependency direction in the data design there is no way to keep the object + * visible otherwise. The better solution eventually would be for objects + * to specify which object they instance, instead of through parenting. */ + if (eval_mode == DAG_EVAL_RENDER || dob) { + const int hide_original_types = OB_DUPLIVERTS | OB_DUPLIFACES; + + if (!dob || !(dob->type & hide_original_types)) { + if (ob->parent && (ob->parent->transflag & hide_original_types)) { + return true; + } + } + } + + return false; } bool deg_objects_dupli_iterator_next(BLI_Iterator *iter) { - DEGObjectIterData *data = (DEGObjectIterData *)iter->data; - while (data->dupli_object_next != NULL) { - DupliObject *dob = data->dupli_object_next; - Object *obd = dob->ob; - - data->dupli_object_next = data->dupli_object_next->next; - - if (dob->no_draw) { - continue; - } - if (obd->type == OB_MBALL) { - continue; - } - if (deg_object_hide_original(data->eval_mode, dob->ob, dob)) { - continue; - } - - verify_id_properties_freed(data); - - data->dupli_object_current = dob; - - /* Temporary object to evaluate. */ - Object *dupli_parent = data->dupli_parent; - Object *temp_dupli_object = &data->temp_dupli_object; - *temp_dupli_object = *dob->ob; - temp_dupli_object->select_id = dupli_parent->select_id; - temp_dupli_object->base_flag = dupli_parent->base_flag | BASE_FROM_DUPLI; - temp_dupli_object->base_local_view_bits = dupli_parent->base_local_view_bits; - temp_dupli_object->dt = MIN2(temp_dupli_object->dt, dupli_parent->dt); - copy_v4_v4(temp_dupli_object->color, dupli_parent->color); - - /* Duplicated elements shouldn't care whether their original collection is visible or not. */ - temp_dupli_object->base_flag |= BASE_VISIBLE; - - int ob_visibility = BKE_object_visibility(temp_dupli_object, data->eval_mode); - if (ob_visibility == 0) { - continue; - } - - copy_m4_m4(data->temp_dupli_object.obmat, dob->mat); - iter->current = &data->temp_dupli_object; - BLI_assert( - DEG::deg_validate_copy_on_write_datablock( - &data->temp_dupli_object.id)); - return true; - } - - return false; + DEGObjectIterData *data = (DEGObjectIterData *)iter->data; + while (data->dupli_object_next != NULL) { + DupliObject *dob = data->dupli_object_next; + Object *obd = dob->ob; + + data->dupli_object_next = data->dupli_object_next->next; + + if (dob->no_draw) { + continue; + } + if (obd->type == OB_MBALL) { + continue; + } + if (deg_object_hide_original(data->eval_mode, dob->ob, dob)) { + continue; + } + + verify_id_properties_freed(data); + + data->dupli_object_current = dob; + + /* Temporary object to evaluate. */ + Object *dupli_parent = data->dupli_parent; + Object *temp_dupli_object = &data->temp_dupli_object; + *temp_dupli_object = *dob->ob; + temp_dupli_object->select_id = dupli_parent->select_id; + temp_dupli_object->base_flag = dupli_parent->base_flag | BASE_FROM_DUPLI; + temp_dupli_object->base_local_view_bits = dupli_parent->base_local_view_bits; + temp_dupli_object->dt = MIN2(temp_dupli_object->dt, dupli_parent->dt); + copy_v4_v4(temp_dupli_object->color, dupli_parent->color); + + /* Duplicated elements shouldn't care whether their original collection is visible or not. */ + temp_dupli_object->base_flag |= BASE_VISIBLE; + + int ob_visibility = BKE_object_visibility(temp_dupli_object, data->eval_mode); + if (ob_visibility == 0) { + continue; + } + + copy_m4_m4(data->temp_dupli_object.obmat, dob->mat); + iter->current = &data->temp_dupli_object; + BLI_assert(DEG::deg_validate_copy_on_write_datablock(&data->temp_dupli_object.id)); + return true; + } + + return false; } void deg_iterator_objects_step(BLI_Iterator *iter, DEG::IDNode *id_node) { - /* Set it early in case we need to exit and we are running from within a loop. */ - iter->skip = true; - - if (!id_node->is_directly_visible) { - return; - } - - DEGObjectIterData *data = (DEGObjectIterData *)iter->data; - const ID_Type id_type = GS(id_node->id_orig->name); - - if (id_type != ID_OB) { - return; - } - - switch (id_node->linked_state) { - case DEG::DEG_ID_LINKED_DIRECTLY: - if ((data->flag & DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY) == 0) { - return; - } - break; - case DEG::DEG_ID_LINKED_VIA_SET: - if ((data->flag & DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET) == 0) { - return; - } - break; - case DEG::DEG_ID_LINKED_INDIRECTLY: - if ((data->flag & DEG_ITER_OBJECT_FLAG_LINKED_INDIRECTLY) == 0) { - return; - } - break; - } - - Object *object = (Object *)id_node->id_cow; - BLI_assert(DEG::deg_validate_copy_on_write_datablock(&object->id)); - - int ob_visibility = OB_VISIBLE_ALL; - if (data->flag & DEG_ITER_OBJECT_FLAG_VISIBLE) { - ob_visibility = BKE_object_visibility(object, data->eval_mode); - - if (deg_object_hide_original(data->eval_mode, object, NULL)) { - return; - } - } - - if (ob_visibility & OB_VISIBLE_INSTANCES) { - if ((data->flag & DEG_ITER_OBJECT_FLAG_DUPLI) && - (object->transflag & OB_DUPLI)) - { - data->dupli_parent = object; - data->dupli_list = object_duplilist(data->graph, data->scene, object); - data->dupli_object_next = (DupliObject *)data->dupli_list->first; - } - } - - if (ob_visibility & (OB_VISIBLE_SELF | OB_VISIBLE_PARTICLES)) { - iter->current = object; - iter->skip = false; - } + /* Set it early in case we need to exit and we are running from within a loop. */ + iter->skip = true; + + if (!id_node->is_directly_visible) { + return; + } + + DEGObjectIterData *data = (DEGObjectIterData *)iter->data; + const ID_Type id_type = GS(id_node->id_orig->name); + + if (id_type != ID_OB) { + return; + } + + switch (id_node->linked_state) { + case DEG::DEG_ID_LINKED_DIRECTLY: + if ((data->flag & DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY) == 0) { + return; + } + break; + case DEG::DEG_ID_LINKED_VIA_SET: + if ((data->flag & DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET) == 0) { + return; + } + break; + case DEG::DEG_ID_LINKED_INDIRECTLY: + if ((data->flag & DEG_ITER_OBJECT_FLAG_LINKED_INDIRECTLY) == 0) { + return; + } + break; + } + + Object *object = (Object *)id_node->id_cow; + BLI_assert(DEG::deg_validate_copy_on_write_datablock(&object->id)); + + int ob_visibility = OB_VISIBLE_ALL; + if (data->flag & DEG_ITER_OBJECT_FLAG_VISIBLE) { + ob_visibility = BKE_object_visibility(object, data->eval_mode); + + if (deg_object_hide_original(data->eval_mode, object, NULL)) { + return; + } + } + + if (ob_visibility & OB_VISIBLE_INSTANCES) { + if ((data->flag & DEG_ITER_OBJECT_FLAG_DUPLI) && (object->transflag & OB_DUPLI)) { + data->dupli_parent = object; + data->dupli_list = object_duplilist(data->graph, data->scene, object); + data->dupli_object_next = (DupliObject *)data->dupli_list->first; + } + } + + if (ob_visibility & (OB_VISIBLE_SELF | OB_VISIBLE_PARTICLES)) { + iter->current = object; + iter->skip = false; + } } } // namespace void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGObjectIterData *data) { - Depsgraph *depsgraph = data->graph; - DEG::Depsgraph *deg_graph = reinterpret_cast(depsgraph); - const size_t num_id_nodes = deg_graph->id_nodes.size(); - - iter->data = data; - - if (num_id_nodes == 0) { - iter->valid = false; - return; - } - - data->dupli_parent = NULL; - data->dupli_list = NULL; - data->dupli_object_next = NULL; - data->dupli_object_current = NULL; - data->scene = DEG_get_evaluated_scene(depsgraph); - data->id_node_index = 0; - data->num_id_nodes = num_id_nodes; - data->eval_mode = DEG_get_mode(depsgraph); - deg_invalidate_iterator_work_data(data); - - DEG::IDNode *id_node = deg_graph->id_nodes[data->id_node_index]; - deg_iterator_objects_step(iter, id_node); - - if (iter->skip) { - DEG_iterator_objects_next(iter); - } + Depsgraph *depsgraph = data->graph; + DEG::Depsgraph *deg_graph = reinterpret_cast(depsgraph); + const size_t num_id_nodes = deg_graph->id_nodes.size(); + + iter->data = data; + + if (num_id_nodes == 0) { + iter->valid = false; + return; + } + + data->dupli_parent = NULL; + data->dupli_list = NULL; + data->dupli_object_next = NULL; + data->dupli_object_current = NULL; + data->scene = DEG_get_evaluated_scene(depsgraph); + data->id_node_index = 0; + data->num_id_nodes = num_id_nodes; + data->eval_mode = DEG_get_mode(depsgraph); + deg_invalidate_iterator_work_data(data); + + DEG::IDNode *id_node = deg_graph->id_nodes[data->id_node_index]; + deg_iterator_objects_step(iter, id_node); + + if (iter->skip) { + DEG_iterator_objects_next(iter); + } } void DEG_iterator_objects_next(BLI_Iterator *iter) { - DEGObjectIterData *data = (DEGObjectIterData *)iter->data; - Depsgraph *depsgraph = data->graph; - DEG::Depsgraph *deg_graph = reinterpret_cast(depsgraph); - do { - iter->skip = false; - if (data->dupli_list) { - if (deg_objects_dupli_iterator_next(iter)) { - return; - } - else { - verify_id_properties_freed(data); - free_object_duplilist(data->dupli_list); - data->dupli_parent = NULL; - data->dupli_list = NULL; - data->dupli_object_next = NULL; - data->dupli_object_current = NULL; - deg_invalidate_iterator_work_data(data); - } - } - - ++data->id_node_index; - if (data->id_node_index == data->num_id_nodes) { - iter->valid = false; - return; - } - - DEG::IDNode *id_node = deg_graph->id_nodes[data->id_node_index]; - deg_iterator_objects_step(iter, id_node); - } while (iter->skip); + DEGObjectIterData *data = (DEGObjectIterData *)iter->data; + Depsgraph *depsgraph = data->graph; + DEG::Depsgraph *deg_graph = reinterpret_cast(depsgraph); + do { + iter->skip = false; + if (data->dupli_list) { + if (deg_objects_dupli_iterator_next(iter)) { + return; + } + else { + verify_id_properties_freed(data); + free_object_duplilist(data->dupli_list); + data->dupli_parent = NULL; + data->dupli_list = NULL; + data->dupli_object_next = NULL; + data->dupli_object_current = NULL; + deg_invalidate_iterator_work_data(data); + } + } + + ++data->id_node_index; + if (data->id_node_index == data->num_id_nodes) { + iter->valid = false; + return; + } + + DEG::IDNode *id_node = deg_graph->id_nodes[data->id_node_index]; + deg_iterator_objects_step(iter, id_node); + } while (iter->skip); } void DEG_iterator_objects_end(BLI_Iterator *iter) { - DEGObjectIterData *data = (DEGObjectIterData *)iter->data; - if (data != NULL) { - /* Force crash in case the iterator data is referenced and accessed down - * the line. (T51718) */ - deg_invalidate_iterator_work_data(data); - } + DEGObjectIterData *data = (DEGObjectIterData *)iter->data; + if (data != NULL) { + /* Force crash in case the iterator data is referenced and accessed down + * the line. (T51718) */ + deg_invalidate_iterator_work_data(data); + } } /* ************************ DEG ID ITERATOR ********************* */ static void DEG_iterator_ids_step(BLI_Iterator *iter, DEG::IDNode *id_node, bool only_updated) { - ID *id_cow = id_node->id_cow; - - if (!id_node->is_directly_visible) { - iter->skip = true; - return; - } - else if (only_updated && !(id_cow->recalc & ID_RECALC_ALL)) { - bNodeTree *ntree = ntreeFromID(id_cow); - - /* Nodetree is considered part of the datablock. */ - if (!(ntree && (ntree->id.recalc & ID_RECALC_ALL))) { - iter->skip = true; - return; - } - } - - iter->current = id_cow; - iter->skip = false; + ID *id_cow = id_node->id_cow; + + if (!id_node->is_directly_visible) { + iter->skip = true; + return; + } + else if (only_updated && !(id_cow->recalc & ID_RECALC_ALL)) { + bNodeTree *ntree = ntreeFromID(id_cow); + + /* Nodetree is considered part of the datablock. */ + if (!(ntree && (ntree->id.recalc & ID_RECALC_ALL))) { + iter->skip = true; + return; + } + } + + iter->current = id_cow; + iter->skip = false; } void DEG_iterator_ids_begin(BLI_Iterator *iter, DEGIDIterData *data) { - Depsgraph *depsgraph = data->graph; - DEG::Depsgraph *deg_graph = reinterpret_cast(depsgraph); - const size_t num_id_nodes = deg_graph->id_nodes.size(); + Depsgraph *depsgraph = data->graph; + DEG::Depsgraph *deg_graph = reinterpret_cast(depsgraph); + const size_t num_id_nodes = deg_graph->id_nodes.size(); - iter->data = data; + iter->data = data; - if ((num_id_nodes == 0) || - (data->only_updated && !DEG_id_type_any_updated(depsgraph))) - { - iter->valid = false; - return; - } + if ((num_id_nodes == 0) || (data->only_updated && !DEG_id_type_any_updated(depsgraph))) { + iter->valid = false; + return; + } - data->id_node_index = 0; - data->num_id_nodes = num_id_nodes; + data->id_node_index = 0; + data->num_id_nodes = num_id_nodes; - DEG::IDNode *id_node = deg_graph->id_nodes[data->id_node_index]; - DEG_iterator_ids_step(iter, id_node, data->only_updated); + DEG::IDNode *id_node = deg_graph->id_nodes[data->id_node_index]; + DEG_iterator_ids_step(iter, id_node, data->only_updated); - if (iter->skip) { - DEG_iterator_ids_next(iter); - } + if (iter->skip) { + DEG_iterator_ids_next(iter); + } } void DEG_iterator_ids_next(BLI_Iterator *iter) { - DEGIDIterData *data = (DEGIDIterData *)iter->data; - Depsgraph *depsgraph = data->graph; - DEG::Depsgraph *deg_graph = reinterpret_cast(depsgraph); - - do { - iter->skip = false; - - ++data->id_node_index; - if (data->id_node_index == data->num_id_nodes) { - iter->valid = false; - return; - } - - DEG::IDNode *id_node = deg_graph->id_nodes[data->id_node_index]; - DEG_iterator_ids_step(iter, id_node, data->only_updated); - } while (iter->skip); + DEGIDIterData *data = (DEGIDIterData *)iter->data; + Depsgraph *depsgraph = data->graph; + DEG::Depsgraph *deg_graph = reinterpret_cast(depsgraph); + + do { + iter->skip = false; + + ++data->id_node_index; + if (data->id_node_index == data->num_id_nodes) { + iter->valid = false; + return; + } + + DEG::IDNode *id_node = deg_graph->id_nodes[data->id_node_index]; + DEG_iterator_ids_step(iter, id_node, data->only_updated); + } while (iter->skip); } void DEG_iterator_ids_end(BLI_Iterator *UNUSED(iter)) diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index daa599b6972..f682dadee8e 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -26,7 +26,7 @@ #include "intern/depsgraph_tag.h" #include -#include /* required for memset */ +#include /* required for memset */ #include #include "BLI_utildefines.h" @@ -79,78 +79,75 @@ namespace DEG { namespace { -void depsgraph_geometry_tag_to_component(const ID *id, - NodeType *component_type) +void depsgraph_geometry_tag_to_component(const ID *id, NodeType *component_type) { - const NodeType result = geometry_tag_to_component(id); - if (result != NodeType::UNDEFINED) { - *component_type = result; - } + const NodeType result = geometry_tag_to_component(id); + if (result != NodeType::UNDEFINED) { + *component_type = result; + } } bool is_selectable_data_id_type(const ID_Type id_type) { - return ELEM(id_type, ID_ME, ID_CU, ID_MB, ID_LT, ID_GD); + return ELEM(id_type, ID_ME, ID_CU, ID_MB, ID_LT, ID_GD); } -void depsgraph_select_tag_to_component_opcode( - const ID *id, - NodeType *component_type, - OperationCode *operation_code) +void depsgraph_select_tag_to_component_opcode(const ID *id, + NodeType *component_type, + OperationCode *operation_code) { - const ID_Type id_type = GS(id->name); - if (id_type == ID_SCE) { - /* We need to flush base flags to all objects in a scene since we - * don't know which ones changed. However, we don't want to update - * the whole scene, so pick up some operation which will do as less - * as possible. - * - * TODO(sergey): We can introduce explicit exit operation which - * does nothing and which is only used to cascade flush down the - * road. */ - *component_type = NodeType::LAYER_COLLECTIONS; - *operation_code = OperationCode::VIEW_LAYER_EVAL; - } - else if (id_type == ID_OB) { - *component_type = NodeType::OBJECT_FROM_LAYER; - *operation_code = OperationCode::OBJECT_BASE_FLAGS; - } - else if (id_type == ID_MC) { - *component_type = NodeType::BATCH_CACHE; - *operation_code = OperationCode::MOVIECLIP_SELECT_UPDATE; - } - else if (is_selectable_data_id_type(id_type)) { - *component_type = NodeType::BATCH_CACHE; - *operation_code = OperationCode::GEOMETRY_SELECT_UPDATE; - } - else { - *component_type = NodeType::COPY_ON_WRITE; - *operation_code = OperationCode::COPY_ON_WRITE; - } + const ID_Type id_type = GS(id->name); + if (id_type == ID_SCE) { + /* We need to flush base flags to all objects in a scene since we + * don't know which ones changed. However, we don't want to update + * the whole scene, so pick up some operation which will do as less + * as possible. + * + * TODO(sergey): We can introduce explicit exit operation which + * does nothing and which is only used to cascade flush down the + * road. */ + *component_type = NodeType::LAYER_COLLECTIONS; + *operation_code = OperationCode::VIEW_LAYER_EVAL; + } + else if (id_type == ID_OB) { + *component_type = NodeType::OBJECT_FROM_LAYER; + *operation_code = OperationCode::OBJECT_BASE_FLAGS; + } + else if (id_type == ID_MC) { + *component_type = NodeType::BATCH_CACHE; + *operation_code = OperationCode::MOVIECLIP_SELECT_UPDATE; + } + else if (is_selectable_data_id_type(id_type)) { + *component_type = NodeType::BATCH_CACHE; + *operation_code = OperationCode::GEOMETRY_SELECT_UPDATE; + } + else { + *component_type = NodeType::COPY_ON_WRITE; + *operation_code = OperationCode::COPY_ON_WRITE; + } } -void depsgraph_base_flags_tag_to_component_opcode( - const ID *id, - NodeType *component_type, - OperationCode *operation_code) +void depsgraph_base_flags_tag_to_component_opcode(const ID *id, + NodeType *component_type, + OperationCode *operation_code) { - const ID_Type id_type = GS(id->name); - if (id_type == ID_SCE) { - *component_type = NodeType::LAYER_COLLECTIONS; - *operation_code = OperationCode::VIEW_LAYER_EVAL; - } - else if (id_type == ID_OB) { - *component_type = NodeType::OBJECT_FROM_LAYER; - *operation_code = OperationCode::OBJECT_BASE_FLAGS; - } + const ID_Type id_type = GS(id->name); + if (id_type == ID_SCE) { + *component_type = NodeType::LAYER_COLLECTIONS; + *operation_code = OperationCode::VIEW_LAYER_EVAL; + } + else if (id_type == ID_OB) { + *component_type = NodeType::OBJECT_FROM_LAYER; + *operation_code = OperationCode::OBJECT_BASE_FLAGS; + } } OperationCode psysTagToOperationCode(IDRecalcFlag tag) { - if (tag == ID_RECALC_PSYS_RESET) { - return OperationCode::PARTICLE_SETTINGS_RESET; - } - return OperationCode::OPERATION; + if (tag == ID_RECALC_PSYS_RESET) { + return OperationCode::PARTICLE_SETTINGS_RESET; + } + return OperationCode::OPERATION; } void depsgraph_tag_to_component_opcode(const ID *id, @@ -158,101 +155,94 @@ void depsgraph_tag_to_component_opcode(const ID *id, NodeType *component_type, OperationCode *operation_code) { - const ID_Type id_type = GS(id->name); - *component_type = NodeType::UNDEFINED; - *operation_code = OperationCode::OPERATION; - /* Special case for now, in the future we should get rid of this. */ - if (tag == 0) { - *component_type = NodeType::ID_REF; - *operation_code = OperationCode::OPERATION; - return; - } - switch (tag) { - case ID_RECALC_TRANSFORM: - *component_type = NodeType::TRANSFORM; - break; - case ID_RECALC_GEOMETRY: - depsgraph_geometry_tag_to_component(id, component_type); - break; - case ID_RECALC_ANIMATION: - *component_type = NodeType::ANIMATION; - break; - case ID_RECALC_PSYS_REDO: - case ID_RECALC_PSYS_RESET: - case ID_RECALC_PSYS_CHILD: - case ID_RECALC_PSYS_PHYS: - if (id_type == ID_PA) { - /* NOTES: - * - For particle settings node we need to use different - * component. Will be nice to get this unified with object, - * but we can survive for now with single exception here. - * Particles needs reconsideration anyway, */ - *component_type = NodeType::PARTICLE_SETTINGS; - *operation_code = psysTagToOperationCode(tag); - } - else { - *component_type = NodeType::PARTICLE_SYSTEM; - } - break; - case ID_RECALC_COPY_ON_WRITE: - *component_type = NodeType::COPY_ON_WRITE; - break; - case ID_RECALC_SHADING: - if (id_type == ID_NT) { - *component_type = NodeType::SHADING_PARAMETERS; - } - else { - *component_type = NodeType::SHADING; - } - break; - case ID_RECALC_SELECT: - depsgraph_select_tag_to_component_opcode(id, - component_type, - operation_code); - break; - case ID_RECALC_BASE_FLAGS: - depsgraph_base_flags_tag_to_component_opcode(id, - component_type, - operation_code); - break; - case ID_RECALC_POINT_CACHE: - *component_type = NodeType::POINT_CACHE; - break; - case ID_RECALC_EDITORS: - /* There is no such node in depsgraph, this tag is to be handled - * separately. */ - break; - case ID_RECALC_ALL: - case ID_RECALC_PSYS_ALL: - BLI_assert(!"Should not happen"); - break; - } + const ID_Type id_type = GS(id->name); + *component_type = NodeType::UNDEFINED; + *operation_code = OperationCode::OPERATION; + /* Special case for now, in the future we should get rid of this. */ + if (tag == 0) { + *component_type = NodeType::ID_REF; + *operation_code = OperationCode::OPERATION; + return; + } + switch (tag) { + case ID_RECALC_TRANSFORM: + *component_type = NodeType::TRANSFORM; + break; + case ID_RECALC_GEOMETRY: + depsgraph_geometry_tag_to_component(id, component_type); + break; + case ID_RECALC_ANIMATION: + *component_type = NodeType::ANIMATION; + break; + case ID_RECALC_PSYS_REDO: + case ID_RECALC_PSYS_RESET: + case ID_RECALC_PSYS_CHILD: + case ID_RECALC_PSYS_PHYS: + if (id_type == ID_PA) { + /* NOTES: + * - For particle settings node we need to use different + * component. Will be nice to get this unified with object, + * but we can survive for now with single exception here. + * Particles needs reconsideration anyway, */ + *component_type = NodeType::PARTICLE_SETTINGS; + *operation_code = psysTagToOperationCode(tag); + } + else { + *component_type = NodeType::PARTICLE_SYSTEM; + } + break; + case ID_RECALC_COPY_ON_WRITE: + *component_type = NodeType::COPY_ON_WRITE; + break; + case ID_RECALC_SHADING: + if (id_type == ID_NT) { + *component_type = NodeType::SHADING_PARAMETERS; + } + else { + *component_type = NodeType::SHADING; + } + break; + case ID_RECALC_SELECT: + depsgraph_select_tag_to_component_opcode(id, component_type, operation_code); + break; + case ID_RECALC_BASE_FLAGS: + depsgraph_base_flags_tag_to_component_opcode(id, component_type, operation_code); + break; + case ID_RECALC_POINT_CACHE: + *component_type = NodeType::POINT_CACHE; + break; + case ID_RECALC_EDITORS: + /* There is no such node in depsgraph, this tag is to be handled + * separately. */ + break; + case ID_RECALC_ALL: + case ID_RECALC_PSYS_ALL: + BLI_assert(!"Should not happen"); + break; + } } -void id_tag_update_ntree_special(Main *bmain, - Depsgraph *graph, - ID *id, - int flag, - eUpdateSource update_source) +void id_tag_update_ntree_special( + Main *bmain, Depsgraph *graph, ID *id, int flag, eUpdateSource update_source) { - bNodeTree *ntree = ntreeFromID(id); - if (ntree == NULL) { - return; - } - graph_id_tag_update(bmain, graph, &ntree->id, flag, update_source); + bNodeTree *ntree = ntreeFromID(id); + if (ntree == NULL) { + return; + } + graph_id_tag_update(bmain, graph, &ntree->id, flag, update_source); } void depsgraph_update_editors_tag(Main *bmain, Depsgraph *graph, ID *id) { - /* NOTE: We handle this immediately, without delaying anything, to be - * sure we don't cause threading issues with OpenGL. */ - /* TODO(sergey): Make sure this works for CoW-ed datablocks as well. */ - DEGEditorUpdateContext update_ctx = {NULL}; - update_ctx.bmain = bmain; - update_ctx.depsgraph = (::Depsgraph *)graph; - update_ctx.scene = graph->scene; - update_ctx.view_layer = graph->view_layer; - deg_editors_id_update(&update_ctx, id); + /* NOTE: We handle this immediately, without delaying anything, to be + * sure we don't cause threading issues with OpenGL. */ + /* TODO(sergey): Make sure this works for CoW-ed datablocks as well. */ + DEGEditorUpdateContext update_ctx = {NULL}; + update_ctx.bmain = bmain; + update_ctx.depsgraph = (::Depsgraph *)graph; + update_ctx.scene = graph->scene; + update_ctx.view_layer = graph->view_layer; + deg_editors_id_update(&update_ctx, id); } void depsgraph_tag_component(Depsgraph *graph, @@ -261,28 +251,25 @@ void depsgraph_tag_component(Depsgraph *graph, OperationCode operation_code, eUpdateSource update_source) { - ComponentNode *component_node = - id_node->find_component(component_type); - if (component_node == NULL) { - return; - } - if (operation_code == OperationCode::OPERATION) { - component_node->tag_update(graph, update_source); - } - else { - OperationNode *operation_node = - component_node->find_operation(operation_code); - if (operation_node != NULL) { - operation_node->tag_update(graph, update_source); - } - } - /* If component depends on copy-on-write, tag it as well. */ - if (component_node->need_tag_cow_before_update()) { - ComponentNode *cow_comp = - id_node->find_component(NodeType::COPY_ON_WRITE); - cow_comp->tag_update(graph, update_source); - id_node->id_orig->recalc |= ID_RECALC_COPY_ON_WRITE; - } + ComponentNode *component_node = id_node->find_component(component_type); + if (component_node == NULL) { + return; + } + if (operation_code == OperationCode::OPERATION) { + component_node->tag_update(graph, update_source); + } + else { + OperationNode *operation_node = component_node->find_operation(operation_code); + if (operation_node != NULL) { + operation_node->tag_update(graph, update_source); + } + } + /* If component depends on copy-on-write, tag it as well. */ + if (component_node->need_tag_cow_before_update()) { + ComponentNode *cow_comp = id_node->find_component(NodeType::COPY_ON_WRITE); + cow_comp->tag_update(graph, update_source); + id_node->id_orig->recalc |= ID_RECALC_COPY_ON_WRITE; + } } /* This is a tag compatibility with legacy code. @@ -290,61 +277,50 @@ void depsgraph_tag_component(Depsgraph *graph, * Mainly, old code was tagging object with ID_RECALC_GEOMETRY tag to inform * that object's data datablock changed. Now API expects that ID is given * explicitly, but not all areas are aware of this yet. */ -void deg_graph_id_tag_legacy_compat(Main *bmain, - Depsgraph *depsgraph, - ID *id, - IDRecalcFlag tag, - eUpdateSource update_source) +void deg_graph_id_tag_legacy_compat( + Main *bmain, Depsgraph *depsgraph, ID *id, IDRecalcFlag tag, eUpdateSource update_source) { - if (tag == ID_RECALC_GEOMETRY || tag == 0) { - switch (GS(id->name)) { - case ID_OB: - { - Object *object = (Object *)id; - ID *data_id = (ID *)object->data; - if (data_id != NULL) { - graph_id_tag_update( - bmain, depsgraph, data_id, 0, update_source); - } - break; - } - /* TODO(sergey): Shape keys are annoying, maybe we should find a - * way to chain geometry evaluation to them, so we don't need extra - * tagging here. */ - case ID_ME: - { - Mesh *mesh = (Mesh *)id; - ID *key_id = &mesh->key->id; - if (key_id != NULL) { - graph_id_tag_update( - bmain, depsgraph, key_id, 0, update_source); - } - break; - } - case ID_LT: - { - Lattice *lattice = (Lattice *)id; - ID *key_id = &lattice->key->id; - if (key_id != NULL) { - graph_id_tag_update( - bmain, depsgraph, key_id, 0, update_source); - } - break; - } - case ID_CU: - { - Curve *curve = (Curve *)id; - ID *key_id = &curve->key->id; - if (key_id != NULL) { - graph_id_tag_update( - bmain, depsgraph, key_id, 0, update_source); - } - break; - } - default: - break; - } - } + if (tag == ID_RECALC_GEOMETRY || tag == 0) { + switch (GS(id->name)) { + case ID_OB: { + Object *object = (Object *)id; + ID *data_id = (ID *)object->data; + if (data_id != NULL) { + graph_id_tag_update(bmain, depsgraph, data_id, 0, update_source); + } + break; + } + /* TODO(sergey): Shape keys are annoying, maybe we should find a + * way to chain geometry evaluation to them, so we don't need extra + * tagging here. */ + case ID_ME: { + Mesh *mesh = (Mesh *)id; + ID *key_id = &mesh->key->id; + if (key_id != NULL) { + graph_id_tag_update(bmain, depsgraph, key_id, 0, update_source); + } + break; + } + case ID_LT: { + Lattice *lattice = (Lattice *)id; + ID *key_id = &lattice->key->id; + if (key_id != NULL) { + graph_id_tag_update(bmain, depsgraph, key_id, 0, update_source); + } + break; + } + case ID_CU: { + Curve *curve = (Curve *)id; + ID *key_id = &curve->key->id; + if (key_id != NULL) { + graph_id_tag_update(bmain, depsgraph, key_id, 0, update_source); + } + break; + } + default: + break; + } + } } static void graph_id_tag_update_single_flag(Main *bmain, @@ -354,90 +330,88 @@ static void graph_id_tag_update_single_flag(Main *bmain, IDRecalcFlag tag, eUpdateSource update_source) { - if (tag == ID_RECALC_EDITORS) { - if (graph != NULL) { - depsgraph_update_editors_tag(bmain, graph, id); - } - return; - } - /* Get description of what is to be tagged. */ - NodeType component_type; - OperationCode operation_code; - depsgraph_tag_to_component_opcode(id, - tag, - &component_type, - &operation_code); - /* Check whether we've got something to tag. */ - if (component_type == NodeType::UNDEFINED) { - /* Given ID does not support tag. */ - /* TODO(sergey): Shall we raise some panic here? */ - return; - } - /* Tag ID recalc flag. */ - DepsNodeFactory *factory = type_get_factory(component_type); - BLI_assert(factory != NULL); - id->recalc |= factory->id_recalc_tag(); - /* Some sanity checks before moving forward. */ - if (id_node == NULL) { - /* Happens when object is tagged for update and not yet in the - * dependency graph (but will be after relations update). */ - return; - } - /* Tag corresponding dependency graph operation for update. */ - if (component_type == NodeType::ID_REF) { - id_node->tag_update(graph, update_source); - } - else { - depsgraph_tag_component( - graph, id_node, component_type, operation_code, update_source); - } - /* TODO(sergey): Get rid of this once all areas are using proper data ID - * for tagging. */ - deg_graph_id_tag_legacy_compat(bmain, graph, id, tag, update_source); - + if (tag == ID_RECALC_EDITORS) { + if (graph != NULL) { + depsgraph_update_editors_tag(bmain, graph, id); + } + return; + } + /* Get description of what is to be tagged. */ + NodeType component_type; + OperationCode operation_code; + depsgraph_tag_to_component_opcode(id, tag, &component_type, &operation_code); + /* Check whether we've got something to tag. */ + if (component_type == NodeType::UNDEFINED) { + /* Given ID does not support tag. */ + /* TODO(sergey): Shall we raise some panic here? */ + return; + } + /* Tag ID recalc flag. */ + DepsNodeFactory *factory = type_get_factory(component_type); + BLI_assert(factory != NULL); + id->recalc |= factory->id_recalc_tag(); + /* Some sanity checks before moving forward. */ + if (id_node == NULL) { + /* Happens when object is tagged for update and not yet in the + * dependency graph (but will be after relations update). */ + return; + } + /* Tag corresponding dependency graph operation for update. */ + if (component_type == NodeType::ID_REF) { + id_node->tag_update(graph, update_source); + } + else { + depsgraph_tag_component(graph, id_node, component_type, operation_code, update_source); + } + /* TODO(sergey): Get rid of this once all areas are using proper data ID + * for tagging. */ + deg_graph_id_tag_legacy_compat(bmain, graph, id, tag, update_source); } -string stringify_append_bit(const string& str, IDRecalcFlag tag) +string stringify_append_bit(const string &str, IDRecalcFlag tag) { - string result = str; - if (!result.empty()) { - result += ", "; - } - result += DEG_update_tag_as_string(tag); - return result; + string result = str; + if (!result.empty()) { + result += ", "; + } + result += DEG_update_tag_as_string(tag); + return result; } string stringify_update_bitfield(int flag) { - if (flag == 0) { - return "LEGACY_0"; - } - string result = ""; - int current_flag = flag; - /* Special cases to avoid ALL flags form being split into - * individual bits. */ - if ((current_flag & ID_RECALC_PSYS_ALL) == ID_RECALC_PSYS_ALL) { - result = stringify_append_bit(result, ID_RECALC_PSYS_ALL); - } - /* Handle all the rest of the flags. */ - while (current_flag != 0) { - IDRecalcFlag tag = - (IDRecalcFlag)(1 << bitscan_forward_clear_i(¤t_flag)); - result = stringify_append_bit(result, tag); - } - return result; + if (flag == 0) { + return "LEGACY_0"; + } + string result = ""; + int current_flag = flag; + /* Special cases to avoid ALL flags form being split into + * individual bits. */ + if ((current_flag & ID_RECALC_PSYS_ALL) == ID_RECALC_PSYS_ALL) { + result = stringify_append_bit(result, ID_RECALC_PSYS_ALL); + } + /* Handle all the rest of the flags. */ + while (current_flag != 0) { + IDRecalcFlag tag = (IDRecalcFlag)(1 << bitscan_forward_clear_i(¤t_flag)); + result = stringify_append_bit(result, tag); + } + return result; } const char *update_source_as_string(eUpdateSource source) { - switch (source) { - case DEG_UPDATE_SOURCE_TIME: return "TIME"; - case DEG_UPDATE_SOURCE_USER_EDIT: return "USER_EDIT"; - case DEG_UPDATE_SOURCE_RELATIONS: return "RELATIONS"; - case DEG_UPDATE_SOURCE_VISIBILITY: return "VISIBILITY"; - } - BLI_assert(!"Should never happen."); - return "UNKNOWN"; + switch (source) { + case DEG_UPDATE_SOURCE_TIME: + return "TIME"; + case DEG_UPDATE_SOURCE_USER_EDIT: + return "USER_EDIT"; + case DEG_UPDATE_SOURCE_RELATIONS: + return "RELATIONS"; + case DEG_UPDATE_SOURCE_VISIBILITY: + return "VISIBILITY"; + } + BLI_assert(!"Should never happen."); + return "UNKNOWN"; } /* Special tag function which tags all components which needs to be tagged @@ -450,212 +424,202 @@ void deg_graph_node_tag_zero(Main *bmain, IDNode *id_node, eUpdateSource update_source) { - if (id_node == NULL) { - return; - } - ID *id = id_node->id_orig; - /* TODO(sergey): Which recalc flags to set here? */ - id->recalc |= ID_RECALC_ALL & ~(ID_RECALC_PSYS_ALL | ID_RECALC_ANIMATION); - GHASH_FOREACH_BEGIN(ComponentNode *, comp_node, id_node->components) - { - if (comp_node->type == NodeType::ANIMATION) { - continue; - } - comp_node->tag_update(graph, update_source); - } - GHASH_FOREACH_END(); - deg_graph_id_tag_legacy_compat( - bmain, graph, id, (IDRecalcFlag)0, update_source); + if (id_node == NULL) { + return; + } + ID *id = id_node->id_orig; + /* TODO(sergey): Which recalc flags to set here? */ + id->recalc |= ID_RECALC_ALL & ~(ID_RECALC_PSYS_ALL | ID_RECALC_ANIMATION); + GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) { + if (comp_node->type == NodeType::ANIMATION) { + continue; + } + comp_node->tag_update(graph, update_source); + } + GHASH_FOREACH_END(); + deg_graph_id_tag_legacy_compat(bmain, graph, id, (IDRecalcFlag)0, update_source); } void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph) { - for (DEG::IDNode *id_node : graph->id_nodes) { - if (!id_node->visible_components_mask) { - /* ID has no components which affects anything visible. - * No need bother with it to tag or anything. */ - continue; - } - if (id_node->visible_components_mask == - id_node->previously_visible_components_mask) - { - /* The ID was already visible and evaluated, all the subsequent - * updates and tags are to be done explicitly. */ - continue; - } - int flag = 0; - if (!DEG::deg_copy_on_write_is_expanded(id_node->id_cow)) { - flag |= ID_RECALC_COPY_ON_WRITE; - /* TODO(sergey): Shouldn't be needed, but currently we are lackign - * some flushing of evaluated data to the original one, which makes, - * for example, files saved with the rest pose. - * Need to solve those issues carefully, for until then we evaluate - * animation for datablocks which appears in the graph for the first - * time. */ - flag |= ID_RECALC_ANIMATION; - } - /* We only tag components which needs an update. Tagging everything is - * not a good idea because that might reset particles cache (or any - * other type of cache). - * - * TODO(sergey): Need to generalize this somehow. */ - const ID_Type id_type = GS(id_node->id_orig->name); - if (id_type == ID_OB) { - flag |= ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY; - } - graph_id_tag_update(bmain, - graph, - id_node->id_orig, - flag, - DEG_UPDATE_SOURCE_VISIBILITY); - if (id_type == ID_SCE) { - /* Make sure collection properties are up to date. */ - id_node->tag_update(graph, DEG_UPDATE_SOURCE_VISIBILITY); - } - /* Now when ID is updated to the new visibility state, prevent it from - * being re-tagged again. Simplest way to do so is to pretend that it - * was already updated by the "previous" dependency graph. - * - * NOTE: Even if the on_visible_update() is called from the state when - * dependency graph is tagged for relations update, it will be fine: - * since dependency graph builder re-schedules entry tags, all the - * tags we request from here will be applied in the updated state of - * dependency graph. */ - id_node->previously_visible_components_mask = - id_node->visible_components_mask; - } + for (DEG::IDNode *id_node : graph->id_nodes) { + if (!id_node->visible_components_mask) { + /* ID has no components which affects anything visible. + * No need bother with it to tag or anything. */ + continue; + } + if (id_node->visible_components_mask == id_node->previously_visible_components_mask) { + /* The ID was already visible and evaluated, all the subsequent + * updates and tags are to be done explicitly. */ + continue; + } + int flag = 0; + if (!DEG::deg_copy_on_write_is_expanded(id_node->id_cow)) { + flag |= ID_RECALC_COPY_ON_WRITE; + /* TODO(sergey): Shouldn't be needed, but currently we are lackign + * some flushing of evaluated data to the original one, which makes, + * for example, files saved with the rest pose. + * Need to solve those issues carefully, for until then we evaluate + * animation for datablocks which appears in the graph for the first + * time. */ + flag |= ID_RECALC_ANIMATION; + } + /* We only tag components which needs an update. Tagging everything is + * not a good idea because that might reset particles cache (or any + * other type of cache). + * + * TODO(sergey): Need to generalize this somehow. */ + const ID_Type id_type = GS(id_node->id_orig->name); + if (id_type == ID_OB) { + flag |= ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY; + } + graph_id_tag_update(bmain, graph, id_node->id_orig, flag, DEG_UPDATE_SOURCE_VISIBILITY); + if (id_type == ID_SCE) { + /* Make sure collection properties are up to date. */ + id_node->tag_update(graph, DEG_UPDATE_SOURCE_VISIBILITY); + } + /* Now when ID is updated to the new visibility state, prevent it from + * being re-tagged again. Simplest way to do so is to pretend that it + * was already updated by the "previous" dependency graph. + * + * NOTE: Even if the on_visible_update() is called from the state when + * dependency graph is tagged for relations update, it will be fine: + * since dependency graph builder re-schedules entry tags, all the + * tags we request from here will be applied in the updated state of + * dependency graph. */ + id_node->previously_visible_components_mask = id_node->visible_components_mask; + } } -} /* namespace */ +} /* namespace */ NodeType geometry_tag_to_component(const ID *id) { - const ID_Type id_type = GS(id->name); - switch (id_type) { - case ID_OB: - { - const Object *object = (Object *)id; - switch (object->type) { - case OB_MESH: - case OB_CURVE: - case OB_SURF: - case OB_FONT: - case OB_LATTICE: - case OB_MBALL: - case OB_GPENCIL: - return NodeType::GEOMETRY; - case OB_ARMATURE: - return NodeType::EVAL_POSE; - /* TODO(sergey): More cases here? */ - } - break; - } - case ID_ME: - case ID_CU: - case ID_LT: - case ID_MB: - return NodeType::GEOMETRY; - case ID_PA: /* Particles */ - return NodeType::UNDEFINED; - case ID_LP: - return NodeType::PARAMETERS; - case ID_GD: - return NodeType::GEOMETRY; - case ID_PAL: /* Palettes */ - return NodeType::PARAMETERS; - default: - break; - } - return NodeType::UNDEFINED; + const ID_Type id_type = GS(id->name); + switch (id_type) { + case ID_OB: { + const Object *object = (Object *)id; + switch (object->type) { + case OB_MESH: + case OB_CURVE: + case OB_SURF: + case OB_FONT: + case OB_LATTICE: + case OB_MBALL: + case OB_GPENCIL: + return NodeType::GEOMETRY; + case OB_ARMATURE: + return NodeType::EVAL_POSE; + /* TODO(sergey): More cases here? */ + } + break; + } + case ID_ME: + case ID_CU: + case ID_LT: + case ID_MB: + return NodeType::GEOMETRY; + case ID_PA: /* Particles */ + return NodeType::UNDEFINED; + case ID_LP: + return NodeType::PARAMETERS; + case ID_GD: + return NodeType::GEOMETRY; + case ID_PAL: /* Palettes */ + return NodeType::PARAMETERS; + default: + break; + } + return NodeType::UNDEFINED; } void id_tag_update(Main *bmain, ID *id, int flag, eUpdateSource update_source) { - graph_id_tag_update(bmain, NULL, id, flag, update_source); - LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { - LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { - Depsgraph *depsgraph = - (Depsgraph *)BKE_scene_get_depsgraph(scene, - view_layer, - false); - if (depsgraph != NULL) { - graph_id_tag_update( - bmain, depsgraph, id, flag, update_source); - } - } - } + graph_id_tag_update(bmain, NULL, id, flag, update_source); + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { + Depsgraph *depsgraph = (Depsgraph *)BKE_scene_get_depsgraph(scene, view_layer, false); + if (depsgraph != NULL) { + graph_id_tag_update(bmain, depsgraph, id, flag, update_source); + } + } + } } -void graph_id_tag_update(Main *bmain, - Depsgraph *graph, - ID *id, - int flag, - eUpdateSource update_source) +void graph_id_tag_update( + Main *bmain, Depsgraph *graph, ID *id, int flag, eUpdateSource update_source) { - const int debug_flags = (graph != NULL) - ? DEG_debug_flags_get((::Depsgraph *)graph) - : G.debug; - if (debug_flags & G_DEBUG_DEPSGRAPH_TAG) { - printf("%s: id=%s flags=%s source=%s\n", - __func__, - id->name, - stringify_update_bitfield(flag).c_str(), - update_source_as_string(update_source)); - } - IDNode *id_node = (graph != NULL) ? graph->find_id_node(id) - : NULL; - if (graph != NULL) { - DEG_graph_id_type_tag(reinterpret_cast<::Depsgraph*>(graph), - GS(id->name)); - } - if (flag == 0) { - deg_graph_node_tag_zero(bmain, graph, id_node, update_source); - } - id->recalc |= flag; - int current_flag = flag; - while (current_flag != 0) { - IDRecalcFlag tag = - (IDRecalcFlag)(1 << bitscan_forward_clear_i(¤t_flag)); - graph_id_tag_update_single_flag( - bmain, graph, id, id_node, tag, update_source); - } - /* Special case for nested node tree datablocks. */ - id_tag_update_ntree_special(bmain, graph, id, flag, update_source); - /* Direct update tags means that something outside of simulated/cached - * physics did change and that cache is to be invalidated. - * This is only needed if data changes. If it's just a drawing, we keep the - * point cache. */ - if (update_source == DEG_UPDATE_SOURCE_USER_EDIT && - flag != ID_RECALC_SHADING) - { - graph_id_tag_update_single_flag( - bmain, graph, id, id_node, ID_RECALC_POINT_CACHE, update_source); - } + const int debug_flags = (graph != NULL) ? DEG_debug_flags_get((::Depsgraph *)graph) : G.debug; + if (debug_flags & G_DEBUG_DEPSGRAPH_TAG) { + printf("%s: id=%s flags=%s source=%s\n", + __func__, + id->name, + stringify_update_bitfield(flag).c_str(), + update_source_as_string(update_source)); + } + IDNode *id_node = (graph != NULL) ? graph->find_id_node(id) : NULL; + if (graph != NULL) { + DEG_graph_id_type_tag(reinterpret_cast<::Depsgraph *>(graph), GS(id->name)); + } + if (flag == 0) { + deg_graph_node_tag_zero(bmain, graph, id_node, update_source); + } + id->recalc |= flag; + int current_flag = flag; + while (current_flag != 0) { + IDRecalcFlag tag = (IDRecalcFlag)(1 << bitscan_forward_clear_i(¤t_flag)); + graph_id_tag_update_single_flag(bmain, graph, id, id_node, tag, update_source); + } + /* Special case for nested node tree datablocks. */ + id_tag_update_ntree_special(bmain, graph, id, flag, update_source); + /* Direct update tags means that something outside of simulated/cached + * physics did change and that cache is to be invalidated. + * This is only needed if data changes. If it's just a drawing, we keep the + * point cache. */ + if (update_source == DEG_UPDATE_SOURCE_USER_EDIT && flag != ID_RECALC_SHADING) { + graph_id_tag_update_single_flag( + bmain, graph, id, id_node, ID_RECALC_POINT_CACHE, update_source); + } } } // namespace DEG const char *DEG_update_tag_as_string(IDRecalcFlag flag) { - switch (flag) { - case ID_RECALC_TRANSFORM: return "TRANSFORM"; - case ID_RECALC_GEOMETRY: return "GEOMETRY"; - case ID_RECALC_ANIMATION: return "ANIMATION"; - case ID_RECALC_PSYS_REDO: return "PSYS_REDO"; - case ID_RECALC_PSYS_RESET: return "PSYS_RESET"; - case ID_RECALC_PSYS_CHILD: return "PSYS_CHILD"; - case ID_RECALC_PSYS_PHYS: return "PSYS_PHYS"; - case ID_RECALC_PSYS_ALL: return "PSYS_ALL"; - case ID_RECALC_COPY_ON_WRITE: return "COPY_ON_WRITE"; - case ID_RECALC_SHADING: return "SHADING"; - case ID_RECALC_SELECT: return "SELECT"; - case ID_RECALC_BASE_FLAGS: return "BASE_FLAGS"; - case ID_RECALC_POINT_CACHE: return "POINT_CACHE"; - case ID_RECALC_EDITORS: return "EDITORS"; - case ID_RECALC_ALL: return "ALL"; - } - BLI_assert(!"Unhandled update flag, should never happen!"); - return "UNKNOWN"; + switch (flag) { + case ID_RECALC_TRANSFORM: + return "TRANSFORM"; + case ID_RECALC_GEOMETRY: + return "GEOMETRY"; + case ID_RECALC_ANIMATION: + return "ANIMATION"; + case ID_RECALC_PSYS_REDO: + return "PSYS_REDO"; + case ID_RECALC_PSYS_RESET: + return "PSYS_RESET"; + case ID_RECALC_PSYS_CHILD: + return "PSYS_CHILD"; + case ID_RECALC_PSYS_PHYS: + return "PSYS_PHYS"; + case ID_RECALC_PSYS_ALL: + return "PSYS_ALL"; + case ID_RECALC_COPY_ON_WRITE: + return "COPY_ON_WRITE"; + case ID_RECALC_SHADING: + return "SHADING"; + case ID_RECALC_SELECT: + return "SELECT"; + case ID_RECALC_BASE_FLAGS: + return "BASE_FLAGS"; + case ID_RECALC_POINT_CACHE: + return "POINT_CACHE"; + case ID_RECALC_EDITORS: + return "EDITORS"; + case ID_RECALC_ALL: + return "ALL"; + } + BLI_assert(!"Unhandled update flag, should never happen!"); + return "UNKNOWN"; } /* Data-Based Tagging */ @@ -663,17 +627,16 @@ const char *DEG_update_tag_as_string(IDRecalcFlag flag) /* Tag given ID for an update in all the dependency graphs. */ void DEG_id_tag_update(ID *id, int flag) { - DEG_id_tag_update_ex(G.main, id, flag); + DEG_id_tag_update_ex(G.main, id, flag); } void DEG_id_tag_update_ex(Main *bmain, ID *id, int flag) { - if (id == NULL) { - /* Ideally should not happen, but old depsgraph allowed this. */ - return; - } - DEG::id_tag_update( - bmain, id, flag, DEG::DEG_UPDATE_SOURCE_USER_EDIT); + if (id == NULL) { + /* Ideally should not happen, but old depsgraph allowed this. */ + return; + } + DEG::id_tag_update(bmain, id, flag, DEG::DEG_UPDATE_SOURCE_USER_EDIT); } void DEG_graph_id_tag_update(struct Main *bmain, @@ -681,132 +644,117 @@ void DEG_graph_id_tag_update(struct Main *bmain, struct ID *id, int flag) { - DEG::Depsgraph *graph = (DEG::Depsgraph *)depsgraph; - DEG::graph_id_tag_update( - bmain, graph, id, flag, DEG::DEG_UPDATE_SOURCE_USER_EDIT); + DEG::Depsgraph *graph = (DEG::Depsgraph *)depsgraph; + DEG::graph_id_tag_update(bmain, graph, id, flag, DEG::DEG_UPDATE_SOURCE_USER_EDIT); } /* Mark a particular datablock type as having changing. */ void DEG_graph_id_type_tag(Depsgraph *depsgraph, short id_type) { - if (id_type == ID_NT) { - /* Stupid workaround so parent datablocks of nested nodetree get looped - * over when we loop over tagged datablock types. */ - DEG_graph_id_type_tag(depsgraph, ID_MA); - DEG_graph_id_type_tag(depsgraph, ID_TE); - DEG_graph_id_type_tag(depsgraph, ID_LA); - DEG_graph_id_type_tag(depsgraph, ID_WO); - DEG_graph_id_type_tag(depsgraph, ID_SCE); - } - const int id_type_index = BKE_idcode_to_index(id_type); - DEG::Depsgraph *deg_graph = reinterpret_cast(depsgraph); - deg_graph->id_type_updated[id_type_index] = 1; + if (id_type == ID_NT) { + /* Stupid workaround so parent datablocks of nested nodetree get looped + * over when we loop over tagged datablock types. */ + DEG_graph_id_type_tag(depsgraph, ID_MA); + DEG_graph_id_type_tag(depsgraph, ID_TE); + DEG_graph_id_type_tag(depsgraph, ID_LA); + DEG_graph_id_type_tag(depsgraph, ID_WO); + DEG_graph_id_type_tag(depsgraph, ID_SCE); + } + const int id_type_index = BKE_idcode_to_index(id_type); + DEG::Depsgraph *deg_graph = reinterpret_cast(depsgraph); + deg_graph->id_type_updated[id_type_index] = 1; } void DEG_id_type_tag(Main *bmain, short id_type) { - LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { - LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { - Depsgraph *depsgraph = - (Depsgraph *)BKE_scene_get_depsgraph(scene, - view_layer, - false); - if (depsgraph != NULL) { - DEG_graph_id_type_tag(depsgraph, id_type); - } - } - } + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { + Depsgraph *depsgraph = (Depsgraph *)BKE_scene_get_depsgraph(scene, view_layer, false); + if (depsgraph != NULL) { + DEG_graph_id_type_tag(depsgraph, id_type); + } + } + } } void DEG_graph_flush_update(Main *bmain, Depsgraph *depsgraph) { - if (depsgraph == NULL) { - return; - } - DEG::deg_graph_flush_updates(bmain, (DEG::Depsgraph *)depsgraph); + if (depsgraph == NULL) { + return; + } + DEG::deg_graph_flush_updates(bmain, (DEG::Depsgraph *)depsgraph); } /* Update dependency graph when visible scenes/layers changes. */ void DEG_graph_on_visible_update(Main *bmain, Depsgraph *depsgraph) { - DEG::Depsgraph *graph = (DEG::Depsgraph *)depsgraph; - DEG::deg_graph_on_visible_update(bmain, graph); + DEG::Depsgraph *graph = (DEG::Depsgraph *)depsgraph; + DEG::deg_graph_on_visible_update(bmain, graph); } void DEG_on_visible_update(Main *bmain, const bool UNUSED(do_time)) { - LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { - LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { - Depsgraph *depsgraph = - (Depsgraph *)BKE_scene_get_depsgraph(scene, - view_layer, - false); - if (depsgraph != NULL) { - DEG_graph_on_visible_update(bmain, depsgraph); - } - } - } + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { + Depsgraph *depsgraph = (Depsgraph *)BKE_scene_get_depsgraph(scene, view_layer, false); + if (depsgraph != NULL) { + DEG_graph_on_visible_update(bmain, depsgraph); + } + } + } } /* Check if something was changed in the database and inform * editors about this. */ -void DEG_ids_check_recalc(Main *bmain, - Depsgraph *depsgraph, - Scene *scene, - ViewLayer *view_layer, - bool time) +void DEG_ids_check_recalc( + Main *bmain, Depsgraph *depsgraph, Scene *scene, ViewLayer *view_layer, bool time) { - bool updated = time || DEG_id_type_any_updated(depsgraph); - - DEGEditorUpdateContext update_ctx = {NULL}; - update_ctx.bmain = bmain; - update_ctx.depsgraph = depsgraph; - update_ctx.scene = scene; - update_ctx.view_layer = view_layer; - DEG::deg_editors_scene_update(&update_ctx, updated); + bool updated = time || DEG_id_type_any_updated(depsgraph); + + DEGEditorUpdateContext update_ctx = {NULL}; + update_ctx.bmain = bmain; + update_ctx.depsgraph = depsgraph; + update_ctx.scene = scene; + update_ctx.view_layer = view_layer; + DEG::deg_editors_scene_update(&update_ctx, updated); } -static void deg_graph_clear_id_node_func( - void *__restrict data_v, - const int i, - const ParallelRangeTLS *__restrict /*tls*/) +static void deg_graph_clear_id_node_func(void *__restrict data_v, + const int i, + const ParallelRangeTLS *__restrict /*tls*/) { - /* TODO: we clear original ID recalc flags here, but this may not work - * correctly when there are multiple depsgraph with others still using - * the recalc flag. */ - DEG::Depsgraph *deg_graph = reinterpret_cast(data_v); - DEG::IDNode *id_node = deg_graph->id_nodes[i]; - id_node->id_cow->recalc &= ~ID_RECALC_ALL; - id_node->id_orig->recalc &= ~ID_RECALC_ALL; - - /* Clear embedded node trees too. */ - bNodeTree *ntree_cow = ntreeFromID(id_node->id_cow); - if (ntree_cow) { - ntree_cow->id.recalc &= ~ID_RECALC_ALL; - } - bNodeTree *ntree_orig = ntreeFromID(id_node->id_orig); - if (ntree_orig) { - ntree_orig->id.recalc &= ~ID_RECALC_ALL; - } + /* TODO: we clear original ID recalc flags here, but this may not work + * correctly when there are multiple depsgraph with others still using + * the recalc flag. */ + DEG::Depsgraph *deg_graph = reinterpret_cast(data_v); + DEG::IDNode *id_node = deg_graph->id_nodes[i]; + id_node->id_cow->recalc &= ~ID_RECALC_ALL; + id_node->id_orig->recalc &= ~ID_RECALC_ALL; + + /* Clear embedded node trees too. */ + bNodeTree *ntree_cow = ntreeFromID(id_node->id_cow); + if (ntree_cow) { + ntree_cow->id.recalc &= ~ID_RECALC_ALL; + } + bNodeTree *ntree_orig = ntreeFromID(id_node->id_orig); + if (ntree_orig) { + ntree_orig->id.recalc &= ~ID_RECALC_ALL; + } } -void DEG_ids_clear_recalc(Main *UNUSED(bmain), - Depsgraph *depsgraph) +void DEG_ids_clear_recalc(Main *UNUSED(bmain), Depsgraph *depsgraph) { - DEG::Depsgraph *deg_graph = reinterpret_cast(depsgraph); - /* TODO(sergey): Re-implement POST_UPDATE_HANDLER_WORKAROUND using entry_tags - * and id_tags storage from the new dependency graph. */ - if (!DEG_id_type_any_updated(depsgraph)) { - return; - } - /* Go over all ID nodes nodes, clearing tags. */ - const int num_id_nodes = deg_graph->id_nodes.size(); - ParallelRangeSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.min_iter_per_thread = 1024; - BLI_task_parallel_range(0, num_id_nodes, - deg_graph, - deg_graph_clear_id_node_func, - &settings); - memset(deg_graph->id_type_updated, 0, sizeof(deg_graph->id_type_updated)); + DEG::Depsgraph *deg_graph = reinterpret_cast(depsgraph); + /* TODO(sergey): Re-implement POST_UPDATE_HANDLER_WORKAROUND using entry_tags + * and id_tags storage from the new dependency graph. */ + if (!DEG_id_type_any_updated(depsgraph)) { + return; + } + /* Go over all ID nodes nodes, clearing tags. */ + const int num_id_nodes = deg_graph->id_nodes.size(); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = 1024; + BLI_task_parallel_range(0, num_id_nodes, deg_graph, deg_graph_clear_id_node_func, &settings); + memset(deg_graph->id_type_updated, 0, sizeof(deg_graph->id_type_updated)); } diff --git a/source/blender/depsgraph/intern/depsgraph_tag.h b/source/blender/depsgraph/intern/depsgraph_tag.h index e4d1158aa3c..e79372f2459 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.h +++ b/source/blender/depsgraph/intern/depsgraph_tag.h @@ -37,10 +37,7 @@ NodeType geometry_tag_to_component(const ID *id); void id_tag_update(Main *bmain, ID *id, int flag, eUpdateSource update_source); /* Tag given ID for an update with in a given dependency graph. */ -void graph_id_tag_update(Main *bmain, - Depsgraph *graph, - ID *id, - int flag, - eUpdateSource update_source); +void graph_id_tag_update( + Main *bmain, Depsgraph *graph, ID *id, int flag, eUpdateSource update_source); } // namespace DEG diff --git a/source/blender/depsgraph/intern/depsgraph_type.cc b/source/blender/depsgraph/intern/depsgraph_type.cc index 5be2cae10d7..ef1fda1df44 100644 --- a/source/blender/depsgraph/intern/depsgraph_type.cc +++ b/source/blender/depsgraph/intern/depsgraph_type.cc @@ -25,7 +25,6 @@ #include // for BLI_assert() - #include "BLI_utildefines.h" #include "BLI_ghash.h" @@ -42,10 +41,10 @@ /* Register all node types */ void DEG_register_node_types(void) { - /* register node types */ - DEG::deg_register_base_depsnodes(); - DEG::deg_register_component_depsnodes(); - DEG::deg_register_operation_depsnodes(); + /* register node types */ + DEG::deg_register_base_depsnodes(); + DEG::deg_register_component_depsnodes(); + DEG::deg_register_operation_depsnodes(); } /* Free registry on exit */ @@ -53,11 +52,11 @@ void DEG_free_node_types(void) { } -DEG::DEGCustomDataMeshMasks::DEGCustomDataMeshMasks(const CustomData_MeshMasks *other) : - vert_mask(other->vmask), - edge_mask(other->emask), - face_mask(other->fmask), - loop_mask(other->lmask), - poly_mask(other->pmask) +DEG::DEGCustomDataMeshMasks::DEGCustomDataMeshMasks(const CustomData_MeshMasks *other) + : vert_mask(other->vmask), + edge_mask(other->emask), + face_mask(other->fmask), + loop_mask(other->lmask), + poly_mask(other->pmask) { } diff --git a/source/blender/depsgraph/intern/depsgraph_type.h b/source/blender/depsgraph/intern/depsgraph_type.h index d96c621f4b2..51ed31b8e25 100644 --- a/source/blender/depsgraph/intern/depsgraph_type.h +++ b/source/blender/depsgraph/intern/depsgraph_type.h @@ -46,16 +46,16 @@ struct CustomData_MeshMasks; namespace DEG { /* Commonly used types. */ -using std::string; -using std::vector; using std::map; using std::pair; +using std::string; using std::unordered_map; +using std::vector; /* Commonly used functions. */ +using std::make_pair; using std::max; using std::to_string; -using std::make_pair; /* Function bindings. */ using std::function; @@ -68,104 +68,97 @@ using namespace std::placeholders; * * TODO(sergey): Find a better place for this. */ enum eUpdateSource { - /* Update is caused by a time change. */ - DEG_UPDATE_SOURCE_TIME = (1 << 0), - /* Update caused by user directly or indirectly influencing the node. */ - DEG_UPDATE_SOURCE_USER_EDIT = (1 << 1), - /* Update is happening as a special response for the relations update. */ - DEG_UPDATE_SOURCE_RELATIONS = (1 << 2), - /* Update is happening due to visibility change. */ - DEG_UPDATE_SOURCE_VISIBILITY = (1 << 3), + /* Update is caused by a time change. */ + DEG_UPDATE_SOURCE_TIME = (1 << 0), + /* Update caused by user directly or indirectly influencing the node. */ + DEG_UPDATE_SOURCE_USER_EDIT = (1 << 1), + /* Update is happening as a special response for the relations update. */ + DEG_UPDATE_SOURCE_RELATIONS = (1 << 2), + /* Update is happening due to visibility change. */ + DEG_UPDATE_SOURCE_VISIBILITY = (1 << 3), }; /* C++ wrapper around DNA's CustomData_MeshMasks struct. */ struct DEGCustomDataMeshMasks { - uint64_t vert_mask; - uint64_t edge_mask; - uint64_t face_mask; - uint64_t loop_mask; - uint64_t poly_mask; - - DEGCustomDataMeshMasks() - : vert_mask(0), - edge_mask(0), - face_mask(0), - loop_mask(0), - poly_mask(0) - { - } - - explicit DEGCustomDataMeshMasks(const CustomData_MeshMasks *other); - - DEGCustomDataMeshMasks& operator|=(const DEGCustomDataMeshMasks& other) - { - this->vert_mask |= other.vert_mask; - this->edge_mask |= other.edge_mask; - this->face_mask |= other.face_mask; - this->loop_mask |= other.loop_mask; - this->poly_mask |= other.poly_mask; - return *this; - } - - DEGCustomDataMeshMasks operator|(const DEGCustomDataMeshMasks& other) const - { - DEGCustomDataMeshMasks result; - result.vert_mask = this->vert_mask | other.vert_mask; - result.edge_mask = this->edge_mask | other.edge_mask; - result.face_mask = this->face_mask | other.face_mask; - result.loop_mask = this->loop_mask | other.loop_mask; - result.poly_mask = this->poly_mask | other.poly_mask; - return result; - } - - bool operator==(const DEGCustomDataMeshMasks& other) const - { - return (this->vert_mask == other.vert_mask && - this->edge_mask == other.edge_mask && - this->face_mask == other.face_mask && - this->loop_mask == other.loop_mask && - this->poly_mask == other.poly_mask); - } - - bool operator!=(const DEGCustomDataMeshMasks& other) const - { - return !(*this == other); - } - - static DEGCustomDataMeshMasks MaskVert(const uint64_t vert_mask) - { - DEGCustomDataMeshMasks result; - result.vert_mask = vert_mask; - return result; - } - - static DEGCustomDataMeshMasks MaskEdge(const uint64_t edge_mask) - { - DEGCustomDataMeshMasks result; - result.edge_mask = edge_mask; - return result; - } - - static DEGCustomDataMeshMasks MaskFace(const uint64_t face_mask) - { - DEGCustomDataMeshMasks result; - result.face_mask = face_mask; - return result; - } - - static DEGCustomDataMeshMasks MaskLoop(const uint64_t loop_mask) - { - DEGCustomDataMeshMasks result; - result.loop_mask = loop_mask; - return result; - } - - static DEGCustomDataMeshMasks MaskPoly(const uint64_t poly_mask) - { - DEGCustomDataMeshMasks result; - result.poly_mask = poly_mask; - return result; - } + uint64_t vert_mask; + uint64_t edge_mask; + uint64_t face_mask; + uint64_t loop_mask; + uint64_t poly_mask; + + DEGCustomDataMeshMasks() : vert_mask(0), edge_mask(0), face_mask(0), loop_mask(0), poly_mask(0) + { + } + + explicit DEGCustomDataMeshMasks(const CustomData_MeshMasks *other); + + DEGCustomDataMeshMasks &operator|=(const DEGCustomDataMeshMasks &other) + { + this->vert_mask |= other.vert_mask; + this->edge_mask |= other.edge_mask; + this->face_mask |= other.face_mask; + this->loop_mask |= other.loop_mask; + this->poly_mask |= other.poly_mask; + return *this; + } + + DEGCustomDataMeshMasks operator|(const DEGCustomDataMeshMasks &other) const + { + DEGCustomDataMeshMasks result; + result.vert_mask = this->vert_mask | other.vert_mask; + result.edge_mask = this->edge_mask | other.edge_mask; + result.face_mask = this->face_mask | other.face_mask; + result.loop_mask = this->loop_mask | other.loop_mask; + result.poly_mask = this->poly_mask | other.poly_mask; + return result; + } + + bool operator==(const DEGCustomDataMeshMasks &other) const + { + return (this->vert_mask == other.vert_mask && this->edge_mask == other.edge_mask && + this->face_mask == other.face_mask && this->loop_mask == other.loop_mask && + this->poly_mask == other.poly_mask); + } + + bool operator!=(const DEGCustomDataMeshMasks &other) const + { + return !(*this == other); + } + + static DEGCustomDataMeshMasks MaskVert(const uint64_t vert_mask) + { + DEGCustomDataMeshMasks result; + result.vert_mask = vert_mask; + return result; + } + + static DEGCustomDataMeshMasks MaskEdge(const uint64_t edge_mask) + { + DEGCustomDataMeshMasks result; + result.edge_mask = edge_mask; + return result; + } + + static DEGCustomDataMeshMasks MaskFace(const uint64_t face_mask) + { + DEGCustomDataMeshMasks result; + result.face_mask = face_mask; + return result; + } + + static DEGCustomDataMeshMasks MaskLoop(const uint64_t loop_mask) + { + DEGCustomDataMeshMasks result; + result.loop_mask = loop_mask; + return result; + } + + static DEGCustomDataMeshMasks MaskPoly(const uint64_t poly_mask) + { + DEGCustomDataMeshMasks result; + result.poly_mask = poly_mask; + return result; + } }; } // namespace DEG diff --git a/source/blender/depsgraph/intern/depsgraph_update.cc b/source/blender/depsgraph/intern/depsgraph_update.cc index 1e09b012c01..ed4ec592fc7 100644 --- a/source/blender/depsgraph/intern/depsgraph_update.cc +++ b/source/blender/depsgraph/intern/depsgraph_update.cc @@ -34,25 +34,23 @@ static DEG_EditorUpdateSceneCb deg_editor_update_scene_cb = NULL; void deg_editors_id_update(const DEGEditorUpdateContext *update_ctx, ID *id) { - if (deg_editor_update_id_cb != NULL) { - deg_editor_update_id_cb(update_ctx, id); - } + if (deg_editor_update_id_cb != NULL) { + deg_editor_update_id_cb(update_ctx, id); + } } -void deg_editors_scene_update(const DEGEditorUpdateContext *update_ctx, - bool updated) +void deg_editors_scene_update(const DEGEditorUpdateContext *update_ctx, bool updated) { - if (deg_editor_update_scene_cb != NULL) { - deg_editor_update_scene_cb(update_ctx, updated); - } + if (deg_editor_update_scene_cb != NULL) { + deg_editor_update_scene_cb(update_ctx, updated); + } } } // namespace DEG /* Set callbacks which are being called when depsgraph changes. */ -void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func, - DEG_EditorUpdateSceneCb scene_func) +void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func, DEG_EditorUpdateSceneCb scene_func) { - DEG::deg_editor_update_id_cb = id_func; - DEG::deg_editor_update_scene_cb = scene_func; + DEG::deg_editor_update_id_cb = id_func; + DEG::deg_editor_update_scene_cb = scene_func; } diff --git a/source/blender/depsgraph/intern/depsgraph_update.h b/source/blender/depsgraph/intern/depsgraph_update.h index 9f886e0dc25..1723658ced3 100644 --- a/source/blender/depsgraph/intern/depsgraph_update.h +++ b/source/blender/depsgraph/intern/depsgraph_update.h @@ -28,10 +28,8 @@ struct ID; namespace DEG { -void deg_editors_id_update(const DEGEditorUpdateContext *update_ctx, - struct ID *id); +void deg_editors_id_update(const DEGEditorUpdateContext *update_ctx, struct ID *id); -void deg_editors_scene_update(const DEGEditorUpdateContext *update_ctx, - bool updated); +void deg_editors_scene_update(const DEGEditorUpdateContext *update_ctx, bool updated); } // namespace DEG diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc index eaafcffac97..950deee2b07 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval.cc @@ -64,180 +64,165 @@ static void schedule_children(TaskPool *pool, const int thread_id); struct DepsgraphEvalState { - Depsgraph *graph; - bool do_stats; - bool is_cow_stage; + Depsgraph *graph; + bool do_stats; + bool is_cow_stage; }; -static void deg_task_run_func(TaskPool *pool, - void *taskdata, - int thread_id) +static void deg_task_run_func(TaskPool *pool, void *taskdata, int thread_id) { - void *userdata_v = BLI_task_pool_userdata(pool); - DepsgraphEvalState *state = (DepsgraphEvalState *)userdata_v; - OperationNode *node = (OperationNode *)taskdata; - /* Sanity checks. */ - BLI_assert(!node->is_noop() && "NOOP nodes should not actually be scheduled"); - /* Perform operation. */ - if (state->do_stats) { - const double start_time = PIL_check_seconds_timer(); - node->evaluate((::Depsgraph *)state->graph); - node->stats.current_time += PIL_check_seconds_timer() - start_time; - } - else { - node->evaluate((::Depsgraph *)state->graph); - } - /* Schedule children. */ - BLI_task_pool_delayed_push_begin(pool, thread_id); - schedule_children(pool, state->graph, node, thread_id); - BLI_task_pool_delayed_push_end(pool, thread_id); + void *userdata_v = BLI_task_pool_userdata(pool); + DepsgraphEvalState *state = (DepsgraphEvalState *)userdata_v; + OperationNode *node = (OperationNode *)taskdata; + /* Sanity checks. */ + BLI_assert(!node->is_noop() && "NOOP nodes should not actually be scheduled"); + /* Perform operation. */ + if (state->do_stats) { + const double start_time = PIL_check_seconds_timer(); + node->evaluate((::Depsgraph *)state->graph); + node->stats.current_time += PIL_check_seconds_timer() - start_time; + } + else { + node->evaluate((::Depsgraph *)state->graph); + } + /* Schedule children. */ + BLI_task_pool_delayed_push_begin(pool, thread_id); + schedule_children(pool, state->graph, node, thread_id); + BLI_task_pool_delayed_push_end(pool, thread_id); } struct CalculatePendingData { - Depsgraph *graph; + Depsgraph *graph; }; static bool check_operation_node_visible(OperationNode *op_node) { - const ComponentNode *comp_node = op_node->owner; - /* Special exception, copy on write component is to be always evaluated, - * to keep copied "database" in a consistent state. */ - if (comp_node->type == NodeType::COPY_ON_WRITE) { - return true; - } - return comp_node->affects_directly_visible; + const ComponentNode *comp_node = op_node->owner; + /* Special exception, copy on write component is to be always evaluated, + * to keep copied "database" in a consistent state. */ + if (comp_node->type == NodeType::COPY_ON_WRITE) { + return true; + } + return comp_node->affects_directly_visible; } -static void calculate_pending_func( - void *__restrict data_v, - const int i, - const ParallelRangeTLS *__restrict /*tls*/) +static void calculate_pending_func(void *__restrict data_v, + const int i, + const ParallelRangeTLS *__restrict /*tls*/) { - CalculatePendingData *data = (CalculatePendingData *)data_v; - Depsgraph *graph = data->graph; - OperationNode *node = graph->operations[i]; - /* Update counters, applies for both visible and invisible IDs. */ - node->num_links_pending = 0; - node->scheduled = false; - /* Invisible IDs requires no pending operations. */ - if (!check_operation_node_visible(node)) { - return; - } - /* No need to bother with anything if node is not tagged for update. */ - if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) == 0) { - return; - } - for (Relation *rel : node->inlinks) { - if (rel->from->type == NodeType::OPERATION && - (rel->flag & RELATION_FLAG_CYCLIC) == 0) - { - OperationNode *from = (OperationNode *)rel->from; - /* TODO(sergey): This is how old layer system was checking for the - * calculation, but how is it possible that visible object depends - * on an invisible? This is something what is prohibited after - * deg_graph_build_flush_layers(). */ - if (!check_operation_node_visible(from)) { - continue; - } - /* No need to vait for operation which is up to date. */ - if ((from->flag & DEPSOP_FLAG_NEEDS_UPDATE) == 0) { - continue; - } - ++node->num_links_pending; - } - } + CalculatePendingData *data = (CalculatePendingData *)data_v; + Depsgraph *graph = data->graph; + OperationNode *node = graph->operations[i]; + /* Update counters, applies for both visible and invisible IDs. */ + node->num_links_pending = 0; + node->scheduled = false; + /* Invisible IDs requires no pending operations. */ + if (!check_operation_node_visible(node)) { + return; + } + /* No need to bother with anything if node is not tagged for update. */ + if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) == 0) { + return; + } + for (Relation *rel : node->inlinks) { + if (rel->from->type == NodeType::OPERATION && (rel->flag & RELATION_FLAG_CYCLIC) == 0) { + OperationNode *from = (OperationNode *)rel->from; + /* TODO(sergey): This is how old layer system was checking for the + * calculation, but how is it possible that visible object depends + * on an invisible? This is something what is prohibited after + * deg_graph_build_flush_layers(). */ + if (!check_operation_node_visible(from)) { + continue; + } + /* No need to vait for operation which is up to date. */ + if ((from->flag & DEPSOP_FLAG_NEEDS_UPDATE) == 0) { + continue; + } + ++node->num_links_pending; + } + } } static void calculate_pending_parents(Depsgraph *graph) { - const int num_operations = graph->operations.size(); - CalculatePendingData data; - data.graph = graph; - ParallelRangeSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.min_iter_per_thread = 1024; - BLI_task_parallel_range(0, - num_operations, - &data, - calculate_pending_func, - &settings); + const int num_operations = graph->operations.size(); + CalculatePendingData data; + data.graph = graph; + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = 1024; + BLI_task_parallel_range(0, num_operations, &data, calculate_pending_func, &settings); } static void initialize_execution(DepsgraphEvalState *state, Depsgraph *graph) { - const bool do_stats = state->do_stats; - calculate_pending_parents(graph); - /* Clear tags and other things which needs to be clear. */ - for (OperationNode *node : graph->operations) { - if (do_stats) { - node->stats.reset_current(); - } - } + const bool do_stats = state->do_stats; + calculate_pending_parents(graph); + /* Clear tags and other things which needs to be clear. */ + for (OperationNode *node : graph->operations) { + if (do_stats) { + node->stats.reset_current(); + } + } } /* Schedule a node if it needs evaluation. * dec_parents: Decrement pending parents count, true when child nodes are * scheduled after a task has been completed. */ -static void schedule_node(TaskPool *pool, Depsgraph *graph, - OperationNode *node, bool dec_parents, - const int thread_id) +static void schedule_node( + TaskPool *pool, Depsgraph *graph, OperationNode *node, bool dec_parents, const int thread_id) { - /* No need to schedule nodes of invisible ID. */ - if (!check_operation_node_visible(node)) { - return; - } - /* No need to schedule operations which are not tagged for update, they are - * considered to be up to date. */ - if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) == 0) { - return; - } - /* TODO(sergey): This is not strictly speaking safe to read - * num_links_pending. */ - if (dec_parents) { - BLI_assert(node->num_links_pending > 0); - atomic_sub_and_fetch_uint32(&node->num_links_pending, 1); - } - /* Cal not schedule operation while its dependencies are not yet - * evaluated. */ - if (node->num_links_pending != 0) { - return; - } - /* During the COW stage only schedule COW nodes. */ - DepsgraphEvalState *state = (DepsgraphEvalState *)BLI_task_pool_userdata(pool); - if (state->is_cow_stage) { - if (node->owner->type != NodeType::COPY_ON_WRITE) { - return; - } - } - else { - BLI_assert(node->scheduled || node->owner->type != NodeType::COPY_ON_WRITE); - } - /* Actually schedule the node. */ - bool is_scheduled = atomic_fetch_and_or_uint8( - (uint8_t *)&node->scheduled, (uint8_t)true); - if (!is_scheduled) { - if (node->is_noop()) { - /* skip NOOP node, schedule children right away */ - schedule_children(pool, graph, node, thread_id); - } - else { - /* children are scheduled once this task is completed */ - BLI_task_pool_push_from_thread(pool, - deg_task_run_func, - node, - false, - TASK_PRIORITY_HIGH, - thread_id); - } - } + /* No need to schedule nodes of invisible ID. */ + if (!check_operation_node_visible(node)) { + return; + } + /* No need to schedule operations which are not tagged for update, they are + * considered to be up to date. */ + if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) == 0) { + return; + } + /* TODO(sergey): This is not strictly speaking safe to read + * num_links_pending. */ + if (dec_parents) { + BLI_assert(node->num_links_pending > 0); + atomic_sub_and_fetch_uint32(&node->num_links_pending, 1); + } + /* Cal not schedule operation while its dependencies are not yet + * evaluated. */ + if (node->num_links_pending != 0) { + return; + } + /* During the COW stage only schedule COW nodes. */ + DepsgraphEvalState *state = (DepsgraphEvalState *)BLI_task_pool_userdata(pool); + if (state->is_cow_stage) { + if (node->owner->type != NodeType::COPY_ON_WRITE) { + return; + } + } + else { + BLI_assert(node->scheduled || node->owner->type != NodeType::COPY_ON_WRITE); + } + /* Actually schedule the node. */ + bool is_scheduled = atomic_fetch_and_or_uint8((uint8_t *)&node->scheduled, (uint8_t) true); + if (!is_scheduled) { + if (node->is_noop()) { + /* skip NOOP node, schedule children right away */ + schedule_children(pool, graph, node, thread_id); + } + else { + /* children are scheduled once this task is completed */ + BLI_task_pool_push_from_thread( + pool, deg_task_run_func, node, false, TASK_PRIORITY_HIGH, thread_id); + } + } } static void schedule_graph(TaskPool *pool, Depsgraph *graph) { - for (OperationNode *node : graph->operations) { - schedule_node(pool, graph, node, false, 0); - } + for (OperationNode *node : graph->operations) { + schedule_node(pool, graph, node, false, 0); + } } static void schedule_children(TaskPool *pool, @@ -245,34 +230,29 @@ static void schedule_children(TaskPool *pool, OperationNode *node, const int thread_id) { - for (Relation *rel : node->outlinks) { - OperationNode *child = (OperationNode *)rel->to; - BLI_assert(child->type == NodeType::OPERATION); - if (child->scheduled) { - /* Happens when having cyclic dependencies. */ - continue; - } - schedule_node(pool, - graph, - child, - (rel->flag & RELATION_FLAG_CYCLIC) == 0, - thread_id); - } + for (Relation *rel : node->outlinks) { + OperationNode *child = (OperationNode *)rel->to; + BLI_assert(child->type == NodeType::OPERATION); + if (child->scheduled) { + /* Happens when having cyclic dependencies. */ + continue; + } + schedule_node(pool, graph, child, (rel->flag & RELATION_FLAG_CYCLIC) == 0, thread_id); + } } static void depsgraph_ensure_view_layer(Depsgraph *graph) { - /* We update copy-on-write scene in the following cases: - * - It was not expanded yet. - * - It was tagged for update of CoW component. - * This allows us to have proper view layer pointer. */ - Scene *scene_cow = graph->scene_cow; - if (!deg_copy_on_write_is_expanded(&scene_cow->id) || - scene_cow->id.recalc & ID_RECALC_COPY_ON_WRITE) - { - const IDNode *id_node = graph->find_id_node(&graph->scene->id); - deg_update_copy_on_write_datablock(graph, id_node); - } + /* We update copy-on-write scene in the following cases: + * - It was not expanded yet. + * - It was tagged for update of CoW component. + * This allows us to have proper view layer pointer. */ + Scene *scene_cow = graph->scene_cow; + if (!deg_copy_on_write_is_expanded(&scene_cow->id) || + scene_cow->id.recalc & ID_RECALC_COPY_ON_WRITE) { + const IDNode *id_node = graph->find_id_node(&graph->scene->id); + deg_update_copy_on_write_datablock(graph, id_node); + } } /** @@ -284,58 +264,57 @@ static void depsgraph_ensure_view_layer(Depsgraph *graph) */ void deg_evaluate_on_refresh(Depsgraph *graph) { - /* Nothing to update, early out. */ - if (BLI_gset_len(graph->entry_tags) == 0) { - return; - } - const bool do_time_debug = ((G.debug & G_DEBUG_DEPSGRAPH_TIME) != 0); - const double start_time = do_time_debug ? PIL_check_seconds_timer() : 0; - graph->debug_is_evaluating = true; - depsgraph_ensure_view_layer(graph); - /* Set up evaluation state. */ - DepsgraphEvalState state; - state.graph = graph; - state.do_stats = do_time_debug; - /* Set up task scheduler and pull for threaded evaluation. */ - TaskScheduler *task_scheduler; - bool need_free_scheduler; - if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) { - task_scheduler = BLI_task_scheduler_create(1); - need_free_scheduler = true; - } - else { - task_scheduler = BLI_task_scheduler_get(); - need_free_scheduler = false; - } - TaskPool *task_pool = BLI_task_pool_create_suspended(task_scheduler, &state); - /* Prepare all nodes for evaluation. */ - initialize_execution(&state, graph); - /* Do actual evaluation now. */ - /* First, process all Copy-On-Write nodes. */ - state.is_cow_stage = true; - schedule_graph(task_pool, graph); - BLI_task_pool_work_wait_and_reset(task_pool); - /* After that, process all other nodes. */ - state.is_cow_stage = false; - schedule_graph(task_pool, graph); - BLI_task_pool_work_and_wait(task_pool); - BLI_task_pool_free(task_pool); - /* Finalize statistics gathering. This is because we only gather single - * operation timing here, without aggregating anything to avoid any extra - * synchronization. */ - if (state.do_stats) { - deg_eval_stats_aggregate(graph); - } - /* Clear any uncleared tags - just in case. */ - deg_graph_clear_tags(graph); - if (need_free_scheduler) { - BLI_task_scheduler_free(task_scheduler); - } - graph->debug_is_evaluating = false; - if (do_time_debug) { - printf("Depsgraph updated in %f seconds.\n", - PIL_check_seconds_timer() - start_time); - } + /* Nothing to update, early out. */ + if (BLI_gset_len(graph->entry_tags) == 0) { + return; + } + const bool do_time_debug = ((G.debug & G_DEBUG_DEPSGRAPH_TIME) != 0); + const double start_time = do_time_debug ? PIL_check_seconds_timer() : 0; + graph->debug_is_evaluating = true; + depsgraph_ensure_view_layer(graph); + /* Set up evaluation state. */ + DepsgraphEvalState state; + state.graph = graph; + state.do_stats = do_time_debug; + /* Set up task scheduler and pull for threaded evaluation. */ + TaskScheduler *task_scheduler; + bool need_free_scheduler; + if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) { + task_scheduler = BLI_task_scheduler_create(1); + need_free_scheduler = true; + } + else { + task_scheduler = BLI_task_scheduler_get(); + need_free_scheduler = false; + } + TaskPool *task_pool = BLI_task_pool_create_suspended(task_scheduler, &state); + /* Prepare all nodes for evaluation. */ + initialize_execution(&state, graph); + /* Do actual evaluation now. */ + /* First, process all Copy-On-Write nodes. */ + state.is_cow_stage = true; + schedule_graph(task_pool, graph); + BLI_task_pool_work_wait_and_reset(task_pool); + /* After that, process all other nodes. */ + state.is_cow_stage = false; + schedule_graph(task_pool, graph); + BLI_task_pool_work_and_wait(task_pool); + BLI_task_pool_free(task_pool); + /* Finalize statistics gathering. This is because we only gather single + * operation timing here, without aggregating anything to avoid any extra + * synchronization. */ + if (state.do_stats) { + deg_eval_stats_aggregate(graph); + } + /* Clear any uncleared tags - just in case. */ + deg_graph_clear_tags(graph); + if (need_free_scheduler) { + BLI_task_scheduler_free(task_scheduler); + } + graph->debug_is_evaluating = false; + if (do_time_debug) { + printf("Depsgraph updated in %f seconds.\n", PIL_check_seconds_timer() - start_time); + } } } // namespace DEG diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc index 387253ab3fe..01b712fcd87 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc @@ -17,7 +17,6 @@ * All rights reserved. */ - /** \file * \ingroup depsgraph */ @@ -95,260 +94,245 @@ extern "C" { namespace DEG { -#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) printf +#define DEBUG_PRINT \ + if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) \ + printf namespace { #ifdef NESTED_ID_NASTY_WORKAROUND union NestedIDHackTempStorage { - Curve curve; - FreestyleLineStyle linestyle; - Light lamp; - Lattice lattice; - Material material; - Mesh mesh; - Scene scene; - Tex tex; - World world; + Curve curve; + FreestyleLineStyle linestyle; + Light lamp; + Lattice lattice; + Material material; + Mesh mesh; + Scene scene; + Tex tex; + World world; }; /* Set nested owned ID pointers to NULL. */ void nested_id_hack_discard_pointers(ID *id_cow) { - switch (GS(id_cow->name)) { -# define SPECIAL_CASE(id_type, dna_type, field) \ - case id_type: \ - { \ - ((dna_type *)id_cow)->field = NULL; \ - break; \ - } - - SPECIAL_CASE(ID_LS, FreestyleLineStyle, nodetree) - SPECIAL_CASE(ID_LA, Light, nodetree) - SPECIAL_CASE(ID_MA, Material, nodetree) - SPECIAL_CASE(ID_TE, Tex, nodetree) - SPECIAL_CASE(ID_WO, World, nodetree) - - SPECIAL_CASE(ID_CU, Curve, key) - SPECIAL_CASE(ID_LT, Lattice, key) - SPECIAL_CASE(ID_ME, Mesh, key) - - case ID_SCE: - { - Scene *scene_cow = (Scene *)id_cow; - /* Node trees always have their own ID node in the graph, and are - * being copied as part of their copy-on-write process. */ - scene_cow->nodetree = NULL; - /* Tool settings pointer is shared with the original scene. */ - scene_cow->toolsettings = NULL; - break; - } - - case ID_OB: - { - /* Clear the ParticleSettings pointer to prevent doubly-freeing it. */ - Object *ob = (Object *)id_cow; - LISTBASE_FOREACH (ParticleSystem *, psys, &ob->particlesystem) { - psys->part = NULL; - } - break; - } + switch (GS(id_cow->name)) { +# define SPECIAL_CASE(id_type, dna_type, field) \ + case id_type: { \ + ((dna_type *)id_cow)->field = NULL; \ + break; \ + } + + SPECIAL_CASE(ID_LS, FreestyleLineStyle, nodetree) + SPECIAL_CASE(ID_LA, Light, nodetree) + SPECIAL_CASE(ID_MA, Material, nodetree) + SPECIAL_CASE(ID_TE, Tex, nodetree) + SPECIAL_CASE(ID_WO, World, nodetree) + + SPECIAL_CASE(ID_CU, Curve, key) + SPECIAL_CASE(ID_LT, Lattice, key) + SPECIAL_CASE(ID_ME, Mesh, key) + + case ID_SCE: { + Scene *scene_cow = (Scene *)id_cow; + /* Node trees always have their own ID node in the graph, and are + * being copied as part of their copy-on-write process. */ + scene_cow->nodetree = NULL; + /* Tool settings pointer is shared with the original scene. */ + scene_cow->toolsettings = NULL; + break; + } + + case ID_OB: { + /* Clear the ParticleSettings pointer to prevent doubly-freeing it. */ + Object *ob = (Object *)id_cow; + LISTBASE_FOREACH (ParticleSystem *, psys, &ob->particlesystem) { + psys->part = NULL; + } + break; + } # undef SPECIAL_CASE - default: - break; - } + default: + break; + } } /* Set ID pointer of nested owned IDs (nodetree, key) to NULL. * * Return pointer to a new ID to be used. */ -const ID *nested_id_hack_get_discarded_pointers(NestedIDHackTempStorage *storage, - const ID *id) +const ID *nested_id_hack_get_discarded_pointers(NestedIDHackTempStorage *storage, const ID *id) { - switch (GS(id->name)) { -# define SPECIAL_CASE(id_type, dna_type, field, variable) \ - case id_type: \ - { \ - storage->variable = *(dna_type *)id; \ - storage->variable.field = NULL; \ - return &storage->variable.id; \ - } - - SPECIAL_CASE(ID_LS, FreestyleLineStyle, nodetree, linestyle) - SPECIAL_CASE(ID_LA, Light, nodetree, lamp) - SPECIAL_CASE(ID_MA, Material, nodetree, material) - SPECIAL_CASE(ID_TE, Tex, nodetree, tex) - SPECIAL_CASE(ID_WO, World, nodetree, world) - - SPECIAL_CASE(ID_CU, Curve, key, curve) - SPECIAL_CASE(ID_LT, Lattice, key, lattice) - SPECIAL_CASE(ID_ME, Mesh, key, mesh) - - case ID_SCE: - { - storage->scene = *(Scene *)id; - storage->scene.toolsettings = NULL; - storage->scene.nodetree = NULL; - return &storage->scene.id; - } + switch (GS(id->name)) { +# define SPECIAL_CASE(id_type, dna_type, field, variable) \ + case id_type: { \ + storage->variable = *(dna_type *)id; \ + storage->variable.field = NULL; \ + return &storage->variable.id; \ + } + + SPECIAL_CASE(ID_LS, FreestyleLineStyle, nodetree, linestyle) + SPECIAL_CASE(ID_LA, Light, nodetree, lamp) + SPECIAL_CASE(ID_MA, Material, nodetree, material) + SPECIAL_CASE(ID_TE, Tex, nodetree, tex) + SPECIAL_CASE(ID_WO, World, nodetree, world) + + SPECIAL_CASE(ID_CU, Curve, key, curve) + SPECIAL_CASE(ID_LT, Lattice, key, lattice) + SPECIAL_CASE(ID_ME, Mesh, key, mesh) + + case ID_SCE: { + storage->scene = *(Scene *)id; + storage->scene.toolsettings = NULL; + storage->scene.nodetree = NULL; + return &storage->scene.id; + } # undef SPECIAL_CASE - default: - break; - } - return id; + default: + break; + } + return id; } /* Set ID pointer of nested owned IDs (nodetree, key) to the original value. */ void nested_id_hack_restore_pointers(const ID *old_id, ID *new_id) { - if (new_id == NULL) { - return; - } - switch (GS(old_id->name)) { -# define SPECIAL_CASE(id_type, dna_type, field) \ - case id_type: \ - { \ - ((dna_type *)(new_id))->field = \ - ((dna_type *)(old_id))->field; \ - break; \ - } - - SPECIAL_CASE(ID_LS, FreestyleLineStyle, nodetree) - SPECIAL_CASE(ID_LA, Light, nodetree) - SPECIAL_CASE(ID_MA, Material, nodetree) - SPECIAL_CASE(ID_SCE, Scene, nodetree) - SPECIAL_CASE(ID_TE, Tex, nodetree) - SPECIAL_CASE(ID_WO, World, nodetree) - - SPECIAL_CASE(ID_CU, Curve, key) - SPECIAL_CASE(ID_LT, Lattice, key) - SPECIAL_CASE(ID_ME, Mesh, key) - -#undef SPECIAL_CASE - default: - break; - } + if (new_id == NULL) { + return; + } + switch (GS(old_id->name)) { +# define SPECIAL_CASE(id_type, dna_type, field) \ + case id_type: { \ + ((dna_type *)(new_id))->field = ((dna_type *)(old_id))->field; \ + break; \ + } + + SPECIAL_CASE(ID_LS, FreestyleLineStyle, nodetree) + SPECIAL_CASE(ID_LA, Light, nodetree) + SPECIAL_CASE(ID_MA, Material, nodetree) + SPECIAL_CASE(ID_SCE, Scene, nodetree) + SPECIAL_CASE(ID_TE, Tex, nodetree) + SPECIAL_CASE(ID_WO, World, nodetree) + + SPECIAL_CASE(ID_CU, Curve, key) + SPECIAL_CASE(ID_LT, Lattice, key) + SPECIAL_CASE(ID_ME, Mesh, key) + +# undef SPECIAL_CASE + default: + break; + } } /* Remap pointer of nested owned IDs (nodetree. key) to the new ID values. */ void ntree_hack_remap_pointers(const Depsgraph *depsgraph, ID *id_cow) { - switch (GS(id_cow->name)) { -# define SPECIAL_CASE(id_type, dna_type, field, field_type) \ - case id_type: \ - { \ - dna_type *data = (dna_type *)id_cow; \ - if (data->field != NULL) { \ - ID *ntree_id_cow = depsgraph->get_cow_id(&data->field->id); \ - if (ntree_id_cow != NULL) { \ - DEG_COW_PRINT(" Remapping datablock for %s: id_orig=%p id_cow=%p\n", \ - data->field->id.name, \ - data->field, \ - ntree_id_cow); \ - data->field = (field_type *)ntree_id_cow; \ - } \ - } \ - break; \ - } - - SPECIAL_CASE(ID_LS, FreestyleLineStyle, nodetree, bNodeTree) - SPECIAL_CASE(ID_LA, Light, nodetree, bNodeTree) - SPECIAL_CASE(ID_MA, Material, nodetree, bNodeTree) - SPECIAL_CASE(ID_SCE, Scene, nodetree, bNodeTree) - SPECIAL_CASE(ID_TE, Tex, nodetree, bNodeTree) - SPECIAL_CASE(ID_WO, World, nodetree, bNodeTree) - - SPECIAL_CASE(ID_CU, Curve, key, Key) - SPECIAL_CASE(ID_LT, Lattice, key, Key) - SPECIAL_CASE(ID_ME, Mesh, key, Key) - -#undef SPECIAL_CASE - default: - break; - } + switch (GS(id_cow->name)) { +# define SPECIAL_CASE(id_type, dna_type, field, field_type) \ + case id_type: { \ + dna_type *data = (dna_type *)id_cow; \ + if (data->field != NULL) { \ + ID *ntree_id_cow = depsgraph->get_cow_id(&data->field->id); \ + if (ntree_id_cow != NULL) { \ + DEG_COW_PRINT(" Remapping datablock for %s: id_orig=%p id_cow=%p\n", \ + data->field->id.name, \ + data->field, \ + ntree_id_cow); \ + data->field = (field_type *)ntree_id_cow; \ + } \ + } \ + break; \ + } + + SPECIAL_CASE(ID_LS, FreestyleLineStyle, nodetree, bNodeTree) + SPECIAL_CASE(ID_LA, Light, nodetree, bNodeTree) + SPECIAL_CASE(ID_MA, Material, nodetree, bNodeTree) + SPECIAL_CASE(ID_SCE, Scene, nodetree, bNodeTree) + SPECIAL_CASE(ID_TE, Tex, nodetree, bNodeTree) + SPECIAL_CASE(ID_WO, World, nodetree, bNodeTree) + + SPECIAL_CASE(ID_CU, Curve, key, Key) + SPECIAL_CASE(ID_LT, Lattice, key, Key) + SPECIAL_CASE(ID_ME, Mesh, key, Key) + +# undef SPECIAL_CASE + default: + break; + } } -#endif /* NODETREE_NASTY_WORKAROUND */ +#endif /* NODETREE_NASTY_WORKAROUND */ struct ValidateData { - bool is_valid; + bool is_valid; }; /* Similar to generic BKE_id_copy() but does not require main and assumes pointer * is already allocated. */ bool id_copy_inplace_no_main(const ID *id, ID *newid) { - const ID *id_for_copy = id; + const ID *id_for_copy = id; #ifdef NESTED_ID_NASTY_WORKAROUND - NestedIDHackTempStorage id_hack_storage; - id_for_copy = nested_id_hack_get_discarded_pointers(&id_hack_storage, id); + NestedIDHackTempStorage id_hack_storage; + id_for_copy = nested_id_hack_get_discarded_pointers(&id_hack_storage, id); #endif - bool result = BKE_id_copy_ex(NULL, - (ID *)id_for_copy, - &newid, - (LIB_ID_COPY_LOCALIZE | - LIB_ID_CREATE_NO_ALLOCATE)); + bool result = BKE_id_copy_ex( + NULL, (ID *)id_for_copy, &newid, (LIB_ID_COPY_LOCALIZE | LIB_ID_CREATE_NO_ALLOCATE)); #ifdef NESTED_ID_NASTY_WORKAROUND - if (result) { - nested_id_hack_restore_pointers(id, newid); - } + if (result) { + nested_id_hack_restore_pointers(id, newid); + } #endif - return result; + return result; } /* Similar to BKE_scene_copy() but does not require main and assumes pointer * is already allocated. */ bool scene_copy_inplace_no_main(const Scene *scene, Scene *new_scene) { - const ID *id_for_copy = &scene->id; + const ID *id_for_copy = &scene->id; #ifdef NESTED_ID_NASTY_WORKAROUND - NestedIDHackTempStorage id_hack_storage; - id_for_copy = nested_id_hack_get_discarded_pointers(&id_hack_storage, - &scene->id); + NestedIDHackTempStorage id_hack_storage; + id_for_copy = nested_id_hack_get_discarded_pointers(&id_hack_storage, &scene->id); #endif - bool result = BKE_id_copy_ex(NULL, - id_for_copy, - (ID **)&new_scene, - LIB_ID_COPY_LOCALIZE | - LIB_ID_CREATE_NO_ALLOCATE); + bool result = BKE_id_copy_ex( + NULL, id_for_copy, (ID **)&new_scene, LIB_ID_COPY_LOCALIZE | LIB_ID_CREATE_NO_ALLOCATE); #ifdef NESTED_ID_NASTY_WORKAROUND - if (result) { - nested_id_hack_restore_pointers(&scene->id, &new_scene->id); - } + if (result) { + nested_id_hack_restore_pointers(&scene->id, &new_scene->id); + } #endif - return result; + return result; } /* For the given scene get view layer which corresponds to an original for the * scene's evaluated one. This depends on how the scene is pulled into the * dependency graph. */ -ViewLayer *get_original_view_layer(const Depsgraph *depsgraph, - const IDNode *id_node) +ViewLayer *get_original_view_layer(const Depsgraph *depsgraph, const IDNode *id_node) { - if (id_node->linked_state == DEG_ID_LINKED_DIRECTLY) { - return depsgraph->view_layer; - } - else if (id_node->linked_state == DEG_ID_LINKED_VIA_SET) { - Scene *scene_orig = reinterpret_cast(id_node->id_orig); - return BKE_view_layer_default_render(scene_orig); - } - /* Is possible to have scene linked indirectly (i.e. via the driver) which - * we need to support. Currently there aer issues somewhere else, which - * makes testing hard. This is a reported problem, so will eventually be - * properly fixed. - * - * TODO(sergey): Support indirectly linked scene. */ - return NULL; + if (id_node->linked_state == DEG_ID_LINKED_DIRECTLY) { + return depsgraph->view_layer; + } + else if (id_node->linked_state == DEG_ID_LINKED_VIA_SET) { + Scene *scene_orig = reinterpret_cast(id_node->id_orig); + return BKE_view_layer_default_render(scene_orig); + } + /* Is possible to have scene linked indirectly (i.e. via the driver) which + * we need to support. Currently there aer issues somewhere else, which + * makes testing hard. This is a reported problem, so will eventually be + * properly fixed. + * + * TODO(sergey): Support indirectly linked scene. */ + return NULL; } /* Remove all view layers but the one which corresponds to an input one. */ @@ -356,102 +340,95 @@ void scene_remove_unused_view_layers(const Depsgraph *depsgraph, const IDNode *id_node, Scene *scene_cow) { - const ViewLayer *view_layer_input = get_original_view_layer( - depsgraph, id_node); - ViewLayer *view_layer_eval = NULL; - /* Find evaluated view layer. At the same time we free memory used by - * all other of the view layers. */ - for (ViewLayer *view_layer_cow = - reinterpret_cast(scene_cow->view_layers.first), - *view_layer_next; - view_layer_cow != NULL; - view_layer_cow = view_layer_next) - { - view_layer_next = view_layer_cow->next; - if (STREQ(view_layer_input->name, view_layer_cow->name)) { - view_layer_eval = view_layer_cow; - } - else { - BKE_view_layer_free_ex(view_layer_cow, false); - } - } - BLI_assert(view_layer_eval != NULL); - /* Make evaluated view layer the only one in the evaluated scene. */ - view_layer_eval->prev = view_layer_eval->next = NULL; - scene_cow->view_layers.first = view_layer_eval; - scene_cow->view_layers.last = view_layer_eval; + const ViewLayer *view_layer_input = get_original_view_layer(depsgraph, id_node); + ViewLayer *view_layer_eval = NULL; + /* Find evaluated view layer. At the same time we free memory used by + * all other of the view layers. */ + for (ViewLayer *view_layer_cow = reinterpret_cast(scene_cow->view_layers.first), + *view_layer_next; + view_layer_cow != NULL; + view_layer_cow = view_layer_next) { + view_layer_next = view_layer_cow->next; + if (STREQ(view_layer_input->name, view_layer_cow->name)) { + view_layer_eval = view_layer_cow; + } + else { + BKE_view_layer_free_ex(view_layer_cow, false); + } + } + BLI_assert(view_layer_eval != NULL); + /* Make evaluated view layer the only one in the evaluated scene. */ + view_layer_eval->prev = view_layer_eval->next = NULL; + scene_cow->view_layers.first = view_layer_eval; + scene_cow->view_layers.last = view_layer_eval; } /* Makes it so given view layer only has bases corresponding to enabled * objects. */ -void view_layer_remove_disabled_bases(const Depsgraph *depsgraph, - ViewLayer *view_layer) +void view_layer_remove_disabled_bases(const Depsgraph *depsgraph, ViewLayer *view_layer) { - ListBase enabled_bases = {NULL, NULL}; - LISTBASE_FOREACH_MUTABLE (Base *, base, &view_layer->object_bases) { - /* TODO(sergey): Would be cool to optimize this somehow, or make it so - * builder tags bases. - * - * NOTE: The idea of using id's tag and check whether its copied ot not - * is not reliable, since object might be indirectly linked into the - * graph. - * - * NOTE: We are using original base since the object which evaluated base - * points to is not yet copied. This is dangerous access from evaluated - * domain to original one, but this is how the entire copy-on-write works: - * it does need to access original for an initial copy. */ - const bool is_object_enabled = - deg_check_base_available_for_build(depsgraph, base->base_orig); - if (is_object_enabled) { - BLI_addtail(&enabled_bases, base); - } - else { - if (base == view_layer->basact) { - view_layer->basact = NULL; - } - MEM_freeN(base); - } - } - view_layer->object_bases = enabled_bases; + ListBase enabled_bases = {NULL, NULL}; + LISTBASE_FOREACH_MUTABLE(Base *, base, &view_layer->object_bases) + { + /* TODO(sergey): Would be cool to optimize this somehow, or make it so + * builder tags bases. + * + * NOTE: The idea of using id's tag and check whether its copied ot not + * is not reliable, since object might be indirectly linked into the + * graph. + * + * NOTE: We are using original base since the object which evaluated base + * points to is not yet copied. This is dangerous access from evaluated + * domain to original one, but this is how the entire copy-on-write works: + * it does need to access original for an initial copy. */ + const bool is_object_enabled = deg_check_base_available_for_build(depsgraph, base->base_orig); + if (is_object_enabled) { + BLI_addtail(&enabled_bases, base); + } + else { + if (base == view_layer->basact) { + view_layer->basact = NULL; + } + MEM_freeN(base); + } + } + view_layer->object_bases = enabled_bases; } void view_layer_update_orig_base_pointers(const ViewLayer *view_layer_orig, ViewLayer *view_layer_eval) { - Base *base_orig = - reinterpret_cast(view_layer_orig->object_bases.first); - LISTBASE_FOREACH (Base *, base_eval, &view_layer_eval->object_bases) { - base_eval->base_orig = base_orig; - base_orig = base_orig->next; - } + Base *base_orig = reinterpret_cast(view_layer_orig->object_bases.first); + LISTBASE_FOREACH (Base *, base_eval, &view_layer_eval->object_bases) { + base_eval->base_orig = base_orig; + base_orig = base_orig->next; + } } void scene_setup_view_layers_before_remap(const Depsgraph *depsgraph, const IDNode *id_node, Scene *scene_cow) { - scene_remove_unused_view_layers(depsgraph, id_node, scene_cow); + scene_remove_unused_view_layers(depsgraph, id_node, scene_cow); } void scene_setup_view_layers_after_remap(const Depsgraph *depsgraph, const IDNode *id_node, Scene *scene_cow) { - const ViewLayer *view_layer_orig = get_original_view_layer( - depsgraph, id_node); - ViewLayer *view_layer_eval = - reinterpret_cast(scene_cow->view_layers.first); - view_layer_update_orig_base_pointers(view_layer_orig, view_layer_eval); - view_layer_remove_disabled_bases(depsgraph, view_layer_eval); - /* TODO(sergey): Remove objects from collections as well. - * Not a HUGE deal for now, nobody is looking into those CURRENTLY. - * Still not an excuse to have those. */ + const ViewLayer *view_layer_orig = get_original_view_layer(depsgraph, id_node); + ViewLayer *view_layer_eval = reinterpret_cast(scene_cow->view_layers.first); + view_layer_update_orig_base_pointers(view_layer_orig, view_layer_eval); + view_layer_remove_disabled_bases(depsgraph, view_layer_eval); + /* TODO(sergey): Remove objects from collections as well. + * Not a HUGE deal for now, nobody is looking into those CURRENTLY. + * Still not an excuse to have those. */ } /* Check whether given ID is expanded or still a shallow copy. */ BLI_INLINE bool check_datablock_expanded(const ID *id_cow) { - return (id_cow->name[0] != '\0'); + return (id_cow->name[0] != '\0'); } /* Those are datablocks which are not covered by dependency graph and hence @@ -461,211 +438,200 @@ BLI_INLINE bool check_datablock_expanded(const ID *id_cow) * to maintain exception lists all over the code? */ bool check_datablocks_copy_on_writable(const ID *id_orig) { - const ID_Type id_type = GS(id_orig->name); - /* We shouldn't bother if copied ID is same as original one. */ - if (!deg_copy_on_write_is_needed(id_orig)) { - return false; - } - return !ELEM(id_type, ID_BR, - ID_LS, - ID_PAL); + const ID_Type id_type = GS(id_orig->name); + /* We shouldn't bother if copied ID is same as original one. */ + if (!deg_copy_on_write_is_needed(id_orig)) { + return false; + } + return !ELEM(id_type, ID_BR, ID_LS, ID_PAL); } /* Callback for BKE_library_foreach_ID_link which remaps original ID pointer * with the one created by CoW system. */ struct RemapCallbackUserData { - /* Dependency graph for which remapping is happening. */ - const Depsgraph *depsgraph; - /* Create placeholder for ID nodes for cases when we need to remap original - * ID to it[s CoW version but we don't have required ID node yet. - * - * This happens when expansion happens a ta construction time. */ - DepsgraphNodeBuilder *node_builder; - bool create_placeholders; + /* Dependency graph for which remapping is happening. */ + const Depsgraph *depsgraph; + /* Create placeholder for ID nodes for cases when we need to remap original + * ID to it[s CoW version but we don't have required ID node yet. + * + * This happens when expansion happens a ta construction time. */ + DepsgraphNodeBuilder *node_builder; + bool create_placeholders; }; -int foreach_libblock_remap_callback(void *user_data_v, - ID *id_self, - ID **id_p, - int /*cb_flag*/) +int foreach_libblock_remap_callback(void *user_data_v, ID *id_self, ID **id_p, int /*cb_flag*/) { - if (*id_p == NULL) { - return IDWALK_RET_NOP; - } - RemapCallbackUserData *user_data = (RemapCallbackUserData *)user_data_v; - const Depsgraph *depsgraph = user_data->depsgraph; - ID *id_orig = *id_p; - if (check_datablocks_copy_on_writable(id_orig)) { - ID *id_cow; - if (user_data->create_placeholders) { - /* Special workaround to stop creating temp datablocks for - * objects which are coming from scene's collection and which - * are never linked to any of layers. - * - * TODO(sergey): Ideally we need to tell ID looper to ignore - * those or at least make it more reliable check where the - * pointer is coming from. */ - const ID_Type id_type = GS(id_orig->name); - const ID_Type id_type_self = GS(id_self->name); - if (id_type == ID_OB && id_type_self == ID_SCE) { - IDNode *id_node = depsgraph->find_id_node(id_orig); - if (id_node == NULL) { - id_cow = id_orig; - } - else { - id_cow = id_node->id_cow; - } - } - else { - id_cow = user_data->node_builder->ensure_cow_id(id_orig); - } - } - else { - id_cow = depsgraph->get_cow_id(id_orig); - } - BLI_assert(id_cow != NULL); - DEG_COW_PRINT(" Remapping datablock for %s: id_orig=%p id_cow=%p\n", - id_orig->name, id_orig, id_cow); - *id_p = id_cow; - } - return IDWALK_RET_NOP; + if (*id_p == NULL) { + return IDWALK_RET_NOP; + } + RemapCallbackUserData *user_data = (RemapCallbackUserData *)user_data_v; + const Depsgraph *depsgraph = user_data->depsgraph; + ID *id_orig = *id_p; + if (check_datablocks_copy_on_writable(id_orig)) { + ID *id_cow; + if (user_data->create_placeholders) { + /* Special workaround to stop creating temp datablocks for + * objects which are coming from scene's collection and which + * are never linked to any of layers. + * + * TODO(sergey): Ideally we need to tell ID looper to ignore + * those or at least make it more reliable check where the + * pointer is coming from. */ + const ID_Type id_type = GS(id_orig->name); + const ID_Type id_type_self = GS(id_self->name); + if (id_type == ID_OB && id_type_self == ID_SCE) { + IDNode *id_node = depsgraph->find_id_node(id_orig); + if (id_node == NULL) { + id_cow = id_orig; + } + else { + id_cow = id_node->id_cow; + } + } + else { + id_cow = user_data->node_builder->ensure_cow_id(id_orig); + } + } + else { + id_cow = depsgraph->get_cow_id(id_orig); + } + BLI_assert(id_cow != NULL); + DEG_COW_PRINT( + " Remapping datablock for %s: id_orig=%p id_cow=%p\n", id_orig->name, id_orig, id_cow); + *id_p = id_cow; + } + return IDWALK_RET_NOP; } void update_armature_edit_mode_pointers(const Depsgraph * /*depsgraph*/, - const ID *id_orig, ID *id_cow) + const ID *id_orig, + ID *id_cow) { - const bArmature *armature_orig = (const bArmature *)id_orig; - bArmature *armature_cow = (bArmature *)id_cow; - armature_cow->edbo = armature_orig->edbo; + const bArmature *armature_orig = (const bArmature *)id_orig; + bArmature *armature_cow = (bArmature *)id_cow; + armature_cow->edbo = armature_orig->edbo; } void update_curve_edit_mode_pointers(const Depsgraph * /*depsgraph*/, - const ID *id_orig, ID *id_cow) + const ID *id_orig, + ID *id_cow) { - const Curve *curve_orig = (const Curve *)id_orig; - Curve *curve_cow = (Curve *)id_cow; - curve_cow->editnurb = curve_orig->editnurb; - curve_cow->editfont = curve_orig->editfont; + const Curve *curve_orig = (const Curve *)id_orig; + Curve *curve_cow = (Curve *)id_cow; + curve_cow->editnurb = curve_orig->editnurb; + curve_cow->editfont = curve_orig->editfont; } void update_mball_edit_mode_pointers(const Depsgraph * /*depsgraph*/, - const ID *id_orig, ID *id_cow) + const ID *id_orig, + ID *id_cow) { - const MetaBall *mball_orig = (const MetaBall *)id_orig; - MetaBall *mball_cow = (MetaBall *)id_cow; - mball_cow->editelems = mball_orig->editelems; + const MetaBall *mball_orig = (const MetaBall *)id_orig; + MetaBall *mball_cow = (MetaBall *)id_cow; + mball_cow->editelems = mball_orig->editelems; } void update_lattice_edit_mode_pointers(const Depsgraph * /*depsgraph*/, - const ID *id_orig, ID *id_cow) + const ID *id_orig, + ID *id_cow) { - const Lattice *lt_orig = (const Lattice *)id_orig; - Lattice *lt_cow = (Lattice *)id_cow; - lt_cow->editlatt = lt_orig->editlatt; + const Lattice *lt_orig = (const Lattice *)id_orig; + Lattice *lt_cow = (Lattice *)id_cow; + lt_cow->editlatt = lt_orig->editlatt; } -void update_mesh_edit_mode_pointers(const Depsgraph *depsgraph, - const ID *id_orig, ID *id_cow) +void update_mesh_edit_mode_pointers(const Depsgraph *depsgraph, const ID *id_orig, ID *id_cow) { - /* For meshes we need to update edit_mesh to make it to point - * to the CoW version of object. - * - * This is kind of confusing, because actual bmesh is not owned by - * the CoW object, so need to be accurate about using link from - * edit_mesh to object. */ - const Mesh *mesh_orig = (const Mesh *)id_orig; - Mesh *mesh_cow = (Mesh *)id_cow; - if (mesh_orig->edit_mesh == NULL) { - return; - } - mesh_cow->edit_mesh = (BMEditMesh *)MEM_dupallocN(mesh_orig->edit_mesh); - mesh_cow->edit_mesh->ob = - (Object *)depsgraph->get_cow_id(&mesh_orig->edit_mesh->ob->id); - mesh_cow->edit_mesh->mesh_eval_cage = NULL; - mesh_cow->edit_mesh->mesh_eval_final = NULL; + /* For meshes we need to update edit_mesh to make it to point + * to the CoW version of object. + * + * This is kind of confusing, because actual bmesh is not owned by + * the CoW object, so need to be accurate about using link from + * edit_mesh to object. */ + const Mesh *mesh_orig = (const Mesh *)id_orig; + Mesh *mesh_cow = (Mesh *)id_cow; + if (mesh_orig->edit_mesh == NULL) { + return; + } + mesh_cow->edit_mesh = (BMEditMesh *)MEM_dupallocN(mesh_orig->edit_mesh); + mesh_cow->edit_mesh->ob = (Object *)depsgraph->get_cow_id(&mesh_orig->edit_mesh->ob->id); + mesh_cow->edit_mesh->mesh_eval_cage = NULL; + mesh_cow->edit_mesh->mesh_eval_final = NULL; } /* Edit data is stored and owned by original datablocks, copied ones * are simply referencing to them. */ -void update_edit_mode_pointers(const Depsgraph *depsgraph, - const ID *id_orig, ID *id_cow) +void update_edit_mode_pointers(const Depsgraph *depsgraph, const ID *id_orig, ID *id_cow) { - const ID_Type type = GS(id_orig->name); - switch (type) { - case ID_AR: - update_armature_edit_mode_pointers(depsgraph, id_orig, id_cow); - break; - case ID_ME: - update_mesh_edit_mode_pointers(depsgraph, id_orig, id_cow); - break; - case ID_CU: - update_curve_edit_mode_pointers(depsgraph, id_orig, id_cow); - break; - case ID_MB: - update_mball_edit_mode_pointers(depsgraph, id_orig, id_cow); - break; - case ID_LT: - update_lattice_edit_mode_pointers(depsgraph, id_orig, id_cow); - break; - default: - break; - } + const ID_Type type = GS(id_orig->name); + switch (type) { + case ID_AR: + update_armature_edit_mode_pointers(depsgraph, id_orig, id_cow); + break; + case ID_ME: + update_mesh_edit_mode_pointers(depsgraph, id_orig, id_cow); + break; + case ID_CU: + update_curve_edit_mode_pointers(depsgraph, id_orig, id_cow); + break; + case ID_MB: + update_mball_edit_mode_pointers(depsgraph, id_orig, id_cow); + break; + case ID_LT: + update_lattice_edit_mode_pointers(depsgraph, id_orig, id_cow); + break; + default: + break; + } } -template +template void update_list_orig_pointers(const ListBase *listbase_orig, ListBase *listbase, T *T::*orig_field) { - T *element_orig = reinterpret_cast(listbase_orig->first); - T *element_cow = reinterpret_cast(listbase->first); - while (element_orig != NULL) { - element_cow->*orig_field = element_orig; - element_cow = element_cow->next; - element_orig = element_orig->next; - } + T *element_orig = reinterpret_cast(listbase_orig->first); + T *element_cow = reinterpret_cast(listbase->first); + while (element_orig != NULL) { + element_cow->*orig_field = element_orig; + element_cow = element_cow->next; + element_orig = element_orig->next; + } } -void update_particle_system_orig_pointers(const Object *object_orig, - Object *object_cow) +void update_particle_system_orig_pointers(const Object *object_orig, Object *object_cow) { - update_list_orig_pointers(&object_orig->particlesystem, - &object_cow->particlesystem, - &ParticleSystem::orig_psys); + update_list_orig_pointers( + &object_orig->particlesystem, &object_cow->particlesystem, &ParticleSystem::orig_psys); } void set_particle_system_modifiers_loaded(Object *object_cow) { - LISTBASE_FOREACH(ModifierData *, md, &object_cow->modifiers) { - if (md->type != eModifierType_ParticleSystem) { - continue; - } - ParticleSystemModifierData *psmd = - reinterpret_cast(md); - psmd->flag |= eParticleSystemFlag_file_loaded; - } + LISTBASE_FOREACH (ModifierData *, md, &object_cow->modifiers) { + if (md->type != eModifierType_ParticleSystem) { + continue; + } + ParticleSystemModifierData *psmd = reinterpret_cast(md); + psmd->flag |= eParticleSystemFlag_file_loaded; + } } void update_particles_after_copy(const Object *object_orig, Object *object_cow) { - update_particle_system_orig_pointers(object_orig, object_cow); - set_particle_system_modifiers_loaded(object_cow); + update_particle_system_orig_pointers(object_orig, object_cow); + set_particle_system_modifiers_loaded(object_cow); } void update_pose_orig_pointers(const bPose *pose_orig, bPose *pose_cow) { - update_list_orig_pointers(&pose_orig->chanbase, - &pose_cow->chanbase, - &bPoseChannel::orig_pchan); + update_list_orig_pointers(&pose_orig->chanbase, &pose_cow->chanbase, &bPoseChannel::orig_pchan); } -void update_modifiers_orig_pointers(const Object *object_orig, - Object *object_cow) +void update_modifiers_orig_pointers(const Object *object_orig, Object *object_cow) { - update_list_orig_pointers(&object_orig->modifiers, - &object_cow->modifiers, - &ModifierData::orig_modifier_data); + update_list_orig_pointers( + &object_orig->modifiers, &object_cow->modifiers, &ModifierData::orig_modifier_data); } /* Do some special treatment of data transfer from original ID to it's @@ -674,50 +640,47 @@ void update_modifiers_orig_pointers(const Object *object_orig, * Only use for the newly created CoW datablocks. */ void update_id_after_copy(const Depsgraph *depsgraph, const IDNode *id_node, - const ID *id_orig, ID *id_cow) + const ID *id_orig, + ID *id_cow) { - const ID_Type type = GS(id_orig->name); - switch (type) { - case ID_OB: - { - /* Ensure we don't drag someone's else derived mesh to the - * new copy of the object. */ - Object *object_cow = (Object *)id_cow; - const Object *object_orig = (const Object *)id_orig; - object_cow->mode = object_orig->mode; - object_cow->sculpt = object_orig->sculpt; - if (object_cow->type == OB_MESH) { - object_cow->runtime.mesh_orig = (Mesh *)object_cow->data; - } - if (object_cow->type == OB_ARMATURE) { - const bArmature *armature_orig = (bArmature *)object_orig->data; - bArmature *armature_cow = (bArmature *)object_cow->data; - BKE_pose_remap_bone_pointers(armature_cow, object_cow->pose); - if (armature_orig->edbo == NULL) { - update_pose_orig_pointers(object_orig->pose, - object_cow->pose); - } - BKE_pose_pchan_index_rebuild(object_cow->pose); - } - update_particles_after_copy(object_orig, object_cow); - update_modifiers_orig_pointers(object_orig, object_cow); - break; - } - case ID_SCE: - { - Scene *scene_cow = (Scene *)id_cow; - const Scene *scene_orig = (const Scene *)id_orig; - scene_cow->toolsettings = scene_orig->toolsettings; - scene_cow->eevee.light_cache = scene_orig->eevee.light_cache; - scene_setup_view_layers_after_remap( - depsgraph, id_node, reinterpret_cast(id_cow)); - break; - } - default: - break; - } - update_edit_mode_pointers(depsgraph, id_orig, id_cow); - BKE_animsys_update_driver_array(id_cow); + const ID_Type type = GS(id_orig->name); + switch (type) { + case ID_OB: { + /* Ensure we don't drag someone's else derived mesh to the + * new copy of the object. */ + Object *object_cow = (Object *)id_cow; + const Object *object_orig = (const Object *)id_orig; + object_cow->mode = object_orig->mode; + object_cow->sculpt = object_orig->sculpt; + if (object_cow->type == OB_MESH) { + object_cow->runtime.mesh_orig = (Mesh *)object_cow->data; + } + if (object_cow->type == OB_ARMATURE) { + const bArmature *armature_orig = (bArmature *)object_orig->data; + bArmature *armature_cow = (bArmature *)object_cow->data; + BKE_pose_remap_bone_pointers(armature_cow, object_cow->pose); + if (armature_orig->edbo == NULL) { + update_pose_orig_pointers(object_orig->pose, object_cow->pose); + } + BKE_pose_pchan_index_rebuild(object_cow->pose); + } + update_particles_after_copy(object_orig, object_cow); + update_modifiers_orig_pointers(object_orig, object_cow); + break; + } + case ID_SCE: { + Scene *scene_cow = (Scene *)id_cow; + const Scene *scene_orig = (const Scene *)id_orig; + scene_cow->toolsettings = scene_orig->toolsettings; + scene_cow->eevee.light_cache = scene_orig->eevee.light_cache; + scene_setup_view_layers_after_remap(depsgraph, id_node, reinterpret_cast(id_cow)); + break; + } + default: + break; + } + update_edit_mode_pointers(depsgraph, id_orig, id_cow); + BKE_animsys_update_driver_array(id_cow); } /* This callback is used to validate that all nested ID datablocks are @@ -727,14 +690,14 @@ int foreach_libblock_validate_callback(void *user_data, ID **id_p, int /*cb_flag*/) { - ValidateData *data = (ValidateData *)user_data; - if (*id_p != NULL) { - if (!check_datablock_expanded(*id_p)) { - data->is_valid = false; - /* TODO(sergey): Store which is is not valid? */ - } - } - return IDWALK_RET_NOP; + ValidateData *data = (ValidateData *)user_data; + if (*id_p != NULL) { + if (!check_datablock_expanded(*id_p)) { + data->is_valid = false; + /* TODO(sergey): Store which is is not valid? */ + } + } + return IDWALK_RET_NOP; } } // namespace @@ -748,90 +711,84 @@ ID *deg_expand_copy_on_write_datablock(const Depsgraph *depsgraph, DepsgraphNodeBuilder *node_builder, bool create_placeholders) { - const ID *id_orig = id_node->id_orig; - ID *id_cow = id_node->id_cow; - const int id_cow_recalc = id_cow->recalc; - /* No need to expand such datablocks, their copied ID is same as original - * one already. */ - if (!deg_copy_on_write_is_needed(id_orig)) { - return id_cow; - } - DEG_COW_PRINT("Expanding datablock for %s: id_orig=%p id_cow=%p\n", - id_orig->name, id_orig, id_cow); - /* Sanity checks. */ - /* NOTE: Disabled for now, conflicts when re-using evaluated datablock when - * rebuilding dependencies. */ - if (check_datablock_expanded(id_cow) && create_placeholders) { - deg_free_copy_on_write_datablock(id_cow); - } - // BLI_assert(check_datablock_expanded(id_cow) == false); - /* Copy data from original ID to a copied version. */ - /* TODO(sergey): Avoid doing full ID copy somehow, make Mesh to reference - * original geometry arrays for until those are modified. */ - /* TODO(sergey): We do some trickery with temp bmain and extra ID pointer - * just to be able to use existing API. Ideally we need to replace this with - * in-place copy from existing datablock to a prepared memory. - * - * NOTE: We don't use BKE_main_{new,free} because: - * - We don't want heap-allocations here. - * - We don't want bmain's content to be freed when main is freed. */ - bool done = false; - /* First we handle special cases which are not covered by BKE_id_copy() yet. - * or cases where we want to do something smarter than simple datablock - * copy. */ - const ID_Type id_type = GS(id_orig->name); - switch (id_type) { - case ID_SCE: - { - done = scene_copy_inplace_no_main((Scene *)id_orig, (Scene *)id_cow); - if (done) { - /* NOTE: This is important to do before remap, because this - * function will make it so less IDs are to be remapped. */ - scene_setup_view_layers_before_remap( - depsgraph, id_node, (Scene *)id_cow); - } - break; - } - case ID_ME: - { - /* TODO(sergey): Ideally we want to handle meshes in a special - * manner here to avoid initial copy of all the geometry arrays. */ - break; - } - default: - break; - } - if (!done) { - done = id_copy_inplace_no_main(id_orig, id_cow); - } - if (!done) { - BLI_assert(!"No idea how to perform CoW on datablock"); - } - /* Update pointers to nested ID datablocks. */ - DEG_COW_PRINT(" Remapping ID links for %s: id_orig=%p id_cow=%p\n", - id_orig->name, id_orig, id_cow); + const ID *id_orig = id_node->id_orig; + ID *id_cow = id_node->id_cow; + const int id_cow_recalc = id_cow->recalc; + /* No need to expand such datablocks, their copied ID is same as original + * one already. */ + if (!deg_copy_on_write_is_needed(id_orig)) { + return id_cow; + } + DEG_COW_PRINT( + "Expanding datablock for %s: id_orig=%p id_cow=%p\n", id_orig->name, id_orig, id_cow); + /* Sanity checks. */ + /* NOTE: Disabled for now, conflicts when re-using evaluated datablock when + * rebuilding dependencies. */ + if (check_datablock_expanded(id_cow) && create_placeholders) { + deg_free_copy_on_write_datablock(id_cow); + } + // BLI_assert(check_datablock_expanded(id_cow) == false); + /* Copy data from original ID to a copied version. */ + /* TODO(sergey): Avoid doing full ID copy somehow, make Mesh to reference + * original geometry arrays for until those are modified. */ + /* TODO(sergey): We do some trickery with temp bmain and extra ID pointer + * just to be able to use existing API. Ideally we need to replace this with + * in-place copy from existing datablock to a prepared memory. + * + * NOTE: We don't use BKE_main_{new,free} because: + * - We don't want heap-allocations here. + * - We don't want bmain's content to be freed when main is freed. */ + bool done = false; + /* First we handle special cases which are not covered by BKE_id_copy() yet. + * or cases where we want to do something smarter than simple datablock + * copy. */ + const ID_Type id_type = GS(id_orig->name); + switch (id_type) { + case ID_SCE: { + done = scene_copy_inplace_no_main((Scene *)id_orig, (Scene *)id_cow); + if (done) { + /* NOTE: This is important to do before remap, because this + * function will make it so less IDs are to be remapped. */ + scene_setup_view_layers_before_remap(depsgraph, id_node, (Scene *)id_cow); + } + break; + } + case ID_ME: { + /* TODO(sergey): Ideally we want to handle meshes in a special + * manner here to avoid initial copy of all the geometry arrays. */ + break; + } + default: + break; + } + if (!done) { + done = id_copy_inplace_no_main(id_orig, id_cow); + } + if (!done) { + BLI_assert(!"No idea how to perform CoW on datablock"); + } + /* Update pointers to nested ID datablocks. */ + DEG_COW_PRINT( + " Remapping ID links for %s: id_orig=%p id_cow=%p\n", id_orig->name, id_orig, id_cow); #ifdef NESTED_ID_NASTY_WORKAROUND - ntree_hack_remap_pointers(depsgraph, id_cow); + ntree_hack_remap_pointers(depsgraph, id_cow); #endif - /* Do it now, so remapping will understand that possibly remapped self ID - * is not to be remapped again. */ - deg_tag_copy_on_write_id(id_cow, id_orig); - /* Perform remapping of the nodes. */ - RemapCallbackUserData user_data = {NULL}; - user_data.depsgraph = depsgraph; - user_data.node_builder = node_builder; - user_data.create_placeholders = create_placeholders; - BKE_library_foreach_ID_link(NULL, - id_cow, - foreach_libblock_remap_callback, - (void *)&user_data, - IDWALK_NOP); - /* Correct or tweak some pointers which are not taken care by foreach - * from above. */ - update_id_after_copy(depsgraph, id_node, id_orig, id_cow); - id_cow->recalc = id_orig->recalc | id_cow_recalc; - return id_cow; + /* Do it now, so remapping will understand that possibly remapped self ID + * is not to be remapped again. */ + deg_tag_copy_on_write_id(id_cow, id_orig); + /* Perform remapping of the nodes. */ + RemapCallbackUserData user_data = {NULL}; + user_data.depsgraph = depsgraph; + user_data.node_builder = node_builder; + user_data.create_placeholders = create_placeholders; + BKE_library_foreach_ID_link( + NULL, id_cow, foreach_libblock_remap_callback, (void *)&user_data, IDWALK_NOP); + /* Correct or tweak some pointers which are not taken care by foreach + * from above. */ + update_id_after_copy(depsgraph, id_node, id_orig, id_cow); + id_cow->recalc = id_orig->recalc | id_cow_recalc; + return id_cow; } /* NOTE: Depsgraph is supposed to have ID node already. */ @@ -840,12 +797,9 @@ ID *deg_expand_copy_on_write_datablock(const Depsgraph *depsgraph, DepsgraphNodeBuilder *node_builder, bool create_placeholders) { - DEG::IDNode *id_node = depsgraph->find_id_node(id_orig); - BLI_assert(id_node != NULL); - return deg_expand_copy_on_write_datablock(depsgraph, - id_node, - node_builder, - create_placeholders); + DEG::IDNode *id_node = depsgraph->find_id_node(id_orig); + BLI_assert(id_node != NULL); + return deg_expand_copy_on_write_datablock(depsgraph, id_node, node_builder, create_placeholders); } namespace { @@ -859,323 +813,315 @@ namespace { * By adding type into matching we are at least ensuring that modifier will not * try to interpret runtime data created by another modifier type. */ class ModifierDataBackupID { -public: - ModifierDataBackupID() : ModifierDataBackupID(NULL, eModifierType_None) - { - } - - ModifierDataBackupID(ModifierData *modifier_data, ModifierType type) - : modifier_data(modifier_data), - type(type) - { - } - - bool operator <(const ModifierDataBackupID& other) const { - if (modifier_data < other.modifier_data) { - return true; - } - if (modifier_data == other.modifier_data) { - return static_cast(type) < static_cast(other.type); - } - return false; - } - - ModifierData *modifier_data; - ModifierType type; + public: + ModifierDataBackupID() : ModifierDataBackupID(NULL, eModifierType_None) + { + } + + ModifierDataBackupID(ModifierData *modifier_data, ModifierType type) + : modifier_data(modifier_data), type(type) + { + } + + bool operator<(const ModifierDataBackupID &other) const + { + if (modifier_data < other.modifier_data) { + return true; + } + if (modifier_data == other.modifier_data) { + return static_cast(type) < static_cast(other.type); + } + return false; + } + + ModifierData *modifier_data; + ModifierType type; }; /* Storage for backed up runtime modifier data. */ -typedef map ModifierRuntimeDataBackup; +typedef map ModifierRuntimeDataBackup; struct ObjectRuntimeBackup { - ObjectRuntimeBackup() - : base_flag(0), - base_local_view_bits(0) - { - /* TODO(sergey): Use something like BKE_object_runtime_reset(). */ - memset(&runtime, 0, sizeof(runtime)); - } - - /* Make a backup of object's evaluation runtime data, additionally - * make object to be safe for free without invalidating backed up - * pointers. */ - void init_from_object(Object *object); - void backup_modifier_runtime_data(Object *object); - - /* Restore all fields to the given object. */ - void restore_to_object(Object *object); - /* NOTE: Will free all runtime data which has not been restored. */ - void restore_modifier_runtime_data(Object *object); - - Object_Runtime runtime; - short base_flag; - unsigned short base_local_view_bits; - ModifierRuntimeDataBackup modifier_runtime_data; + ObjectRuntimeBackup() : base_flag(0), base_local_view_bits(0) + { + /* TODO(sergey): Use something like BKE_object_runtime_reset(). */ + memset(&runtime, 0, sizeof(runtime)); + } + + /* Make a backup of object's evaluation runtime data, additionally + * make object to be safe for free without invalidating backed up + * pointers. */ + void init_from_object(Object *object); + void backup_modifier_runtime_data(Object *object); + + /* Restore all fields to the given object. */ + void restore_to_object(Object *object); + /* NOTE: Will free all runtime data which has not been restored. */ + void restore_modifier_runtime_data(Object *object); + + Object_Runtime runtime; + short base_flag; + unsigned short base_local_view_bits; + ModifierRuntimeDataBackup modifier_runtime_data; }; void ObjectRuntimeBackup::init_from_object(Object *object) { - /* Store evaluated mesh and curve_cache, and make sure we don't free it. */ - Mesh *mesh_eval = object->runtime.mesh_eval; - runtime = object->runtime; - BKE_object_runtime_reset(object); - /* Keep bbox (for now at least). */ - object->runtime.bb = runtime.bb; - /* Object update will override actual object->data to an evaluated version. - * Need to make sure we don't have data set to evaluated one before free - * anything. */ - if (mesh_eval != NULL && object->data == mesh_eval) { - object->data = runtime.mesh_orig; - } - /* Make a backup of base flags. */ - base_flag = object->base_flag; - base_local_view_bits = object->base_local_view_bits; - /* Backup tuntime data of all modifiers. */ - backup_modifier_runtime_data(object); + /* Store evaluated mesh and curve_cache, and make sure we don't free it. */ + Mesh *mesh_eval = object->runtime.mesh_eval; + runtime = object->runtime; + BKE_object_runtime_reset(object); + /* Keep bbox (for now at least). */ + object->runtime.bb = runtime.bb; + /* Object update will override actual object->data to an evaluated version. + * Need to make sure we don't have data set to evaluated one before free + * anything. */ + if (mesh_eval != NULL && object->data == mesh_eval) { + object->data = runtime.mesh_orig; + } + /* Make a backup of base flags. */ + base_flag = object->base_flag; + base_local_view_bits = object->base_local_view_bits; + /* Backup tuntime data of all modifiers. */ + backup_modifier_runtime_data(object); } -inline ModifierDataBackupID create_modifier_data_id( - const ModifierData *modifier_data) +inline ModifierDataBackupID create_modifier_data_id(const ModifierData *modifier_data) { - return ModifierDataBackupID(modifier_data->orig_modifier_data, - static_cast(modifier_data->type)); + return ModifierDataBackupID(modifier_data->orig_modifier_data, + static_cast(modifier_data->type)); } void ObjectRuntimeBackup::backup_modifier_runtime_data(Object *object) { - LISTBASE_FOREACH(ModifierData *, modifier_data, &object->modifiers) { - if (modifier_data->runtime == NULL) { - continue; - } - BLI_assert(modifier_data->orig_modifier_data != NULL); - ModifierDataBackupID modifier_data_id = - create_modifier_data_id(modifier_data); - modifier_runtime_data.insert( - make_pair(modifier_data_id, modifier_data->runtime)); - modifier_data->runtime = NULL; - } + LISTBASE_FOREACH (ModifierData *, modifier_data, &object->modifiers) { + if (modifier_data->runtime == NULL) { + continue; + } + BLI_assert(modifier_data->orig_modifier_data != NULL); + ModifierDataBackupID modifier_data_id = create_modifier_data_id(modifier_data); + modifier_runtime_data.insert(make_pair(modifier_data_id, modifier_data->runtime)); + modifier_data->runtime = NULL; + } } void ObjectRuntimeBackup::restore_to_object(Object *object) { - Mesh *mesh_orig = object->runtime.mesh_orig; - BoundBox *bb = object->runtime.bb; - object->runtime = runtime; - object->runtime.mesh_orig = mesh_orig; - object->runtime.bb = bb; - if (object->type == OB_MESH && object->runtime.mesh_eval != NULL) { - if (object->id.recalc & ID_RECALC_GEOMETRY) { - /* If geometry is tagged for update it means, that part of - * evaluated mesh are not valid anymore. In this case we can not - * have any "persistent" pointers to point to an invalid data. - * - * We restore object's data datablock to an original copy of - * that datablock. */ - object->data = mesh_orig; - - /* After that, immediately free the invalidated caches. */ - BKE_object_free_derived_caches(object); - } - else { - Mesh *mesh_eval = object->runtime.mesh_eval; - /* Do same thing as object update: override actual object data - * pointer with evaluated datablock. */ - object->data = mesh_eval; - /* Evaluated mesh simply copied edit_mesh pointer from - * original mesh during update, need to make sure no dead - * pointers are left behind. */ - mesh_eval->edit_mesh = mesh_orig->edit_mesh; - } - } - object->base_flag = base_flag; - object->base_local_view_bits = base_local_view_bits; - /* Restore modifier's runtime data. - * NOTE: Data of unused modifiers will be freed there. */ - restore_modifier_runtime_data(object); + Mesh *mesh_orig = object->runtime.mesh_orig; + BoundBox *bb = object->runtime.bb; + object->runtime = runtime; + object->runtime.mesh_orig = mesh_orig; + object->runtime.bb = bb; + if (object->type == OB_MESH && object->runtime.mesh_eval != NULL) { + if (object->id.recalc & ID_RECALC_GEOMETRY) { + /* If geometry is tagged for update it means, that part of + * evaluated mesh are not valid anymore. In this case we can not + * have any "persistent" pointers to point to an invalid data. + * + * We restore object's data datablock to an original copy of + * that datablock. */ + object->data = mesh_orig; + + /* After that, immediately free the invalidated caches. */ + BKE_object_free_derived_caches(object); + } + else { + Mesh *mesh_eval = object->runtime.mesh_eval; + /* Do same thing as object update: override actual object data + * pointer with evaluated datablock. */ + object->data = mesh_eval; + /* Evaluated mesh simply copied edit_mesh pointer from + * original mesh during update, need to make sure no dead + * pointers are left behind. */ + mesh_eval->edit_mesh = mesh_orig->edit_mesh; + } + } + object->base_flag = base_flag; + object->base_local_view_bits = base_local_view_bits; + /* Restore modifier's runtime data. + * NOTE: Data of unused modifiers will be freed there. */ + restore_modifier_runtime_data(object); } void ObjectRuntimeBackup::restore_modifier_runtime_data(Object *object) { - LISTBASE_FOREACH(ModifierData *, modifier_data, &object->modifiers) { - BLI_assert(modifier_data->orig_modifier_data != NULL); - ModifierDataBackupID modifier_data_id = - create_modifier_data_id(modifier_data); - ModifierRuntimeDataBackup::iterator runtime_data_iterator = - modifier_runtime_data.find(modifier_data_id); - if (runtime_data_iterator != modifier_runtime_data.end()) { - modifier_data->runtime = runtime_data_iterator->second; - runtime_data_iterator->second = NULL; - } - } - for (ModifierRuntimeDataBackup::value_type value : modifier_runtime_data) { - const ModifierDataBackupID modifier_data_id = value.first; - void *runtime = value.second; - if (value.second == NULL) { - continue; - } - const ModifierTypeInfo *modifier_type_info = - modifierType_getInfo(modifier_data_id.type); - BLI_assert(modifier_type_info != NULL); - modifier_type_info->freeRuntimeData(runtime); - } + LISTBASE_FOREACH (ModifierData *, modifier_data, &object->modifiers) { + BLI_assert(modifier_data->orig_modifier_data != NULL); + ModifierDataBackupID modifier_data_id = create_modifier_data_id(modifier_data); + ModifierRuntimeDataBackup::iterator runtime_data_iterator = modifier_runtime_data.find( + modifier_data_id); + if (runtime_data_iterator != modifier_runtime_data.end()) { + modifier_data->runtime = runtime_data_iterator->second; + runtime_data_iterator->second = NULL; + } + } + for (ModifierRuntimeDataBackup::value_type value : modifier_runtime_data) { + const ModifierDataBackupID modifier_data_id = value.first; + void *runtime = value.second; + if (value.second == NULL) { + continue; + } + const ModifierTypeInfo *modifier_type_info = modifierType_getInfo(modifier_data_id.type); + BLI_assert(modifier_type_info != NULL); + modifier_type_info->freeRuntimeData(runtime); + } } class RuntimeBackup { -public: - RuntimeBackup() : drawdata_ptr(NULL) { - drawdata_backup.first = drawdata_backup.last = NULL; - } + public: + RuntimeBackup() : drawdata_ptr(NULL) + { + drawdata_backup.first = drawdata_backup.last = NULL; + } - /* NOTE: Will reset all runbtime fields which has been backed up to NULL. */ - void init_from_id(ID *id); + /* NOTE: Will reset all runbtime fields which has been backed up to NULL. */ + void init_from_id(ID *id); - /* Restore fields to the given ID. */ - void restore_to_id(ID *id); + /* Restore fields to the given ID. */ + void restore_to_id(ID *id); - ObjectRuntimeBackup object_backup; - DrawDataList drawdata_backup; - DrawDataList *drawdata_ptr; + ObjectRuntimeBackup object_backup; + DrawDataList drawdata_backup; + DrawDataList *drawdata_ptr; }; void RuntimeBackup::init_from_id(ID *id) { - if (!check_datablock_expanded(id)) { - return; - } - const ID_Type id_type = GS(id->name); - switch (id_type) { - case ID_OB: - object_backup.init_from_object(reinterpret_cast(id)); - break; - default: - break; - } - /* Note that we never free GPU draw data from here since that's not - * safe for threading and draw data is likely to be re-used. */ - drawdata_ptr = DRW_drawdatalist_from_id(id); - if (drawdata_ptr != NULL) { - drawdata_backup = *drawdata_ptr; - drawdata_ptr->first = drawdata_ptr->last = NULL; - } + if (!check_datablock_expanded(id)) { + return; + } + const ID_Type id_type = GS(id->name); + switch (id_type) { + case ID_OB: + object_backup.init_from_object(reinterpret_cast(id)); + break; + default: + break; + } + /* Note that we never free GPU draw data from here since that's not + * safe for threading and draw data is likely to be re-used. */ + drawdata_ptr = DRW_drawdatalist_from_id(id); + if (drawdata_ptr != NULL) { + drawdata_backup = *drawdata_ptr; + drawdata_ptr->first = drawdata_ptr->last = NULL; + } } void RuntimeBackup::restore_to_id(ID *id) { - const ID_Type id_type = GS(id->name); - switch (id_type) { - case ID_OB: - object_backup.restore_to_object(reinterpret_cast(id)); - break; - default: - break; - } - if (drawdata_ptr != NULL) { - *drawdata_ptr = drawdata_backup; - } + const ID_Type id_type = GS(id->name); + switch (id_type) { + case ID_OB: + object_backup.restore_to_object(reinterpret_cast(id)); + break; + default: + break; + } + if (drawdata_ptr != NULL) { + *drawdata_ptr = drawdata_backup; + } } } // namespace -ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, - const IDNode *id_node) +ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, const IDNode *id_node) { - const ID *id_orig = id_node->id_orig; - ID *id_cow = id_node->id_cow; - /* Similar to expansion, no need to do anything here. */ - if (!deg_copy_on_write_is_needed(id_orig)) { - return id_cow; - } - RuntimeBackup backup; - backup.init_from_id(id_cow); - deg_free_copy_on_write_datablock(id_cow); - deg_expand_copy_on_write_datablock(depsgraph, id_node); - backup.restore_to_id(id_cow); - return id_cow; + const ID *id_orig = id_node->id_orig; + ID *id_cow = id_node->id_cow; + /* Similar to expansion, no need to do anything here. */ + if (!deg_copy_on_write_is_needed(id_orig)) { + return id_cow; + } + RuntimeBackup backup; + backup.init_from_id(id_cow); + deg_free_copy_on_write_datablock(id_cow); + deg_expand_copy_on_write_datablock(depsgraph, id_node); + backup.restore_to_id(id_cow); + return id_cow; } /* NOTE: Depsgraph is supposed to have ID node already. */ -ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, - ID *id_orig) +ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, ID *id_orig) { - DEG::IDNode *id_node = depsgraph->find_id_node(id_orig); - BLI_assert(id_node != NULL); - return deg_update_copy_on_write_datablock(depsgraph, id_node); + DEG::IDNode *id_node = depsgraph->find_id_node(id_orig); + BLI_assert(id_node != NULL); + return deg_update_copy_on_write_datablock(depsgraph, id_node); } namespace { void discard_armature_edit_mode_pointers(ID *id_cow) { - bArmature *armature_cow = (bArmature *)id_cow; - armature_cow->edbo = NULL; + bArmature *armature_cow = (bArmature *)id_cow; + armature_cow->edbo = NULL; } void discard_curve_edit_mode_pointers(ID *id_cow) { - Curve *curve_cow = (Curve *)id_cow; - curve_cow->editnurb = NULL; - curve_cow->editfont = NULL; + Curve *curve_cow = (Curve *)id_cow; + curve_cow->editnurb = NULL; + curve_cow->editfont = NULL; } void discard_mball_edit_mode_pointers(ID *id_cow) { - MetaBall *mball_cow = (MetaBall *)id_cow; - mball_cow->editelems = NULL; + MetaBall *mball_cow = (MetaBall *)id_cow; + mball_cow->editelems = NULL; } void discard_lattice_edit_mode_pointers(ID *id_cow) { - Lattice *lt_cow = (Lattice *)id_cow; - lt_cow->editlatt = NULL; + Lattice *lt_cow = (Lattice *)id_cow; + lt_cow->editlatt = NULL; } void discard_mesh_edit_mode_pointers(ID *id_cow) { - Mesh *mesh_cow = (Mesh *)id_cow; - if (mesh_cow->edit_mesh == NULL) { - return; - } - BKE_editmesh_free_derivedmesh(mesh_cow->edit_mesh); - MEM_freeN(mesh_cow->edit_mesh); - mesh_cow->edit_mesh = NULL; + Mesh *mesh_cow = (Mesh *)id_cow; + if (mesh_cow->edit_mesh == NULL) { + return; + } + BKE_editmesh_free_derivedmesh(mesh_cow->edit_mesh); + MEM_freeN(mesh_cow->edit_mesh); + mesh_cow->edit_mesh = NULL; } void discard_scene_pointers(ID *id_cow) { - Scene *scene_cow = (Scene *)id_cow; - scene_cow->toolsettings = NULL; - scene_cow->eevee.light_cache = NULL; + Scene *scene_cow = (Scene *)id_cow; + scene_cow->toolsettings = NULL; + scene_cow->eevee.light_cache = NULL; } /* NULL-ify all edit mode pointers which points to data from * original object. */ void discard_edit_mode_pointers(ID *id_cow) { - const ID_Type type = GS(id_cow->name); - switch (type) { - case ID_AR: - discard_armature_edit_mode_pointers(id_cow); - break; - case ID_ME: - discard_mesh_edit_mode_pointers(id_cow); - break; - case ID_CU: - discard_curve_edit_mode_pointers(id_cow); - break; - case ID_MB: - discard_mball_edit_mode_pointers(id_cow); - break; - case ID_LT: - discard_lattice_edit_mode_pointers(id_cow); - break; - case ID_SCE: - /* Not really edit mode but still needs to run before - * BKE_libblock_free_datablock() */ - discard_scene_pointers(id_cow); - break; - default: - break; - } + const ID_Type type = GS(id_cow->name); + switch (type) { + case ID_AR: + discard_armature_edit_mode_pointers(id_cow); + break; + case ID_ME: + discard_mesh_edit_mode_pointers(id_cow); + break; + case ID_CU: + discard_curve_edit_mode_pointers(id_cow); + break; + case ID_MB: + discard_mball_edit_mode_pointers(id_cow); + break; + case ID_LT: + discard_lattice_edit_mode_pointers(id_cow); + break; + case ID_SCE: + /* Not really edit mode but still needs to run before + * BKE_libblock_free_datablock() */ + discard_scene_pointers(id_cow); + break; + default: + break; + } } } // namespace @@ -1186,83 +1132,77 @@ void discard_edit_mode_pointers(ID *id_cow) * - Does not free datablock itself. */ void deg_free_copy_on_write_datablock(ID *id_cow) { - if (!check_datablock_expanded(id_cow)) { - /* Actual content was never copied on top of CoW block, we have - * nothing to free. */ - return; - } - const ID_Type type = GS(id_cow->name); + if (!check_datablock_expanded(id_cow)) { + /* Actual content was never copied on top of CoW block, we have + * nothing to free. */ + return; + } + const ID_Type type = GS(id_cow->name); #ifdef NESTED_ID_NASTY_WORKAROUND - nested_id_hack_discard_pointers(id_cow); + nested_id_hack_discard_pointers(id_cow); #endif - switch (type) { - case ID_OB: - { - /* TODO(sergey): This workaround is only to prevent free derived - * caches from modifying object->data. This is currently happening - * due to mesh/curve datablock boundbox tagging dirty. */ - Object *ob_cow = (Object *)id_cow; - ob_cow->data = NULL; - ob_cow->sculpt = NULL; - break; - } - default: - break; - } - discard_edit_mode_pointers(id_cow); - BKE_libblock_free_datablock(id_cow, 0); - BKE_libblock_free_data(id_cow, false); - /* Signal datablock as not being expanded. */ - id_cow->name[0] = '\0'; + switch (type) { + case ID_OB: { + /* TODO(sergey): This workaround is only to prevent free derived + * caches from modifying object->data. This is currently happening + * due to mesh/curve datablock boundbox tagging dirty. */ + Object *ob_cow = (Object *)id_cow; + ob_cow->data = NULL; + ob_cow->sculpt = NULL; + break; + } + default: + break; + } + discard_edit_mode_pointers(id_cow); + BKE_libblock_free_datablock(id_cow, 0); + BKE_libblock_free_data(id_cow, false); + /* Signal datablock as not being expanded. */ + id_cow->name[0] = '\0'; } -void deg_evaluate_copy_on_write(struct ::Depsgraph *graph, - const IDNode *id_node) +void deg_evaluate_copy_on_write(struct ::Depsgraph *graph, const IDNode *id_node) { - const DEG::Depsgraph *depsgraph = reinterpret_cast(graph); - DEG_debug_print_eval(graph, __func__, id_node->id_orig->name, id_node->id_cow); - if (id_node->id_orig == &depsgraph->scene->id) { - /* NOTE: This is handled by eval_ctx setup routines, which - * ensures scene and view layer pointers are valid. */ - return; - } - deg_update_copy_on_write_datablock(depsgraph, id_node); + const DEG::Depsgraph *depsgraph = reinterpret_cast(graph); + DEG_debug_print_eval(graph, __func__, id_node->id_orig->name, id_node->id_cow); + if (id_node->id_orig == &depsgraph->scene->id) { + /* NOTE: This is handled by eval_ctx setup routines, which + * ensures scene and view layer pointers are valid. */ + return; + } + deg_update_copy_on_write_datablock(depsgraph, id_node); } bool deg_validate_copy_on_write_datablock(ID *id_cow) { - if (id_cow == NULL) { - return false; - } - ValidateData data; - data.is_valid = true; - BKE_library_foreach_ID_link(NULL, - id_cow, - foreach_libblock_validate_callback, - &data, - IDWALK_NOP); - return data.is_valid; + if (id_cow == NULL) { + return false; + } + ValidateData data; + data.is_valid = true; + BKE_library_foreach_ID_link(NULL, id_cow, foreach_libblock_validate_callback, &data, IDWALK_NOP); + return data.is_valid; } void deg_tag_copy_on_write_id(ID *id_cow, const ID *id_orig) { - BLI_assert(id_cow != id_orig); - BLI_assert((id_orig->tag & LIB_TAG_COPIED_ON_WRITE) == 0); - id_cow->tag |= LIB_TAG_COPIED_ON_WRITE; - /* This ID is no longer localized, is a self-sustaining copy now. */ - id_cow->tag &= ~LIB_TAG_LOCALIZED; - id_cow->orig_id = (ID *)id_orig; + BLI_assert(id_cow != id_orig); + BLI_assert((id_orig->tag & LIB_TAG_COPIED_ON_WRITE) == 0); + id_cow->tag |= LIB_TAG_COPIED_ON_WRITE; + /* This ID is no longer localized, is a self-sustaining copy now. */ + id_cow->tag &= ~LIB_TAG_LOCALIZED; + id_cow->orig_id = (ID *)id_orig; } bool deg_copy_on_write_is_expanded(const ID *id_cow) { - return check_datablock_expanded(id_cow); + return check_datablock_expanded(id_cow); } bool deg_copy_on_write_is_needed(const ID *id_orig) { - const ID_Type id_type = GS(id_orig->name); - return !ELEM(id_type, ID_IM); + const ID_Type id_type = GS(id_orig->name); + return !ELEM(id_type, ID_IM); } } // namespace DEG diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h index 6f9141a7c19..c913bb0f3f2 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h @@ -62,10 +62,8 @@ ID *deg_expand_copy_on_write_datablock(const struct Depsgraph *depsgraph, /* Makes sure given CoW datablock is brought back to state of the original * datablock. */ -ID *deg_update_copy_on_write_datablock(const struct Depsgraph *depsgraph, - const IDNode *id_node); -ID *deg_update_copy_on_write_datablock(const struct Depsgraph *depsgraph, - struct ID *id_orig); +ID *deg_update_copy_on_write_datablock(const struct Depsgraph *depsgraph, const IDNode *id_node); +ID *deg_update_copy_on_write_datablock(const struct Depsgraph *depsgraph, struct ID *id_orig); /* Helper function which frees memory used by copy-on-written databnlock. */ void deg_free_copy_on_write_datablock(struct ID *id_cow); @@ -73,8 +71,7 @@ void deg_free_copy_on_write_datablock(struct ID *id_cow); /* Callback function for depsgraph operation node which ensures copy-on-write * datablock is ready for use by further evaluation routines. */ -void deg_evaluate_copy_on_write(struct ::Depsgraph *depsgraph, - const struct IDNode *id_node); +void deg_evaluate_copy_on_write(struct ::Depsgraph *depsgraph, const struct IDNode *id_node); /* Check that given ID is properly expanded and does not have any shallow * copies inside. diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc index 08c7b87d5e3..0bd5b3b4f82 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc @@ -70,83 +70,75 @@ extern "C" { namespace DEG { enum { - ID_STATE_NONE = 0, - ID_STATE_MODIFIED = 1, + ID_STATE_NONE = 0, + ID_STATE_MODIFIED = 1, }; enum { - COMPONENT_STATE_NONE = 0, - COMPONENT_STATE_SCHEDULED = 1, - COMPONENT_STATE_DONE = 2, + COMPONENT_STATE_NONE = 0, + COMPONENT_STATE_SCHEDULED = 1, + COMPONENT_STATE_DONE = 2, }; typedef std::deque FlushQueue; namespace { -void flush_init_operation_node_func( - void *__restrict data_v, - const int i, - const ParallelRangeTLS *__restrict /*tls*/) +void flush_init_operation_node_func(void *__restrict data_v, + const int i, + const ParallelRangeTLS *__restrict /*tls*/) { - Depsgraph *graph = (Depsgraph *)data_v; - OperationNode *node = graph->operations[i]; - node->scheduled = false; + Depsgraph *graph = (Depsgraph *)data_v; + OperationNode *node = graph->operations[i]; + node->scheduled = false; } -void flush_init_id_node_func( - void *__restrict data_v, - const int i, - const ParallelRangeTLS *__restrict /*tls*/) +void flush_init_id_node_func(void *__restrict data_v, + const int i, + const ParallelRangeTLS *__restrict /*tls*/) { - Depsgraph *graph = (Depsgraph *)data_v; - IDNode *id_node = graph->id_nodes[i]; - id_node->custom_flags = ID_STATE_NONE; - GHASH_FOREACH_BEGIN(ComponentNode *, comp_node, id_node->components) - comp_node->custom_flags = COMPONENT_STATE_NONE; - GHASH_FOREACH_END(); + Depsgraph *graph = (Depsgraph *)data_v; + IDNode *id_node = graph->id_nodes[i]; + id_node->custom_flags = ID_STATE_NONE; + GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) + comp_node->custom_flags = COMPONENT_STATE_NONE; + GHASH_FOREACH_END(); } BLI_INLINE void flush_prepare(Depsgraph *graph) { - { - const int num_operations = graph->operations.size(); - ParallelRangeSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.min_iter_per_thread = 1024; - BLI_task_parallel_range(0, num_operations, - graph, - flush_init_operation_node_func, - &settings); - } - { - const int num_id_nodes = graph->id_nodes.size(); - ParallelRangeSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.min_iter_per_thread = 1024; - BLI_task_parallel_range(0, num_id_nodes, - graph, - flush_init_id_node_func, - &settings); - } + { + const int num_operations = graph->operations.size(); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = 1024; + BLI_task_parallel_range(0, num_operations, graph, flush_init_operation_node_func, &settings); + } + { + const int num_id_nodes = graph->id_nodes.size(); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = 1024; + BLI_task_parallel_range(0, num_id_nodes, graph, flush_init_id_node_func, &settings); + } } BLI_INLINE void flush_schedule_entrypoints(Depsgraph *graph, FlushQueue *queue) { - GSET_FOREACH_BEGIN(OperationNode *, op_node, graph->entry_tags) - { - queue->push_back(op_node); - op_node->scheduled = true; - DEG_DEBUG_PRINTF((::Depsgraph *)graph, - EVAL, "Operation is entry point for update: %s\n", - op_node->identifier().c_str()); - } - GSET_FOREACH_END(); + GSET_FOREACH_BEGIN (OperationNode *, op_node, graph->entry_tags) { + queue->push_back(op_node); + op_node->scheduled = true; + DEG_DEBUG_PRINTF((::Depsgraph *)graph, + EVAL, + "Operation is entry point for update: %s\n", + op_node->identifier().c_str()); + } + GSET_FOREACH_END(); } BLI_INLINE void flush_handle_id_node(IDNode *id_node) { - id_node->custom_flags = ID_STATE_MODIFIED; + id_node->custom_flags = ID_STATE_MODIFIED; } /* TODO(sergey): We can reduce number of arguments here. */ @@ -154,33 +146,31 @@ BLI_INLINE void flush_handle_component_node(IDNode *id_node, ComponentNode *comp_node, FlushQueue *queue) { - /* We only handle component once. */ - if (comp_node->custom_flags == COMPONENT_STATE_DONE) { - return; - } - comp_node->custom_flags = COMPONENT_STATE_DONE; - /* Tag all required operations in component for update, unless this is a - * special component where we don't want all operations to be tagged. - * - * TODO(sergey): Make this a more generic solution. */ - if (comp_node->type != NodeType::PARTICLE_SETTINGS && - comp_node->type != NodeType::PARTICLE_SYSTEM) - { - for (OperationNode *op : comp_node->operations) { - op->flag |= DEPSOP_FLAG_NEEDS_UPDATE; - } - } - /* when some target changes bone, we might need to re-run the - * whole IK solver, otherwise result might be unpredictable. */ - if (comp_node->type == NodeType::BONE) { - ComponentNode *pose_comp = - id_node->find_component(NodeType::EVAL_POSE); - BLI_assert(pose_comp != NULL); - if (pose_comp->custom_flags == COMPONENT_STATE_NONE) { - queue->push_front(pose_comp->get_entry_operation()); - pose_comp->custom_flags = COMPONENT_STATE_SCHEDULED; - } - } + /* We only handle component once. */ + if (comp_node->custom_flags == COMPONENT_STATE_DONE) { + return; + } + comp_node->custom_flags = COMPONENT_STATE_DONE; + /* Tag all required operations in component for update, unless this is a + * special component where we don't want all operations to be tagged. + * + * TODO(sergey): Make this a more generic solution. */ + if (comp_node->type != NodeType::PARTICLE_SETTINGS && + comp_node->type != NodeType::PARTICLE_SYSTEM) { + for (OperationNode *op : comp_node->operations) { + op->flag |= DEPSOP_FLAG_NEEDS_UPDATE; + } + } + /* when some target changes bone, we might need to re-run the + * whole IK solver, otherwise result might be unpredictable. */ + if (comp_node->type == NodeType::BONE) { + ComponentNode *pose_comp = id_node->find_component(NodeType::EVAL_POSE); + BLI_assert(pose_comp != NULL); + if (pose_comp->custom_flags == COMPONENT_STATE_NONE) { + queue->push_front(pose_comp->get_entry_operation()); + pose_comp->custom_flags = COMPONENT_STATE_SCHEDULED; + } + } } /* Schedule children of the given operation node for traversal. @@ -189,168 +179,161 @@ BLI_INLINE void flush_handle_component_node(IDNode *id_node, * return value, so it can start being handled right away, without building too * much of a queue. */ -BLI_INLINE OperationNode *flush_schedule_children( - OperationNode *op_node, - FlushQueue *queue) +BLI_INLINE OperationNode *flush_schedule_children(OperationNode *op_node, FlushQueue *queue) { - OperationNode *result = NULL; - for (Relation *rel : op_node->outlinks) { - /* Flush is forbidden, completely. */ - if (rel->flag & RELATION_FLAG_NO_FLUSH) { - continue; - } - /* Relation only allows flushes on user changes, but the node was not - * affected by user. */ - if ((rel->flag & RELATION_FLAG_FLUSH_USER_EDIT_ONLY) && - (op_node->flag & DEPSOP_FLAG_USER_MODIFIED) == 0) - { - continue; - } - OperationNode *to_node = (OperationNode *)rel->to; - /* Always flush flushable flags, so children always know what happened - * to their parents. */ - to_node->flag |= (op_node->flag & DEPSOP_FLAG_FLUSH); - /* Flush update over the relation, if it was not flushed yet. */ - if (to_node->scheduled) { - continue; - } - if (result != NULL) { - queue->push_front(to_node); - } - else { - result = to_node; - } - to_node->scheduled = true; - } - return result; + OperationNode *result = NULL; + for (Relation *rel : op_node->outlinks) { + /* Flush is forbidden, completely. */ + if (rel->flag & RELATION_FLAG_NO_FLUSH) { + continue; + } + /* Relation only allows flushes on user changes, but the node was not + * affected by user. */ + if ((rel->flag & RELATION_FLAG_FLUSH_USER_EDIT_ONLY) && + (op_node->flag & DEPSOP_FLAG_USER_MODIFIED) == 0) { + continue; + } + OperationNode *to_node = (OperationNode *)rel->to; + /* Always flush flushable flags, so children always know what happened + * to their parents. */ + to_node->flag |= (op_node->flag & DEPSOP_FLAG_FLUSH); + /* Flush update over the relation, if it was not flushed yet. */ + if (to_node->scheduled) { + continue; + } + if (result != NULL) { + queue->push_front(to_node); + } + else { + result = to_node; + } + to_node->scheduled = true; + } + return result; } void flush_engine_data_update(ID *id) { - DrawDataList *draw_data_list = DRW_drawdatalist_from_id(id); - if (draw_data_list == NULL) { - return; - } - LISTBASE_FOREACH (DrawData *, draw_data, draw_data_list) { - draw_data->recalc |= id->recalc; - } + DrawDataList *draw_data_list = DRW_drawdatalist_from_id(id); + if (draw_data_list == NULL) { + return; + } + LISTBASE_FOREACH (DrawData *, draw_data, draw_data_list) { + draw_data->recalc |= id->recalc; + } } /* NOTE: It will also accumulate flags from changed components. */ -void flush_editors_id_update(Depsgraph *graph, - const DEGEditorUpdateContext *update_ctx) +void flush_editors_id_update(Depsgraph *graph, const DEGEditorUpdateContext *update_ctx) { - for (IDNode *id_node : graph->id_nodes) { - if (id_node->custom_flags != ID_STATE_MODIFIED) { - continue; - } - DEG_graph_id_type_tag(reinterpret_cast<::Depsgraph*>(graph), - GS(id_node->id_orig->name)); - /* TODO(sergey): Do we need to pass original or evaluated ID here? */ - ID *id_orig = id_node->id_orig; - ID *id_cow = id_node->id_cow; - /* Copy tag from original data to CoW storage. - * This is because DEG_id_tag_update() sets tags on original - * data. */ - id_cow->recalc |= (id_orig->recalc & ID_RECALC_ALL); - /* Gather recalc flags from all changed components. */ - GHASH_FOREACH_BEGIN(ComponentNode *, comp_node, id_node->components) - { - if (comp_node->custom_flags != COMPONENT_STATE_DONE) { - continue; - } - DepsNodeFactory *factory = type_get_factory(comp_node->type); - BLI_assert(factory != NULL); - id_cow->recalc |= factory->id_recalc_tag(); - } - GHASH_FOREACH_END(); - DEG_DEBUG_PRINTF((::Depsgraph *)graph, - EVAL, "Accumulated recalc bits for %s: %u\n", - id_orig->name, (unsigned int)id_cow->recalc); - - /* Inform editors. Only if the datablock is being evaluated a second - * time, to distinguish between user edits and initial evaluation when - * the datablock becomes visible. - * - * TODO: image datablocks do not use COW, so might not be detected - * correctly. */ - if (deg_copy_on_write_is_expanded(id_cow)) { - if (graph->is_active) { - deg_editors_id_update(update_ctx, id_orig); - } - /* ID may need to get its auto-override operations refreshed. */ - if (ID_IS_STATIC_OVERRIDE_AUTO(id_orig)) { - id_orig->tag |= LIB_TAG_OVERRIDESTATIC_AUTOREFRESH; - } - /* Inform draw engines that something was changed. */ - flush_engine_data_update(id_cow); - } - } + for (IDNode *id_node : graph->id_nodes) { + if (id_node->custom_flags != ID_STATE_MODIFIED) { + continue; + } + DEG_graph_id_type_tag(reinterpret_cast<::Depsgraph *>(graph), GS(id_node->id_orig->name)); + /* TODO(sergey): Do we need to pass original or evaluated ID here? */ + ID *id_orig = id_node->id_orig; + ID *id_cow = id_node->id_cow; + /* Copy tag from original data to CoW storage. + * This is because DEG_id_tag_update() sets tags on original + * data. */ + id_cow->recalc |= (id_orig->recalc & ID_RECALC_ALL); + /* Gather recalc flags from all changed components. */ + GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) { + if (comp_node->custom_flags != COMPONENT_STATE_DONE) { + continue; + } + DepsNodeFactory *factory = type_get_factory(comp_node->type); + BLI_assert(factory != NULL); + id_cow->recalc |= factory->id_recalc_tag(); + } + GHASH_FOREACH_END(); + DEG_DEBUG_PRINTF((::Depsgraph *)graph, + EVAL, + "Accumulated recalc bits for %s: %u\n", + id_orig->name, + (unsigned int)id_cow->recalc); + + /* Inform editors. Only if the datablock is being evaluated a second + * time, to distinguish between user edits and initial evaluation when + * the datablock becomes visible. + * + * TODO: image datablocks do not use COW, so might not be detected + * correctly. */ + if (deg_copy_on_write_is_expanded(id_cow)) { + if (graph->is_active) { + deg_editors_id_update(update_ctx, id_orig); + } + /* ID may need to get its auto-override operations refreshed. */ + if (ID_IS_STATIC_OVERRIDE_AUTO(id_orig)) { + id_orig->tag |= LIB_TAG_OVERRIDESTATIC_AUTOREFRESH; + } + /* Inform draw engines that something was changed. */ + flush_engine_data_update(id_cow); + } + } } #ifdef INVALIDATE_ON_FLUSH void invalidate_tagged_evaluated_transform(ID *id) { - const ID_Type id_type = GS(id->name); - switch (id_type) { - case ID_OB: - { - Object *object = (Object *)id; - copy_vn_fl((float *)object->obmat, 16, NAN); - break; - } - default: - break; - } + const ID_Type id_type = GS(id->name); + switch (id_type) { + case ID_OB: { + Object *object = (Object *)id; + copy_vn_fl((float *)object->obmat, 16, NAN); + break; + } + default: + break; + } } void invalidate_tagged_evaluated_geometry(ID *id) { - const ID_Type id_type = GS(id->name); - switch (id_type) { - case ID_OB: - { - Object *object = (Object *)id; - BKE_object_free_derived_caches(object); - break; - } - default: - break; - } + const ID_Type id_type = GS(id->name); + switch (id_type) { + case ID_OB: { + Object *object = (Object *)id; + BKE_object_free_derived_caches(object); + break; + } + default: + break; + } } #endif void invalidate_tagged_evaluated_data(Depsgraph *graph) { #ifdef INVALIDATE_ON_FLUSH - for (IDNode *id_node : graph->id_nodes) { - if (id_node->custom_flags != ID_STATE_MODIFIED) { - continue; - } - ID *id_cow = id_node->id_cow; - if (!deg_copy_on_write_is_expanded(id_cow)) { - continue; - } - GHASH_FOREACH_BEGIN(ComponentNode *, comp_node, id_node->components) - { - if (comp_node->custom_flags != COMPONENT_STATE_DONE) { - continue; - } - switch (comp_node->type) { - case ID_RECALC_TRANSFORM: - invalidate_tagged_evaluated_transform(id_cow); - break; - case ID_RECALC_GEOMETRY: - invalidate_tagged_evaluated_geometry(id_cow); - break; - default: - break; - } - } - GHASH_FOREACH_END(); - } + for (IDNode *id_node : graph->id_nodes) { + if (id_node->custom_flags != ID_STATE_MODIFIED) { + continue; + } + ID *id_cow = id_node->id_cow; + if (!deg_copy_on_write_is_expanded(id_cow)) { + continue; + } + GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) { + if (comp_node->custom_flags != COMPONENT_STATE_DONE) { + continue; + } + switch (comp_node->type) { + case ID_RECALC_TRANSFORM: + invalidate_tagged_evaluated_transform(id_cow); + break; + case ID_RECALC_GEOMETRY: + invalidate_tagged_evaluated_geometry(id_cow); + break; + default: + break; + } + } + GHASH_FOREACH_END(); + } #else - (void) graph; + (void)graph; #endif } @@ -361,76 +344,71 @@ void invalidate_tagged_evaluated_data(Depsgraph *graph) */ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph) { - /* Sanity checks. */ - BLI_assert(bmain != NULL); - BLI_assert(graph != NULL); - /* Nothing to update, early out. */ - if (BLI_gset_len(graph->entry_tags) == 0) { - return; - } - /* Reset all flags, get ready for the flush. */ - flush_prepare(graph); - /* Starting from the tagged "entry" nodes, flush outwards. */ - FlushQueue queue; - flush_schedule_entrypoints(graph, &queue); - /* Prepare update context for editors. */ - DEGEditorUpdateContext update_ctx; - update_ctx.bmain = bmain; - update_ctx.depsgraph = (::Depsgraph *)graph; - update_ctx.scene = graph->scene; - update_ctx.view_layer = graph->view_layer; - /* Do actual flush. */ - while (!queue.empty()) { - OperationNode *op_node = queue.front(); - queue.pop_front(); - while (op_node != NULL) { - /* Tag operation as required for update. */ - op_node->flag |= DEPSOP_FLAG_NEEDS_UPDATE; - /* Inform corresponding ID and component nodes about the change. */ - ComponentNode *comp_node = op_node->owner; - IDNode *id_node = comp_node->owner; - flush_handle_id_node(id_node); - flush_handle_component_node(id_node, comp_node, &queue); - /* Flush to nodes along links. */ - op_node = flush_schedule_children(op_node, &queue); - } - } - /* Inform editors about all changes. */ - flush_editors_id_update(graph, &update_ctx); - /* Reset evaluation result tagged which is tagged for update to some state - * which is obvious to catch. */ - invalidate_tagged_evaluated_data(graph); + /* Sanity checks. */ + BLI_assert(bmain != NULL); + BLI_assert(graph != NULL); + /* Nothing to update, early out. */ + if (BLI_gset_len(graph->entry_tags) == 0) { + return; + } + /* Reset all flags, get ready for the flush. */ + flush_prepare(graph); + /* Starting from the tagged "entry" nodes, flush outwards. */ + FlushQueue queue; + flush_schedule_entrypoints(graph, &queue); + /* Prepare update context for editors. */ + DEGEditorUpdateContext update_ctx; + update_ctx.bmain = bmain; + update_ctx.depsgraph = (::Depsgraph *)graph; + update_ctx.scene = graph->scene; + update_ctx.view_layer = graph->view_layer; + /* Do actual flush. */ + while (!queue.empty()) { + OperationNode *op_node = queue.front(); + queue.pop_front(); + while (op_node != NULL) { + /* Tag operation as required for update. */ + op_node->flag |= DEPSOP_FLAG_NEEDS_UPDATE; + /* Inform corresponding ID and component nodes about the change. */ + ComponentNode *comp_node = op_node->owner; + IDNode *id_node = comp_node->owner; + flush_handle_id_node(id_node); + flush_handle_component_node(id_node, comp_node, &queue); + /* Flush to nodes along links. */ + op_node = flush_schedule_children(op_node, &queue); + } + } + /* Inform editors about all changes. */ + flush_editors_id_update(graph, &update_ctx); + /* Reset evaluation result tagged which is tagged for update to some state + * which is obvious to catch. */ + invalidate_tagged_evaluated_data(graph); } -static void graph_clear_operation_func( - void *__restrict data_v, - const int i, - const ParallelRangeTLS *__restrict /*tls*/) +static void graph_clear_operation_func(void *__restrict data_v, + const int i, + const ParallelRangeTLS *__restrict /*tls*/) { - Depsgraph *graph = (Depsgraph *)data_v; - OperationNode *node = graph->operations[i]; - /* Clear node's "pending update" settings. */ - node->flag &= ~(DEPSOP_FLAG_DIRECTLY_MODIFIED | - DEPSOP_FLAG_NEEDS_UPDATE | - DEPSOP_FLAG_USER_MODIFIED); + Depsgraph *graph = (Depsgraph *)data_v; + OperationNode *node = graph->operations[i]; + /* Clear node's "pending update" settings. */ + node->flag &= ~(DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE | + DEPSOP_FLAG_USER_MODIFIED); } /* Clear tags from all operation nodes. */ void deg_graph_clear_tags(Depsgraph *graph) { - /* Go over all operation nodes, clearing tags. */ - { - const int num_operations = graph->operations.size(); - ParallelRangeSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.min_iter_per_thread = 1024; - BLI_task_parallel_range(0, num_operations, - graph, - graph_clear_operation_func, - &settings); - } - /* Clear any entry tags which haven't been flushed. */ - BLI_gset_clear(graph->entry_tags, NULL); + /* Go over all operation nodes, clearing tags. */ + { + const int num_operations = graph->operations.size(); + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = 1024; + BLI_task_parallel_range(0, num_operations, graph, graph_clear_operation_func, &settings); + } + /* Clear any entry tags which haven't been flushed. */ + BLI_gset_clear(graph->entry_tags, NULL); } } // namespace DEG diff --git a/source/blender/depsgraph/intern/eval/deg_eval_stats.cc b/source/blender/depsgraph/intern/eval/deg_eval_stats.cc index 0bf525a0e19..25c32e88021 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_stats.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_stats.cc @@ -37,24 +37,23 @@ namespace DEG { void deg_eval_stats_aggregate(Depsgraph *graph) { - /* Reset current evaluation stats for ID and component nodes. - * Those are not filled in by the evaluation engine. */ - for (Node *node : graph->id_nodes) { - IDNode *id_node = (IDNode *)node; - GHASH_FOREACH_BEGIN(ComponentNode *, comp_node, id_node->components) - { - comp_node->stats.reset_current(); - } - GHASH_FOREACH_END(); - id_node->stats.reset_current(); - } - /* Now accumulate operation timings to components and IDs. */ - for (OperationNode *op_node : graph->operations) { - ComponentNode *comp_node = op_node->owner; - IDNode *id_node = comp_node->owner; - id_node->stats.current_time += op_node->stats.current_time; - comp_node->stats.current_time += op_node->stats.current_time; - } + /* Reset current evaluation stats for ID and component nodes. + * Those are not filled in by the evaluation engine. */ + for (Node *node : graph->id_nodes) { + IDNode *id_node = (IDNode *)node; + GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) { + comp_node->stats.reset_current(); + } + GHASH_FOREACH_END(); + id_node->stats.reset_current(); + } + /* Now accumulate operation timings to components and IDs. */ + for (OperationNode *op_node : graph->operations) { + ComponentNode *comp_node = op_node->owner; + IDNode *id_node = comp_node->owner; + id_node->stats.current_time += op_node->stats.current_time; + comp_node->stats.current_time += op_node->stats.current_time; + } } } // namespace DEG diff --git a/source/blender/depsgraph/intern/node/deg_node.cc b/source/blender/depsgraph/intern/node/deg_node.cc index 1eaee3d9e5b..5692983fbe2 100644 --- a/source/blender/depsgraph/intern/node/deg_node.cc +++ b/source/blender/depsgraph/intern/node/deg_node.cc @@ -39,67 +39,92 @@ namespace DEG { const char *nodeClassAsString(NodeClass node_class) { - switch (node_class) { - case NodeClass::GENERIC: return "GENERIC"; - case NodeClass::COMPONENT: return "COMPONENT"; - case NodeClass::OPERATION: return "OPERATION"; - } - BLI_assert(!"Unhandled node class, should never happen."); - return "UNKNOWN"; + switch (node_class) { + case NodeClass::GENERIC: + return "GENERIC"; + case NodeClass::COMPONENT: + return "COMPONENT"; + case NodeClass::OPERATION: + return "OPERATION"; + } + BLI_assert(!"Unhandled node class, should never happen."); + return "UNKNOWN"; } const char *nodeTypeAsString(NodeType type) { - switch (type) { - case NodeType::UNDEFINED: return "UNDEFINED"; - case NodeType::OPERATION: return "OPERATION"; - /* **** Generic Types **** */ - case NodeType::TIMESOURCE: return "TIMESOURCE"; - case NodeType::ID_REF: return "ID_REF"; - /* **** Outer Types **** */ - case NodeType::PARAMETERS: return "PARAMETERS"; - case NodeType::PROXY: return "PROXY"; - case NodeType::ANIMATION: return "ANIMATION"; - case NodeType::TRANSFORM: return "TRANSFORM"; - case NodeType::GEOMETRY: return "GEOMETRY"; - case NodeType::SEQUENCER: return "SEQUENCER"; - case NodeType::LAYER_COLLECTIONS: return "LAYER_COLLECTIONS"; - case NodeType::COPY_ON_WRITE: return "COPY_ON_WRITE"; - case NodeType::OBJECT_FROM_LAYER: return "OBJECT_FROM_LAYER"; - /* **** Evaluation-Related Outer Types (with Subdata) **** */ - case NodeType::EVAL_POSE: return "EVAL_POSE"; - case NodeType::BONE: return "BONE"; - case NodeType::PARTICLE_SYSTEM: return "PARTICLE_SYSTEM"; - case NodeType::PARTICLE_SETTINGS: return "PARTICLE_SETTINGS"; - case NodeType::SHADING: return "SHADING"; - case NodeType::SHADING_PARAMETERS: return "SHADING_PARAMETERS"; - case NodeType::CACHE: return "CACHE"; - case NodeType::POINT_CACHE: return "POINT_CACHE"; - case NodeType::BATCH_CACHE: return "BATCH_CACHE"; - /* Duplication. */ - case NodeType::DUPLI: return "DUPLI"; - /* Synchronization. */ - case NodeType::SYNCHRONIZATION: return "SYNCHRONIZATION"; - /* Generic datablock. */ - case NodeType::GENERIC_DATABLOCK: return "GENERIC_DATABLOCK"; - - /* Total number of meaningful node types. */ - case NodeType::NUM_TYPES: return "SpecialCase"; - } - BLI_assert(!"Unhandled node type, should never happen."); - return "UNKNOWN"; + switch (type) { + case NodeType::UNDEFINED: + return "UNDEFINED"; + case NodeType::OPERATION: + return "OPERATION"; + /* **** Generic Types **** */ + case NodeType::TIMESOURCE: + return "TIMESOURCE"; + case NodeType::ID_REF: + return "ID_REF"; + /* **** Outer Types **** */ + case NodeType::PARAMETERS: + return "PARAMETERS"; + case NodeType::PROXY: + return "PROXY"; + case NodeType::ANIMATION: + return "ANIMATION"; + case NodeType::TRANSFORM: + return "TRANSFORM"; + case NodeType::GEOMETRY: + return "GEOMETRY"; + case NodeType::SEQUENCER: + return "SEQUENCER"; + case NodeType::LAYER_COLLECTIONS: + return "LAYER_COLLECTIONS"; + case NodeType::COPY_ON_WRITE: + return "COPY_ON_WRITE"; + case NodeType::OBJECT_FROM_LAYER: + return "OBJECT_FROM_LAYER"; + /* **** Evaluation-Related Outer Types (with Subdata) **** */ + case NodeType::EVAL_POSE: + return "EVAL_POSE"; + case NodeType::BONE: + return "BONE"; + case NodeType::PARTICLE_SYSTEM: + return "PARTICLE_SYSTEM"; + case NodeType::PARTICLE_SETTINGS: + return "PARTICLE_SETTINGS"; + case NodeType::SHADING: + return "SHADING"; + case NodeType::SHADING_PARAMETERS: + return "SHADING_PARAMETERS"; + case NodeType::CACHE: + return "CACHE"; + case NodeType::POINT_CACHE: + return "POINT_CACHE"; + case NodeType::BATCH_CACHE: + return "BATCH_CACHE"; + /* Duplication. */ + case NodeType::DUPLI: + return "DUPLI"; + /* Synchronization. */ + case NodeType::SYNCHRONIZATION: + return "SYNCHRONIZATION"; + /* Generic datablock. */ + case NodeType::GENERIC_DATABLOCK: + return "GENERIC_DATABLOCK"; + + /* Total number of meaningful node types. */ + case NodeType::NUM_TYPES: + return "SpecialCase"; + } + BLI_assert(!"Unhandled node type, should never happen."); + return "UNKNOWN"; } /******************************************************************************* * Type information. */ -Node::TypeInfo::TypeInfo(NodeType type, - const char *type_name, - int id_recalc_tag) - : type(type), - type_name(type_name), - id_recalc_tag(id_recalc_tag) +Node::TypeInfo::TypeInfo(NodeType type, const char *type_name, int id_recalc_tag) + : type(type), type_name(type_name), id_recalc_tag(id_recalc_tag) { } @@ -109,17 +134,17 @@ Node::TypeInfo::TypeInfo(NodeType type, Node::Stats::Stats() { - reset(); + reset(); } void Node::Stats::reset() { - current_time = 0.0; + current_time = 0.0; } void Node::Stats::reset_current() { - current_time = 0.0; + current_time = 0.0; } /******************************************************************************* @@ -128,37 +153,37 @@ void Node::Stats::reset_current() Node::Node() { - name = ""; + name = ""; } Node::~Node() { - /* Free links. */ - /* NOTE: We only free incoming links. This is to avoid double-free of links - * when we're trying to free same link from both it's sides. We don't have - * dangling links so this is not a problem from memory leaks point of view. */ - for (Relation *rel : inlinks) { - OBJECT_GUARDED_DELETE(rel, Relation); - } + /* Free links. */ + /* NOTE: We only free incoming links. This is to avoid double-free of links + * when we're trying to free same link from both it's sides. We don't have + * dangling links so this is not a problem from memory leaks point of view. */ + for (Relation *rel : inlinks) { + OBJECT_GUARDED_DELETE(rel, Relation); + } } - /* Generic identifier for Depsgraph Nodes. */ string Node::identifier() const { - return string(nodeTypeAsString(type)) + " : " + name; + return string(nodeTypeAsString(type)) + " : " + name; } -NodeClass Node::get_class() const { - if (type == NodeType::OPERATION) { - return NodeClass::OPERATION; - } - else if (type < NodeType::PARAMETERS) { - return NodeClass::GENERIC; - } - else { - return NodeClass::COMPONENT; - } +NodeClass Node::get_class() const +{ + if (type == NodeType::OPERATION) { + return NodeClass::OPERATION; + } + else if (type < NodeType::PARAMETERS) { + return NodeClass::GENERIC; + } + else { + return NodeClass::COMPONENT; + } } /******************************************************************************* @@ -173,8 +198,8 @@ static DepsNodeFactoryImpl DNTI_ID_REF; void deg_register_base_depsnodes() { - register_node_typeinfo(&DNTI_TIMESOURCE); - register_node_typeinfo(&DNTI_ID_REF); + register_node_typeinfo(&DNTI_TIMESOURCE); + register_node_typeinfo(&DNTI_ID_REF); } } // namespace DEG diff --git a/source/blender/depsgraph/intern/node/deg_node.h b/source/blender/depsgraph/intern/node/deg_node.h index 0677b0edc15..ece43657b38 100644 --- a/source/blender/depsgraph/intern/node/deg_node.h +++ b/source/blender/depsgraph/intern/node/deg_node.h @@ -40,154 +40,161 @@ struct Relation; /* Metatype of Nodes - The general "level" in the graph structure * the node serves. */ enum class NodeClass { - /* Types generally unassociated with user-visible entities, - * but needed for graph functioning. */ - GENERIC = 0, - /* [Outer Node] An "aspect" of evaluating/updating an ID-Block, requiring - * certain types of evaluation behavior. */ - COMPONENT = 1, - /* [Inner Node] A glorified function-pointer/callback for scheduling up - * evaluation operations for components, subject to relationship - * requirements. */ - OPERATION = 2, + /* Types generally unassociated with user-visible entities, + * but needed for graph functioning. */ + GENERIC = 0, + /* [Outer Node] An "aspect" of evaluating/updating an ID-Block, requiring + * certain types of evaluation behavior. */ + COMPONENT = 1, + /* [Inner Node] A glorified function-pointer/callback for scheduling up + * evaluation operations for components, subject to relationship + * requirements. */ + OPERATION = 2, }; const char *nodeClassAsString(NodeClass node_class); /* Types of Nodes */ enum class NodeType { - /* Fallback type for invalid return value */ - UNDEFINED = 0, - /* Inner Node (Operation) */ - OPERATION, - - /* **** Generic Types **** */ - - /* Time-Source */ - TIMESOURCE, - /* ID-Block reference - used as landmarks/collection point for components, - * but not usually part of main graph. */ - ID_REF, - - /* **** Outer Types **** */ - - /* Parameters Component - Default when nothing else fits - * (i.e. just SDNA property setting). */ - PARAMETERS, - /* Generic "Proxy-Inherit" Component. */ - PROXY, - /* Animation Component */ - ANIMATION, - /* Transform Component (Parenting/Constraints) */ - TRANSFORM, - /* Geometry Component (Mesh/Displist) */ - GEOMETRY, - /* Sequencer Component (Scene Only) */ - SEQUENCER, - /* Component which contains all operations needed for layer collections - * evaluation. */ - LAYER_COLLECTIONS, - /* Entry component of majority of ID nodes: prepares CoW pointers for - * execution. */ - COPY_ON_WRITE, - /* Used by all operations which are updating object when something is - * changed in view layer. */ - OBJECT_FROM_LAYER, - /* Un-interestying datablock, which is a part of dependency graph, but does - * not have very distinctive update procedure. */ - GENERIC_DATABLOCK, - - /* **** Evaluation-Related Outer Types (with Subdata) **** */ - - /* Pose Component - Owner/Container of Bones Eval */ - EVAL_POSE, - /* Bone Component - Child/Subcomponent of Pose */ - BONE, - /* Particle Systems Component */ - PARTICLE_SYSTEM, - PARTICLE_SETTINGS, - /* Material Shading Component */ - SHADING, - SHADING_PARAMETERS, - /* Point cache Component */ - POINT_CACHE, - /* Cache Component */ - /* TODO(sergey); Verify that we really need this. */ - CACHE, - /* Batch Cache Component. - * TODO (dfelinto/sergey): rename to make it more generic. */ - BATCH_CACHE, - /* Duplication system. Used to force duplicated objects visible when - * when duplicator is visible. */ - DUPLI, - /* Synchronization back to original datablock. */ - SYNCHRONIZATION, - - /* Total number of meaningful node types. */ - NUM_TYPES, + /* Fallback type for invalid return value */ + UNDEFINED = 0, + /* Inner Node (Operation) */ + OPERATION, + + /* **** Generic Types **** */ + + /* Time-Source */ + TIMESOURCE, + /* ID-Block reference - used as landmarks/collection point for components, + * but not usually part of main graph. */ + ID_REF, + + /* **** Outer Types **** */ + + /* Parameters Component - Default when nothing else fits + * (i.e. just SDNA property setting). */ + PARAMETERS, + /* Generic "Proxy-Inherit" Component. */ + PROXY, + /* Animation Component */ + ANIMATION, + /* Transform Component (Parenting/Constraints) */ + TRANSFORM, + /* Geometry Component (Mesh/Displist) */ + GEOMETRY, + /* Sequencer Component (Scene Only) */ + SEQUENCER, + /* Component which contains all operations needed for layer collections + * evaluation. */ + LAYER_COLLECTIONS, + /* Entry component of majority of ID nodes: prepares CoW pointers for + * execution. */ + COPY_ON_WRITE, + /* Used by all operations which are updating object when something is + * changed in view layer. */ + OBJECT_FROM_LAYER, + /* Un-interestying datablock, which is a part of dependency graph, but does + * not have very distinctive update procedure. */ + GENERIC_DATABLOCK, + + /* **** Evaluation-Related Outer Types (with Subdata) **** */ + + /* Pose Component - Owner/Container of Bones Eval */ + EVAL_POSE, + /* Bone Component - Child/Subcomponent of Pose */ + BONE, + /* Particle Systems Component */ + PARTICLE_SYSTEM, + PARTICLE_SETTINGS, + /* Material Shading Component */ + SHADING, + SHADING_PARAMETERS, + /* Point cache Component */ + POINT_CACHE, + /* Cache Component */ + /* TODO(sergey); Verify that we really need this. */ + CACHE, + /* Batch Cache Component. + * TODO (dfelinto/sergey): rename to make it more generic. */ + BATCH_CACHE, + /* Duplication system. Used to force duplicated objects visible when + * when duplicator is visible. */ + DUPLI, + /* Synchronization back to original datablock. */ + SYNCHRONIZATION, + + /* Total number of meaningful node types. */ + NUM_TYPES, }; const char *nodeTypeAsString(NodeType type); /* All nodes in Depsgraph are descended from this. */ struct Node { - /* Helper class for static typeinfo in subclasses. */ - struct TypeInfo { - TypeInfo(NodeType type, - const char *type_name, - int id_recalc_tag = 0); - NodeType type; - const char *type_name; - int id_recalc_tag; - }; - struct Stats { - Stats(); - /* Reset all the counters. Including all stats needed for average - * evaluation time calculation. */ - void reset(); - /* Reset counters needed for the current graph evaluation, does not - * touch averaging accumulators. */ - void reset_current(); - /* Time spend on this node during current graph evaluation. */ - double current_time; - }; - /* Relationships between nodes - * The reason why all depsgraph nodes are descended from this type (apart - * from basic serialization benefits - from the typeinfo) is that we can - * have relationships between these nodes. */ - typedef vector Relations; - - string name; /* Identifier - mainly for debugging purposes. */ - NodeType type; /* Structural type of node. */ - Relations inlinks; /* Nodes which this one depends on. */ - Relations outlinks; /* Nodes which depend on this one. */ - Stats stats; /* Evaluation statistics. */ - - /* Generic tags for traversal algorithms and such. - * - * Actual meaning of values depends on a specific area. Every area is to - * clean this before use. */ - int custom_flags; - - /* Methods. */ - Node(); - virtual ~Node(); - - virtual string identifier() const; - - virtual void init(const ID * /*id*/, const char * /*subdata*/) {} - - virtual void tag_update(Depsgraph * /*graph*/, eUpdateSource /*source*/) {} - - virtual OperationNode *get_entry_operation() { return NULL; } - virtual OperationNode *get_exit_operation() { return NULL; } - - virtual NodeClass get_class() const; + /* Helper class for static typeinfo in subclasses. */ + struct TypeInfo { + TypeInfo(NodeType type, const char *type_name, int id_recalc_tag = 0); + NodeType type; + const char *type_name; + int id_recalc_tag; + }; + struct Stats { + Stats(); + /* Reset all the counters. Including all stats needed for average + * evaluation time calculation. */ + void reset(); + /* Reset counters needed for the current graph evaluation, does not + * touch averaging accumulators. */ + void reset_current(); + /* Time spend on this node during current graph evaluation. */ + double current_time; + }; + /* Relationships between nodes + * The reason why all depsgraph nodes are descended from this type (apart + * from basic serialization benefits - from the typeinfo) is that we can + * have relationships between these nodes. */ + typedef vector Relations; + + string name; /* Identifier - mainly for debugging purposes. */ + NodeType type; /* Structural type of node. */ + Relations inlinks; /* Nodes which this one depends on. */ + Relations outlinks; /* Nodes which depend on this one. */ + Stats stats; /* Evaluation statistics. */ + + /* Generic tags for traversal algorithms and such. + * + * Actual meaning of values depends on a specific area. Every area is to + * clean this before use. */ + int custom_flags; + + /* Methods. */ + Node(); + virtual ~Node(); + + virtual string identifier() const; + + virtual void init(const ID * /*id*/, const char * /*subdata*/) + { + } + + virtual void tag_update(Depsgraph * /*graph*/, eUpdateSource /*source*/) + { + } + + virtual OperationNode *get_entry_operation() + { + return NULL; + } + virtual OperationNode *get_exit_operation() + { + return NULL; + } + + virtual NodeClass get_class() const; }; /* Macros for common static typeinfo. */ -#define DEG_DEPSNODE_DECLARE \ - static const Node::TypeInfo typeinfo +#define DEG_DEPSNODE_DECLARE static const Node::TypeInfo typeinfo #define DEG_DEPSNODE_DEFINE(NodeType, type_, tname_) \ - const Node::TypeInfo NodeType::typeinfo = Node::TypeInfo(type_, tname_) + const Node::TypeInfo NodeType::typeinfo = Node::TypeInfo(type_, tname_) void deg_register_base_depsnodes(); diff --git a/source/blender/depsgraph/intern/node/deg_node_component.cc b/source/blender/depsgraph/intern/node/deg_node_component.cc index 06ede835a27..dc7ca371de3 100644 --- a/source/blender/depsgraph/intern/node/deg_node_component.cc +++ b/source/blender/depsgraph/intern/node/deg_node_component.cc @@ -24,7 +24,7 @@ #include "intern/node/deg_node_component.h" #include -#include /* required for STREQ later on. */ +#include /* required for STREQ later on. */ #include "BLI_utildefines.h" #include "BLI_ghash.h" @@ -47,308 +47,281 @@ namespace DEG { /* Standard Component Methods ============================= */ ComponentNode::OperationIDKey::OperationIDKey() - : opcode(OperationCode::OPERATION), - name(""), - name_tag(-1) + : opcode(OperationCode::OPERATION), name(""), name_tag(-1) { } ComponentNode::OperationIDKey::OperationIDKey(OperationCode opcode) - : opcode(opcode), - name(""), - name_tag(-1) + : opcode(opcode), name(""), name_tag(-1) { } -ComponentNode::OperationIDKey::OperationIDKey(OperationCode opcode, - const char *name, - int name_tag) - : opcode(opcode), - name(name), - name_tag(name_tag) +ComponentNode::OperationIDKey::OperationIDKey(OperationCode opcode, const char *name, int name_tag) + : opcode(opcode), name(name), name_tag(name_tag) { } string ComponentNode::OperationIDKey::identifier() const { - const string codebuf = to_string(static_cast(opcode)); - return "OperationIDKey(" + codebuf + ", " + name + ")"; + const string codebuf = to_string(static_cast(opcode)); + return "OperationIDKey(" + codebuf + ", " + name + ")"; } -bool ComponentNode::OperationIDKey::operator==( - const OperationIDKey &other) const +bool ComponentNode::OperationIDKey::operator==(const OperationIDKey &other) const { - return (opcode == other.opcode) && - (STREQ(name, other.name)) && - (name_tag == other.name_tag); + return (opcode == other.opcode) && (STREQ(name, other.name)) && (name_tag == other.name_tag); } static unsigned int comp_node_hash_key(const void *key_v) { - const ComponentNode::OperationIDKey *key = - reinterpret_cast(key_v); - int opcode_as_int = static_cast(key->opcode); - return BLI_ghashutil_combine_hash(BLI_ghashutil_uinthash(opcode_as_int), - BLI_ghashutil_strhash_p(key->name)); + const ComponentNode::OperationIDKey *key = + reinterpret_cast(key_v); + int opcode_as_int = static_cast(key->opcode); + return BLI_ghashutil_combine_hash(BLI_ghashutil_uinthash(opcode_as_int), + BLI_ghashutil_strhash_p(key->name)); } static bool comp_node_hash_key_cmp(const void *a, const void *b) { - const ComponentNode::OperationIDKey *key_a = - reinterpret_cast(a); - const ComponentNode::OperationIDKey *key_b = - reinterpret_cast(b); - return !(*key_a == *key_b); + const ComponentNode::OperationIDKey *key_a = + reinterpret_cast(a); + const ComponentNode::OperationIDKey *key_b = + reinterpret_cast(b); + return !(*key_a == *key_b); } static void comp_node_hash_key_free(void *key_v) { - typedef ComponentNode::OperationIDKey OperationIDKey; - OperationIDKey *key = reinterpret_cast(key_v); - OBJECT_GUARDED_DELETE(key, OperationIDKey); + typedef ComponentNode::OperationIDKey OperationIDKey; + OperationIDKey *key = reinterpret_cast(key_v); + OBJECT_GUARDED_DELETE(key, OperationIDKey); } static void comp_node_hash_value_free(void *value_v) { - OperationNode *op_node = reinterpret_cast(value_v); - OBJECT_GUARDED_DELETE(op_node, OperationNode); + OperationNode *op_node = reinterpret_cast(value_v); + OBJECT_GUARDED_DELETE(op_node, OperationNode); } -ComponentNode::ComponentNode() : - entry_operation(NULL), - exit_operation(NULL), - affects_directly_visible(false) +ComponentNode::ComponentNode() + : entry_operation(NULL), exit_operation(NULL), affects_directly_visible(false) { - operations_map = BLI_ghash_new(comp_node_hash_key, - comp_node_hash_key_cmp, - "Depsgraph id hash"); + operations_map = BLI_ghash_new(comp_node_hash_key, comp_node_hash_key_cmp, "Depsgraph id hash"); } /* Initialize 'component' node - from pointer data given */ -void ComponentNode::init(const ID * /*id*/, - const char * /*subdata*/) +void ComponentNode::init(const ID * /*id*/, const char * /*subdata*/) { - /* hook up eval context? */ - // XXX: maybe this needs a special API? + /* hook up eval context? */ + // XXX: maybe this needs a special API? } /* Free 'component' node */ ComponentNode::~ComponentNode() { - clear_operations(); - if (operations_map != NULL) { - BLI_ghash_free(operations_map, - comp_node_hash_key_free, - comp_node_hash_value_free); - } + clear_operations(); + if (operations_map != NULL) { + BLI_ghash_free(operations_map, comp_node_hash_key_free, comp_node_hash_value_free); + } } string ComponentNode::identifier() const { - const string idname = this->owner->name; - const string typebuf = "" + to_string(static_cast(type)) + ")"; - return typebuf + name + " : " + idname + - "( affects_directly_visible: " + - (affects_directly_visible ? "true" - : "false") + ")"; -; + const string idname = this->owner->name; + const string typebuf = "" + to_string(static_cast(type)) + ")"; + return typebuf + name + " : " + idname + + "( affects_directly_visible: " + (affects_directly_visible ? "true" : "false") + ")"; + ; } OperationNode *ComponentNode::find_operation(OperationIDKey key) const { - OperationNode *node = NULL; - if (operations_map != NULL) { - node = (OperationNode *)BLI_ghash_lookup(operations_map, &key); - } - else { - for (OperationNode *op_node : operations) { - if (op_node->opcode == key.opcode && - op_node->name_tag == key.name_tag && - STREQ(op_node->name.c_str(), key.name)) - { - node = op_node; - break; - } - } - } - return node; + OperationNode *node = NULL; + if (operations_map != NULL) { + node = (OperationNode *)BLI_ghash_lookup(operations_map, &key); + } + else { + for (OperationNode *op_node : operations) { + if (op_node->opcode == key.opcode && op_node->name_tag == key.name_tag && + STREQ(op_node->name.c_str(), key.name)) { + node = op_node; + break; + } + } + } + return node; } OperationNode *ComponentNode::find_operation(OperationCode opcode, - const char *name, - int name_tag) const + const char *name, + int name_tag) const { - OperationIDKey key(opcode, name, name_tag); - return find_operation(key); + OperationIDKey key(opcode, name, name_tag); + return find_operation(key); } OperationNode *ComponentNode::get_operation(OperationIDKey key) const { - OperationNode *node = find_operation(key); - if (node == NULL) { - fprintf(stderr, "%s: find_operation(%s) failed\n", - this->identifier().c_str(), key.identifier().c_str()); - BLI_assert(!"Request for non-existing operation, should not happen"); - return NULL; - } - return node; + OperationNode *node = find_operation(key); + if (node == NULL) { + fprintf(stderr, + "%s: find_operation(%s) failed\n", + this->identifier().c_str(), + key.identifier().c_str()); + BLI_assert(!"Request for non-existing operation, should not happen"); + return NULL; + } + return node; } OperationNode *ComponentNode::get_operation(OperationCode opcode, - const char *name, - int name_tag) const + const char *name, + int name_tag) const { - OperationIDKey key(opcode, name, name_tag); - return get_operation(key); + OperationIDKey key(opcode, name, name_tag); + return get_operation(key); } bool ComponentNode::has_operation(OperationIDKey key) const { - return find_operation(key) != NULL; + return find_operation(key) != NULL; } -bool ComponentNode::has_operation(OperationCode opcode, - const char *name, - int name_tag) const +bool ComponentNode::has_operation(OperationCode opcode, const char *name, int name_tag) const { - OperationIDKey key(opcode, name, name_tag); - return has_operation(key); + OperationIDKey key(opcode, name, name_tag); + return has_operation(key); } -OperationNode *ComponentNode::add_operation(const DepsEvalOperationCb& op, - OperationCode opcode, - const char *name, - int name_tag) +OperationNode *ComponentNode::add_operation(const DepsEvalOperationCb &op, + OperationCode opcode, + const char *name, + int name_tag) { - OperationNode *op_node = find_operation(opcode, name, name_tag); - if (!op_node) { - DepsNodeFactory *factory = type_get_factory(NodeType::OPERATION); - op_node = (OperationNode *)factory->create_node(this->owner->id_orig, "", name); - - /* register opnode in this component's operation set */ - OperationIDKey *key = OBJECT_GUARDED_NEW(OperationIDKey, opcode, name, name_tag); - BLI_ghash_insert(operations_map, key, op_node); - - /* set backlink */ - op_node->owner = this; - } - else { - fprintf(stderr, "add_operation: Operation already exists - %s has %s at %p\n", - this->identifier().c_str(), op_node->identifier().c_str(), op_node); - BLI_assert(!"Should not happen!"); - } - - /* attach extra data */ - op_node->evaluate = op; - op_node->opcode = opcode; - op_node->name = name; - op_node->name_tag = name_tag; - - return op_node; + OperationNode *op_node = find_operation(opcode, name, name_tag); + if (!op_node) { + DepsNodeFactory *factory = type_get_factory(NodeType::OPERATION); + op_node = (OperationNode *)factory->create_node(this->owner->id_orig, "", name); + + /* register opnode in this component's operation set */ + OperationIDKey *key = OBJECT_GUARDED_NEW(OperationIDKey, opcode, name, name_tag); + BLI_ghash_insert(operations_map, key, op_node); + + /* set backlink */ + op_node->owner = this; + } + else { + fprintf(stderr, + "add_operation: Operation already exists - %s has %s at %p\n", + this->identifier().c_str(), + op_node->identifier().c_str(), + op_node); + BLI_assert(!"Should not happen!"); + } + + /* attach extra data */ + op_node->evaluate = op; + op_node->opcode = opcode; + op_node->name = name; + op_node->name_tag = name_tag; + + return op_node; } void ComponentNode::set_entry_operation(OperationNode *op_node) { - BLI_assert(entry_operation == NULL); - entry_operation = op_node; + BLI_assert(entry_operation == NULL); + entry_operation = op_node; } void ComponentNode::set_exit_operation(OperationNode *op_node) { - BLI_assert(exit_operation == NULL); - exit_operation = op_node; + BLI_assert(exit_operation == NULL); + exit_operation = op_node; } void ComponentNode::clear_operations() { - if (operations_map != NULL) { - BLI_ghash_clear(operations_map, - comp_node_hash_key_free, - comp_node_hash_value_free); - } - for (OperationNode *op_node : operations) { - OBJECT_GUARDED_DELETE(op_node, OperationNode); - } - operations.clear(); + if (operations_map != NULL) { + BLI_ghash_clear(operations_map, comp_node_hash_key_free, comp_node_hash_value_free); + } + for (OperationNode *op_node : operations) { + OBJECT_GUARDED_DELETE(op_node, OperationNode); + } + operations.clear(); } void ComponentNode::tag_update(Depsgraph *graph, eUpdateSource source) { - OperationNode *entry_op = get_entry_operation(); - if (entry_op != NULL && entry_op->flag & DEPSOP_FLAG_NEEDS_UPDATE) { - return; - } - for (OperationNode *op_node : operations) { - op_node->tag_update(graph, source); - } - // It is possible that tag happens before finalization. - if (operations_map != NULL) { - GHASH_FOREACH_BEGIN(OperationNode *, op_node, operations_map) - { - op_node->tag_update(graph, source); - } - GHASH_FOREACH_END(); - } + OperationNode *entry_op = get_entry_operation(); + if (entry_op != NULL && entry_op->flag & DEPSOP_FLAG_NEEDS_UPDATE) { + return; + } + for (OperationNode *op_node : operations) { + op_node->tag_update(graph, source); + } + // It is possible that tag happens before finalization. + if (operations_map != NULL) { + GHASH_FOREACH_BEGIN (OperationNode *, op_node, operations_map) { + op_node->tag_update(graph, source); + } + GHASH_FOREACH_END(); + } } OperationNode *ComponentNode::get_entry_operation() { - if (entry_operation) { - return entry_operation; - } - else if (operations_map != NULL && BLI_ghash_len(operations_map) == 1) { - OperationNode *op_node = NULL; - /* TODO(sergey): This is somewhat slow. */ - GHASH_FOREACH_BEGIN(OperationNode *, tmp, operations_map) - { - op_node = tmp; - } - GHASH_FOREACH_END(); - /* Cache for the subsequent usage. */ - entry_operation = op_node; - return op_node; - } - else if (operations.size() == 1) { - return operations[0]; - } - return NULL; + if (entry_operation) { + return entry_operation; + } + else if (operations_map != NULL && BLI_ghash_len(operations_map) == 1) { + OperationNode *op_node = NULL; + /* TODO(sergey): This is somewhat slow. */ + GHASH_FOREACH_BEGIN (OperationNode *, tmp, operations_map) { + op_node = tmp; + } + GHASH_FOREACH_END(); + /* Cache for the subsequent usage. */ + entry_operation = op_node; + return op_node; + } + else if (operations.size() == 1) { + return operations[0]; + } + return NULL; } OperationNode *ComponentNode::get_exit_operation() { - if (exit_operation) { - return exit_operation; - } - else if (operations_map != NULL && BLI_ghash_len(operations_map) == 1) { - OperationNode *op_node = NULL; - /* TODO(sergey): This is somewhat slow. */ - GHASH_FOREACH_BEGIN(OperationNode *, tmp, operations_map) - { - op_node = tmp; - } - GHASH_FOREACH_END(); - /* Cache for the subsequent usage. */ - exit_operation = op_node; - return op_node; - } - else if (operations.size() == 1) { - return operations[0]; - } - return NULL; + if (exit_operation) { + return exit_operation; + } + else if (operations_map != NULL && BLI_ghash_len(operations_map) == 1) { + OperationNode *op_node = NULL; + /* TODO(sergey): This is somewhat slow. */ + GHASH_FOREACH_BEGIN (OperationNode *, tmp, operations_map) { + op_node = tmp; + } + GHASH_FOREACH_END(); + /* Cache for the subsequent usage. */ + exit_operation = op_node; + return op_node; + } + else if (operations.size() == 1) { + return operations[0]; + } + return NULL; } void ComponentNode::finalize_build(Depsgraph * /*graph*/) { - operations.reserve(BLI_ghash_len(operations_map)); - GHASH_FOREACH_BEGIN(OperationNode *, op_node, operations_map) - { - operations.push_back(op_node); - } - GHASH_FOREACH_END(); - BLI_ghash_free(operations_map, - comp_node_hash_key_free, - NULL); - operations_map = NULL; + operations.reserve(BLI_ghash_len(operations_map)); + GHASH_FOREACH_BEGIN (OperationNode *, op_node, operations_map) { + operations.push_back(op_node); + } + GHASH_FOREACH_END(); + BLI_ghash_free(operations_map, comp_node_hash_key_free, NULL); + operations_map = NULL; } /* Bone Component ========================================= */ @@ -356,69 +329,69 @@ void ComponentNode::finalize_build(Depsgraph * /*graph*/) /* Initialize 'bone component' node - from pointer data given */ void BoneComponentNode::init(const ID *id, const char *subdata) { - /* generic component-node... */ - ComponentNode::init(id, subdata); + /* generic component-node... */ + ComponentNode::init(id, subdata); - /* name of component comes is bone name */ - /* TODO(sergey): This sets name to an empty string because subdata is - * empty. Is it a bug? */ - //this->name = subdata; + /* name of component comes is bone name */ + /* TODO(sergey): This sets name to an empty string because subdata is + * empty. Is it a bug? */ + //this->name = subdata; - /* bone-specific node data */ - Object *object = (Object *)id; - this->pchan = BKE_pose_channel_find_name(object->pose, subdata); + /* bone-specific node data */ + Object *object = (Object *)id; + this->pchan = BKE_pose_channel_find_name(object->pose, subdata); } /* Register all components. =============================== */ -DEG_COMPONENT_NODE_DEFINE(Animation, ANIMATION, ID_RECALC_ANIMATION); +DEG_COMPONENT_NODE_DEFINE(Animation, ANIMATION, ID_RECALC_ANIMATION); /* TODO(sergey): Is this a correct tag? */ -DEG_COMPONENT_NODE_DEFINE(BatchCache, BATCH_CACHE, ID_RECALC_SHADING); -DEG_COMPONENT_NODE_DEFINE(Bone, BONE, ID_RECALC_GEOMETRY); -DEG_COMPONENT_NODE_DEFINE(Cache, CACHE, 0); -DEG_COMPONENT_NODE_DEFINE(CopyOnWrite, COPY_ON_WRITE, ID_RECALC_COPY_ON_WRITE); -DEG_COMPONENT_NODE_DEFINE(Geometry, GEOMETRY, ID_RECALC_GEOMETRY); -DEG_COMPONENT_NODE_DEFINE(LayerCollections, LAYER_COLLECTIONS, 0); -DEG_COMPONENT_NODE_DEFINE(Parameters, PARAMETERS, 0); -DEG_COMPONENT_NODE_DEFINE(Particles, PARTICLE_SYSTEM, ID_RECALC_GEOMETRY); -DEG_COMPONENT_NODE_DEFINE(ParticleSettings, PARTICLE_SETTINGS, 0); -DEG_COMPONENT_NODE_DEFINE(PointCache, POINT_CACHE, 0); -DEG_COMPONENT_NODE_DEFINE(Pose, EVAL_POSE, ID_RECALC_GEOMETRY); -DEG_COMPONENT_NODE_DEFINE(Proxy, PROXY, ID_RECALC_GEOMETRY); -DEG_COMPONENT_NODE_DEFINE(Sequencer, SEQUENCER, 0); -DEG_COMPONENT_NODE_DEFINE(Shading, SHADING, ID_RECALC_SHADING); +DEG_COMPONENT_NODE_DEFINE(BatchCache, BATCH_CACHE, ID_RECALC_SHADING); +DEG_COMPONENT_NODE_DEFINE(Bone, BONE, ID_RECALC_GEOMETRY); +DEG_COMPONENT_NODE_DEFINE(Cache, CACHE, 0); +DEG_COMPONENT_NODE_DEFINE(CopyOnWrite, COPY_ON_WRITE, ID_RECALC_COPY_ON_WRITE); +DEG_COMPONENT_NODE_DEFINE(Geometry, GEOMETRY, ID_RECALC_GEOMETRY); +DEG_COMPONENT_NODE_DEFINE(LayerCollections, LAYER_COLLECTIONS, 0); +DEG_COMPONENT_NODE_DEFINE(Parameters, PARAMETERS, 0); +DEG_COMPONENT_NODE_DEFINE(Particles, PARTICLE_SYSTEM, ID_RECALC_GEOMETRY); +DEG_COMPONENT_NODE_DEFINE(ParticleSettings, PARTICLE_SETTINGS, 0); +DEG_COMPONENT_NODE_DEFINE(PointCache, POINT_CACHE, 0); +DEG_COMPONENT_NODE_DEFINE(Pose, EVAL_POSE, ID_RECALC_GEOMETRY); +DEG_COMPONENT_NODE_DEFINE(Proxy, PROXY, ID_RECALC_GEOMETRY); +DEG_COMPONENT_NODE_DEFINE(Sequencer, SEQUENCER, 0); +DEG_COMPONENT_NODE_DEFINE(Shading, SHADING, ID_RECALC_SHADING); DEG_COMPONENT_NODE_DEFINE(ShadingParameters, SHADING_PARAMETERS, ID_RECALC_SHADING); -DEG_COMPONENT_NODE_DEFINE(Transform, TRANSFORM, ID_RECALC_TRANSFORM); -DEG_COMPONENT_NODE_DEFINE(ObjectFromLayer, OBJECT_FROM_LAYER, 0); -DEG_COMPONENT_NODE_DEFINE(Dupli, DUPLI, 0); -DEG_COMPONENT_NODE_DEFINE(Synchronization, SYNCHRONIZATION, 0); -DEG_COMPONENT_NODE_DEFINE(GenericDatablock, GENERIC_DATABLOCK, 0); +DEG_COMPONENT_NODE_DEFINE(Transform, TRANSFORM, ID_RECALC_TRANSFORM); +DEG_COMPONENT_NODE_DEFINE(ObjectFromLayer, OBJECT_FROM_LAYER, 0); +DEG_COMPONENT_NODE_DEFINE(Dupli, DUPLI, 0); +DEG_COMPONENT_NODE_DEFINE(Synchronization, SYNCHRONIZATION, 0); +DEG_COMPONENT_NODE_DEFINE(GenericDatablock, GENERIC_DATABLOCK, 0); /* Node Types Register =================================== */ void deg_register_component_depsnodes() { - register_node_typeinfo(&DNTI_ANIMATION); - register_node_typeinfo(&DNTI_BONE); - register_node_typeinfo(&DNTI_CACHE); - register_node_typeinfo(&DNTI_BATCH_CACHE); - register_node_typeinfo(&DNTI_COPY_ON_WRITE); - register_node_typeinfo(&DNTI_GEOMETRY); - register_node_typeinfo(&DNTI_LAYER_COLLECTIONS); - register_node_typeinfo(&DNTI_PARAMETERS); - register_node_typeinfo(&DNTI_PARTICLE_SYSTEM); - register_node_typeinfo(&DNTI_PARTICLE_SETTINGS); - register_node_typeinfo(&DNTI_POINT_CACHE); - register_node_typeinfo(&DNTI_PROXY); - register_node_typeinfo(&DNTI_EVAL_POSE); - register_node_typeinfo(&DNTI_SEQUENCER); - register_node_typeinfo(&DNTI_SHADING); - register_node_typeinfo(&DNTI_SHADING_PARAMETERS); - register_node_typeinfo(&DNTI_TRANSFORM); - register_node_typeinfo(&DNTI_OBJECT_FROM_LAYER); - register_node_typeinfo(&DNTI_DUPLI); - register_node_typeinfo(&DNTI_SYNCHRONIZATION); - register_node_typeinfo(&DNTI_GENERIC_DATABLOCK); + register_node_typeinfo(&DNTI_ANIMATION); + register_node_typeinfo(&DNTI_BONE); + register_node_typeinfo(&DNTI_CACHE); + register_node_typeinfo(&DNTI_BATCH_CACHE); + register_node_typeinfo(&DNTI_COPY_ON_WRITE); + register_node_typeinfo(&DNTI_GEOMETRY); + register_node_typeinfo(&DNTI_LAYER_COLLECTIONS); + register_node_typeinfo(&DNTI_PARAMETERS); + register_node_typeinfo(&DNTI_PARTICLE_SYSTEM); + register_node_typeinfo(&DNTI_PARTICLE_SETTINGS); + register_node_typeinfo(&DNTI_POINT_CACHE); + register_node_typeinfo(&DNTI_PROXY); + register_node_typeinfo(&DNTI_EVAL_POSE); + register_node_typeinfo(&DNTI_SEQUENCER); + register_node_typeinfo(&DNTI_SHADING); + register_node_typeinfo(&DNTI_SHADING_PARAMETERS); + register_node_typeinfo(&DNTI_TRANSFORM); + register_node_typeinfo(&DNTI_OBJECT_FROM_LAYER); + register_node_typeinfo(&DNTI_DUPLI); + register_node_typeinfo(&DNTI_SYNCHRONIZATION); + register_node_typeinfo(&DNTI_GENERIC_DATABLOCK); } } // namespace DEG diff --git a/source/blender/depsgraph/intern/node/deg_node_component.h b/source/blender/depsgraph/intern/node/deg_node_component.h index 4392a120935..038b5917a86 100644 --- a/source/blender/depsgraph/intern/node/deg_node_component.h +++ b/source/blender/depsgraph/intern/node/deg_node_component.h @@ -42,134 +42,130 @@ struct OperationNode; /* ID Component - Base type for all components */ struct ComponentNode : public Node { - /* Key used to look up operations within a component */ - struct OperationIDKey - { - OperationCode opcode; - const char *name; - int name_tag; - - OperationIDKey(); - OperationIDKey(OperationCode opcode); - OperationIDKey(OperationCode opcode, - const char *name, - int name_tag); - - string identifier() const; - bool operator==(const OperationIDKey &other) const; - }; - - /* Typedef for container of operations */ - ComponentNode(); - ~ComponentNode(); - - void init(const ID *id, const char *subdata) override; - - virtual string identifier() const override; - - /* Find an existing operation, if requested operation does not exist - * NULL will be returned. */ - OperationNode *find_operation(OperationIDKey key) const; - OperationNode *find_operation(OperationCode opcode, - const char *name, - int name_tag) const; - - /* Find an existing operation, will throw an assert() if it does not exist. */ - OperationNode *get_operation(OperationIDKey key) const; - OperationNode *get_operation(OperationCode opcode, - const char *name, - int name_tag) const; - - /* Check operation exists and return it. */ - bool has_operation(OperationIDKey key) const; - bool has_operation(OperationCode opcode, - const char *name, - int name_tag) const; - - /** - * Create a new node for representing an operation and add this to graph - * \warning If an existing node is found, it will be modified. This helps - * when node may have been partially created earlier (e.g. parent ref before - * parent item is added) - * - * \param type: Operation node type (corresponding to context/component that - * it operates in) - * \param optype: Role that operation plays within component - * (i.e. where in eval process) - * \param op: The operation to perform - * \param name: Identifier for operation - used to find/locate it again */ - OperationNode *add_operation(const DepsEvalOperationCb& op, - OperationCode opcode, - const char *name, - int name_tag); - - /* Entry/exit operations management. - * - * Use those instead of direct set since this will perform sanity checks. */ - void set_entry_operation(OperationNode *op_node); - void set_exit_operation(OperationNode *op_node); - - void clear_operations(); - - virtual void tag_update(Depsgraph *graph, eUpdateSource source) override; - - virtual OperationNode *get_entry_operation() override; - virtual OperationNode *get_exit_operation() override; - - void finalize_build(Depsgraph *graph); - - IDNode *owner; - - /* ** Inner nodes for this component ** */ - - /* Operations stored as a hash map, for faster build. - * This hash map will be freed when graph is fully built. */ - GHash *operations_map; - - /* This is a "normal" list of operations, used by evaluation - * and other routines after construction. */ - vector operations; - - OperationNode *entry_operation; - OperationNode *exit_operation; - - virtual bool depends_on_cow() { return true; } - - /* Denotes whether COW component is to be tagged when this component - * is tagged for update. */ - virtual bool need_tag_cow_before_update() { return true; } - - /* Denotes whether this component affects (possibly indirectly) on a - * directly visible object. */ - bool affects_directly_visible; + /* Key used to look up operations within a component */ + struct OperationIDKey { + OperationCode opcode; + const char *name; + int name_tag; + + OperationIDKey(); + OperationIDKey(OperationCode opcode); + OperationIDKey(OperationCode opcode, const char *name, int name_tag); + + string identifier() const; + bool operator==(const OperationIDKey &other) const; + }; + + /* Typedef for container of operations */ + ComponentNode(); + ~ComponentNode(); + + void init(const ID *id, const char *subdata) override; + + virtual string identifier() const override; + + /* Find an existing operation, if requested operation does not exist + * NULL will be returned. */ + OperationNode *find_operation(OperationIDKey key) const; + OperationNode *find_operation(OperationCode opcode, const char *name, int name_tag) const; + + /* Find an existing operation, will throw an assert() if it does not exist. */ + OperationNode *get_operation(OperationIDKey key) const; + OperationNode *get_operation(OperationCode opcode, const char *name, int name_tag) const; + + /* Check operation exists and return it. */ + bool has_operation(OperationIDKey key) const; + bool has_operation(OperationCode opcode, const char *name, int name_tag) const; + + /** + * Create a new node for representing an operation and add this to graph + * \warning If an existing node is found, it will be modified. This helps + * when node may have been partially created earlier (e.g. parent ref before + * parent item is added) + * + * \param type: Operation node type (corresponding to context/component that + * it operates in) + * \param optype: Role that operation plays within component + * (i.e. where in eval process) + * \param op: The operation to perform + * \param name: Identifier for operation - used to find/locate it again */ + OperationNode *add_operation(const DepsEvalOperationCb &op, + OperationCode opcode, + const char *name, + int name_tag); + + /* Entry/exit operations management. + * + * Use those instead of direct set since this will perform sanity checks. */ + void set_entry_operation(OperationNode *op_node); + void set_exit_operation(OperationNode *op_node); + + void clear_operations(); + + virtual void tag_update(Depsgraph *graph, eUpdateSource source) override; + + virtual OperationNode *get_entry_operation() override; + virtual OperationNode *get_exit_operation() override; + + void finalize_build(Depsgraph *graph); + + IDNode *owner; + + /* ** Inner nodes for this component ** */ + + /* Operations stored as a hash map, for faster build. + * This hash map will be freed when graph is fully built. */ + GHash *operations_map; + + /* This is a "normal" list of operations, used by evaluation + * and other routines after construction. */ + vector operations; + + OperationNode *entry_operation; + OperationNode *exit_operation; + + virtual bool depends_on_cow() + { + return true; + } + + /* Denotes whether COW component is to be tagged when this component + * is tagged for update. */ + virtual bool need_tag_cow_before_update() + { + return true; + } + + /* Denotes whether this component affects (possibly indirectly) on a + * directly visible object. */ + bool affects_directly_visible; }; /* ---------------------------------------- */ -#define DEG_COMPONENT_NODE_DEFINE_TYPEINFO(\ - NodeType, type_, type_name_, id_recalc_tag) \ - const Node::TypeInfo NodeType::typeinfo = \ - Node::TypeInfo(type_, type_name_, id_recalc_tag) +#define DEG_COMPONENT_NODE_DEFINE_TYPEINFO(NodeType, type_, type_name_, id_recalc_tag) \ + const Node::TypeInfo NodeType::typeinfo = Node::TypeInfo(type_, type_name_, id_recalc_tag) #define DEG_COMPONENT_NODE_DECLARE DEG_DEPSNODE_DECLARE -#define DEG_COMPONENT_NODE_DEFINE(name, NAME, id_recalc_tag) \ - DEG_COMPONENT_NODE_DEFINE_TYPEINFO(name ## ComponentNode, \ - NodeType:: NAME, \ - #name " Component", \ - id_recalc_tag) ; \ - static DepsNodeFactoryImpl DNTI_ ## NAME - -#define DEG_COMPONENT_NODE_DECLARE_GENERIC(name) \ - struct name ## ComponentNode : public ComponentNode { \ - DEG_COMPONENT_NODE_DECLARE; \ - } - -#define DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_UPDATE(name) \ - struct name ## ComponentNode : public ComponentNode { \ - DEG_COMPONENT_NODE_DECLARE; \ - virtual bool need_tag_cow_before_update() { return false; } \ - } +#define DEG_COMPONENT_NODE_DEFINE(name, NAME, id_recalc_tag) \ + DEG_COMPONENT_NODE_DEFINE_TYPEINFO( \ + name##ComponentNode, NodeType::NAME, #name " Component", id_recalc_tag); \ + static DepsNodeFactoryImpl DNTI_##NAME + +#define DEG_COMPONENT_NODE_DECLARE_GENERIC(name) \ + struct name##ComponentNode : public ComponentNode { \ + DEG_COMPONENT_NODE_DECLARE; \ + } + +#define DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_UPDATE(name) \ + struct name##ComponentNode : public ComponentNode { \ + DEG_COMPONENT_NODE_DECLARE; \ + virtual bool need_tag_cow_before_update() \ + { \ + return false; \ + } \ + } DEG_COMPONENT_NODE_DECLARE_GENERIC(Animation); DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_UPDATE(BatchCache); @@ -194,11 +190,11 @@ DEG_COMPONENT_NODE_DECLARE_GENERIC(GenericDatablock); /* Bone Component */ struct BoneComponentNode : public ComponentNode { - void init(const ID *id, const char *subdata); + void init(const ID *id, const char *subdata); - struct bPoseChannel *pchan; /* the bone that this component represents */ + struct bPoseChannel *pchan; /* the bone that this component represents */ - DEG_COMPONENT_NODE_DECLARE; + DEG_COMPONENT_NODE_DECLARE; }; void deg_register_component_depsnodes(); diff --git a/source/blender/depsgraph/intern/node/deg_node_factory.cc b/source/blender/depsgraph/intern/node/deg_node_factory.cc index e6f2fd1841d..4a11ed2a4fb 100644 --- a/source/blender/depsgraph/intern/node/deg_node_factory.cc +++ b/source/blender/depsgraph/intern/node/deg_node_factory.cc @@ -26,21 +26,20 @@ namespace DEG { /* Global type registry */ -static DepsNodeFactory * -node_typeinfo_registry[static_cast(NodeType::NUM_TYPES)] = {NULL}; +static DepsNodeFactory *node_typeinfo_registry[static_cast(NodeType::NUM_TYPES)] = {NULL}; void register_node_typeinfo(DepsNodeFactory *factory) { - BLI_assert(factory != NULL); - const int type_as_int = static_cast(factory->type()); - node_typeinfo_registry[type_as_int] = factory; + BLI_assert(factory != NULL); + const int type_as_int = static_cast(factory->type()); + node_typeinfo_registry[type_as_int] = factory; } DepsNodeFactory *type_get_factory(const NodeType type) { - /* Look up type - at worst, it doesn't exist in table yet, and we fail. */ - const int type_as_int = static_cast(type); - return node_typeinfo_registry[type_as_int]; + /* Look up type - at worst, it doesn't exist in table yet, and we fail. */ + const int type_as_int = static_cast(type); + return node_typeinfo_registry[type_as_int]; } } // namespace DEG diff --git a/source/blender/depsgraph/intern/node/deg_node_factory.h b/source/blender/depsgraph/intern/node/deg_node_factory.h index 29a3eebba2b..38487e7f979 100644 --- a/source/blender/depsgraph/intern/node/deg_node_factory.h +++ b/source/blender/depsgraph/intern/node/deg_node_factory.h @@ -33,26 +33,21 @@ struct ID; namespace DEG { struct DepsNodeFactory { - virtual NodeType type() const = 0; - virtual const char *type_name() const = 0; + virtual NodeType type() const = 0; + virtual const char *type_name() const = 0; - virtual int id_recalc_tag() const = 0; + virtual int id_recalc_tag() const = 0; - virtual Node *create_node(const ID *id, - const char *subdata, - const char *name) const = 0; + virtual Node *create_node(const ID *id, const char *subdata, const char *name) const = 0; }; -template -struct DepsNodeFactoryImpl : public DepsNodeFactory { - virtual NodeType type() const override; - virtual const char *type_name() const override; +template struct DepsNodeFactoryImpl : public DepsNodeFactory { + virtual NodeType type() const override; + virtual const char *type_name() const override; - virtual int id_recalc_tag() const override; + virtual int id_recalc_tag() const override; - virtual Node *create_node(const ID *id, - const char *subdata, - const char *name) const override; + virtual Node *create_node(const ID *id, const char *subdata, const char *name) const override; }; /* Register typeinfo */ diff --git a/source/blender/depsgraph/intern/node/deg_node_factory_impl.h b/source/blender/depsgraph/intern/node/deg_node_factory_impl.h index f2d478d4c16..ad25ffdf26c 100644 --- a/source/blender/depsgraph/intern/node/deg_node_factory_impl.h +++ b/source/blender/depsgraph/intern/node/deg_node_factory_impl.h @@ -29,38 +29,38 @@ struct ID; namespace DEG { -template -NodeType DepsNodeFactoryImpl::type() const +template NodeType DepsNodeFactoryImpl::type() const { - return ModeObjectType::typeinfo.type; + return ModeObjectType::typeinfo.type; } -template -const char *DepsNodeFactoryImpl::type_name() const { - return ModeObjectType::typeinfo.type_name; +template const char *DepsNodeFactoryImpl::type_name() const +{ + return ModeObjectType::typeinfo.type_name; } -template -int DepsNodeFactoryImpl::id_recalc_tag() const { - return ModeObjectType::typeinfo.id_recalc_tag; +template int DepsNodeFactoryImpl::id_recalc_tag() const +{ + return ModeObjectType::typeinfo.id_recalc_tag; } -template -Node *DepsNodeFactoryImpl::create_node( - const ID *id, const char *subdata, const char *name) const +template +Node *DepsNodeFactoryImpl::create_node(const ID *id, + const char *subdata, + const char *name) const { - Node *node = OBJECT_GUARDED_NEW(ModeObjectType); - /* Populate base node settings. */ - node->type = type(); - /* Set name if provided, or use default type name. */ - if (name[0] != '\0') { - node->name = name; - } - else { - node->name = type_name(); - } - node->init(id, subdata); - return node; + Node *node = OBJECT_GUARDED_NEW(ModeObjectType); + /* Populate base node settings. */ + node->type = type(); + /* Set name if provided, or use default type name. */ + if (name[0] != '\0') { + node->name = name; + } + else { + node->name = type_name(); + } + node->init(id, subdata); + return node; } } // namespace DEG diff --git a/source/blender/depsgraph/intern/node/deg_node_id.cc b/source/blender/depsgraph/intern/node/deg_node_id.cc index d391f727d35..77e8f4f37e0 100644 --- a/source/blender/depsgraph/intern/node/deg_node_id.cc +++ b/source/blender/depsgraph/intern/node/deg_node_id.cc @@ -24,7 +24,7 @@ #include "intern/node/deg_node_id.h" #include -#include /* required for STREQ later on. */ +#include /* required for STREQ later on. */ #include "BLI_utildefines.h" #include "BLI_ghash.h" @@ -49,198 +49,188 @@ namespace DEG { const char *linkedStateAsString(eDepsNode_LinkedState_Type linked_state) { - switch (linked_state) { - case DEG_ID_LINKED_INDIRECTLY: return "INDIRECTLY"; - case DEG_ID_LINKED_VIA_SET: return "VIA_SET"; - case DEG_ID_LINKED_DIRECTLY: return "DIRECTLY"; - } - BLI_assert(!"Unhandled linked state, should never happen."); - return "UNKNOW"; + switch (linked_state) { + case DEG_ID_LINKED_INDIRECTLY: + return "INDIRECTLY"; + case DEG_ID_LINKED_VIA_SET: + return "VIA_SET"; + case DEG_ID_LINKED_DIRECTLY: + return "DIRECTLY"; + } + BLI_assert(!"Unhandled linked state, should never happen."); + return "UNKNOW"; } -IDNode::ComponentIDKey::ComponentIDKey(NodeType type, - const char *name) - : type(type), name(name) +IDNode::ComponentIDKey::ComponentIDKey(NodeType type, const char *name) : type(type), name(name) { } -bool IDNode::ComponentIDKey::operator== (const ComponentIDKey &other) const +bool IDNode::ComponentIDKey::operator==(const ComponentIDKey &other) const { - return type == other.type && - STREQ(name, other.name); + return type == other.type && STREQ(name, other.name); } static unsigned int id_deps_node_hash_key(const void *key_v) { - const IDNode::ComponentIDKey *key = - reinterpret_cast(key_v); - const int type_as_int = static_cast(key->type); - return BLI_ghashutil_combine_hash(BLI_ghashutil_uinthash(type_as_int), - BLI_ghashutil_strhash_p(key->name)); + const IDNode::ComponentIDKey *key = reinterpret_cast(key_v); + const int type_as_int = static_cast(key->type); + return BLI_ghashutil_combine_hash(BLI_ghashutil_uinthash(type_as_int), + BLI_ghashutil_strhash_p(key->name)); } static bool id_deps_node_hash_key_cmp(const void *a, const void *b) { - const IDNode::ComponentIDKey *key_a = - reinterpret_cast(a); - const IDNode::ComponentIDKey *key_b = - reinterpret_cast(b); - return !(*key_a == *key_b); + const IDNode::ComponentIDKey *key_a = reinterpret_cast(a); + const IDNode::ComponentIDKey *key_b = reinterpret_cast(b); + return !(*key_a == *key_b); } static void id_deps_node_hash_key_free(void *key_v) { - typedef IDNode::ComponentIDKey ComponentIDKey; - ComponentIDKey *key = reinterpret_cast(key_v); - OBJECT_GUARDED_DELETE(key, ComponentIDKey); + typedef IDNode::ComponentIDKey ComponentIDKey; + ComponentIDKey *key = reinterpret_cast(key_v); + OBJECT_GUARDED_DELETE(key, ComponentIDKey); } static void id_deps_node_hash_value_free(void *value_v) { - ComponentNode *comp_node = reinterpret_cast(value_v); - OBJECT_GUARDED_DELETE(comp_node, ComponentNode); + ComponentNode *comp_node = reinterpret_cast(value_v); + OBJECT_GUARDED_DELETE(comp_node, ComponentNode); } /* Initialize 'id' node - from pointer data given. */ void IDNode::init(const ID *id, const char *UNUSED(subdata)) { - BLI_assert(id != NULL); - /* Store ID-pointer. */ - id_orig = (ID *)id; - eval_flags = 0; - previous_eval_flags = 0; - customdata_masks = DEGCustomDataMeshMasks(); - previous_customdata_masks = DEGCustomDataMeshMasks(); - linked_state = DEG_ID_LINKED_INDIRECTLY; - is_directly_visible = true; - is_collection_fully_expanded = false; + BLI_assert(id != NULL); + /* Store ID-pointer. */ + id_orig = (ID *)id; + eval_flags = 0; + previous_eval_flags = 0; + customdata_masks = DEGCustomDataMeshMasks(); + previous_customdata_masks = DEGCustomDataMeshMasks(); + linked_state = DEG_ID_LINKED_INDIRECTLY; + is_directly_visible = true; + is_collection_fully_expanded = false; - visible_components_mask = 0; - previously_visible_components_mask = 0; + visible_components_mask = 0; + previously_visible_components_mask = 0; - components = BLI_ghash_new(id_deps_node_hash_key, - id_deps_node_hash_key_cmp, - "Depsgraph id components hash"); + components = BLI_ghash_new( + id_deps_node_hash_key, id_deps_node_hash_key_cmp, "Depsgraph id components hash"); } void IDNode::init_copy_on_write(ID *id_cow_hint) { - /* Create pointer as early as possible, so we can use it for function - * bindings. Rest of data we'll be copying to the new datablock when - * it is actually needed. */ - if (id_cow_hint != NULL) { - // BLI_assert(deg_copy_on_write_is_needed(id_orig)); - if (deg_copy_on_write_is_needed(id_orig)) { - id_cow = id_cow_hint; - } - else { - id_cow = id_orig; - } - } - else if (deg_copy_on_write_is_needed(id_orig)) { - id_cow = (ID *)BKE_libblock_alloc_notest(GS(id_orig->name)); - DEG_COW_PRINT("Create shallow copy for %s: id_orig=%p id_cow=%p\n", - id_orig->name, id_orig, id_cow); - deg_tag_copy_on_write_id(id_cow, id_orig); - } - else { - id_cow = id_orig; - } + /* Create pointer as early as possible, so we can use it for function + * bindings. Rest of data we'll be copying to the new datablock when + * it is actually needed. */ + if (id_cow_hint != NULL) { + // BLI_assert(deg_copy_on_write_is_needed(id_orig)); + if (deg_copy_on_write_is_needed(id_orig)) { + id_cow = id_cow_hint; + } + else { + id_cow = id_orig; + } + } + else if (deg_copy_on_write_is_needed(id_orig)) { + id_cow = (ID *)BKE_libblock_alloc_notest(GS(id_orig->name)); + DEG_COW_PRINT( + "Create shallow copy for %s: id_orig=%p id_cow=%p\n", id_orig->name, id_orig, id_cow); + deg_tag_copy_on_write_id(id_cow, id_orig); + } + else { + id_cow = id_orig; + } } /* Free 'id' node. */ IDNode::~IDNode() { - destroy(); + destroy(); } void IDNode::destroy() { - if (id_orig == NULL) { - return; - } + if (id_orig == NULL) { + return; + } - BLI_ghash_free(components, - id_deps_node_hash_key_free, - id_deps_node_hash_value_free); + BLI_ghash_free(components, id_deps_node_hash_key_free, id_deps_node_hash_value_free); - /* Free memory used by this CoW ID. */ - if (id_cow != id_orig && id_cow != NULL) { - deg_free_copy_on_write_datablock(id_cow); - MEM_freeN(id_cow); - id_cow = NULL; - DEG_COW_PRINT("Destroy CoW for %s: id_orig=%p id_cow=%p\n", - id_orig->name, id_orig, id_cow); - } + /* Free memory used by this CoW ID. */ + if (id_cow != id_orig && id_cow != NULL) { + deg_free_copy_on_write_datablock(id_cow); + MEM_freeN(id_cow); + id_cow = NULL; + DEG_COW_PRINT("Destroy CoW for %s: id_orig=%p id_cow=%p\n", id_orig->name, id_orig, id_cow); + } - /* Tag that the node is freed. */ - id_orig = NULL; + /* Tag that the node is freed. */ + id_orig = NULL; } string IDNode::identifier() const { - char orig_ptr[24], cow_ptr[24]; - BLI_snprintf(orig_ptr, sizeof(orig_ptr), "%p", id_orig); - BLI_snprintf(cow_ptr, sizeof(cow_ptr), "%p", id_cow); - return string(nodeTypeAsString(type)) + " : " + name + - " (orig: " + orig_ptr + ", eval: " + cow_ptr + - ", is_directly_visible " + (is_directly_visible ? "true" - : "false") + ")"; + char orig_ptr[24], cow_ptr[24]; + BLI_snprintf(orig_ptr, sizeof(orig_ptr), "%p", id_orig); + BLI_snprintf(cow_ptr, sizeof(cow_ptr), "%p", id_cow); + return string(nodeTypeAsString(type)) + " : " + name + " (orig: " + orig_ptr + + ", eval: " + cow_ptr + ", is_directly_visible " + + (is_directly_visible ? "true" : "false") + ")"; } ComponentNode *IDNode::find_component(NodeType type, const char *name) const { - ComponentIDKey key(type, name); - return reinterpret_cast(BLI_ghash_lookup(components, &key)); + ComponentIDKey key(type, name); + return reinterpret_cast(BLI_ghash_lookup(components, &key)); } ComponentNode *IDNode::add_component(NodeType type, const char *name) { - ComponentNode *comp_node = find_component(type, name); - if (!comp_node) { - DepsNodeFactory *factory = type_get_factory(type); - comp_node = (ComponentNode *)factory->create_node(this->id_orig, "", name); + ComponentNode *comp_node = find_component(type, name); + if (!comp_node) { + DepsNodeFactory *factory = type_get_factory(type); + comp_node = (ComponentNode *)factory->create_node(this->id_orig, "", name); - /* Register. */ - ComponentIDKey *key = OBJECT_GUARDED_NEW(ComponentIDKey, type, name); - BLI_ghash_insert(components, key, comp_node); - comp_node->owner = this; - } - return comp_node; + /* Register. */ + ComponentIDKey *key = OBJECT_GUARDED_NEW(ComponentIDKey, type, name); + BLI_ghash_insert(components, key, comp_node); + comp_node->owner = this; + } + return comp_node; } void IDNode::tag_update(Depsgraph *graph, eUpdateSource source) { - GHASH_FOREACH_BEGIN(ComponentNode *, comp_node, components) - { - comp_node->tag_update(graph, source); - } - GHASH_FOREACH_END(); + GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, components) { + comp_node->tag_update(graph, source); + } + GHASH_FOREACH_END(); } void IDNode::finalize_build(Depsgraph *graph) { - /* Finalize build of all components. */ - GHASH_FOREACH_BEGIN(ComponentNode *, comp_node, components) - { - comp_node->finalize_build(graph); - } - GHASH_FOREACH_END(); - visible_components_mask = get_visible_components_mask(); -} - -IDComponentsMask IDNode::get_visible_components_mask() const { - IDComponentsMask result = 0; - GHASH_FOREACH_BEGIN(ComponentNode *, comp_node, components) - { - if (comp_node->affects_directly_visible) { - const int component_type_as_int = static_cast(comp_node->type); - BLI_assert(component_type_as_int < 64); - result |= (1ULL << component_type_as_int); - } - } - GHASH_FOREACH_END(); - return result; + /* Finalize build of all components. */ + GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, components) { + comp_node->finalize_build(graph); + } + GHASH_FOREACH_END(); + visible_components_mask = get_visible_components_mask(); +} + +IDComponentsMask IDNode::get_visible_components_mask() const +{ + IDComponentsMask result = 0; + GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, components) { + if (comp_node->affects_directly_visible) { + const int component_type_as_int = static_cast(comp_node->type); + BLI_assert(component_type_as_int < 64); + result |= (1ULL << component_type_as_int); + } + } + GHASH_FOREACH_END(); + return result; } } // namespace DEG diff --git a/source/blender/depsgraph/intern/node/deg_node_id.h b/source/blender/depsgraph/intern/node/deg_node_id.h index bbf671790c7..34d78e29060 100644 --- a/source/blender/depsgraph/intern/node/deg_node_id.h +++ b/source/blender/depsgraph/intern/node/deg_node_id.h @@ -35,71 +35,71 @@ typedef uint64_t IDComponentsMask; /* NOTE: We use max comparison to mark an id node that is linked more than once * So keep this enum ordered accordingly. */ enum eDepsNode_LinkedState_Type { - /* Generic indirectly linked id node. */ - DEG_ID_LINKED_INDIRECTLY = 0, - /* Id node present in the set (background) only. */ - DEG_ID_LINKED_VIA_SET = 1, - /* Id node directly linked via the SceneLayer. */ - DEG_ID_LINKED_DIRECTLY = 2, + /* Generic indirectly linked id node. */ + DEG_ID_LINKED_INDIRECTLY = 0, + /* Id node present in the set (background) only. */ + DEG_ID_LINKED_VIA_SET = 1, + /* Id node directly linked via the SceneLayer. */ + DEG_ID_LINKED_DIRECTLY = 2, }; const char *linkedStateAsString(eDepsNode_LinkedState_Type linked_state); /* ID-Block Reference */ struct IDNode : public Node { - struct ComponentIDKey { - ComponentIDKey(NodeType type, const char *name = ""); - bool operator==(const ComponentIDKey &other) const; + struct ComponentIDKey { + ComponentIDKey(NodeType type, const char *name = ""); + bool operator==(const ComponentIDKey &other) const; - NodeType type; - const char *name; - }; + NodeType type; + const char *name; + }; - virtual void init(const ID *id, const char *subdata) override; - void init_copy_on_write(ID *id_cow_hint = NULL); - ~IDNode(); - void destroy(); + virtual void init(const ID *id, const char *subdata) override; + void init_copy_on_write(ID *id_cow_hint = NULL); + ~IDNode(); + void destroy(); - virtual string identifier() const override; + virtual string identifier() const override; - ComponentNode *find_component(NodeType type, const char *name = "") const; - ComponentNode *add_component(NodeType type, const char *name = ""); + ComponentNode *find_component(NodeType type, const char *name = "") const; + ComponentNode *add_component(NodeType type, const char *name = ""); - virtual void tag_update(Depsgraph *graph, eUpdateSource source) override; + virtual void tag_update(Depsgraph *graph, eUpdateSource source) override; - void finalize_build(Depsgraph *graph); + void finalize_build(Depsgraph *graph); - IDComponentsMask get_visible_components_mask() const; + IDComponentsMask get_visible_components_mask() const; - /* ID Block referenced. */ - ID *id_orig; - ID *id_cow; + /* ID Block referenced. */ + ID *id_orig; + ID *id_cow; - /* Hash to make it faster to look up components. */ - GHash *components; + /* Hash to make it faster to look up components. */ + GHash *components; - /* Additional flags needed for scene evaluation. - * TODO(sergey): Only needed for until really granular updates - * of all the entities. */ - uint32_t eval_flags; - uint32_t previous_eval_flags; + /* Additional flags needed for scene evaluation. + * TODO(sergey): Only needed for until really granular updates + * of all the entities. */ + uint32_t eval_flags; + uint32_t previous_eval_flags; - /* Extra customdata mask which needs to be evaluated for the mesh object. */ - DEGCustomDataMeshMasks customdata_masks; - DEGCustomDataMeshMasks previous_customdata_masks; + /* Extra customdata mask which needs to be evaluated for the mesh object. */ + DEGCustomDataMeshMasks customdata_masks; + DEGCustomDataMeshMasks previous_customdata_masks; - eDepsNode_LinkedState_Type linked_state; + eDepsNode_LinkedState_Type linked_state; - /* Indicates the datablock is visible in the evaluated scene. */ - bool is_directly_visible; + /* Indicates the datablock is visible in the evaluated scene. */ + bool is_directly_visible; - /* For the collection type of ID, denotes whether collection was fully - * recursed into. */ - bool is_collection_fully_expanded; + /* For the collection type of ID, denotes whether collection was fully + * recursed into. */ + bool is_collection_fully_expanded; - IDComponentsMask visible_components_mask; - IDComponentsMask previously_visible_components_mask; + IDComponentsMask visible_components_mask; + IDComponentsMask previously_visible_components_mask; - DEG_DEPSNODE_DECLARE; + DEG_DEPSNODE_DECLARE; }; } // namespace DEG diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.cc b/source/blender/depsgraph/intern/node/deg_node_operation.cc index b0b47f89acf..54a5ecef35c 100644 --- a/source/blender/depsgraph/intern/node/deg_node_operation.cc +++ b/source/blender/depsgraph/intern/node/deg_node_operation.cc @@ -37,112 +37,161 @@ namespace DEG { const char *operationCodeAsString(OperationCode opcode) { - switch (opcode) { - /* Generic Operations. */ - case OperationCode::OPERATION: return "OPERATION"; - case OperationCode::ID_PROPERTY: return "ID_PROPERTY"; - case OperationCode::PARAMETERS_ENTRY: return "PARAMETERS_ENTRY"; - case OperationCode::PARAMETERS_EVAL: return "PARAMETERS_EVAL"; - case OperationCode::PARAMETERS_EXIT: return "PARAMETERS_EXIT"; - /* Animation, Drivers, etc. */ - case OperationCode::ANIMATION_ENTRY: return "ANIMATION_ENTRY"; - case OperationCode::ANIMATION_EVAL: return "ANIMATION_EVAL"; - case OperationCode::ANIMATION_EXIT: return "ANIMATION_EXIT"; - case OperationCode::DRIVER: return "DRIVER"; - /* Scene related. */ - case OperationCode::SCENE_EVAL: return "SCENE_EVAL"; - /* Object related. */ - case OperationCode::OBJECT_BASE_FLAGS: return "OBJECT_BASE_FLAGS"; - /* Transform. */ - case OperationCode::TRANSFORM_INIT: return "TRANSFORM_INIT"; - case OperationCode::TRANSFORM_LOCAL: return "TRANSFORM_LOCAL"; - case OperationCode::TRANSFORM_PARENT: return "TRANSFORM_PARENT"; - case OperationCode::TRANSFORM_CONSTRAINTS: - return "TRANSFORM_CONSTRAINTS"; - case OperationCode::TRANSFORM_FINAL: return "TRANSFORM_FINAL"; - case OperationCode::TRANSFORM_EVAL: return "TRANSFORM_EVAL"; - case OperationCode::TRANSFORM_SIMULATION_INIT: - return "TRANSFORM_SIMULATION_INIT"; - /* Rigid body. */ - case OperationCode::RIGIDBODY_REBUILD: return "RIGIDBODY_REBUILD"; - case OperationCode::RIGIDBODY_SIM: return "RIGIDBODY_SIM"; - case OperationCode::RIGIDBODY_TRANSFORM_COPY: - return "RIGIDBODY_TRANSFORM_COPY"; - /* Geometry. */ - case OperationCode::GEOMETRY_EVAL_INIT: return "GEOMETRY_EVAL_INIT"; - case OperationCode::GEOMETRY_EVAL: return "GEOMETRY_EVAL"; - case OperationCode::GEOMETRY_EVAL_DONE: return "GEOMETRY_EVAL_DONE"; - case OperationCode::GEOMETRY_SHAPEKEY: return "GEOMETRY_SHAPEKEY"; - /* Object data. */ - case OperationCode::LIGHT_PROBE_EVAL: return "LIGHT_PROBE_EVAL"; - case OperationCode::SPEAKER_EVAL: return "SPEAKER_EVAL"; - case OperationCode::ARMATURE_EVAL: return "ARMATURE_EVAL"; - /* Pose. */ - case OperationCode::POSE_INIT: return "POSE_INIT"; - case OperationCode::POSE_INIT_IK: return "POSE_INIT_IK"; - case OperationCode::POSE_CLEANUP: return "POSE_CLEANUP"; - case OperationCode::POSE_DONE: return "POSE_DONE"; - case OperationCode::POSE_IK_SOLVER: return "POSE_IK_SOLVER"; - case OperationCode::POSE_SPLINE_IK_SOLVER: - return "POSE_SPLINE_IK_SOLVER"; - /* Bone. */ - case OperationCode::BONE_LOCAL: return "BONE_LOCAL"; - case OperationCode::BONE_POSE_PARENT: return "BONE_POSE_PARENT"; - case OperationCode::BONE_CONSTRAINTS: return "BONE_CONSTRAINTS"; - case OperationCode::BONE_READY: return "BONE_READY"; - case OperationCode::BONE_DONE: return "BONE_DONE"; - case OperationCode::BONE_SEGMENTS: return "BONE_SEGMENTS"; - /* Particle System. */ - case OperationCode::PARTICLE_SYSTEM_INIT: return "PARTICLE_SYSTEM_INIT"; - case OperationCode::PARTICLE_SYSTEM_EVAL: return "PARTICLE_SYSTEM_EVAL"; - case OperationCode::PARTICLE_SYSTEM_DONE: return "PARTICLE_SYSTEM_DONE"; - /* Particles Settings. */ - case OperationCode::PARTICLE_SETTINGS_INIT: - return "PARTICLE_SETTINGS_INIT"; - case OperationCode::PARTICLE_SETTINGS_EVAL: - return "PARTICLE_SETTINGS_EVAL"; - case OperationCode::PARTICLE_SETTINGS_RESET: - return "PARTICLE_SETTINGS_RESET"; - /* Point Cache. */ - case OperationCode::POINT_CACHE_RESET: return "POINT_CACHE_RESET"; - /* File cache. */ - case OperationCode::FILE_CACHE_UPDATE: return "FILE_CACHE_UPDATE"; - /* Batch cache. */ - case OperationCode::GEOMETRY_SELECT_UPDATE: - return "GEOMETRY_SELECT_UPDATE"; - /* Masks. */ - case OperationCode::MASK_ANIMATION: return "MASK_ANIMATION"; - case OperationCode::MASK_EVAL: return "MASK_EVAL"; - /* Collections. */ - case OperationCode::VIEW_LAYER_EVAL: return "VIEW_LAYER_EVAL"; - /* Copy on write. */ - case OperationCode::COPY_ON_WRITE: return "COPY_ON_WRITE"; - /* Shading. */ - case OperationCode::SHADING: return "SHADING"; - case OperationCode::MATERIAL_UPDATE: return "MATERIAL_UPDATE"; - case OperationCode::WORLD_UPDATE: return "WORLD_UPDATE"; - /* Movie clip. */ - case OperationCode::MOVIECLIP_EVAL: return "MOVIECLIP_EVAL"; - case OperationCode::MOVIECLIP_SELECT_UPDATE: - return "MOVIECLIP_SELECT_UPDATE"; - /* Image. */ - case OperationCode::IMAGE_ANIMATION: return "IMAGE_ANIMATION"; - /* Synchronization. */ - case OperationCode::SYNCHRONIZE_TO_ORIGINAL: - return "SYNCHRONIZE_TO_ORIGINAL"; - /* Generic datablock. */ - case OperationCode::GENERIC_DATABLOCK_UPDATE: - return "GENERIC_DATABLOCK_UPDATE"; - /* instancing/duplication. */ - case OperationCode::DUPLI: return "DUPLI"; - } - BLI_assert(!"Unhandled operation code, should never happen."); - return "UNKNOWN"; + switch (opcode) { + /* Generic Operations. */ + case OperationCode::OPERATION: + return "OPERATION"; + case OperationCode::ID_PROPERTY: + return "ID_PROPERTY"; + case OperationCode::PARAMETERS_ENTRY: + return "PARAMETERS_ENTRY"; + case OperationCode::PARAMETERS_EVAL: + return "PARAMETERS_EVAL"; + case OperationCode::PARAMETERS_EXIT: + return "PARAMETERS_EXIT"; + /* Animation, Drivers, etc. */ + case OperationCode::ANIMATION_ENTRY: + return "ANIMATION_ENTRY"; + case OperationCode::ANIMATION_EVAL: + return "ANIMATION_EVAL"; + case OperationCode::ANIMATION_EXIT: + return "ANIMATION_EXIT"; + case OperationCode::DRIVER: + return "DRIVER"; + /* Scene related. */ + case OperationCode::SCENE_EVAL: + return "SCENE_EVAL"; + /* Object related. */ + case OperationCode::OBJECT_BASE_FLAGS: + return "OBJECT_BASE_FLAGS"; + /* Transform. */ + case OperationCode::TRANSFORM_INIT: + return "TRANSFORM_INIT"; + case OperationCode::TRANSFORM_LOCAL: + return "TRANSFORM_LOCAL"; + case OperationCode::TRANSFORM_PARENT: + return "TRANSFORM_PARENT"; + case OperationCode::TRANSFORM_CONSTRAINTS: + return "TRANSFORM_CONSTRAINTS"; + case OperationCode::TRANSFORM_FINAL: + return "TRANSFORM_FINAL"; + case OperationCode::TRANSFORM_EVAL: + return "TRANSFORM_EVAL"; + case OperationCode::TRANSFORM_SIMULATION_INIT: + return "TRANSFORM_SIMULATION_INIT"; + /* Rigid body. */ + case OperationCode::RIGIDBODY_REBUILD: + return "RIGIDBODY_REBUILD"; + case OperationCode::RIGIDBODY_SIM: + return "RIGIDBODY_SIM"; + case OperationCode::RIGIDBODY_TRANSFORM_COPY: + return "RIGIDBODY_TRANSFORM_COPY"; + /* Geometry. */ + case OperationCode::GEOMETRY_EVAL_INIT: + return "GEOMETRY_EVAL_INIT"; + case OperationCode::GEOMETRY_EVAL: + return "GEOMETRY_EVAL"; + case OperationCode::GEOMETRY_EVAL_DONE: + return "GEOMETRY_EVAL_DONE"; + case OperationCode::GEOMETRY_SHAPEKEY: + return "GEOMETRY_SHAPEKEY"; + /* Object data. */ + case OperationCode::LIGHT_PROBE_EVAL: + return "LIGHT_PROBE_EVAL"; + case OperationCode::SPEAKER_EVAL: + return "SPEAKER_EVAL"; + case OperationCode::ARMATURE_EVAL: + return "ARMATURE_EVAL"; + /* Pose. */ + case OperationCode::POSE_INIT: + return "POSE_INIT"; + case OperationCode::POSE_INIT_IK: + return "POSE_INIT_IK"; + case OperationCode::POSE_CLEANUP: + return "POSE_CLEANUP"; + case OperationCode::POSE_DONE: + return "POSE_DONE"; + case OperationCode::POSE_IK_SOLVER: + return "POSE_IK_SOLVER"; + case OperationCode::POSE_SPLINE_IK_SOLVER: + return "POSE_SPLINE_IK_SOLVER"; + /* Bone. */ + case OperationCode::BONE_LOCAL: + return "BONE_LOCAL"; + case OperationCode::BONE_POSE_PARENT: + return "BONE_POSE_PARENT"; + case OperationCode::BONE_CONSTRAINTS: + return "BONE_CONSTRAINTS"; + case OperationCode::BONE_READY: + return "BONE_READY"; + case OperationCode::BONE_DONE: + return "BONE_DONE"; + case OperationCode::BONE_SEGMENTS: + return "BONE_SEGMENTS"; + /* Particle System. */ + case OperationCode::PARTICLE_SYSTEM_INIT: + return "PARTICLE_SYSTEM_INIT"; + case OperationCode::PARTICLE_SYSTEM_EVAL: + return "PARTICLE_SYSTEM_EVAL"; + case OperationCode::PARTICLE_SYSTEM_DONE: + return "PARTICLE_SYSTEM_DONE"; + /* Particles Settings. */ + case OperationCode::PARTICLE_SETTINGS_INIT: + return "PARTICLE_SETTINGS_INIT"; + case OperationCode::PARTICLE_SETTINGS_EVAL: + return "PARTICLE_SETTINGS_EVAL"; + case OperationCode::PARTICLE_SETTINGS_RESET: + return "PARTICLE_SETTINGS_RESET"; + /* Point Cache. */ + case OperationCode::POINT_CACHE_RESET: + return "POINT_CACHE_RESET"; + /* File cache. */ + case OperationCode::FILE_CACHE_UPDATE: + return "FILE_CACHE_UPDATE"; + /* Batch cache. */ + case OperationCode::GEOMETRY_SELECT_UPDATE: + return "GEOMETRY_SELECT_UPDATE"; + /* Masks. */ + case OperationCode::MASK_ANIMATION: + return "MASK_ANIMATION"; + case OperationCode::MASK_EVAL: + return "MASK_EVAL"; + /* Collections. */ + case OperationCode::VIEW_LAYER_EVAL: + return "VIEW_LAYER_EVAL"; + /* Copy on write. */ + case OperationCode::COPY_ON_WRITE: + return "COPY_ON_WRITE"; + /* Shading. */ + case OperationCode::SHADING: + return "SHADING"; + case OperationCode::MATERIAL_UPDATE: + return "MATERIAL_UPDATE"; + case OperationCode::WORLD_UPDATE: + return "WORLD_UPDATE"; + /* Movie clip. */ + case OperationCode::MOVIECLIP_EVAL: + return "MOVIECLIP_EVAL"; + case OperationCode::MOVIECLIP_SELECT_UPDATE: + return "MOVIECLIP_SELECT_UPDATE"; + /* Image. */ + case OperationCode::IMAGE_ANIMATION: + return "IMAGE_ANIMATION"; + /* Synchronization. */ + case OperationCode::SYNCHRONIZE_TO_ORIGINAL: + return "SYNCHRONIZE_TO_ORIGINAL"; + /* Generic datablock. */ + case OperationCode::GENERIC_DATABLOCK_UPDATE: + return "GENERIC_DATABLOCK_UPDATE"; + /* instancing/duplication. */ + case OperationCode::DUPLI: + return "DUPLI"; + } + BLI_assert(!"Unhandled operation code, should never happen."); + return "UNKNOWN"; } -OperationNode::OperationNode() : - name_tag(-1), - flag(0) +OperationNode::OperationNode() : name_tag(-1), flag(0) { } @@ -152,52 +201,52 @@ OperationNode::~OperationNode() string OperationNode::identifier() const { - return string(operationCodeAsString(opcode)) + "(" + name + ")"; + return string(operationCodeAsString(opcode)) + "(" + name + ")"; } /* Full node identifier, including owner name. * used for logging and debug prints. */ string OperationNode::full_identifier() const { - string owner_str = ""; - if (owner->type == NodeType::BONE) { - owner_str = string(owner->owner->name) + "." + owner->name; - } - else { - owner_str = owner->owner->name; - } - return owner_str + "." + identifier(); + string owner_str = ""; + if (owner->type == NodeType::BONE) { + owner_str = string(owner->owner->name) + "." + owner->name; + } + else { + owner_str = owner->owner->name; + } + return owner_str + "." + identifier(); } void OperationNode::tag_update(Depsgraph *graph, eUpdateSource source) { - if ((flag & DEPSOP_FLAG_NEEDS_UPDATE) == 0) { - graph->add_entry_tag(this); - } - /* Tag for update, but also note that this was the source of an update. */ - flag |= (DEPSOP_FLAG_NEEDS_UPDATE | DEPSOP_FLAG_DIRECTLY_MODIFIED); - switch (source) { - case DEG_UPDATE_SOURCE_TIME: - case DEG_UPDATE_SOURCE_RELATIONS: - case DEG_UPDATE_SOURCE_VISIBILITY: - /* Currently nothing. */ - break; - case DEG_UPDATE_SOURCE_USER_EDIT: - flag |= DEPSOP_FLAG_USER_MODIFIED; - break; - } + if ((flag & DEPSOP_FLAG_NEEDS_UPDATE) == 0) { + graph->add_entry_tag(this); + } + /* Tag for update, but also note that this was the source of an update. */ + flag |= (DEPSOP_FLAG_NEEDS_UPDATE | DEPSOP_FLAG_DIRECTLY_MODIFIED); + switch (source) { + case DEG_UPDATE_SOURCE_TIME: + case DEG_UPDATE_SOURCE_RELATIONS: + case DEG_UPDATE_SOURCE_VISIBILITY: + /* Currently nothing. */ + break; + case DEG_UPDATE_SOURCE_USER_EDIT: + flag |= DEPSOP_FLAG_USER_MODIFIED; + break; + } } void OperationNode::set_as_entry() { - BLI_assert(owner != NULL); - owner->set_entry_operation(this); + BLI_assert(owner != NULL); + owner->set_entry_operation(this); } void OperationNode::set_as_exit() { - BLI_assert(owner != NULL); - owner->set_exit_operation(this); + BLI_assert(owner != NULL); + owner->set_exit_operation(this); } DEG_DEPSNODE_DEFINE(OperationNode, NodeType::OPERATION, "Operation"); @@ -205,7 +254,7 @@ static DepsNodeFactoryImpl DNTI_OPERATION; void deg_register_operation_depsnodes() { - register_node_typeinfo(&DNTI_OPERATION); + register_node_typeinfo(&DNTI_OPERATION); } } // namespace DEG diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.h b/source/blender/depsgraph/intern/node/deg_node_operation.h index 56207b08d4a..c959f7f34e0 100644 --- a/source/blender/depsgraph/intern/node/deg_node_operation.h +++ b/source/blender/depsgraph/intern/node/deg_node_operation.h @@ -40,158 +40,158 @@ typedef function DepsEvalOperationCb; /* Identifiers for common operations (as an enum). */ enum class OperationCode { - /* Generic Operations. -------------------------------------------------- */ - - /* Placeholder for operations which don't need special mention */ - OPERATION = 0, - - /* Generic parameters evaluation. */ - ID_PROPERTY, - PARAMETERS_ENTRY, - PARAMETERS_EVAL, - PARAMETERS_EXIT, - - /* Animation, Drivers, etc. --------------------------------------------- */ - /* NLA + Action */ - ANIMATION_ENTRY, - ANIMATION_EVAL, - ANIMATION_EXIT, - /* Driver */ - DRIVER, - - /* Scene related. ------------------------------------------------------- */ - SCENE_EVAL, - - /* Object related. ------------------------------------------------------ */ - OBJECT_BASE_FLAGS, - - /* Transform. ----------------------------------------------------------- */ - /* Transform entry point. */ - TRANSFORM_INIT, - /* Local transforms only */ - TRANSFORM_LOCAL, - /* Parenting */ - TRANSFORM_PARENT, - /* Constraints */ - TRANSFORM_CONSTRAINTS, - /* Handle object-level updates, mainly proxies hacks and recalc flags. */ - TRANSFORM_EVAL, - /* Initializes transformation for simulation. - * For example, ensures point cache is properly reset before doing rigid - * body simulation. */ - TRANSFORM_SIMULATION_INIT, - /* Transform exit point */ - TRANSFORM_FINAL, - - /* Rigid body. ---------------------------------------------------------- */ - /* Perform Simulation */ - RIGIDBODY_REBUILD, - RIGIDBODY_SIM, - /* Copy results to object */ - RIGIDBODY_TRANSFORM_COPY, - - /* Geometry. ------------------------------------------------------------ */ - - /* Initialize evaluation of the geometry. Is an entry operation of geometry - * component. */ - GEOMETRY_EVAL_INIT, - /* Evaluate the whole geometry, including modifiers. */ - GEOMETRY_EVAL, - /* Evaluation of geometry is completely done.. */ - GEOMETRY_EVAL_DONE, - /* Evaluation of a shape key. - * NOTE: Currently only for object data datablocks. */ - GEOMETRY_SHAPEKEY, - - /* Object data. --------------------------------------------------------- */ - LIGHT_PROBE_EVAL, - SPEAKER_EVAL, - ARMATURE_EVAL, - - /* Pose. ---------------------------------------------------------------- */ - /* Init pose, clear flags, etc. */ - POSE_INIT, - /* Initialize IK solver related pose stuff. */ - POSE_INIT_IK, - /* Pose is evaluated, and runtime data can be freed. */ - POSE_CLEANUP, - /* Pose has been fully evaluated and ready to be used by others. */ - POSE_DONE, - /* IK/Spline Solvers */ - POSE_IK_SOLVER, - POSE_SPLINE_IK_SOLVER, - - /* Bone. ---------------------------------------------------------------- */ - /* Bone local transforms - entry point */ - BONE_LOCAL, - /* Pose-space conversion (includes parent + restpose, */ - BONE_POSE_PARENT, - /* Constraints */ - BONE_CONSTRAINTS, - /* Bone transforms are ready - * - * - "READY" This (internal, noop is used to signal that all pre-IK - * operations are done. Its role is to help mediate situations - * where cyclic relations may otherwise form (i.e. one bone in - * chain targeting another in same chain, - * - * - "DONE" This noop is used to signal that the bone's final pose - * transform can be read by others. */ - // TODO: deform mats could get calculated in the final_transform ops... - BONE_READY, - BONE_DONE, - /* B-Bone segment shape computation (after DONE) */ - BONE_SEGMENTS, - - /* Particle System. ----------------------------------------------------- */ - PARTICLE_SYSTEM_INIT, - PARTICLE_SYSTEM_EVAL, - PARTICLE_SYSTEM_DONE, - - /* Particle Settings. --------------------------------------------------- */ - PARTICLE_SETTINGS_INIT, - PARTICLE_SETTINGS_EVAL, - PARTICLE_SETTINGS_RESET, - - /* Point Cache. --------------------------------------------------------- */ - POINT_CACHE_RESET, - - /* File cache. ---------------------------------------------------------- */ - FILE_CACHE_UPDATE, - - /* Collections. --------------------------------------------------------- */ - VIEW_LAYER_EVAL, - - /* Copy on Write. ------------------------------------------------------- */ - COPY_ON_WRITE, - - /* Shading. ------------------------------------------------------------- */ - SHADING, - MATERIAL_UPDATE, - WORLD_UPDATE, - - /* Batch caches. -------------------------------------------------------- */ - GEOMETRY_SELECT_UPDATE, - - /* Masks. --------------------------------------------------------------- */ - MASK_ANIMATION, - MASK_EVAL, - - /* Movie clips. --------------------------------------------------------- */ - MOVIECLIP_EVAL, - MOVIECLIP_SELECT_UPDATE, - - /* Images. -------------------------------------------------------------- */ - IMAGE_ANIMATION, - - /* Synchronization clips. ----------------------------------------------- */ - SYNCHRONIZE_TO_ORIGINAL, - - /* Generic datablock ---------------------------------------------------- */ - GENERIC_DATABLOCK_UPDATE, - - /* Duplication/instancing system. --------------------------------------- */ - DUPLI, + /* Generic Operations. -------------------------------------------------- */ + + /* Placeholder for operations which don't need special mention */ + OPERATION = 0, + + /* Generic parameters evaluation. */ + ID_PROPERTY, + PARAMETERS_ENTRY, + PARAMETERS_EVAL, + PARAMETERS_EXIT, + + /* Animation, Drivers, etc. --------------------------------------------- */ + /* NLA + Action */ + ANIMATION_ENTRY, + ANIMATION_EVAL, + ANIMATION_EXIT, + /* Driver */ + DRIVER, + + /* Scene related. ------------------------------------------------------- */ + SCENE_EVAL, + + /* Object related. ------------------------------------------------------ */ + OBJECT_BASE_FLAGS, + + /* Transform. ----------------------------------------------------------- */ + /* Transform entry point. */ + TRANSFORM_INIT, + /* Local transforms only */ + TRANSFORM_LOCAL, + /* Parenting */ + TRANSFORM_PARENT, + /* Constraints */ + TRANSFORM_CONSTRAINTS, + /* Handle object-level updates, mainly proxies hacks and recalc flags. */ + TRANSFORM_EVAL, + /* Initializes transformation for simulation. + * For example, ensures point cache is properly reset before doing rigid + * body simulation. */ + TRANSFORM_SIMULATION_INIT, + /* Transform exit point */ + TRANSFORM_FINAL, + + /* Rigid body. ---------------------------------------------------------- */ + /* Perform Simulation */ + RIGIDBODY_REBUILD, + RIGIDBODY_SIM, + /* Copy results to object */ + RIGIDBODY_TRANSFORM_COPY, + + /* Geometry. ------------------------------------------------------------ */ + + /* Initialize evaluation of the geometry. Is an entry operation of geometry + * component. */ + GEOMETRY_EVAL_INIT, + /* Evaluate the whole geometry, including modifiers. */ + GEOMETRY_EVAL, + /* Evaluation of geometry is completely done.. */ + GEOMETRY_EVAL_DONE, + /* Evaluation of a shape key. + * NOTE: Currently only for object data datablocks. */ + GEOMETRY_SHAPEKEY, + + /* Object data. --------------------------------------------------------- */ + LIGHT_PROBE_EVAL, + SPEAKER_EVAL, + ARMATURE_EVAL, + + /* Pose. ---------------------------------------------------------------- */ + /* Init pose, clear flags, etc. */ + POSE_INIT, + /* Initialize IK solver related pose stuff. */ + POSE_INIT_IK, + /* Pose is evaluated, and runtime data can be freed. */ + POSE_CLEANUP, + /* Pose has been fully evaluated and ready to be used by others. */ + POSE_DONE, + /* IK/Spline Solvers */ + POSE_IK_SOLVER, + POSE_SPLINE_IK_SOLVER, + + /* Bone. ---------------------------------------------------------------- */ + /* Bone local transforms - entry point */ + BONE_LOCAL, + /* Pose-space conversion (includes parent + restpose, */ + BONE_POSE_PARENT, + /* Constraints */ + BONE_CONSTRAINTS, + /* Bone transforms are ready + * + * - "READY" This (internal, noop is used to signal that all pre-IK + * operations are done. Its role is to help mediate situations + * where cyclic relations may otherwise form (i.e. one bone in + * chain targeting another in same chain, + * + * - "DONE" This noop is used to signal that the bone's final pose + * transform can be read by others. */ + // TODO: deform mats could get calculated in the final_transform ops... + BONE_READY, + BONE_DONE, + /* B-Bone segment shape computation (after DONE) */ + BONE_SEGMENTS, + + /* Particle System. ----------------------------------------------------- */ + PARTICLE_SYSTEM_INIT, + PARTICLE_SYSTEM_EVAL, + PARTICLE_SYSTEM_DONE, + + /* Particle Settings. --------------------------------------------------- */ + PARTICLE_SETTINGS_INIT, + PARTICLE_SETTINGS_EVAL, + PARTICLE_SETTINGS_RESET, + + /* Point Cache. --------------------------------------------------------- */ + POINT_CACHE_RESET, + + /* File cache. ---------------------------------------------------------- */ + FILE_CACHE_UPDATE, + + /* Collections. --------------------------------------------------------- */ + VIEW_LAYER_EVAL, + + /* Copy on Write. ------------------------------------------------------- */ + COPY_ON_WRITE, + + /* Shading. ------------------------------------------------------------- */ + SHADING, + MATERIAL_UPDATE, + WORLD_UPDATE, + + /* Batch caches. -------------------------------------------------------- */ + GEOMETRY_SELECT_UPDATE, + + /* Masks. --------------------------------------------------------------- */ + MASK_ANIMATION, + MASK_EVAL, + + /* Movie clips. --------------------------------------------------------- */ + MOVIECLIP_EVAL, + MOVIECLIP_SELECT_UPDATE, + + /* Images. -------------------------------------------------------------- */ + IMAGE_ANIMATION, + + /* Synchronization clips. ----------------------------------------------- */ + SYNCHRONIZE_TO_ORIGINAL, + + /* Generic datablock ---------------------------------------------------- */ + GENERIC_DATABLOCK_UPDATE, + + /* Duplication/instancing system. --------------------------------------- */ + DUPLI, }; const char *operationCodeAsString(OperationCode opcode); @@ -199,58 +199,63 @@ const char *operationCodeAsString(OperationCode opcode); * NOTE: IS a bit shifts to allow usage as an accumulated. bitmask. */ enum OperationFlag { - /* Node needs to be updated. */ - DEPSOP_FLAG_NEEDS_UPDATE = (1 << 0), - /* Node was directly modified, causing need for update. */ - DEPSOP_FLAG_DIRECTLY_MODIFIED = (1 << 1), - /* Node was updated due to user input. */ - DEPSOP_FLAG_USER_MODIFIED = (1 << 2), - - /* Set of flags which gets flushed along the relations. */ - DEPSOP_FLAG_FLUSH = (DEPSOP_FLAG_USER_MODIFIED), + /* Node needs to be updated. */ + DEPSOP_FLAG_NEEDS_UPDATE = (1 << 0), + /* Node was directly modified, causing need for update. */ + DEPSOP_FLAG_DIRECTLY_MODIFIED = (1 << 1), + /* Node was updated due to user input. */ + DEPSOP_FLAG_USER_MODIFIED = (1 << 2), + + /* Set of flags which gets flushed along the relations. */ + DEPSOP_FLAG_FLUSH = (DEPSOP_FLAG_USER_MODIFIED), }; /* Atomic Operation - Base type for all operations */ struct OperationNode : public Node { - OperationNode(); - ~OperationNode(); + OperationNode(); + ~OperationNode(); - virtual string identifier() const override; - string full_identifier() const; + virtual string identifier() const override; + string full_identifier() const; - virtual void tag_update(Depsgraph *graph, eUpdateSource source) override; + virtual void tag_update(Depsgraph *graph, eUpdateSource source) override; - bool is_noop() const { return (bool)evaluate == false; } + bool is_noop() const + { + return (bool)evaluate == false; + } - virtual OperationNode *get_entry_operation() override { - return this; - } - virtual OperationNode *get_exit_operation() override { - return this; - } + virtual OperationNode *get_entry_operation() override + { + return this; + } + virtual OperationNode *get_exit_operation() override + { + return this; + } - /* Set this operation as component's entry/exit operation. */ - void set_as_entry(); - void set_as_exit(); + /* Set this operation as component's entry/exit operation. */ + void set_as_entry(); + void set_as_exit(); - /* Component that contains the operation. */ - ComponentNode *owner; + /* Component that contains the operation. */ + ComponentNode *owner; - /* Callback for operation. */ - DepsEvalOperationCb evaluate; + /* Callback for operation. */ + DepsEvalOperationCb evaluate; - /* How many inlinks are we still waiting on before we can be evaluated. */ - uint32_t num_links_pending; - bool scheduled; + /* How many inlinks are we still waiting on before we can be evaluated. */ + uint32_t num_links_pending; + bool scheduled; - /* Identifier for the operation being performed. */ - OperationCode opcode; - int name_tag; + /* Identifier for the operation being performed. */ + OperationCode opcode; + int name_tag; - /* (OperationFlag) extra settings affecting evaluation. */ - int flag; + /* (OperationFlag) extra settings affecting evaluation. */ + int flag; - DEG_DEPSNODE_DECLARE; + DEG_DEPSNODE_DECLARE; }; void deg_register_operation_depsnodes(); diff --git a/source/blender/depsgraph/intern/node/deg_node_time.cc b/source/blender/depsgraph/intern/node/deg_node_time.cc index 24d99d23c25..cae98ef56c0 100644 --- a/source/blender/depsgraph/intern/node/deg_node_time.cc +++ b/source/blender/depsgraph/intern/node/deg_node_time.cc @@ -31,10 +31,10 @@ namespace DEG { void TimeSourceNode::tag_update(Depsgraph *graph, eUpdateSource /*source*/) { - for (Relation *rel : outlinks) { - Node *node = rel->to; - node->tag_update(graph, DEG_UPDATE_SOURCE_TIME); - } + for (Relation *rel : outlinks) { + Node *node = rel->to; + node->tag_update(graph, DEG_UPDATE_SOURCE_TIME); + } } } // namespace DEG diff --git a/source/blender/depsgraph/intern/node/deg_node_time.h b/source/blender/depsgraph/intern/node/deg_node_time.h index 44b67ebc307..684414f7780 100644 --- a/source/blender/depsgraph/intern/node/deg_node_time.h +++ b/source/blender/depsgraph/intern/node/deg_node_time.h @@ -29,17 +29,17 @@ namespace DEG { /* Time Source Node. */ struct TimeSourceNode : public Node { - /* New "current time". */ - float cfra; + /* New "current time". */ + float cfra; - /* time-offset relative to the "official" time source that this one has. */ - float offset; + /* time-offset relative to the "official" time source that this one has. */ + float offset; - // TODO: evaluate() operation needed + // TODO: evaluate() operation needed - virtual void tag_update(Depsgraph *graph, eUpdateSource source) override; + virtual void tag_update(Depsgraph *graph, eUpdateSource source) override; - DEG_DEPSNODE_DECLARE; + DEG_DEPSNODE_DECLARE; }; } // namespace DEG -- cgit v1.2.3