From 2280a71f900eb7907c243f76930a7e9779a90d7d Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 19 Jul 2022 12:41:47 +0200 Subject: Depsgraph: Refactor evaluation into smaller reusable functions Should be no functional changes. --- source/blender/depsgraph/intern/eval/deg_eval.cc | 52 +++++++++++++++++------- 1 file changed, 37 insertions(+), 15 deletions(-) (limited to 'source/blender/depsgraph') diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc index 64334e95c4c..9da9586c1cf 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval.cc @@ -302,8 +302,28 @@ 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; + + 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; + } + + state->stage = EvaluationStage::SINGLE_THREADED_WORKAROUND; + GSQueue *evaluation_queue = BLI_gsqueue_new(sizeof(OperationNode *)); schedule_graph(state, schedule_node_to_queue, evaluation_queue); @@ -371,25 +391,27 @@ void deg_evaluate_on_refresh(Depsgraph *graph) /* Prepare all nodes for evaluation. */ initialize_execution(&state, graph); - TaskPool *task_pool = deg_evaluate_task_pool_create(&state); + /* 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. + * + * - 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. */ - /* Do actual evaluation now. */ - /* First, process all Copy-On-Write nodes. */ - state.stage = EvaluationStage::COPY_ON_WRITE; - schedule_graph(&state, schedule_node_to_pool, task_pool); - BLI_task_pool_work_and_wait(task_pool); + TaskPool *task_pool = deg_evaluate_task_pool_create(&state); - /* After that, process all other nodes. */ - state.stage = EvaluationStage::THREADED_EVALUATION; - schedule_graph(&state, schedule_node_to_pool, task_pool); - BLI_task_pool_work_and_wait(task_pool); + evaluate_graph_threaded_stage(&state, task_pool, EvaluationStage::COPY_ON_WRITE); + evaluate_graph_threaded_stage(&state, task_pool, EvaluationStage::THREADED_EVALUATION); BLI_task_pool_free(task_pool); - if (state.need_single_thread_pass) { - state.stage = EvaluationStage::SINGLE_THREADED_WORKAROUND; - evaluate_graph_single_threaded(&state); - } + 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 -- cgit v1.2.3