diff options
Diffstat (limited to 'source/blender/depsgraph/intern/eval')
19 files changed, 316 insertions, 104 deletions
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc index 2d9d40aede6..426e04a5cf9 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval.cc @@ -37,6 +37,7 @@ #include "intern/eval/deg_eval_copy_on_write.h" #include "intern/eval/deg_eval_flush.h" #include "intern/eval/deg_eval_stats.h" +#include "intern/eval/deg_eval_visibility.h" #include "intern/node/deg_node.h" #include "intern/node/deg_node_component.h" #include "intern/node/deg_node_id.h" @@ -69,6 +70,9 @@ enum class EvaluationStage { * involved. */ COPY_ON_WRITE, + /* Evaluate actual ID nodes visiblity based on the current state of animation and drivers. */ + DYNAMIC_VISIBILITY, + /* Threaded evaluation of all possible operations. */ THREADED_EVALUATION, @@ -83,7 +87,8 @@ struct DepsgraphEvalState { Depsgraph *graph; bool do_stats; EvaluationStage stage; - bool need_single_thread_pass; + bool need_update_pending_parents = true; + bool need_single_thread_pass = false; }; void evaluate_node(const DepsgraphEvalState *state, OperationNode *operation_node) @@ -101,6 +106,12 @@ void evaluate_node(const DepsgraphEvalState *state, OperationNode *operation_nod else { operation_node->evaluate(depsgraph); } + + /* Clear the flag early on, allowing partial updates without re-evaluating the same node multiple + * times. + * This is a thread-safe modification as the node's flags are only read for a non-scheduled nodes + * and this node has been scheduled. */ + operation_node->flag &= ~DEPSOP_FLAG_NEEDS_UPDATE; } void deg_task_run_func(TaskPool *pool, void *taskdata) @@ -116,24 +127,31 @@ void deg_task_run_func(TaskPool *pool, void *taskdata) schedule_children(state, operation_node, schedule_node_to_pool, pool); } -bool check_operation_node_visible(OperationNode *op_node) +bool check_operation_node_visible(const DepsgraphEvalState *state, 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. */ + /* Special case for copy on write component: it 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; + + /* Special case for dynamic visiblity pass: the actual visibility is not yet known, so limit to + * only operations which affects visibility. */ + if (state->stage == EvaluationStage::DYNAMIC_VISIBILITY) { + return op_node->flag & OperationFlag::DEPSOP_FLAG_AFFECTS_VISIBILITY; + } + + return comp_node->affects_visible_id; } -void calculate_pending_parents_for_node(OperationNode *node) +void calculate_pending_parents_for_node(const DepsgraphEvalState *state, OperationNode *node) { /* 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)) { + if (!check_operation_node_visible(state, node)) { return; } /* No need to bother with anything if node is not tagged for update. */ @@ -147,7 +165,7 @@ void calculate_pending_parents_for_node(OperationNode *node) * 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)) { + if (!check_operation_node_visible(state, from)) { continue; } /* No need to wait for operation which is up to date. */ @@ -159,20 +177,24 @@ void calculate_pending_parents_for_node(OperationNode *node) } } -void calculate_pending_parents(Depsgraph *graph) +void calculate_pending_parents_if_needed(DepsgraphEvalState *state) { - for (OperationNode *node : graph->operations) { - calculate_pending_parents_for_node(node); + if (!state->need_update_pending_parents) { + return; } + + for (OperationNode *node : state->graph->operations) { + calculate_pending_parents_for_node(state, node); + } + + state->need_update_pending_parents = false; } 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) { + if (state->do_stats) { + for (OperationNode *node : graph->operations) { node->stats.reset_current(); } } @@ -197,11 +219,10 @@ bool need_evaluate_operation_at_stage(DepsgraphEvalState *state, case EvaluationStage::COPY_ON_WRITE: return (component_node->type == NodeType::COPY_ON_WRITE); + case EvaluationStage::DYNAMIC_VISIBILITY: + return operation_node->flag & OperationFlag::DEPSOP_FLAG_AFFECTS_VISIBILITY; + case EvaluationStage::THREADED_EVALUATION: - /* Sanity check: copy-on-write node should be evaluated already. This will be indicated by - * scheduled flag (we assume that scheduled operations have been actually handled by previous - * stage). */ - BLI_assert(operation_node->scheduled || component_node->type != NodeType::COPY_ON_WRITE); if (is_metaball_object_operation(operation_node)) { state->need_single_thread_pass = true; return false; @@ -227,7 +248,7 @@ void schedule_node(DepsgraphEvalState *state, ScheduleFunctionArgs... schedule_function_args) { /* No need to schedule nodes of invisible ID. */ - if (!check_operation_node_visible(node)) { + if (!check_operation_node_visible(state, node)) { return; } /* No need to schedule operations which are not tagged for update, they are @@ -302,8 +323,32 @@ void schedule_node_to_queue(OperationNode *node, BLI_gsqueue_push(evaluation_queue, &node); } -void evaluate_graph_single_threaded(DepsgraphEvalState *state) +/* Evaluate given stage of the dependency graph evaluation using multiple threads. + * + * NOTE: Will assign the `state->stage` to the given stage. */ +void evaluate_graph_threaded_stage(DepsgraphEvalState *state, + TaskPool *task_pool, + const EvaluationStage stage) +{ + state->stage = stage; + + calculate_pending_parents_if_needed(state); + + schedule_graph(state, schedule_node_to_pool, task_pool); + BLI_task_pool_work_and_wait(task_pool); +} + +/* Evaluate remaining operations of the dependency graph in a single threaded manner. */ +void evaluate_graph_single_threaded_if_needed(DepsgraphEvalState *state) { + if (!state->need_single_thread_pass) { + return; + } + + BLI_assert(!state->need_update_pending_parents); + + state->stage = EvaluationStage::SINGLE_THREADED_WORKAROUND; + GSQueue *evaluation_queue = BLI_gsqueue_new(sizeof(OperationNode *)); schedule_graph(state, schedule_node_to_queue, evaluation_queue); @@ -334,9 +379,7 @@ void depsgraph_ensure_view_layer(Depsgraph *graph) deg_update_copy_on_write_datablock(graph, scene_id_node); } -} // namespace - -static TaskPool *deg_evaluate_task_pool_create(DepsgraphEvalState *state) +TaskPool *deg_evaluate_task_pool_create(DepsgraphEvalState *state) { if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) { return BLI_task_pool_create_no_threads(state); @@ -345,6 +388,8 @@ static TaskPool *deg_evaluate_task_pool_create(DepsgraphEvalState *state) return BLI_task_pool_create_suspended(state, TASK_PRIORITY_HIGH); } +} // namespace + void deg_evaluate_on_refresh(Depsgraph *graph) { /* Nothing to update, early out. */ @@ -361,40 +406,66 @@ void deg_evaluate_on_refresh(Depsgraph *graph) graph->is_evaluating = true; depsgraph_ensure_view_layer(graph); + /* Set up evaluation state. */ DepsgraphEvalState state; state.graph = graph; state.do_stats = graph->debug.do_time_debug(); - state.need_single_thread_pass = false; + /* Prepare all nodes for evaluation. */ initialize_execution(&state, graph); - /* Do actual evaluation now. */ - /* First, process all Copy-On-Write nodes. */ - state.stage = EvaluationStage::COPY_ON_WRITE; + /* Evaluation happens in several incremental steps: + * + * - Start with the copy-on-write operations which never form dependency cycles. This will ensure + * that if a dependency graph has a cycle evaluation functions will always "see" valid expanded + * datablock. It might not be evaluated yet, but at least the datablock will be valid. + * + * - If there is potentially dynamically changing visibility in the graph update the actual + * nodes visibilities, so that actual heavy data evaluation can benefit from knowledge that + * something heavy is not currently visible. + * + * - Multi-threaded evaluation of all possible nodes. + * Certain operations (and their subtrees) could be ignored. For example, meta-balls are not + * safe from threading point of view, so the threaded evaluation will stop at the metaball + * operation node. + * + * - Single-threaded pass of all remaining operations. */ + TaskPool *task_pool = deg_evaluate_task_pool_create(&state); - schedule_graph(&state, schedule_node_to_pool, task_pool); - BLI_task_pool_work_and_wait(task_pool); - BLI_task_pool_free(task_pool); - /* After that, process all other nodes. */ - state.stage = EvaluationStage::THREADED_EVALUATION; - task_pool = deg_evaluate_task_pool_create(&state); - schedule_graph(&state, schedule_node_to_pool, task_pool); - BLI_task_pool_work_and_wait(task_pool); - BLI_task_pool_free(task_pool); + evaluate_graph_threaded_stage(&state, task_pool, EvaluationStage::COPY_ON_WRITE); + + if (graph->has_animated_visibility) { + /* Update pending parents including only the ones which are affecting operations which are + * affecting visibility. */ + state.need_update_pending_parents = true; + + evaluate_graph_threaded_stage(&state, task_pool, EvaluationStage::DYNAMIC_VISIBILITY); + + deg_graph_flush_visibility_flags_if_needed(graph); - if (state.need_single_thread_pass) { - state.stage = EvaluationStage::SINGLE_THREADED_WORKAROUND; - evaluate_graph_single_threaded(&state); + /* Update parents to an updated visibility and evaluation stage. + * + * Need to do it regardless of whether visibility is actually changed or not: current state of + * the pending parents are all zeroes because it was previously calculated for only visibility + * related nodes and those are fully evaluated by now. */ + state.need_update_pending_parents = true; } + evaluate_graph_threaded_stage(&state, task_pool, EvaluationStage::THREADED_EVALUATION); + + BLI_task_pool_free(task_pool); + + evaluate_graph_single_threaded_if_needed(&state); + /* 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); graph->is_evaluating = false; diff --git a/source/blender/depsgraph/intern/eval/deg_eval.h b/source/blender/depsgraph/intern/eval/deg_eval.h index ba86e1a349d..6937231d81a 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval.h +++ b/source/blender/depsgraph/intern/eval/deg_eval.h @@ -9,8 +9,7 @@ #pragma once -namespace blender { -namespace deg { +namespace blender::deg { struct Depsgraph; @@ -23,5 +22,4 @@ struct Depsgraph; */ void deg_evaluate_on_refresh(Depsgraph *graph); -} // namespace deg -} // namespace blender +} // namespace blender::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 29322d58218..cbf450aa3f1 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 @@ -27,8 +27,7 @@ struct ID; struct Depsgraph; -namespace blender { -namespace deg { +namespace blender::deg { struct Depsgraph; class DepsgraphNodeBuilder; @@ -77,5 +76,4 @@ bool deg_copy_on_write_is_expanded(const struct ID *id_cow); bool deg_copy_on_write_is_needed(const ID *id_orig); bool deg_copy_on_write_is_needed(const ID_Type id_type); -} // namespace deg -} // namespace blender +} // namespace blender::deg diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.h b/source/blender/depsgraph/intern/eval/deg_eval_flush.h index 6eb232e76e5..614ca66faed 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.h @@ -9,8 +9,7 @@ #pragma once -namespace blender { -namespace deg { +namespace blender::deg { struct Depsgraph; @@ -24,5 +23,4 @@ void deg_graph_flush_updates(struct Depsgraph *graph); */ void deg_graph_clear_tags(struct Depsgraph *graph); -} // namespace deg -} // namespace blender +} // namespace blender::deg diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h index deb21715a28..3d9b308c5ad 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h @@ -17,8 +17,7 @@ #include "intern/eval/deg_eval_runtime_backup_sound.h" #include "intern/eval/deg_eval_runtime_backup_volume.h" -namespace blender { -namespace deg { +namespace blender::deg { struct Depsgraph; @@ -59,5 +58,4 @@ class RuntimeBackup { GPencilBackup gpencil_backup; }; -} // namespace deg -} // namespace blender +} // namespace blender::deg diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.h index 92847b330e8..807cc91242e 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.h @@ -11,8 +11,7 @@ #include "intern/depsgraph_type.h" -namespace blender { -namespace deg { +namespace blender::deg { struct Depsgraph; @@ -46,5 +45,4 @@ class AnimationBackup { Vector<AnimationValueBackup> values_backup; }; -} // namespace deg -} // namespace blender +} // namespace blender::deg diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_gpencil.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_gpencil.h index 68eff01fd60..95c0ca3a2fe 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_gpencil.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_gpencil.h @@ -9,8 +9,7 @@ struct bGPdata; -namespace blender { -namespace deg { +namespace blender::deg { struct Depsgraph; @@ -25,5 +24,4 @@ class GPencilBackup { const Depsgraph *depsgraph; }; -} // namespace deg -} // namespace blender +} // namespace blender::deg diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.h index faec8f7c065..ee51204b24c 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.h @@ -11,8 +11,7 @@ struct ModifierData; -namespace blender { -namespace deg { +namespace blender::deg { class ModifierDataBackup { public: @@ -22,5 +21,4 @@ class ModifierDataBackup { void *runtime; }; -} // namespace deg -} // namespace blender +} // namespace blender::deg diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.h index 0e826e8f72a..aa13914d8c8 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.h @@ -11,8 +11,7 @@ struct MovieClip; struct MovieClipCache; struct anim; -namespace blender { -namespace deg { +namespace blender::deg { struct Depsgraph; @@ -30,5 +29,4 @@ class MovieClipBackup { struct MovieClipCache *cache; }; -} // namespace deg -} // namespace blender +} // namespace blender::deg diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.h index 3b138feec0b..c9cc167d927 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.h @@ -17,8 +17,7 @@ struct Object; -namespace blender { -namespace deg { +namespace blender::deg { struct Depsgraph; @@ -46,5 +45,4 @@ class ObjectRuntimeBackup { Map<SessionUUID, bPoseChannel_Runtime> pose_channel_runtime_data; }; -} // namespace deg -} // namespace blender +} // namespace blender::deg diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.h index 8fd5de44001..2f6a3dd4371 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.h @@ -11,8 +11,6 @@ #include "DNA_action_types.h" -namespace blender { -namespace deg { +namespace blender::deg { -} -} // namespace blender +} // namespace blender::deg diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.h index 17683966a22..155cb42a96d 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.h @@ -11,8 +11,7 @@ struct Scene; -namespace blender { -namespace deg { +namespace blender::deg { struct Depsgraph; @@ -40,5 +39,4 @@ class SceneBackup { SequencerBackup sequencer_backup; }; -} // namespace deg -} // namespace blender +} // namespace blender::deg diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.h index 95fbd2a3e4e..f97b6b200e9 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.h @@ -11,8 +11,7 @@ struct Sequence; -namespace blender { -namespace deg { +namespace blender::deg { struct Depsgraph; @@ -32,5 +31,4 @@ class SequenceBackup { ListBase anims; }; -} // namespace deg -} // namespace blender +} // namespace blender::deg diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.h index 19e1a63ab4c..38fb8e81cc3 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.h @@ -16,8 +16,7 @@ struct Scene; -namespace blender { -namespace deg { +namespace blender::deg { struct Depsgraph; @@ -34,5 +33,4 @@ class SequencerBackup { Map<SessionUUID, SequenceBackup> sequences_backup; }; -} // namespace deg -} // namespace blender +} // namespace blender::deg diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.h index c4267be1421..9e1d15251e8 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.h @@ -9,8 +9,7 @@ struct bSound; -namespace blender { -namespace deg { +namespace blender::deg { struct Depsgraph; @@ -29,5 +28,4 @@ class SoundBackup { void *playback_handle; }; -} // namespace deg -} // namespace blender +} // namespace blender::deg diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_volume.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_volume.h index bc263cc58f8..60cba64f120 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_volume.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_volume.h @@ -10,8 +10,7 @@ struct Volume; struct VolumeGridVector; -namespace blender { -namespace deg { +namespace blender::deg { struct Depsgraph; @@ -27,5 +26,4 @@ class VolumeBackup { char filepath[1024]; /* FILE_MAX */ }; -} // namespace deg -} // namespace blender +} // namespace blender::deg diff --git a/source/blender/depsgraph/intern/eval/deg_eval_stats.h b/source/blender/depsgraph/intern/eval/deg_eval_stats.h index a1e3cdaca76..c24c5f07135 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_stats.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_stats.h @@ -7,13 +7,11 @@ #pragma once -namespace blender { -namespace deg { +namespace blender::deg { struct Depsgraph; /* Aggregate operation timings to overall component and ID nodes timing. */ void deg_eval_stats_aggregate(Depsgraph *graph); -} // namespace deg -} // namespace blender +} // namespace blender::deg diff --git a/source/blender/depsgraph/intern/eval/deg_eval_visibility.cc b/source/blender/depsgraph/intern/eval/deg_eval_visibility.cc new file mode 100644 index 00000000000..8bf26e45e2a --- /dev/null +++ b/source/blender/depsgraph/intern/eval/deg_eval_visibility.cc @@ -0,0 +1,147 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup depsgraph + */ + +#include "intern/eval/deg_eval_visibility.h" + +#include "DNA_layer_types.h" +#include "DNA_object_types.h" + +#include "BLI_assert.h" +#include "BLI_stack.h" + +#include "DEG_depsgraph.h" + +#include "intern/depsgraph.h" +#include "intern/depsgraph_relation.h" +#include "intern/node/deg_node.h" +#include "intern/node/deg_node_component.h" +#include "intern/node/deg_node_id.h" +#include "intern/node/deg_node_operation.h" + +namespace blender::deg { + +void deg_evaluate_object_node_visibility(::Depsgraph *depsgraph, IDNode *id_node) +{ + BLI_assert(GS(id_node->id_cow->name) == ID_OB); + + Depsgraph *graph = reinterpret_cast<Depsgraph *>(depsgraph); + const Object *object = reinterpret_cast<const Object *>(id_node->id_cow); + + DEG_debug_print_eval(depsgraph, __func__, object->id.name, &object->id); + + const int required_flags = (graph->mode == DAG_EVAL_VIEWPORT) ? BASE_ENABLED_VIEWPORT : + BASE_ENABLED_RENDER; + + const bool is_enabled = object->base_flag & required_flags; + + if (id_node->is_enabled_on_eval != is_enabled) { + id_node->is_enabled_on_eval = is_enabled; + + /* Tag dependency graph for changed visibility, so that it is updated on all dependencies prior + * to a pass of an actual evaluation. */ + graph->need_update_nodes_visibility = true; + } +} + +void deg_graph_flush_visibility_flags(Depsgraph *graph) +{ + enum { + DEG_NODE_VISITED = (1 << 0), + }; + + for (IDNode *id_node : graph->id_nodes) { + for (ComponentNode *comp_node : id_node->components.values()) { + comp_node->possibly_affects_visible_id = id_node->is_visible_on_build; + comp_node->affects_visible_id = id_node->is_visible_on_build && id_node->is_enabled_on_eval; + } + } + + BLI_Stack *stack = BLI_stack_new(sizeof(OperationNode *), "DEG flush layers stack"); + + 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 flags to parents. */ + for (Relation *rel : op_node->inlinks) { + if (rel->from->type == NodeType::OPERATION) { + const OperationNode *op_to = reinterpret_cast<const OperationNode *>(rel->to); + const ComponentNode *comp_to = op_to->owner; + OperationNode *op_from = reinterpret_cast<OperationNode *>(rel->from); + ComponentNode *comp_from = op_from->owner; + + const bool target_possibly_affects_visible_id = comp_to->possibly_affects_visible_id; + const bool target_affects_visible_id = comp_to->affects_visible_id; + + op_from->flag |= (op_to->flag & OperationFlag::DEPSOP_FLAG_AFFECTS_VISIBILITY); + + /* Visibility component forces all components of the current ID to be considered as + * affecting directly visible. */ + if (comp_from->type == NodeType::VISIBILITY) { + const IDNode *id_node_from = comp_from->owner; + if (target_possibly_affects_visible_id) { + for (ComponentNode *comp_node : id_node_from->components.values()) { + comp_node->possibly_affects_visible_id |= target_possibly_affects_visible_id; + } + } + if (target_affects_visible_id) { + for (ComponentNode *comp_node : id_node_from->components.values()) { + comp_node->affects_visible_id |= target_affects_visible_id; + } + } + } + else { + comp_from->possibly_affects_visible_id |= target_possibly_affects_visible_id; + comp_from->affects_visible_id |= target_affects_visible_id; + } + } + } + + /* 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); + + graph->need_update_nodes_visibility = false; +} + +void deg_graph_flush_visibility_flags_if_needed(Depsgraph *graph) +{ + if (!graph->need_update_nodes_visibility) { + return; + } + + deg_graph_flush_visibility_flags(graph); +} + +} // namespace blender::deg diff --git a/source/blender/depsgraph/intern/eval/deg_eval_visibility.h b/source/blender/depsgraph/intern/eval/deg_eval_visibility.h new file mode 100644 index 00000000000..9e9db8ab34a --- /dev/null +++ b/source/blender/depsgraph/intern/eval/deg_eval_visibility.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup depsgraph + */ + +#pragma once + +struct Depsgraph; + +namespace blender::deg { + +struct Depsgraph; +struct IDNode; + +/* Evaluate actual node visibility flags based on the current state of object's visibility + * restriction flags. */ +void deg_evaluate_object_node_visibility(::Depsgraph *depsgraph, IDNode *id_node); + +/* Flush both static and dynamic visibility flags from leaves up to the roots, making it possible + * to know whether a node has affect on something (potentially) visible. */ +void deg_graph_flush_visibility_flags(Depsgraph *graph); +void deg_graph_flush_visibility_flags_if_needed(Depsgraph *graph); + +} // namespace blender::deg |