Blender V5.0
task_graph.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include "MEM_guardedalloc.h"
12
13#include "BLI_task.h"
14
15#include <memory>
16#include <vector>
17
18#ifdef WITH_TBB
19# include <tbb/flow_graph.h>
20#endif
21
22/* Task Graph */
23struct TaskGraph {
24#ifdef WITH_TBB
25 tbb::flow::graph tbb_graph;
26#endif
27 std::vector<std::unique_ptr<TaskNode>> nodes;
28
29 MEM_CXX_CLASS_ALLOC_FUNCS("task_graph:TaskGraph")
30};
31
32/* TaskNode - a node in the task graph. */
33struct TaskNode {
34 /* TBB Node. */
35#ifdef WITH_TBB
36 tbb::flow::continue_node<tbb::flow::continue_msg> tbb_node;
37#endif
38 /* Successors to execute after this task, for serial execution fallback. */
39 std::vector<TaskNode *> successors;
40
41 /* User function to be executed with given task data. */
43 void *task_data;
44 /* Optional callback to free task data along with the graph. If task data
45 * is shared between nodes, only a single task node should free the data. */
47
48 TaskNode(TaskGraph *task_graph,
50 void *task_data,
52 :
53#ifdef WITH_TBB
54 tbb_node(task_graph->tbb_graph,
55 tbb::flow::unlimited,
56 [&](const tbb::flow::continue_msg input) { run(input); }),
57#endif
61 {
62#ifndef WITH_TBB
63 UNUSED_VARS(task_graph);
64#endif
65 }
66
67 TaskNode(const TaskNode &other) = delete;
68 TaskNode &operator=(const TaskNode &other) = delete;
69
71 {
72 if (task_data && free_func) {
74 }
75 }
76
77#ifdef WITH_TBB
78 tbb::flow::continue_msg run(const tbb::flow::continue_msg /*input*/)
79 {
81 return tbb::flow::continue_msg();
82 }
83#endif
84
86 {
88 for (TaskNode *successor : successors) {
89 successor->run_serial();
90 }
91 }
92
93 MEM_CXX_CLASS_ALLOC_FUNCS("task_graph:TaskNode")
94};
95
97{
98 return new TaskGraph();
99}
100
102{
103 delete task_graph;
104}
105
107{
108#ifdef WITH_TBB
109 task_graph->tbb_graph.wait_for_all();
110#else
111 UNUSED_VARS(task_graph);
112#endif
113}
114
117 void *user_data,
119{
120 TaskNode *task_node = new TaskNode(task_graph, run, user_data, free_func);
121 task_graph->nodes.push_back(std::unique_ptr<TaskNode>(task_node));
122 return task_node;
123}
124
126{
127#ifdef WITH_TBB
129 return task_node->tbb_node.try_put(tbb::flow::continue_msg());
130 }
131#endif
132
133 task_node->run_serial();
134 return true;
135}
136
138{
139#ifdef WITH_TBB
141 tbb::flow::make_edge(from_node->tbb_node, to_node->tbb_node);
142 return;
143 }
144#endif
145
146 from_node->successors.push_back(to_node);
147}
int BLI_task_scheduler_num_threads(void)
void(* TaskGraphNodeFreeFunction)(void *task_data)
Definition BLI_task.h:316
void(* TaskGraphNodeRunFunction)(void *__restrict task_data)
Definition BLI_task.h:315
#define UNUSED_VARS(...)
Read Guarded memory(de)allocation.
#define input
static PyObject * free_func(PyObject *, PyObject *value)
Definition python.cpp:226
std::vector< std::unique_ptr< TaskNode > > nodes
Definition task_graph.cc:27
TaskNode(TaskGraph *task_graph, TaskGraphNodeRunFunction run_func, void *task_data, TaskGraphNodeFreeFunction free_func)
Definition task_graph.cc:48
TaskNode(const TaskNode &other)=delete
std::vector< TaskNode * > successors
Definition task_graph.cc:39
TaskGraphNodeFreeFunction free_func
Definition task_graph.cc:46
void run_serial()
Definition task_graph.cc:85
TaskNode & operator=(const TaskNode &other)=delete
TaskGraphNodeRunFunction run_func
Definition task_graph.cc:42
void * task_data
Definition task_graph.cc:43
TaskGraph * BLI_task_graph_create()
Definition task_graph.cc:96
void BLI_task_graph_work_and_wait(TaskGraph *task_graph)
bool BLI_task_graph_node_push_work(TaskNode *task_node)
void BLI_task_graph_free(TaskGraph *task_graph)
TaskNode * BLI_task_graph_node_create(TaskGraph *task_graph, TaskGraphNodeRunFunction run, void *user_data, TaskGraphNodeFreeFunction free_func)
void BLI_task_graph_edge_create(TaskNode *from_node, TaskNode *to_node)