Blender  V3.3
COM_ConstantFolder.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2021 Blender Foundation. */
3 
4 #include "BLI_map.hh"
5 #include "BLI_set.hh"
6 
7 #include "COM_ConstantFolder.h"
10 #include "COM_SetValueOperation.h"
11 #include "COM_SetVectorOperation.h"
12 #include "COM_WorkScheduler.h"
13 
14 namespace blender::compositor {
15 
17  : operations_builder_(operations_builder)
18 {
19  BLI_rcti_init(&max_area_, INT_MIN, INT_MAX, INT_MIN, INT_MAX);
20  BLI_rcti_init(&first_elem_area_, 0, 1, 0, 1);
21 }
22 
23 static bool is_constant_foldable(NodeOperation *operation)
24 {
25  if (operation->get_flags().can_be_constant && !operation->get_flags().is_constant_operation) {
26  for (int i = 0; i < operation->get_number_of_input_sockets(); i++) {
27  NodeOperation *input = operation->get_input_operation(i);
28  if (!input->get_flags().is_constant_operation ||
29  !static_cast<ConstantOperation *>(input)->can_get_constant_elem()) {
30  return false;
31  }
32  }
33  return true;
34  }
35  return false;
36 }
37 
39 {
40  Set<NodeOperation *> foldable_ops;
41  for (NodeOperation *op : operations) {
42  if (is_constant_foldable(op)) {
43  foldable_ops.add(op);
44  }
45  }
46  return foldable_ops;
47 }
48 
49 static ConstantOperation *create_constant_operation(DataType data_type, const float *constant_elem)
50 {
51  switch (data_type) {
52  case DataType::Color: {
53  SetColorOperation *color_op = new SetColorOperation();
54  color_op->set_channels(constant_elem);
55  return color_op;
56  }
57  case DataType::Vector: {
58  SetVectorOperation *vector_op = new SetVectorOperation();
59  vector_op->set_vector(constant_elem);
60  return vector_op;
61  }
62  case DataType::Value: {
63  SetValueOperation *value_op = new SetValueOperation();
64  value_op->set_value(*constant_elem);
65  return value_op;
66  }
67  default: {
68  BLI_assert_msg(0, "Non implemented data type");
69  return nullptr;
70  }
71  }
72 }
73 
74 ConstantOperation *ConstantFolder::fold_operation(NodeOperation *operation)
75 {
76  const DataType data_type = operation->get_output_socket()->get_data_type();
77  MemoryBuffer fold_buf(data_type, first_elem_area_);
78  Vector<MemoryBuffer *> input_bufs = get_constant_input_buffers(operation);
79  operation->init_data();
80  operation->render(&fold_buf, {first_elem_area_}, input_bufs);
81 
82  MemoryBuffer *constant_buf = create_constant_buffer(data_type);
83  constant_buf->copy_from(&fold_buf, first_elem_area_);
84  ConstantOperation *constant_op = create_constant_operation(data_type,
85  constant_buf->get_buffer());
86  operations_builder_.replace_operation_with_constant(operation, constant_op);
87  constant_buffers_.add_new(constant_op, constant_buf);
88  return constant_op;
89 }
90 
91 MemoryBuffer *ConstantFolder::create_constant_buffer(const DataType data_type)
92 {
93  /* Create a single elem buffer with maximum area possible so readers can read any coordinate
94  * returning always same element. */
95  return new MemoryBuffer(data_type, max_area_, true);
96 }
97 
98 Vector<MemoryBuffer *> ConstantFolder::get_constant_input_buffers(NodeOperation *operation)
99 {
100  const int num_inputs = operation->get_number_of_input_sockets();
101  Vector<MemoryBuffer *> inputs_bufs(num_inputs);
102  for (int i = 0; i < num_inputs; i++) {
103  BLI_assert(operation->get_input_operation(i)->get_flags().is_constant_operation);
104  ConstantOperation *constant_op = static_cast<ConstantOperation *>(
105  operation->get_input_operation(i));
106  MemoryBuffer *constant_buf = constant_buffers_.lookup_or_add_cb(constant_op, [=] {
107  MemoryBuffer *buf = create_constant_buffer(
108  constant_op->get_output_socket()->get_data_type());
109  constant_op->render(buf, {first_elem_area_}, {});
110  return buf;
111  });
112  inputs_bufs[i] = constant_buf;
113  }
114  return inputs_bufs;
115 }
116 
117 Vector<ConstantOperation *> ConstantFolder::try_fold_operations(Span<NodeOperation *> operations)
118 {
119  Set<NodeOperation *> foldable_ops = find_constant_foldable_operations(operations);
120  if (foldable_ops.size() == 0) {
121  return Vector<ConstantOperation *>();
122  }
123 
124  Vector<ConstantOperation *> new_folds;
125  for (NodeOperation *op : foldable_ops) {
126  ConstantOperation *constant_op = fold_operation(op);
127  new_folds.append(constant_op);
128  }
129  return new_folds;
130 }
131 
133 {
134  WorkScheduler::start(operations_builder_.context());
135  Vector<ConstantOperation *> last_folds = try_fold_operations(
136  operations_builder_.get_operations());
137  int folds_count = last_folds.size();
138  while (last_folds.size() > 0) {
139  Vector<NodeOperation *> ops_to_fold;
140  for (ConstantOperation *fold : last_folds) {
141  get_operation_output_operations(fold, ops_to_fold);
142  }
143  last_folds = try_fold_operations(ops_to_fold);
144  folds_count += last_folds.size();
145  }
147 
148  delete_constant_buffers();
149 
150  return folds_count;
151 }
152 
153 void ConstantFolder::delete_constant_buffers()
154 {
155  for (MemoryBuffer *buf : constant_buffers_.values()) {
156  delete buf;
157  }
158  constant_buffers_.clear();
159 }
160 
161 void ConstantFolder::get_operation_output_operations(NodeOperation *operation,
162  Vector<NodeOperation *> &r_outputs)
163 {
164  const Vector<NodeOperationBuilder::Link> &links = operations_builder_.get_links();
165  for (const NodeOperationBuilder::Link &link : links) {
166  if (&link.from()->get_operation() == operation) {
167  r_outputs.append(&link.to()->get_operation());
168  }
169  }
170 }
171 
172 } // namespace blender::compositor
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition: BLI_assert.h:53
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition: rct.c:417
struct Link Link
bool add(const Key &key)
Definition: BLI_set.hh:253
int64_t size() const
Definition: BLI_vector.hh:694
ConstantFolder(NodeOperationBuilder &operations_builder)
a MemoryBuffer contains access to the data of a chunk
void replace_operation_with_constant(NodeOperation *operation, ConstantOperation *constant_operation)
const Vector< NodeOperation * > & get_operations() const
const CompositorContext & context() const
NodeOperation contains calculation logic.
const NodeOperationFlags get_flags() const
unsigned int get_number_of_input_sockets() const
NodeOperation * get_input_operation(int index)
DataType
possible data types for sockets
Definition: COM_defines.h:30
@ Vector
Vector data type.
ccl_global KernelShaderEvalInput * input
static bool is_constant_foldable(NodeOperation *operation)
static ConstantOperation * create_constant_operation(DataType data_type, const float *constant_elem)
static Set< NodeOperation * > find_constant_foldable_operations(Span< NodeOperation * > operations)
static void start(const CompositorContext &context)
Start the execution this methods will start the WorkScheduler. Inside this method all threads are ini...
static void stop()
stop the execution All created thread by the start method are destroyed.