Blender  V3.3
COM_ExecutionSystem.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2011 Blender Foundation. */
3 
4 #include "COM_ExecutionSystem.h"
5 
6 #include "COM_Debug.h"
7 #include "COM_ExecutionGroup.h"
9 #include "COM_NodeOperation.h"
12 #include "COM_WorkPackage.h"
13 #include "COM_WorkScheduler.h"
14 
15 #ifdef WITH_CXX_GUARDEDALLOC
16 # include "MEM_guardedalloc.h"
17 #endif
18 
19 namespace blender::compositor {
20 
22  Scene *scene,
23  bNodeTree *editingtree,
24  bool rendering,
25  bool fastcalculation,
26  const char *view_name)
27 {
28  num_work_threads_ = WorkScheduler::get_num_cpu_threads();
29  context_.set_view_name(view_name);
30  context_.set_scene(scene);
31  context_.set_bnodetree(editingtree);
32  context_.set_preview_hash(editingtree->previews);
33  context_.set_fast_calculation(fastcalculation);
34  /* initialize the CompositorContext */
35  if (rendering) {
36  context_.set_quality((eCompositorQuality)editingtree->render_quality);
37  }
38  else {
39  context_.set_quality((eCompositorQuality)editingtree->edit_quality);
40  }
41  context_.set_rendering(rendering);
43  (editingtree->flag & NTREE_COM_OPENCL));
44 
45  context_.set_render_data(rd);
46 
47  BLI_mutex_init(&work_mutex_);
48  BLI_condition_init(&work_finished_cond_);
49 
50  {
51  NodeOperationBuilder builder(&context_, editingtree, this);
52  builder.convert_to_operations(this);
53  }
54 
55  switch (context_.get_execution_model()) {
57  execution_model_ = new TiledExecutionModel(context_, operations_, groups_);
58  break;
60  execution_model_ = new FullFrameExecutionModel(context_, active_buffers_, operations_);
61  break;
62  default:
63  BLI_assert_msg(0, "Non implemented execution model");
64  break;
65  }
66 }
67 
69 {
70  BLI_condition_end(&work_finished_cond_);
71  BLI_mutex_end(&work_mutex_);
72 
73  delete execution_model_;
74 
75  for (NodeOperation *operation : operations_) {
76  delete operation;
77  }
78  operations_.clear();
79 
80  for (ExecutionGroup *group : groups_) {
81  delete group;
82  }
83  groups_.clear();
84 }
85 
87  const Vector<ExecutionGroup *> &groups)
88 {
89  operations_ = operations;
90  groups_ = groups;
91 }
92 
94 {
96  for (NodeOperation *op : operations_) {
97  op->init_data();
98  }
99  execution_model_->execute(*this);
100 }
101 
102 void ExecutionSystem::execute_work(const rcti &work_rect,
103  std::function<void(const rcti &split_rect)> work_func)
104 {
105  if (is_breaked()) {
106  return;
107  }
108 
109  /* Split work vertically to maximize continuous memory. */
110  const int work_height = BLI_rcti_size_y(&work_rect);
111  const int num_sub_works = MIN2(num_work_threads_, work_height);
112  const int split_height = num_sub_works == 0 ? 0 : work_height / num_sub_works;
113  int remaining_height = work_height - split_height * num_sub_works;
114 
115  Vector<WorkPackage> sub_works(num_sub_works);
116  int sub_work_y = work_rect.ymin;
117  int num_sub_works_finished = 0;
118  for (int i = 0; i < num_sub_works; i++) {
119  int sub_work_height = split_height;
120 
121  /* Distribute remaining height between sub-works. */
122  if (remaining_height > 0) {
123  sub_work_height++;
124  remaining_height--;
125  }
126 
127  WorkPackage &sub_work = sub_works[i];
129  sub_work.execute_fn = [=, &work_func, &work_rect]() {
130  if (is_breaked()) {
131  return;
132  }
133  rcti split_rect;
135  &split_rect, work_rect.xmin, work_rect.xmax, sub_work_y, sub_work_y + sub_work_height);
136  work_func(split_rect);
137  };
138  sub_work.executed_fn = [&]() {
139  BLI_mutex_lock(&work_mutex_);
140  num_sub_works_finished++;
141  if (num_sub_works_finished == num_sub_works) {
142  BLI_condition_notify_one(&work_finished_cond_);
143  }
144  BLI_mutex_unlock(&work_mutex_);
145  };
146  WorkScheduler::schedule(&sub_work);
147  sub_work_y += sub_work_height;
148  }
149  BLI_assert(sub_work_y == work_rect.ymax);
150 
152 
153  /* Ensure all sub-works finished.
154  * TODO: This a workaround for WorkScheduler::finish() not waiting all works on queue threading
155  * model. Sync code should be removed once it's fixed. */
156  BLI_mutex_lock(&work_mutex_);
157  if (num_sub_works_finished < num_sub_works) {
158  BLI_condition_wait(&work_finished_cond_, &work_mutex_);
159  }
160  BLI_mutex_unlock(&work_mutex_);
161 }
162 
164 {
165  const bNodeTree *btree = context_.get_bnodetree();
166  return btree->test_break(btree->tbh);
167 }
168 
169 } // namespace blender::compositor
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition: BLI_assert.h:53
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition: BLI_rect.h:190
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition: rct.c:417
void BLI_mutex_end(ThreadMutex *mutex)
Definition: threads.cc:388
void BLI_condition_wait(ThreadCondition *cond, ThreadMutex *mutex)
Definition: threads.cc:579
void BLI_mutex_init(ThreadMutex *mutex)
Definition: threads.cc:368
void BLI_condition_end(ThreadCondition *cond)
Definition: threads.cc:599
void BLI_condition_notify_one(ThreadCondition *cond)
Definition: threads.cc:589
void BLI_condition_init(ThreadCondition *cond)
Definition: threads.cc:574
void BLI_mutex_lock(ThreadMutex *mutex)
Definition: threads.cc:373
void BLI_mutex_unlock(ThreadMutex *mutex)
Definition: threads.cc:378
#define MIN2(a, b)
#define NTREE_COM_OPENCL
Read Guarded memory(de)allocation.
void set_quality(eCompositorQuality quality)
set the quality
void set_bnodetree(bNodeTree *bnodetree)
set the bnodetree of the context
void set_preview_hash(bNodeInstanceHash *previews)
set the preview image hash table
void set_view_name(const char *view_name)
set the active rendering view
void setHasActiveOpenCLDevices(bool hasAvtiveOpenCLDevices)
set has this system active opencl_devices?
void set_render_data(RenderData *rd)
set the scene of the context
void set_fast_calculation(bool fast_calculation)
const bNodeTree * get_bnodetree() const
get the bnodetree of the context
void set_rendering(bool rendering)
set the rendering field of the context
static void execute_started(const ExecutionSystem *system)
Definition: COM_Debug.h:60
Class ExecutionGroup is a group of Operations that are executed as one. This grouping is used to comb...
virtual void execute(ExecutionSystem &exec_system)=0
void set_operations(const Vector< NodeOperation * > &operations, const Vector< ExecutionGroup * > &groups)
ExecutionSystem(RenderData *rd, Scene *scene, bNodeTree *editingtree, bool rendering, bool fastcalculation, const char *view_name)
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)
void convert_to_operations(ExecutionSystem *system)
NodeOperation contains calculation logic.
Scene scene
eCompositorQuality
Possible quality settings.
Definition: COM_Enums.h:19
@ CustomFunction
Executes a custom function.
short render_quality
int(* test_break)(void *)
struct bNodeInstanceHash * previews
short edit_quality
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 bool has_gpu_devices()
Are there OpenCL capable GPU devices initialized? the result of this method is stored in the Composit...
static void finish()
wait for all work to be completed.
int ymin
Definition: DNA_vec_types.h:64
int ymax
Definition: DNA_vec_types.h:64
int xmin
Definition: DNA_vec_types.h:63
int xmax
Definition: DNA_vec_types.h:63