Blender V5.0
compile_state.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
5#include <limits>
6
8
9#include "DNA_node_types.h"
10
12
13#include "COM_compile_state.hh"
14#include "COM_context.hh"
15#include "COM_domain.hh"
17#include "COM_node_operation.hh"
19#include "COM_result.hh"
20#include "COM_scheduler.hh"
21#include "COM_utilities.hh"
22
23namespace blender::compositor {
24
25using namespace nodes::derived_node_tree_types;
26
27CompileState::CompileState(const Context &context, const Schedule &schedule)
28 : context_(context), schedule_(schedule)
29{
30}
31
33{
34 return schedule_;
35}
36
38{
39 node_operations_.add_new(node, operations);
40}
41
43{
44 pixel_operations_.add_new(node, operations);
45}
46
48{
49 /* The output belongs to a node that was compiled into a standard node operation, so return a
50 * reference to the result from that operation using the output identifier. */
51 if (node_operations_.contains(output.node())) {
52 NodeOperation *operation = node_operations_.lookup(output.node());
53 return operation->get_result(output->identifier);
54 }
55
56 /* Otherwise, the output belongs to a node that was compiled into a pixel operation, so retrieve
57 * the internal identifier of that output and return a reference to the result from that
58 * operation using the retrieved identifier. */
59 PixelOperation *operation = pixel_operations_.lookup(output.node());
60 return operation->get_result(operation->get_output_identifier_from_output_socket(output));
61}
62
64{
65 pixel_compile_unit_.add_new(node);
66
67 /* If this is the first node in the compile unit, then we should initialize the single value
68 * type, as well as the domain in case the node was not single value. */
69 const bool is_first_node_in_operation = pixel_compile_unit_.size() == 1;
70 if (is_first_node_in_operation) {
71 is_pixel_compile_unit_single_value_ = this->is_pixel_node_single_value(node);
72
73 /* If the node was not a single value, compute and initialize the domain. */
74 if (!is_pixel_compile_unit_single_value_) {
75 pixel_compile_unit_domain_ = this->compute_pixel_node_domain(node);
76 }
77 }
78}
79
81{
82 return pixel_compile_unit_;
83}
84
86{
87 return is_pixel_compile_unit_single_value_;
88}
89
91{
92 pixel_compile_unit_.clear();
93 pixel_compile_unit_domain_.reset();
94}
95
97{
98 /* If the pixel compile unit is empty, then it can't be compiled yet. */
99 if (pixel_compile_unit_.is_empty()) {
100 return false;
101 }
102
103 /* If the node is not a pixel node, then it can't be added to the pixel compile unit and the
104 * pixel compile unit is considered complete and should be compiled. */
105 if (!is_pixel_node(node)) {
106 return true;
107 }
108
109 /* If the compile unit is single value and the given node is not or vice versa, then it can't be
110 * added to the pixel compile unit and the pixel compile unit is considered complete and should
111 * be compiled. */
112 if (is_pixel_compile_unit_single_value_ != this->is_pixel_node_single_value(node)) {
113 return true;
114 }
115
116 /* For non single value compile units, if the computed domain of the node doesn't matches the
117 * domain of the pixel compile unit, then it can't be added to the pixel compile unit and the
118 * pixel compile unit is considered complete and should be compiled. */
119 if (!is_pixel_compile_unit_single_value_) {
120 if (pixel_compile_unit_domain_.value() != this->compute_pixel_node_domain(node)) {
121 return true;
122 }
123 }
124
125 /* Otherwise, the node is compatible and can be added to the compile unit and it shouldn't be
126 * compiled just yet. */
127 return false;
128}
129
131{
132 const DOutputSocket preview_output = find_preview_output_socket(node);
133
134 int outputs_count = 0;
135 for (const bNodeSocket *output : node->output_sockets()) {
136 const DOutputSocket doutput{node.context(), output};
137
139 continue;
140 }
141
142 /* If the output is used as the node preview, then an operation output will exist for it. */
143 const bool is_preview_output = doutput == preview_output;
144
145 /* If any of the nodes linked to the output are not part of the pixel compile unit but are
146 * part of the execution schedule, then an operation output will exist for it. */
147 const bool is_operation_output = is_output_linked_to_node_conditioned(
148 doutput, [&](DNode node) {
149 return schedule_.contains(node) && !pixel_compile_unit_.contains(node);
150 });
151
152 if (is_operation_output || is_preview_output) {
153 outputs_count += 1;
154 }
155 }
156
157 return outputs_count;
158}
159
160bool CompileState::is_pixel_node_single_value(DNode node)
161{
162 /* The pixel node is single value when all of its inputs are single values. */
163 for (int i = 0; i < node->input_sockets().size(); i++) {
164 const DInputSocket input{node.context(), node->input_sockets()[i]};
165
166 if (!is_socket_available(input.bsocket())) {
167 continue;
168 }
169
170 /* The origin socket is an input, that means the input is unlinked. */
171 const DSocket origin = get_input_origin_socket(input);
172 if (origin->is_input()) {
173 const InputDescriptor origin_descriptor = input_descriptor_from_input_socket(
174 origin.bsocket());
175
176 /* The input does not have an implicit input, so it is a single value. */
177 if (origin_descriptor.implicit_input == ImplicitInput::None) {
178 continue;
179 }
180
181 /* Otherwise, it has an implicit input, which is never a single value. */
182 return false;
183 }
184
185 /* Otherwise, the origin socket is an output, which means it is linked. */
186 const DOutputSocket output = DOutputSocket(origin);
187
188 /* If the output belongs to a node that is part of the pixel compile unit and that compile unit
189 * is not single value, then the node is not single value. */
190 if (pixel_compile_unit_.contains(output.node())) {
191 if (is_pixel_compile_unit_single_value_) {
192 continue;
193 }
194 return false;
195 }
196
198 if (!result.is_single_value()) {
199 return false;
200 }
201 }
202
203 return true;
204}
205
206Domain CompileState::compute_pixel_node_domain(DNode node)
207{
208 /* Default to an identity domain in case no domain input was found, most likely because all
209 * inputs are single values. */
210 Domain node_domain = Domain::identity();
211 int current_domain_priority = std::numeric_limits<int>::max();
212
213 /* Go over the inputs and find the domain of the non single value input with the highest domain
214 * priority. */
215 for (int i = 0; i < node->input_sockets().size(); i++) {
216 const DInputSocket input{node.context(), node->input_sockets()[i]};
217
218 if (!is_socket_available(input.bsocket())) {
219 continue;
220 }
221
222 const InputDescriptor input_descriptor = input_descriptor_from_input_socket(input.bsocket());
223
224 /* The origin socket is an input, that means the input is unlinked. */
225 const DSocket origin = get_input_origin_socket(input);
226 if (origin->is_input()) {
227 const InputDescriptor origin_descriptor = input_descriptor_from_input_socket(
228 origin.bsocket());
229
230 /* The input does not have an implicit input, so it is a single that can't be a domain input
231 * and we skip it. */
232 if (origin_descriptor.implicit_input == ImplicitInput::None) {
233 continue;
234 }
235
236 /* Otherwise, the input has the domain of the implicit input, which is the domain of the
237 * compositing region. Notice that the lower the domain priority value is, the higher the
238 * priority is, hence the less than comparison. */
239 if (input_descriptor.domain_priority < current_domain_priority) {
240 node_domain = Domain(context_.get_compositing_region_size());
241 current_domain_priority = input_descriptor.domain_priority;
242 }
243 continue;
244 }
245
246 /* Otherwise, the origin socket is an output, which means it is linked. */
247 const DOutputSocket output = DOutputSocket(origin);
248
249 /* If the output belongs to a node that is part of the pixel compile unit, then the domain of
250 * the input is the domain of the compile unit itself. */
251 if (pixel_compile_unit_.contains(output.node())) {
252 /* Notice that the lower the domain priority value is, the higher the priority is, hence the
253 * less than comparison. */
254 if (input_descriptor.domain_priority < current_domain_priority) {
255 node_domain = pixel_compile_unit_domain_.value();
256 current_domain_priority = input_descriptor.domain_priority;
257 }
258 continue;
259 }
260
262
263 /* A single value input can't be a domain input. */
264 if (result.is_single_value() || input_descriptor.expects_single_value) {
265 continue;
266 }
267
268 /* An input that skips operation domain realization can't be a domain input. */
269 if (input_descriptor.realization_mode != InputRealizationMode::OperationDomain) {
270 continue;
271 }
272
273 /* Notice that the lower the domain priority value is, the higher the priority is, hence the
274 * less than comparison. */
275 if (input_descriptor.domain_priority < current_domain_priority) {
276 node_domain = result.domain();
277 current_domain_priority = input_descriptor.domain_priority;
278 }
279 }
280
281 return node_domain;
282}
283
284} // namespace blender::compositor
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
void add_new(const Key &key)
PixelCompileUnit & get_pixel_compile_unit()
CompileState(const Context &context, const Schedule &schedule)
Result & get_result_from_output_socket(DOutputSocket output)
void map_node_to_node_operation(DNode node, NodeOperation *operation)
void add_node_to_pixel_compile_unit(DNode node)
bool should_compile_pixel_compile_unit(DNode node)
void map_node_to_pixel_operation(DNode node, PixelOperation *operation)
int compute_pixel_node_operation_outputs_count(DNode node)
static Domain identity()
Definition domain.cc:36
Result & get_result(StringRef identifier)
Definition operation.cc:39
StringRef get_output_identifier_from_output_socket(DOutputSocket output_socket)
#define input
#define output
bool is_output_linked_to_node_conditioned(DOutputSocket output, FunctionRef< bool(DNode)> condition)
Definition utilities.cc:113
DSocket get_input_origin_socket(DInputSocket input)
Definition utilities.cc:32
VectorSet< DNode > Schedule
VectorSet< DNode > PixelCompileUnit
DOutputSocket find_preview_output_socket(const DNode &node)
Definition utilities.cc:226
InputDescriptor input_descriptor_from_input_socket(const bNodeSocket *socket)
Definition utilities.cc:169
bool is_pixel_node(DNode node)
Definition utilities.cc:143
bool is_socket_available(const bNodeSocket *socket)
Definition utilities.cc:27
i
Definition text_draw.cc:230