Changeset View
Changeset View
Standalone View
Standalone View
source/blender/depsgraph/intern/eval/deg_eval.cc
| /* SPDX-License-Identifier: GPL-2.0-or-later | /* SPDX-License-Identifier: GPL-2.0-or-later | ||||
| * Copyright 2013 Blender Foundation. All rights reserved. */ | * Copyright 2013 Blender Foundation. All rights reserved. */ | ||||
| /** \file | /** \file | ||||
| * \ingroup depsgraph | * \ingroup depsgraph | ||||
| * | * | ||||
| * Evaluation engine entry-points for Depsgraph Engine. | * Evaluation engine entry-points for Depsgraph Engine. | ||||
| */ | */ | ||||
| #include "intern/eval/deg_eval.h" | #include "intern/eval/deg_eval.h" | ||||
| #include "PIL_time.h" | #include "PIL_time.h" | ||||
| #include "BLI_compiler_attrs.h" | #include "BLI_compiler_attrs.h" | ||||
| #include "BLI_function_ref.hh" | |||||
| #include "BLI_gsqueue.h" | #include "BLI_gsqueue.h" | ||||
| #include "BLI_task.h" | #include "BLI_task.h" | ||||
| #include "BLI_utildefines.h" | #include "BLI_utildefines.h" | ||||
| #include "BKE_global.h" | #include "BKE_global.h" | ||||
| #include "DNA_node_types.h" | #include "DNA_node_types.h" | ||||
| #include "DNA_object_types.h" | #include "DNA_object_types.h" | ||||
| Show All 24 Lines | |||||
| namespace blender::deg { | namespace blender::deg { | ||||
| namespace { | namespace { | ||||
| struct DepsgraphEvalState; | struct DepsgraphEvalState; | ||||
| void deg_task_run_func(TaskPool *pool, void *taskdata); | void deg_task_run_func(TaskPool *pool, void *taskdata); | ||||
| template<typename ScheduleFunction, typename... ScheduleFunctionArgs> | |||||
| void schedule_children(DepsgraphEvalState *state, | void schedule_children(DepsgraphEvalState *state, | ||||
| OperationNode *node, | OperationNode *node, | ||||
| ScheduleFunction *schedule_function, | FunctionRef<void(OperationNode *node)> schedule_fn); | ||||
| ScheduleFunctionArgs... schedule_function_args); | |||||
| void schedule_node_to_pool(OperationNode *node, const int /*thread_id*/, TaskPool *pool) | |||||
| { | |||||
| BLI_task_pool_push(pool, deg_task_run_func, node, false, nullptr); | |||||
| } | |||||
| /* Denotes which part of dependency graph is being evaluated. */ | /* Denotes which part of dependency graph is being evaluated. */ | ||||
| enum class EvaluationStage { | enum class EvaluationStage { | ||||
| /* Stage 1: Only Copy-on-Write operations are to be evaluated, prior to anything else. | /* Stage 1: Only Copy-on-Write operations are to be evaluated, prior to anything else. | ||||
| * This allows other operations to access its dependencies when there is a dependency cycle | * This allows other operations to access its dependencies when there is a dependency cycle | ||||
| * involved. */ | * involved. */ | ||||
| COPY_ON_WRITE, | COPY_ON_WRITE, | ||||
| ▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | void deg_task_run_func(TaskPool *pool, void *taskdata) | ||||
| void *userdata_v = BLI_task_pool_user_data(pool); | void *userdata_v = BLI_task_pool_user_data(pool); | ||||
| DepsgraphEvalState *state = (DepsgraphEvalState *)userdata_v; | DepsgraphEvalState *state = (DepsgraphEvalState *)userdata_v; | ||||
| /* Evaluate node. */ | /* Evaluate node. */ | ||||
| OperationNode *operation_node = reinterpret_cast<OperationNode *>(taskdata); | OperationNode *operation_node = reinterpret_cast<OperationNode *>(taskdata); | ||||
| evaluate_node(state, operation_node); | evaluate_node(state, operation_node); | ||||
| /* Schedule children. */ | /* Schedule children. */ | ||||
| schedule_children(state, operation_node, schedule_node_to_pool, pool); | schedule_children(state, operation_node, [&](OperationNode *node) { | ||||
| BLI_task_pool_push(pool, deg_task_run_func, node, false, nullptr); | |||||
| }); | |||||
| } | } | ||||
| bool check_operation_node_visible(const DepsgraphEvalState *state, OperationNode *op_node) | bool check_operation_node_visible(const DepsgraphEvalState *state, OperationNode *op_node) | ||||
| { | { | ||||
| const ComponentNode *comp_node = op_node->owner; | const ComponentNode *comp_node = op_node->owner; | ||||
| /* Special case for copy on write component: it is to be always evaluated, to keep copied | /* Special case for copy on write component: it is to be always evaluated, to keep copied | ||||
| * "database" in a consistent state. */ | * "database" in a consistent state. */ | ||||
| if (comp_node->type == NodeType::COPY_ON_WRITE) { | if (comp_node->type == NodeType::COPY_ON_WRITE) { | ||||
| ▲ Show 20 Lines • Show All 99 Lines • ▼ Show 20 Lines | bool need_evaluate_operation_at_stage(DepsgraphEvalState *state, | ||||
| BLI_assert_msg(0, "Unhandled evaluation stage, should never happen."); | BLI_assert_msg(0, "Unhandled evaluation stage, should never happen."); | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* Schedule a node if it needs evaluation. | /* Schedule a node if it needs evaluation. | ||||
| * dec_parents: Decrement pending parents count, true when child nodes are | * dec_parents: Decrement pending parents count, true when child nodes are | ||||
| * scheduled after a task has been completed. | * scheduled after a task has been completed. | ||||
| */ | */ | ||||
| template<typename ScheduleFunction, typename... ScheduleFunctionArgs> | |||||
| void schedule_node(DepsgraphEvalState *state, | void schedule_node(DepsgraphEvalState *state, | ||||
| OperationNode *node, | OperationNode *node, | ||||
| bool dec_parents, | bool dec_parents, | ||||
| ScheduleFunction *schedule_function, | const FunctionRef<void(OperationNode *node)> schedule_fn) | ||||
| ScheduleFunctionArgs... schedule_function_args) | |||||
| { | { | ||||
| /* No need to schedule nodes of invisible ID. */ | /* No need to schedule nodes of invisible ID. */ | ||||
| if (!check_operation_node_visible(state, node)) { | if (!check_operation_node_visible(state, node)) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* No need to schedule operations which are not tagged for update, they are | /* No need to schedule operations which are not tagged for update, they are | ||||
| * considered to be up to date. */ | * considered to be up to date. */ | ||||
| if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) == 0) { | if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) == 0) { | ||||
| Show All 14 Lines | void schedule_node(DepsgraphEvalState *state, | ||||
| if (!need_evaluate_operation_at_stage(state, node)) { | if (!need_evaluate_operation_at_stage(state, node)) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* Actually schedule the node. */ | /* Actually schedule the node. */ | ||||
| bool is_scheduled = atomic_fetch_and_or_uint8((uint8_t *)&node->scheduled, uint8_t(true)); | bool is_scheduled = atomic_fetch_and_or_uint8((uint8_t *)&node->scheduled, uint8_t(true)); | ||||
| if (!is_scheduled) { | if (!is_scheduled) { | ||||
| if (node->is_noop()) { | if (node->is_noop()) { | ||||
| /* skip NOOP node, schedule children right away */ | /* skip NOOP node, schedule children right away */ | ||||
| schedule_children(state, node, schedule_function, schedule_function_args...); | schedule_children(state, node, schedule_fn); | ||||
| } | } | ||||
| else { | else { | ||||
| /* children are scheduled once this task is completed */ | /* children are scheduled once this task is completed */ | ||||
| schedule_function(node, 0, schedule_function_args...); | schedule_fn(node); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| template<typename ScheduleFunction, typename... ScheduleFunctionArgs> | |||||
| void schedule_graph(DepsgraphEvalState *state, | void schedule_graph(DepsgraphEvalState *state, | ||||
| ScheduleFunction *schedule_function, | const FunctionRef<void(OperationNode *node)> schedule_fn) | ||||
| ScheduleFunctionArgs... schedule_function_args) | |||||
| { | { | ||||
| for (OperationNode *node : state->graph->operations) { | for (OperationNode *node : state->graph->operations) { | ||||
| schedule_node(state, node, false, schedule_function, schedule_function_args...); | schedule_node(state, node, false, schedule_fn); | ||||
| } | } | ||||
| } | } | ||||
| template<typename ScheduleFunction, typename... ScheduleFunctionArgs> | |||||
| void schedule_children(DepsgraphEvalState *state, | void schedule_children(DepsgraphEvalState *state, | ||||
| OperationNode *node, | OperationNode *node, | ||||
| ScheduleFunction *schedule_function, | const FunctionRef<void(OperationNode *node)> schedule_fn) | ||||
| ScheduleFunctionArgs... schedule_function_args) | |||||
| { | { | ||||
| for (Relation *rel : node->outlinks) { | for (Relation *rel : node->outlinks) { | ||||
| OperationNode *child = (OperationNode *)rel->to; | OperationNode *child = (OperationNode *)rel->to; | ||||
| BLI_assert(child->type == NodeType::OPERATION); | BLI_assert(child->type == NodeType::OPERATION); | ||||
| if (child->scheduled) { | if (child->scheduled) { | ||||
| /* Happens when having cyclic dependencies. */ | /* Happens when having cyclic dependencies. */ | ||||
| continue; | continue; | ||||
| } | } | ||||
| schedule_node(state, | schedule_node(state, child, (rel->flag & RELATION_FLAG_CYCLIC) == 0, schedule_fn); | ||||
| child, | |||||
| (rel->flag & RELATION_FLAG_CYCLIC) == 0, | |||||
| schedule_function, | |||||
| schedule_function_args...); | |||||
| } | } | ||||
| } | } | ||||
| void schedule_node_to_queue(OperationNode *node, | |||||
| const int /*thread_id*/, | |||||
| GSQueue *evaluation_queue) | |||||
| { | |||||
| BLI_gsqueue_push(evaluation_queue, &node); | |||||
| } | |||||
| /* Evaluate given stage of the dependency graph evaluation using multiple threads. | /* Evaluate given stage of the dependency graph evaluation using multiple threads. | ||||
| * | * | ||||
| * NOTE: Will assign the `state->stage` to the given stage. */ | * NOTE: Will assign the `state->stage` to the given stage. */ | ||||
| void evaluate_graph_threaded_stage(DepsgraphEvalState *state, | void evaluate_graph_threaded_stage(DepsgraphEvalState *state, | ||||
| TaskPool *task_pool, | TaskPool *task_pool, | ||||
| const EvaluationStage stage) | const EvaluationStage stage) | ||||
| { | { | ||||
| state->stage = stage; | state->stage = stage; | ||||
| calculate_pending_parents_if_needed(state); | calculate_pending_parents_if_needed(state); | ||||
| schedule_graph(state, schedule_node_to_pool, task_pool); | schedule_graph(state, [&](OperationNode *node) { | ||||
| BLI_task_pool_push(task_pool, deg_task_run_func, node, false, nullptr); | |||||
| }); | |||||
| BLI_task_pool_work_and_wait(task_pool); | BLI_task_pool_work_and_wait(task_pool); | ||||
| } | } | ||||
| /* Evaluate remaining operations of the dependency graph in a single threaded manner. */ | /* Evaluate remaining operations of the dependency graph in a single threaded manner. */ | ||||
| void evaluate_graph_single_threaded_if_needed(DepsgraphEvalState *state) | void evaluate_graph_single_threaded_if_needed(DepsgraphEvalState *state) | ||||
| { | { | ||||
| if (!state->need_single_thread_pass) { | if (!state->need_single_thread_pass) { | ||||
| return; | return; | ||||
| } | } | ||||
| BLI_assert(!state->need_update_pending_parents); | BLI_assert(!state->need_update_pending_parents); | ||||
| state->stage = EvaluationStage::SINGLE_THREADED_WORKAROUND; | state->stage = EvaluationStage::SINGLE_THREADED_WORKAROUND; | ||||
| GSQueue *evaluation_queue = BLI_gsqueue_new(sizeof(OperationNode *)); | GSQueue *evaluation_queue = BLI_gsqueue_new(sizeof(OperationNode *)); | ||||
| schedule_graph(state, schedule_node_to_queue, evaluation_queue); | auto schedule_node_to_queue = [&](OperationNode *node) { | ||||
| BLI_gsqueue_push(evaluation_queue, &node); | |||||
| }; | |||||
| schedule_graph(state, schedule_node_to_queue); | |||||
| while (!BLI_gsqueue_is_empty(evaluation_queue)) { | while (!BLI_gsqueue_is_empty(evaluation_queue)) { | ||||
| OperationNode *operation_node; | OperationNode *operation_node; | ||||
| BLI_gsqueue_pop(evaluation_queue, &operation_node); | BLI_gsqueue_pop(evaluation_queue, &operation_node); | ||||
| evaluate_node(state, operation_node); | evaluate_node(state, operation_node); | ||||
| schedule_children(state, operation_node, schedule_node_to_queue, evaluation_queue); | schedule_children(state, operation_node, schedule_node_to_queue); | ||||
| } | } | ||||
| BLI_gsqueue_free(evaluation_queue); | BLI_gsqueue_free(evaluation_queue); | ||||
| } | } | ||||
| void depsgraph_ensure_view_layer(Depsgraph *graph) | void depsgraph_ensure_view_layer(Depsgraph *graph) | ||||
| { | { | ||||
| /* We update copy-on-write scene in the following cases: | /* We update copy-on-write scene in the following cases: | ||||
| ▲ Show 20 Lines • Show All 112 Lines • Show Last 20 Lines | |||||