Blender  V3.3
depsgraph_query_foreach.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2017 Blender Foundation. All rights reserved. */
3 
10 #include "MEM_guardedalloc.h"
11 
12 #include "BLI_utildefines.h"
13 
14 #include "DNA_object_types.h"
15 #include "DNA_scene_types.h"
16 
17 #include "DEG_depsgraph.h"
18 #include "DEG_depsgraph_query.h"
19 
20 #include "intern/depsgraph.h"
22 #include "intern/node/deg_node.h"
26 
27 namespace deg = blender::deg;
28 
29 /* ************************ DEG TRAVERSAL ********************* */
30 
31 namespace blender::deg {
32 namespace {
33 
34 using TraversalQueue = deque<OperationNode *>;
35 
36 using DEGForeachOperation = void (*)(OperationNode *, void *);
37 
38 bool deg_foreach_needs_visit(const OperationNode *op_node, const int flags)
39 {
41  if (op_node->opcode == OperationCode::RIGIDBODY_SIM) {
42  return false;
43  }
44  }
45  return true;
46 }
47 
48 void deg_foreach_dependent_operation(const Depsgraph *UNUSED(graph),
49  const IDNode *target_id_node,
50  eDepsObjectComponentType source_component_type,
51  int flags,
52  DEGForeachOperation callback,
53  void *user_data)
54 {
55  if (target_id_node == nullptr) {
56  /* TODO(sergey): Shall we inform or assert here about attempt to start
57  * iterating over non-existing ID? */
58  return;
59  }
60  /* Start with scheduling all operations from ID node. */
61  TraversalQueue queue;
62  Set<OperationNode *> scheduled;
63  for (ComponentNode *comp_node : target_id_node->components.values()) {
64  if (comp_node->type == NodeType::VISIBILITY) {
65  /* Visibility component is only used internally. It is not to be reporting dependencies to
66  * the outer world. */
67  continue;
68  }
69 
70  if (source_component_type != DEG_OB_COMP_ANY &&
71  nodeTypeToObjectComponent(comp_node->type) != source_component_type) {
72  continue;
73  }
74  for (OperationNode *op_node : comp_node->operations) {
75  if (!deg_foreach_needs_visit(op_node, flags)) {
76  continue;
77  }
78  queue.push_back(op_node);
79  scheduled.add(op_node);
80  }
81  }
82  /* Process the queue. */
83  while (!queue.empty()) {
84  /* get next operation node to process. */
85  OperationNode *op_node = queue.front();
86  queue.pop_front();
87  for (;;) {
88  callback(op_node, user_data);
89  /* Schedule outgoing operation nodes. */
90  if (op_node->outlinks.size() == 1) {
91  OperationNode *to_node = (OperationNode *)op_node->outlinks[0]->to;
92  if (!scheduled.contains(to_node) && deg_foreach_needs_visit(to_node, flags)) {
93  scheduled.add_new(to_node);
94  op_node = to_node;
95  }
96  else {
97  break;
98  }
99  }
100  else {
101  for (Relation *rel : op_node->outlinks) {
102  OperationNode *to_node = (OperationNode *)rel->to;
103  if (!scheduled.contains(to_node) && deg_foreach_needs_visit(to_node, flags)) {
104  queue.push_front(to_node);
105  scheduled.add_new(to_node);
106  }
107  }
108  break;
109  }
110  }
111  }
112 }
113 
114 struct ForeachIDComponentData {
116  void *user_data;
117  IDNode *target_id_node;
118  Set<ComponentNode *> visited;
119 };
120 
121 void deg_foreach_dependent_component_callback(OperationNode *op_node, void *user_data_v)
122 {
123  ForeachIDComponentData *user_data = reinterpret_cast<ForeachIDComponentData *>(user_data_v);
124  ComponentNode *comp_node = op_node->owner;
125  IDNode *id_node = comp_node->owner;
126  if (id_node != user_data->target_id_node && !user_data->visited.contains(comp_node)) {
127  user_data->callback(
128  id_node->id_orig, nodeTypeToObjectComponent(comp_node->type), user_data->user_data);
129  user_data->visited.add_new(comp_node);
130  }
131 }
132 
133 void deg_foreach_dependent_ID_component(const Depsgraph *graph,
134  const ID *id,
135  eDepsObjectComponentType source_component_type,
136  int flags,
138  void *user_data)
139 {
140  ForeachIDComponentData data;
141  data.callback = callback;
142  data.user_data = user_data;
143  data.target_id_node = graph->find_id_node(id);
144  deg_foreach_dependent_operation(graph,
145  data.target_id_node,
146  source_component_type,
147  flags,
148  deg_foreach_dependent_component_callback,
149  &data);
150 }
151 
152 struct ForeachIDData {
154  void *user_data;
155  IDNode *target_id_node;
156  Set<IDNode *> visited;
157 };
158 
159 void deg_foreach_dependent_ID_callback(OperationNode *op_node, void *user_data_v)
160 {
161  ForeachIDData *user_data = reinterpret_cast<ForeachIDData *>(user_data_v);
162  ComponentNode *comp_node = op_node->owner;
163  IDNode *id_node = comp_node->owner;
164  if (id_node != user_data->target_id_node && !user_data->visited.contains(id_node)) {
165  user_data->callback(id_node->id_orig, user_data->user_data);
166  user_data->visited.add_new(id_node);
167  }
168 }
169 
170 void deg_foreach_dependent_ID(const Depsgraph *graph,
171  const ID *id,
173  void *user_data)
174 {
175  ForeachIDData data;
176  data.callback = callback;
177  data.user_data = user_data;
178  data.target_id_node = graph->find_id_node(id);
179  deg_foreach_dependent_operation(
180  graph, data.target_id_node, DEG_OB_COMP_ANY, 0, deg_foreach_dependent_ID_callback, &data);
181 }
182 
183 void deg_foreach_ancestor_ID(const Depsgraph *graph,
184  const ID *id,
186  void *user_data)
187 {
188  /* Start with getting ID node from the graph. */
189  IDNode *target_id_node = graph->find_id_node(id);
190  if (target_id_node == nullptr) {
191  /* TODO(sergey): Shall we inform or assert here about attempt to start
192  * iterating over non-existing ID? */
193  return;
194  }
195  /* Start with scheduling all operations from ID node. */
196  TraversalQueue queue;
197  Set<OperationNode *> scheduled;
198  for (ComponentNode *comp_node : target_id_node->components.values()) {
199  for (OperationNode *op_node : comp_node->operations) {
200  queue.push_back(op_node);
201  scheduled.add(op_node);
202  }
203  }
204  Set<IDNode *> visited;
205  visited.add_new(target_id_node);
206  /* Process the queue. */
207  while (!queue.empty()) {
208  /* get next operation node to process. */
209  OperationNode *op_node = queue.front();
210  queue.pop_front();
211  for (;;) {
212  /* Check whether we need to inform callee about corresponding ID node. */
213  ComponentNode *comp_node = op_node->owner;
214  IDNode *id_node = comp_node->owner;
215  if (!visited.contains(id_node)) {
216  /* TODO(sergey): Is it orig or CoW? */
218  visited.add_new(id_node);
219  }
220  /* Schedule incoming operation nodes. */
221  if (op_node->inlinks.size() == 1) {
222  Node *from = op_node->inlinks[0]->from;
223  if (from->get_class() == NodeClass::OPERATION) {
224  OperationNode *from_node = (OperationNode *)from;
225  if (scheduled.add(from_node)) {
226  op_node = from_node;
227  }
228  else {
229  break;
230  }
231  }
232  }
233  else {
234  for (Relation *rel : op_node->inlinks) {
235  Node *from = rel->from;
236  if (from->get_class() == NodeClass::OPERATION) {
237  OperationNode *from_node = (OperationNode *)from;
238  if (scheduled.add(from_node)) {
239  queue.push_front(from_node);
240  }
241  }
242  }
243  break;
244  }
245  }
246  }
247 }
248 
249 void deg_foreach_id(const Depsgraph *depsgraph, DEGForeachIDCallback callback, void *user_data)
250 {
251  for (const IDNode *id_node : depsgraph->id_nodes) {
253  }
254 }
255 
256 } // namespace
257 } // namespace blender::deg
258 
260  const ID *id,
262  void *user_data)
263 {
264  deg::deg_foreach_dependent_ID((const deg::Depsgraph *)depsgraph, id, callback, user_data);
265 }
266 
268  const ID *id,
269  eDepsObjectComponentType source_component_type,
270  int flags,
272  void *user_data)
273 {
274  deg::deg_foreach_dependent_ID_component(
275  (const deg::Depsgraph *)depsgraph, id, source_component_type, flags, callback, user_data);
276 }
277 
279  const ID *id,
281  void *user_data)
282 {
283  deg::deg_foreach_ancestor_ID((const deg::Depsgraph *)depsgraph, id, callback, user_data);
284 }
285 
287 {
288  deg::deg_foreach_id((const deg::Depsgraph *)depsgraph, callback, user_data);
289 }
#define UNUSED(x)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
eDepsObjectComponentType
@ DEG_OB_COMP_ANY
@ DEG_FOREACH_COMPONENT_IGNORE_TRANSFORM_SOLVERS
void(* DEGForeachIDComponentCallback)(ID *id, eDepsObjectComponentType component, void *user_data)
void(* DEGForeachIDCallback)(ID *id, void *user_data)
Object is a sort of wrapper for general info.
Read Guarded memory(de)allocation.
Depsgraph * graph
StackEntry * from
const IDNode * id_node
const Depsgraph * depsgraph
void DEG_foreach_dependent_ID_component(const Depsgraph *depsgraph, const ID *id, eDepsObjectComponentType source_component_type, int flags, DEGForeachIDComponentCallback callback, void *user_data)
void * user_data
IDNode * target_id_node
void DEG_foreach_ID(const Depsgraph *depsgraph, DEGForeachIDCallback callback, void *user_data)
void DEG_foreach_dependent_ID(const Depsgraph *depsgraph, const ID *id, DEGForeachIDCallback callback, void *user_data)
Set< ComponentNode * > visited
DEGForeachIDComponentCallback callback
void DEG_foreach_ancestor_ID(const Depsgraph *depsgraph, const ID *id, DEGForeachIDCallback callback, void *user_data)
SyclQueue * queue
SyclQueue void void size_t num_bytes void
eDepsObjectComponentType nodeTypeToObjectComponent(NodeType type)
Definition: deg_node.cc:196
Definition: DNA_ID.h:368
IDNode * find_id_node(const ID *id) const
Definition: depsgraph.cc:101
IDDepsNodes id_nodes
Definition: depsgraph.h:86
Map< ComponentIDKey, ComponentNode * > components
Definition: deg_node_id.h:80