Blender V4.3
COM_ExecutionSystem.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
6
7#include "COM_Debug.h"
9#include "COM_NodeOperation.h"
11#include "COM_WorkPackage.h"
12#include "COM_WorkScheduler.h"
13
14#include "COM_profiler.hh"
15
16#ifdef WITH_CXX_GUARDEDALLOC
17# include "MEM_guardedalloc.h"
18#endif
19
20namespace blender::compositor {
21
23 Scene *scene,
24 bNodeTree *editingtree,
25 bool rendering,
26 const char *view_name,
29{
30 num_work_threads_ = WorkScheduler::get_num_cpu_threads();
31 context_.set_render_context(render_context);
32 context_.set_profiler(profiler);
33 context_.set_view_name(view_name);
34 context_.set_scene(scene);
35 context_.set_bnodetree(editingtree);
36 context_.set_preview_hash(editingtree->previews);
37 context_.set_rendering(rendering);
38
39 context_.set_render_data(rd);
40
41 BLI_mutex_init(&work_mutex_);
42 BLI_condition_init(&work_finished_cond_);
43
44 {
45 NodeOperationBuilder builder(&context_, editingtree, this);
46 builder.convert_to_operations(this);
47 }
48
49 execution_model_ = new FullFrameExecutionModel(context_, active_buffers_, operations_);
50}
51
53{
54 BLI_condition_end(&work_finished_cond_);
55 BLI_mutex_end(&work_mutex_);
56
57 delete execution_model_;
58
59 for (NodeOperation *operation : operations_) {
60 delete operation;
61 }
62 operations_.clear();
63}
64
66{
67 operations_ = operations;
68}
69
71{
73 for (NodeOperation *op : operations_) {
74 op->init_data();
75 }
76 execution_model_->execute(*this);
77 if (context_.get_profiler()) {
78 context_.get_profiler()->finalize(*context_.get_bnodetree());
79 }
80}
81
82void ExecutionSystem::execute_work(const rcti &work_rect,
83 std::function<void(const rcti &split_rect)> work_func)
84{
85 if (is_breaked()) {
86 return;
87 }
88
89 /* Split work vertically to maximize continuous memory. */
90 const int work_height = BLI_rcti_size_y(&work_rect);
91 const int num_sub_works = std::min(num_work_threads_, work_height);
92 const int split_height = num_sub_works == 0 ? 0 : work_height / num_sub_works;
93 int remaining_height = work_height - split_height * num_sub_works;
94
95 Vector<WorkPackage> sub_works(num_sub_works);
96 int sub_work_y = work_rect.ymin;
97 int num_sub_works_finished = 0;
98 for (int i = 0; i < num_sub_works; i++) {
99 int sub_work_height = split_height;
100
101 /* Distribute remaining height between sub-works. */
102 if (remaining_height > 0) {
103 sub_work_height++;
104 remaining_height--;
105 }
106
107 WorkPackage &sub_work = sub_works[i];
108 sub_work.execute_fn = [=, &work_func, &work_rect]() {
109 if (is_breaked()) {
110 return;
111 }
112 rcti split_rect;
114 &split_rect, work_rect.xmin, work_rect.xmax, sub_work_y, sub_work_y + sub_work_height);
115 work_func(split_rect);
116 };
117 sub_work.executed_fn = [&]() {
118 BLI_mutex_lock(&work_mutex_);
119 num_sub_works_finished++;
120 if (num_sub_works_finished == num_sub_works) {
121 BLI_condition_notify_one(&work_finished_cond_);
122 }
123 BLI_mutex_unlock(&work_mutex_);
124 };
125 WorkScheduler::schedule(&sub_work);
126 sub_work_y += sub_work_height;
127 }
128 BLI_assert(sub_work_y == work_rect.ymax);
129
131
132 /* Ensure all sub-works finished.
133 * TODO: This a workaround for WorkScheduler::finish() not waiting all works on queue threading
134 * model. Sync code should be removed once it's fixed. */
135 BLI_mutex_lock(&work_mutex_);
136 if (num_sub_works_finished < num_sub_works) {
137 BLI_condition_wait(&work_finished_cond_, &work_mutex_);
138 }
139 BLI_mutex_unlock(&work_mutex_);
140}
141
143{
144 const bNodeTree *btree = context_.get_bnodetree();
145 return btree->runtime->test_break(btree->runtime->tbh);
146}
147
148} // namespace blender::compositor
#define BLI_assert(a)
Definition BLI_assert.h:50
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:193
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition rct.c:418
void BLI_mutex_end(ThreadMutex *mutex)
Definition threads.cc:360
void BLI_condition_wait(ThreadCondition *cond, ThreadMutex *mutex)
Definition threads.cc:582
void BLI_mutex_init(ThreadMutex *mutex)
Definition threads.cc:340
void BLI_condition_end(ThreadCondition *cond)
Definition threads.cc:602
void BLI_condition_notify_one(ThreadCondition *cond)
Definition threads.cc:592
void BLI_condition_init(ThreadCondition *cond)
Definition threads.cc:577
void BLI_mutex_lock(ThreadMutex *mutex)
Definition threads.cc:345
void BLI_mutex_unlock(ThreadMutex *mutex)
Definition threads.cc:350
Read Guarded memory(de)allocation.
void set_bnodetree(bNodeTree *bnodetree)
set the bnodetree of the context
const bNodeTree * get_bnodetree() const
get the bnodetree of the context
realtime_compositor::Profiler * get_profiler() const
get the profiler
void set_render_context(realtime_compositor::RenderContext *render_context)
set the render context
void set_view_name(const char *view_name)
set the active rendering view
void set_profiler(realtime_compositor::Profiler *profiler)
set the profiler
void set_preview_hash(bke::bNodeInstanceHash *previews)
set the preview image hash table
void set_render_data(RenderData *rd)
set the scene of the context
void set_rendering(bool rendering)
set the rendering field of the context
virtual void execute(ExecutionSystem &exec_system)=0
void set_operations(Span< NodeOperation * > operations)
ExecutionSystem(RenderData *rd, Scene *scene, bNodeTree *editingtree, bool rendering, const char *view_name, realtime_compositor::RenderContext *render_context, realtime_compositor::Profiler *profiler)
Create a new ExecutionSystem and initialize it with the editingtree.
void execute_work(const rcti &work_rect, std::function< void(const rcti &split_rect)> work_func)
NodeOperation contains calculation logic.
void finalize(const bNodeTree &node_tree)
Definition profiler.cc:66
bNodeTreeRuntimeHandle * runtime
NodeInstanceHashHandle * previews
contains data about work that can be scheduled
std::function< void()> executed_fn
std::function< void()> execute_fn
static void schedule(WorkPackage *package)
schedule a chunk of a group to be calculated. An execution group schedules a chunk in the WorkSchedul...
static void finish()
wait for all work to be completed.
int ymin
int ymax
int xmin
int xmax