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