Blender V4.3
node_tree_zones.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 <iostream>
6
7#include "BKE_node.hh"
8#include "BKE_node_runtime.hh"
10
12#include "BLI_bit_span_ops.hh"
13#include "BLI_set.hh"
15
16namespace blender::bke {
17
19{
20 if (zone.depth >= 0) {
21 return;
22 }
23 if (zone.parent_zone == nullptr) {
24 zone.depth = 0;
25 return;
26 }
27 update_zone_depths(*zone.parent_zone);
28 zone.depth = zone.parent_zone->depth + 1;
29}
30
32 const bNodeTree &tree,
33 bNodeTreeZones &owner,
34 Map<const bNode *, bNodeTreeZone *> &r_zone_by_inout_node)
35{
37
39 Vector<const bNode *> zone_output_nodes;
40 for (const bNodeZoneType *zone_type : zone_types) {
41 zone_output_nodes.extend(tree.nodes_by_type(zone_type->output_idname));
42 }
43 for (const bNode *node : zone_output_nodes) {
44 auto zone = std::make_unique<bNodeTreeZone>();
45 zone->owner = &owner;
46 zone->index = zones.size();
47 zone->output_node = node;
48 r_zone_by_inout_node.add(node, zone.get());
49 zones.append_and_get_index(std::move(zone));
50 }
51 for (const bNodeZoneType *zone_type : zone_types) {
52 for (const bNode *input_node : tree.nodes_by_type(zone_type->input_idname)) {
53 if (const bNode *output_node = zone_type->get_corresponding_output(tree, *input_node)) {
54 if (bNodeTreeZone *zone = r_zone_by_inout_node.lookup_default(output_node, nullptr)) {
55 zone->input_node = input_node;
56 r_zone_by_inout_node.add(input_node, zone);
57 }
58 }
59 }
60 }
61 return zones;
62}
63
67
68 uint64_t hash() const
69 {
70 return get_default_hash(this->parent, this->child);
71 }
72
74};
75
76static std::optional<Vector<ZoneRelation>> get_direct_zone_relations(
77 const Span<std::unique_ptr<bNodeTreeZone>> all_zones,
78 const BitGroupVector<> &depend_on_input_flag_array)
79{
80 VectorSet<ZoneRelation> all_zone_relations;
81
82 /* Gather all relations, even the transitive once. */
83 for (const std::unique_ptr<bNodeTreeZone> &zone : all_zones) {
84 const int zone_i = zone->index;
85 for (const bNode *node : {zone->output_node}) {
86 if (node == nullptr) {
87 continue;
88 }
89 const BoundedBitSpan depend_on_input_flags = depend_on_input_flag_array[node->index()];
90 bits::foreach_1_index(depend_on_input_flags, [&](const int parent_zone_i) {
91 if (parent_zone_i != zone_i) {
92 all_zone_relations.add_new({all_zones[parent_zone_i].get(), zone.get()});
93 }
94 });
95 }
96 }
97
98 for (const ZoneRelation &relation : all_zone_relations) {
99 const ZoneRelation reverse_relation{relation.child, relation.parent};
100 if (all_zone_relations.contains(reverse_relation)) {
101 /* There is a cyclic zone dependency. */
102 return std::nullopt;
103 }
104 }
105
106 /* Remove transitive relations. This is a brute force algorithm currently. */
107 Vector<int> transitive_relations;
108 for (const int a : all_zone_relations.index_range()) {
109 const ZoneRelation &relation_a = all_zone_relations[a];
110 for (const int b : all_zone_relations.index_range()) {
111 if (a == b) {
112 continue;
113 }
114 const ZoneRelation &relation_b = all_zone_relations[b];
115 if (relation_a.child != relation_b.parent) {
116 continue;
117 }
118 const ZoneRelation transitive_relation{relation_a.parent, relation_b.child};
119 const int transitive_relation_i = all_zone_relations.index_of_try(transitive_relation);
120 if (transitive_relation_i != -1) {
121 transitive_relations.append_non_duplicates(transitive_relation_i);
122 }
123 }
124 }
125 std::sort(transitive_relations.begin(), transitive_relations.end(), std::greater<>());
126
127 Vector<ZoneRelation> zone_relations = all_zone_relations.as_span();
128 for (const int i : transitive_relations) {
129 zone_relations.remove_and_reorder(i);
130 }
131
132 return zone_relations;
133}
134
135static bool update_zone_per_node(const Span<const bNode *> all_nodes,
136 const Span<std::unique_ptr<bNodeTreeZone>> all_zones,
137 const BitGroupVector<> &depend_on_input_flag_array,
138 const Map<const bNode *, bNodeTreeZone *> &zone_by_inout_node,
139 Map<int, int> &r_zone_by_node_id,
140 Vector<const bNode *> &r_node_outside_zones)
141{
142 bool found_node_in_multiple_zones = false;
143 for (const int node_i : all_nodes.index_range()) {
144 const bNode &node = *all_nodes[node_i];
145 const BoundedBitSpan depend_on_input_flags = depend_on_input_flag_array[node_i];
146 bNodeTreeZone *parent_zone = nullptr;
147 bits::foreach_1_index(depend_on_input_flags, [&](const int parent_zone_i) {
148 bNodeTreeZone *zone = all_zones[parent_zone_i].get();
149 if (ELEM(&node, zone->input_node, zone->output_node)) {
150 return;
151 }
152 if (parent_zone == nullptr) {
153 parent_zone = zone;
154 return;
155 }
156 for (bNodeTreeZone *iter_zone = zone->parent_zone; iter_zone;
157 iter_zone = iter_zone->parent_zone)
158 {
159 if (iter_zone == parent_zone) {
160 /* This zone is nested in the parent zone, so it becomes the new parent of the node. */
161 parent_zone = zone;
162 return;
163 }
164 }
165 for (bNodeTreeZone *iter_zone = parent_zone->parent_zone; iter_zone;
166 iter_zone = iter_zone->parent_zone)
167 {
168 if (iter_zone == zone) {
169 /* This zone is a parent of the current parent of the node, do nothing. */
170 return;
171 }
172 }
173 found_node_in_multiple_zones = true;
174 });
175 if (parent_zone == nullptr) {
176 if (!zone_by_inout_node.contains(&node)) {
177 r_node_outside_zones.append(&node);
178 }
179 }
180 else {
181 r_zone_by_node_id.add(node.identifier, parent_zone->index);
182 }
183 }
184 for (const MapItem<const bNode *, bNodeTreeZone *> item : zone_by_inout_node.items()) {
185 r_zone_by_node_id.add_overwrite(item.key->identifier, item.value->index);
186 }
187 return found_node_in_multiple_zones;
188}
189
191{
192 tree.ensure_topology_cache();
193 for (const bNodeLink *link : tree.all_links()) {
194 if (!link->is_available()) {
195 continue;
196 }
197 if (link->is_muted()) {
198 continue;
199 }
200 if (link->fromnode->is_dangling_reroute()) {
201 continue;
202 }
203 bNodeTreeZone *from_zone = const_cast<bNodeTreeZone *>(
204 tree_zones.get_zone_by_socket(*link->fromsock));
205 bNodeTreeZone *to_zone = const_cast<bNodeTreeZone *>(
206 tree_zones.get_zone_by_socket(*link->tosock));
207 if (from_zone == to_zone) {
208 continue;
209 }
210 BLI_assert(from_zone == nullptr || from_zone->contains_zone_recursively(*to_zone));
211 for (bNodeTreeZone *zone = to_zone; zone != from_zone; zone = zone->parent_zone) {
212 zone->border_links.append(link);
213 }
214 }
215}
216
217static std::unique_ptr<bNodeTreeZones> discover_tree_zones(const bNodeTree &tree)
218{
219 tree.ensure_topology_cache();
220 if (tree.has_available_link_cycle()) {
221 return {};
222 }
223
224 const Span<int> input_types = all_zone_input_node_types();
225 const Span<int> output_types = all_zone_output_node_types();
226
227 std::unique_ptr<bNodeTreeZones> tree_zones = std::make_unique<bNodeTreeZones>();
228
229 const Span<const bNode *> all_nodes = tree.all_nodes();
230 Map<const bNode *, bNodeTreeZone *> zone_by_inout_node;
231 tree_zones->zones = find_zone_nodes(tree, *tree_zones, zone_by_inout_node);
232
233 const int zones_num = tree_zones->zones.size();
234 const int nodes_num = all_nodes.size();
235 /* A bit for every node-zone-combination. The bit is set when the node is in the zone. */
236 BitGroupVector<> depend_on_input_flag_array(nodes_num, zones_num, false);
237 /* The bit is set when the node depends on the output of the zone. */
238 BitGroupVector<> depend_on_output_flag_array(nodes_num, zones_num, false);
239
240 const Span<const bNode *> sorted_nodes = tree.toposort_left_to_right();
241 for (const bNode *node : sorted_nodes) {
242 const int node_i = node->index();
243 MutableBoundedBitSpan depend_on_input_flags = depend_on_input_flag_array[node_i];
244 MutableBoundedBitSpan depend_on_output_flags = depend_on_output_flag_array[node_i];
245
246 /* Forward all bits from the nodes to the left. */
247 for (const bNodeSocket *input_socket : node->input_sockets()) {
248 if (!input_socket->is_available()) {
249 continue;
250 }
251 for (const bNodeLink *link : input_socket->directly_linked_links()) {
252 if (link->is_muted()) {
253 continue;
254 }
255 const bNode &from_node = *link->fromnode;
256 const int from_node_i = from_node.index();
257 depend_on_input_flags |= depend_on_input_flag_array[from_node_i];
258 depend_on_output_flags |= depend_on_output_flag_array[from_node_i];
259 }
260 }
261 if (input_types.contains(node->type)) {
262 if (const bNodeTreeZone *zone = zone_by_inout_node.lookup_default(node, nullptr)) {
263 /* Now entering a zone, so set the corresponding bit. */
264 depend_on_input_flags[zone->index].set();
265 }
266 }
267 else if (output_types.contains(node->type)) {
268 if (const bNodeTreeZone *zone = zone_by_inout_node.lookup_default(node, nullptr)) {
269 /* The output is implicitly linked to the input, so also propagate the bits from there. */
270 if (const bNode *zone_input_node = zone->input_node) {
271 const int input_node_i = zone_input_node->index();
272 depend_on_input_flags |= depend_on_input_flag_array[input_node_i];
273 depend_on_output_flags |= depend_on_output_flag_array[input_node_i];
274 }
275 /* Now exiting a zone, so change the bits accordingly. */
276 depend_on_input_flags[zone->index].reset();
277 depend_on_output_flags[zone->index].set();
278 }
279 }
280
281 if (bits::has_common_set_bits(depend_on_input_flags, depend_on_output_flags)) {
282 /* A node can not be inside and after a zone at the same time. */
283 return {};
284 }
285 }
286
287 const std::optional<Vector<ZoneRelation>> zone_relations = get_direct_zone_relations(
288 tree_zones->zones, depend_on_input_flag_array);
289 if (!zone_relations) {
290 /* Found cyclic relations. */
291 return {};
292 }
293
294 /* Set parent and child pointers in zones. */
295 for (const ZoneRelation &relation : *zone_relations) {
296 relation.parent->child_zones.append(relation.child);
297 BLI_assert(relation.child->parent_zone == nullptr);
298 relation.child->parent_zone = relation.parent;
299 }
300
301 Set<const bNodeTreeZone *> found_zones;
302 for (std::unique_ptr<bNodeTreeZone> &main_zone : tree_zones->zones) {
303 found_zones.clear();
304 for (bNodeTreeZone *zone = main_zone.get(); zone; zone = zone->parent_zone) {
305 if (!found_zones.add(zone)) {
306 /* Found cyclic parent relationships between zones. */
307 return {};
308 }
309 }
310 }
311
312 /* Update depths. */
313 for (std::unique_ptr<bNodeTreeZone> &zone : tree_zones->zones) {
314 update_zone_depths(*zone);
315 }
316
317 for (std::unique_ptr<bNodeTreeZone> &zone : tree_zones->zones) {
318 if (zone->depth == 0) {
319 tree_zones->root_zones.append(zone.get());
320 }
321 }
322
323 const bool found_node_in_multiple_zones = update_zone_per_node(all_nodes,
324 tree_zones->zones,
325 depend_on_input_flag_array,
326 zone_by_inout_node,
327 tree_zones->zone_by_node_id,
328 tree_zones->nodes_outside_zones);
329 if (found_node_in_multiple_zones) {
330 return {};
331 }
332
333 for (const bNode *node : tree.nodes_by_type("NodeGroupOutput")) {
334 if (tree_zones->zone_by_node_id.contains(node->identifier)) {
335 /* Group output nodes must not be in a zone. */
336 return {};
337 }
338 }
339
340 for (const int node_i : all_nodes.index_range()) {
341 const bNode *node = all_nodes[node_i];
342 const int zone_i = tree_zones->zone_by_node_id.lookup_default(node->identifier, -1);
343 if (zone_i == -1) {
344 continue;
345 }
346 const bNodeTreeZone &zone = *tree_zones->zones[zone_i];
347 if (ELEM(node, zone.input_node, zone.output_node)) {
348 continue;
349 }
350 tree_zones->zones[zone_i]->child_nodes.append(node);
351 }
352
353 update_zone_border_links(tree, *tree_zones);
354
355 // std::cout << *tree_zones << std::endl;
356 return tree_zones;
357}
358
360{
361 tree.ensure_topology_cache();
362 tree.runtime->tree_zones_cache_mutex.ensure(
363 [&]() { tree.runtime->tree_zones = discover_tree_zones(tree); });
364 return tree.runtime->tree_zones.get();
365}
366
368{
369 const bNodeTreeZones *zones = this->owner;
370 const int zone_i = zones->zone_by_node_id.lookup_default(node.identifier, -1);
371 if (zone_i == -1) {
372 return false;
373 }
374 for (const bNodeTreeZone *zone = zones->zones[zone_i].get(); zone; zone = zone->parent_zone) {
375 if (zone == this) {
376 return true;
377 }
378 }
379 return false;
380}
381
383{
384 for (const bNodeTreeZone *zone = other_zone.parent_zone; zone; zone = zone->parent_zone) {
385 if (zone == this) {
386 return true;
387 }
388 }
389 return false;
390}
391
393{
394 const bNode &node = socket.owner_node();
395 const bNodeTreeZone *zone = this->get_zone_by_node(node.identifier);
396 if (zone == nullptr) {
397 return zone;
398 }
399 if (zone->input_node == &node) {
400 if (socket.is_input()) {
401 return zone->parent_zone;
402 }
403 }
404 if (zone->output_node == &node) {
405 if (socket.is_output()) {
406 return zone->parent_zone;
407 }
408 }
409 return zone;
410}
411
413{
414 const int zone_i = this->zone_by_node_id.lookup_default(node_id, -1);
415 if (zone_i == -1) {
416 return nullptr;
417 }
418 return this->zones[zone_i].get();
419}
420
422{
423 const bNodeTreeZone *zone = this->get_zone_by_node(node_id);
424 if (zone == nullptr) {
425 return {};
426 }
428 for (; zone; zone = zone->parent_zone) {
429 zone_stack.append(zone);
430 }
431 std::reverse(zone_stack.begin(), zone_stack.end());
432 return zone_stack;
433}
434
436 const bNode &output_bnode) const
437{
438 for (const bNode *node : tree.nodes_by_type(this->input_idname)) {
439 if (this->get_corresponding_output_id(*node) == output_bnode.identifier) {
440 return node;
441 }
442 }
443 return nullptr;
444}
445
447 const bNode &input_bnode) const
448{
449 return tree.node_by_id(this->get_corresponding_output_id(input_bnode));
450}
451
453{
454 return const_cast<bNode *>(
455 this->get_corresponding_input(const_cast<const bNodeTree &>(tree), output_bnode));
456}
457
459{
460 return const_cast<bNode *>(
461 this->get_corresponding_output(const_cast<const bNodeTree &>(tree), input_bnode));
462}
463
465{
466 static Vector<const bNodeZoneType *> zone_types;
467 return zone_types;
468};
469
471{
472 get_zone_types_vector().append(&zone_type);
473}
474
479
481{
482 static const Vector<int> node_types = []() {
483 Vector<int> node_types;
484 for (const bNodeZoneType *zone_type : all_zone_types()) {
485 node_types.append(zone_type->input_type);
486 node_types.append(zone_type->output_type);
487 }
488 return node_types;
489 }();
490 return node_types;
491}
492
494{
495 static const Vector<int> node_types = []() {
496 Vector<int> node_types;
497 for (const bNodeZoneType *zone_type : all_zone_types()) {
498 node_types.append(zone_type->input_type);
499 }
500 return node_types;
501 }();
502 return node_types;
503}
504
506{
507 static const Vector<int> node_types = []() {
508 Vector<int> node_types;
509 for (const bNodeZoneType *zone_type : all_zone_types()) {
510 node_types.append(zone_type->output_type);
511 }
512 return node_types;
513 }();
514 return node_types;
515}
516
517const bNodeZoneType *zone_type_by_node_type(const int node_type)
518{
519 for (const bNodeZoneType *zone_type : all_zone_types()) {
520 if (ELEM(node_type, zone_type->input_type, zone_type->output_type)) {
521 return zone_type;
522 }
523 }
524 return nullptr;
525}
526
527std::ostream &operator<<(std::ostream &stream, const bNodeTreeZones &zones)
528{
529 for (const std::unique_ptr<bNodeTreeZone> &zone : zones.zones) {
530 stream << *zone;
531 if (zones.zones.last().get() != zone.get()) {
532 stream << "\n";
533 }
534 }
535 return stream;
536}
537
538std::ostream &operator<<(std::ostream &stream, const bNodeTreeZone &zone)
539{
540 stream << zone.index << ": Parent index: ";
541 if (zone.parent_zone != nullptr) {
542 stream << zone.parent_zone->index;
543 }
544 else {
545 stream << "*";
546 }
547
548 stream << "; Input: " << (zone.input_node ? zone.input_node->name : "null");
549 stream << ", Output: " << (zone.output_node ? zone.output_node->name : "null");
550
551 stream << "; Border Links: {\n";
552 for (const bNodeLink *border_link : zone.border_links) {
553 stream << " " << border_link->fromnode->name << ": " << border_link->fromsock->name << " -> ";
554 stream << border_link->tonode->name << ": " << border_link->tosock->name << ";\n";
555 }
556 stream << "}.";
557 return stream;
558}
559
560} // namespace blender::bke
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_STRUCT_EQUALITY_OPERATORS_2(Type, m1, m2)
#define ELEM(...)
bool add_overwrite(const Key &key, const Value &value)
Definition BLI_map.hh:301
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:271
Value lookup_default(const Key &key, const Value &default_value) const
Definition BLI_map.hh:531
ItemIterator items() const
Definition BLI_map.hh:864
bool contains(const Key &key) const
Definition BLI_map.hh:329
bool add(const Key &key)
Definition BLI_set.hh:248
void clear()
Definition BLI_set.hh:532
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
constexpr bool contains(const T &value) const
Definition BLI_span.hh:278
void add_new(const Key &key)
int64_t index_of_try(const Key &key) const
IndexRange index_range() const
Span< Key > as_span() const
bool contains(const Key &key) const
int64_t size() const
void remove_and_reorder(const int64_t index)
int64_t append_and_get_index(const T &value)
void append(const T &value)
void extend(Span< T > array)
void append_non_duplicates(const T &value)
bool contains_zone_recursively(const bNodeTreeZone &other_zone) const
bool contains_node_recursively(const bNode &node) const
Vector< const bNodeTreeZone * > get_zone_stack_for_node(const int32_t node_id) const
const bNodeTreeZone * get_zone_by_node(const int32_t node_id) const
Vector< std::unique_ptr< bNodeTreeZone > > zones
const bNodeTreeZone * get_zone_by_socket(const bNodeSocket &socket) const
const bNode * get_corresponding_input(const bNodeTree &tree, const bNode &output_bnode) const
virtual const int & get_corresponding_output_id(const bNode &input_bnode) const =0
const bNode * get_corresponding_output(const bNodeTree &tree, const bNode &input_bnode) const
local_group_size(16, 16) .push_constant(Type b
OperationNode * node
KDTree_3d * tree
bool has_common_set_bits(const BitSpanT &...args)
void foreach_1_index(const BitSpanT &data, Fn &&fn)
const bNodeZoneType * zone_type_by_node_type(const int node_type)
static void update_zone_depths(bNodeTreeZone &zone)
static Vector< const bNodeZoneType * > & get_zone_types_vector()
static Vector< std::unique_ptr< bNodeTreeZone > > find_zone_nodes(const bNodeTree &tree, bNodeTreeZones &owner, Map< const bNode *, bNodeTreeZone * > &r_zone_by_inout_node)
Span< int > all_zone_output_node_types()
static void update_zone_border_links(const bNodeTree &tree, bNodeTreeZones &tree_zones)
static bool update_zone_per_node(const Span< const bNode * > all_nodes, const Span< std::unique_ptr< bNodeTreeZone > > all_zones, const BitGroupVector<> &depend_on_input_flag_array, const Map< const bNode *, bNodeTreeZone * > &zone_by_inout_node, Map< int, int > &r_zone_by_node_id, Vector< const bNode * > &r_node_outside_zones)
Span< const bNodeZoneType * > all_zone_types()
Span< int > all_zone_node_types()
void register_node_zone_type(const bNodeZoneType &zone_type)
Span< int > all_zone_input_node_types()
static std::unique_ptr< bNodeTreeZones > discover_tree_zones(const bNodeTree &tree)
static std::optional< Vector< ZoneRelation > > get_direct_zone_relations(const Span< std::unique_ptr< bNodeTreeZone > > all_zones, const BitGroupVector<> &depend_on_input_flag_array)
std::ostream & operator<<(std::ostream &stream, const GeometrySet &geometry_set)
const bNodeTreeZones * get_tree_zones(const bNodeTree &tree)
uint64_t get_default_hash(const T &v)
Definition BLI_hash.hh:219
signed int int32_t
Definition stdint.h:77
unsigned __int64 uint64_t
Definition stdint.h:90
int32_t identifier