Blender V4.3
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_domain.hh"
16#include "COM_node_operation.hh"
18#include "COM_result.hh"
19#include "COM_scheduler.hh"
20#include "COM_utilities.hh"
21
23
24using namespace nodes::derived_node_tree_types;
25
26CompileState::CompileState(const Schedule &schedule) : schedule_(schedule) {}
27
29{
30 return schedule_;
31}
32
34{
35 return node_operations_.add_new(node, operations);
36}
37
39{
40 return pixel_operations_.add_new(node, operations);
41}
42
44{
45 /* The output belongs to a node that was compiled into a standard node operation, so return a
46 * reference to the result from that operation using the output identifier. */
47 if (node_operations_.contains(output.node())) {
48 NodeOperation *operation = node_operations_.lookup(output.node());
49 return operation->get_result(output->identifier);
50 }
51
52 /* Otherwise, the output belongs to a node that was compiled into a pixel operation, so retrieve
53 * the internal identifier of that output and return a reference to the result from that
54 * operation using the retrieved identifier. */
55 PixelOperation *operation = pixel_operations_.lookup(output.node());
56 return operation->get_result(operation->get_output_identifier_from_output_socket(output));
57}
58
60{
61 pixel_compile_unit_.add_new(node);
62
63 /* If the domain of the pixel compile unit is not yet determined or was determined to be
64 * an identity domain, update it to be the computed domain of the node. */
65 if (pixel_compile_unit_domain_ == Domain::identity()) {
66 pixel_compile_unit_domain_ = compute_pixel_node_domain(node);
67 }
68}
69
71{
72 return pixel_compile_unit_;
73}
74
76{
77 pixel_compile_unit_.clear();
78 pixel_compile_unit_domain_ = Domain::identity();
79}
80
82{
83 /* If the pixel compile unit is empty, then it can't be compiled yet. */
84 if (pixel_compile_unit_.is_empty()) {
85 return false;
86 }
87
88 /* If the node is not a pixel node, then it can't be added to the pixel compile unit and the
89 * pixel compile unit is considered complete and should be compiled. */
90 if (!is_pixel_node(node)) {
91 return true;
92 }
93
94 /* If the computed domain of the node doesn't matches the domain of the pixel compile unit, then
95 * it can't be added to the pixel compile unit and the pixel compile unit is considered
96 * complete and should be compiled. Identity domains are an exception as they are always
97 * compatible because they represents single values. */
98 if (pixel_compile_unit_domain_ != Domain::identity() &&
99 pixel_compile_unit_domain_ != compute_pixel_node_domain(node))
100 {
101 return true;
102 }
103
104 /* Otherwise, the node is compatible and can be added to the compile unit and it shouldn't be
105 * compiled just yet. */
106 return false;
107}
108
110{
111 const DOutputSocket preview_output = find_preview_output_socket(node);
112
113 int outputs_count = 0;
114 for (const bNodeSocket *output : node->output_sockets()) {
115 const DOutputSocket doutput{node.context(), output};
116
117 /* If the output is used as the node preview, then an operation output will exist for it. */
118 const bool is_preview_output = doutput == preview_output;
119
120 /* If any of the nodes linked to the output are not part of the pixel compile unit but are
121 * part of the execution schedule, then an operation output will exist for it. */
122 const bool is_operation_output = is_output_linked_to_node_conditioned(
123 doutput, [&](DNode node) {
124 return schedule_.contains(node) && !pixel_compile_unit_.contains(node);
125 });
126
127 if (is_operation_output || is_preview_output) {
128 outputs_count += 1;
129 }
130 }
131
132 return outputs_count;
133}
134
135Domain CompileState::compute_pixel_node_domain(DNode node)
136{
137 /* Default to an identity domain in case no domain input was found, most likely because all
138 * inputs are single values. */
139 Domain node_domain = Domain::identity();
140 int current_domain_priority = std::numeric_limits<int>::max();
141
142 /* Go over the inputs and find the domain of the non single value input with the highest domain
143 * priority. */
144 for (const bNodeSocket *input : node->input_sockets()) {
145 const DInputSocket dinput{node.context(), input};
146
147 /* Get the output linked to the input. If it is null, that means the input is unlinked, so skip
148 * it. */
149 const DOutputSocket output = get_output_linked_to_input(dinput);
150 if (!output) {
151 continue;
152 }
153
154 const InputDescriptor input_descriptor = input_descriptor_from_input_socket(input);
155
156 /* If the output belongs to a node that is part of the pixel compile unit, then the domain of
157 * the input is the domain of the compile unit itself. */
158 if (pixel_compile_unit_.contains(output.node())) {
159 /* Single value inputs can't be domain inputs. */
160 if (pixel_compile_unit_domain_.size == int2(1)) {
161 continue;
162 }
163
164 /* Notice that the lower the domain priority value is, the higher the priority is, hence the
165 * less than comparison. */
166 if (input_descriptor.domain_priority < current_domain_priority) {
167 node_domain = pixel_compile_unit_domain_;
168 current_domain_priority = input_descriptor.domain_priority;
169 }
170 continue;
171 }
172
173 const Result &result = get_result_from_output_socket(output);
174
175 /* A single value input can't be a domain input. */
176 if (result.is_single_value() || input_descriptor.expects_single_value) {
177 continue;
178 }
179
180 /* An input that skips operation domain realization can't be a domain input. */
181 if (!input_descriptor.realization_options.realize_on_operation_domain) {
182 continue;
183 }
184
185 /* Notice that the lower the domain priority value is, the higher the priority is, hence the
186 * less than comparison. */
187 if (input_descriptor.domain_priority < current_domain_priority) {
188 node_domain = result.domain();
189 current_domain_priority = input_descriptor.domain_priority;
190 }
191 }
192
193 return node_domain;
194}
195
196} // namespace blender::realtime_compositor
void add_new(const Key &key)
bool contains(const Key &key) const
const DTreeContext * context() const
void map_node_to_node_operation(DNode node, NodeOperation *operation)
void map_node_to_pixel_operation(DNode node, PixelOperation *operation)
Result & get_result_from_output_socket(DOutputSocket output)
Result & get_result(StringRef identifier)
Definition operation.cc:46
StringRef get_output_identifier_from_output_socket(DOutputSocket output_socket)
bool is_pixel_node(DNode node)
Definition utilities.cc:104
bool is_output_linked_to_node_conditioned(DOutputSocket output, FunctionRef< bool(DNode)> condition)
Definition utilities.cc:78
DOutputSocket get_output_linked_to_input(DInputSocket input)
Definition utilities.cc:47
DOutputSocket find_preview_output_socket(const DNode &node)
Definition utilities.cc:161
InputDescriptor input_descriptor_from_input_socket(const bNodeSocket *socket)
Definition utilities.cc:109