Blender  V2.93
depsgraph_query_foreach.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2017 Blender Foundation.
17  * All rights reserved.
18  */
19 
26 #include "MEM_guardedalloc.h"
27 
28 #include "BLI_utildefines.h"
29 
30 #include "DNA_object_types.h"
31 #include "DNA_scene_types.h"
32 
33 #include "DEG_depsgraph.h"
34 #include "DEG_depsgraph_query.h"
35 
36 #include "intern/depsgraph.h"
38 #include "intern/node/deg_node.h"
42 
43 namespace deg = blender::deg;
44 
45 /* ************************ DEG TRAVERSAL ********************* */
46 
47 namespace blender::deg {
48 namespace {
49 
50 using TraversalQueue = deque<OperationNode *>;
51 
52 using DEGForeachOperation = void (*)(OperationNode *, void *);
53 
54 bool deg_foreach_needs_visit(const OperationNode *op_node, const int flags)
55 {
57  if (op_node->opcode == OperationCode::RIGIDBODY_SIM) {
58  return false;
59  }
60  }
61  return true;
62 }
63 
64 void deg_foreach_dependent_operation(const Depsgraph *UNUSED(graph),
65  const IDNode *target_id_node,
66  eDepsObjectComponentType source_component_type,
67  int flags,
68  DEGForeachOperation callback,
69  void *user_data)
70 {
71  if (target_id_node == nullptr) {
72  /* TODO(sergey): Shall we inform or assert here about attempt to start
73  * iterating over non-existing ID? */
74  return;
75  }
76  /* Start with scheduling all operations from ID node. */
77  TraversalQueue queue;
78  Set<OperationNode *> scheduled;
79  for (ComponentNode *comp_node : target_id_node->components.values()) {
80  if (source_component_type != DEG_OB_COMP_ANY &&
81  nodeTypeToObjectComponent(comp_node->type) != source_component_type) {
82  continue;
83  }
84  for (OperationNode *op_node : comp_node->operations) {
85  if (!deg_foreach_needs_visit(op_node, flags)) {
86  continue;
87  }
88  queue.push_back(op_node);
89  scheduled.add(op_node);
90  }
91  }
92  /* Process the queue. */
93  while (!queue.empty()) {
94  /* get next operation node to process. */
95  OperationNode *op_node = queue.front();
96  queue.pop_front();
97  for (;;) {
98  callback(op_node, user_data);
99  /* Schedule outgoing operation nodes. */
100  if (op_node->outlinks.size() == 1) {
101  OperationNode *to_node = (OperationNode *)op_node->outlinks[0]->to;
102  if (!scheduled.contains(to_node) && deg_foreach_needs_visit(to_node, flags)) {
103  scheduled.add_new(to_node);
104  op_node = to_node;
105  }
106  else {
107  break;
108  }
109  }
110  else {
111  for (Relation *rel : op_node->outlinks) {
112  OperationNode *to_node = (OperationNode *)rel->to;
113  if (!scheduled.contains(to_node) && deg_foreach_needs_visit(to_node, flags)) {
114  queue.push_front(to_node);
115  scheduled.add_new(to_node);
116  }
117  }
118  break;
119  }
120  }
121  }
122 }
123 
124 struct ForeachIDComponentData {
126  void *user_data;
127  IDNode *target_id_node;
128  Set<ComponentNode *> visited;
129 };
130 
131 void deg_foreach_dependent_component_callback(OperationNode *op_node, void *user_data_v)
132 {
133  ForeachIDComponentData *user_data = reinterpret_cast<ForeachIDComponentData *>(user_data_v);
134  ComponentNode *comp_node = op_node->owner;
135  IDNode *id_node = comp_node->owner;
136  if (id_node != user_data->target_id_node && !user_data->visited.contains(comp_node)) {
137  user_data->callback(
138  id_node->id_orig, nodeTypeToObjectComponent(comp_node->type), user_data->user_data);
139  user_data->visited.add_new(comp_node);
140  }
141 }
142 
143 void deg_foreach_dependent_ID_component(const Depsgraph *graph,
144  const ID *id,
145  eDepsObjectComponentType source_component_type,
146  int flags,
148  void *user_data)
149 {
150  ForeachIDComponentData data;
151  data.callback = callback;
152  data.user_data = user_data;
153  data.target_id_node = graph->find_id_node(id);
154  deg_foreach_dependent_operation(graph,
155  data.target_id_node,
156  source_component_type,
157  flags,
158  deg_foreach_dependent_component_callback,
159  &data);
160 }
161 
162 struct ForeachIDData {
164  void *user_data;
165  IDNode *target_id_node;
166  Set<IDNode *> visited;
167 };
168 
169 void deg_foreach_dependent_ID_callback(OperationNode *op_node, void *user_data_v)
170 {
171  ForeachIDData *user_data = reinterpret_cast<ForeachIDData *>(user_data_v);
172  ComponentNode *comp_node = op_node->owner;
173  IDNode *id_node = comp_node->owner;
174  if (id_node != user_data->target_id_node && !user_data->visited.contains(id_node)) {
175  user_data->callback(id_node->id_orig, user_data->user_data);
176  user_data->visited.add_new(id_node);
177  }
178 }
179 
180 void deg_foreach_dependent_ID(const Depsgraph *graph,
181  const ID *id,
183  void *user_data)
184 {
185  ForeachIDData data;
186  data.callback = callback;
187  data.user_data = user_data;
188  data.target_id_node = graph->find_id_node(id);
189  deg_foreach_dependent_operation(
190  graph, data.target_id_node, DEG_OB_COMP_ANY, 0, deg_foreach_dependent_ID_callback, &data);
191 }
192 
193 void deg_foreach_ancestor_ID(const Depsgraph *graph,
194  const ID *id,
196  void *user_data)
197 {
198  /* Start with getting ID node from the graph. */
199  IDNode *target_id_node = graph->find_id_node(id);
200  if (target_id_node == nullptr) {
201  /* TODO(sergey): Shall we inform or assert here about attempt to start
202  * iterating over non-existing ID? */
203  return;
204  }
205  /* Start with scheduling all operations from ID node. */
206  TraversalQueue queue;
207  Set<OperationNode *> scheduled;
208  for (ComponentNode *comp_node : target_id_node->components.values()) {
209  for (OperationNode *op_node : comp_node->operations) {
210  queue.push_back(op_node);
211  scheduled.add(op_node);
212  }
213  }
214  Set<IDNode *> visited;
215  visited.add_new(target_id_node);
216  /* Process the queue. */
217  while (!queue.empty()) {
218  /* get next operation node to process. */
219  OperationNode *op_node = queue.front();
220  queue.pop_front();
221  for (;;) {
222  /* Check whether we need to inform callee about corresponding ID node. */
223  ComponentNode *comp_node = op_node->owner;
224  IDNode *id_node = comp_node->owner;
225  if (!visited.contains(id_node)) {
226  /* TODO(sergey): Is it orig or CoW? */
228  visited.add_new(id_node);
229  }
230  /* Schedule incoming operation nodes. */
231  if (op_node->inlinks.size() == 1) {
232  Node *from = op_node->inlinks[0]->from;
233  if (from->get_class() == NodeClass::OPERATION) {
234  OperationNode *from_node = (OperationNode *)from;
235  if (scheduled.add(from_node)) {
236  op_node = from_node;
237  }
238  else {
239  break;
240  }
241  }
242  }
243  else {
244  for (Relation *rel : op_node->inlinks) {
245  Node *from = rel->from;
246  if (from->get_class() == NodeClass::OPERATION) {
247  OperationNode *from_node = (OperationNode *)from;
248  if (scheduled.add(from_node)) {
249  queue.push_front(from_node);
250  }
251  }
252  }
253  break;
254  }
255  }
256  }
257 }
258 
259 void deg_foreach_id(const Depsgraph *depsgraph, DEGForeachIDCallback callback, void *user_data)
260 {
261  for (const IDNode *id_node : depsgraph->id_nodes) {
263  }
264 }
265 
266 } // namespace
267 } // namespace blender::deg
268 
270  const ID *id,
272  void *user_data)
273 {
274  deg::deg_foreach_dependent_ID((const deg::Depsgraph *)depsgraph, id, callback, user_data);
275 }
276 
278  const ID *id,
279  eDepsObjectComponentType source_component_type,
280  int flags,
282  void *user_data)
283 {
284  deg::deg_foreach_dependent_ID_component(
285  (const deg::Depsgraph *)depsgraph, id, source_component_type, flags, callback, user_data);
286 }
287 
289  const ID *id,
291  void *user_data)
292 {
293  deg::deg_foreach_ancestor_ID((const deg::Depsgraph *)depsgraph, id, callback, user_data);
294 }
295 
297 {
298  deg::deg_foreach_id((const deg::Depsgraph *)depsgraph, callback, user_data);
299 }
#define UNUSED(x)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:51
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)
ThreadQueue * queue
all scheduled work for the cpu
eDepsObjectComponentType nodeTypeToObjectComponent(NodeType type)
Definition: deg_node.cc:211
Definition: DNA_ID.h:273
Definition: node.h:98
IDNode * find_id_node(const ID *id) const
Definition: depsgraph.cc:112
IDDepsNodes id_nodes
Definition: depsgraph.h:103
Map< ComponentIDKey, ComponentNode * > components
Definition: deg_node_id.h:96