Blender V4.5
depsgraph_query.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2013 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include <cstring> /* XXX: `memcpy`. */
12
13#include "BLI_listbase.h"
14
15#include "BKE_action.hh" /* XXX: BKE_pose_channel_find_name */
16#include "BKE_idtype.hh"
17#include "BKE_main.hh"
18
19#include "DNA_object_types.h"
20#include "DNA_scene_types.h"
21
22#include "RNA_access.hh"
23#include "RNA_path.hh"
24#include "RNA_prototypes.hh"
25
26#include "DEG_depsgraph.hh"
28
29#include "intern/depsgraph.hh"
33
34namespace blender::deg {
35
36static const ID *get_original_id(const ID *id)
37{
38 if (id == nullptr) {
39 return nullptr;
40 }
41 if (id->orig_id == nullptr) {
42 return id;
43 }
45 return (ID *)id->orig_id;
46}
47
48static ID *get_original_id(ID *id)
49{
50 const ID *const_id = id;
51 return const_cast<ID *>(get_original_id(const_id));
52}
53
54static const ID *get_evaluated_id(const Depsgraph *deg_graph, const ID *id)
55{
56 if (id == nullptr) {
57 return nullptr;
58 }
59 /* TODO(sergey): This is a duplicate of Depsgraph::get_cow_id(),
60 * but here we never do assert, since we don't know nature of the
61 * incoming ID data-block. */
62 const IDNode *id_node = deg_graph->find_id_node(id);
63 if (id_node == nullptr) {
64 return id;
65 }
66 return id_node->id_cow;
67}
68
69static ID *get_evaluated_id(const Depsgraph *deg_graph, ID *id)
70{
71 const ID *const_id = id;
72 return const_cast<ID *>(get_evaluated_id(deg_graph, const_id));
73}
74
75} // namespace blender::deg
76
77namespace deg = blender::deg;
78
79Scene *DEG_get_input_scene(const Depsgraph *graph)
80{
81 const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph);
82 return deg_graph->scene;
83}
84
85ViewLayer *DEG_get_input_view_layer(const Depsgraph *graph)
86{
87 const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph);
88 return deg_graph->view_layer;
89}
90
91Main *DEG_get_bmain(const Depsgraph *graph)
92{
93 const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph);
94 return deg_graph->bmain;
95}
96
97eEvaluationMode DEG_get_mode(const Depsgraph *graph)
98{
99 const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph);
100 return deg_graph->mode;
101}
102
103float DEG_get_ctime(const Depsgraph *graph)
104{
105 const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph);
106 return deg_graph->ctime;
107}
108
109bool DEG_id_type_updated(const Depsgraph *graph, short id_type)
110{
111 const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph);
112 return deg_graph->id_type_updated[BKE_idtype_idcode_to_index(id_type)] != 0;
113}
114
115bool DEG_id_type_any_updated(const Depsgraph *graph)
116{
117 const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph);
118
119 /* Loop over all ID types. */
120 for (char id_type_index : deg_graph->id_type_updated) {
121 if (id_type_index) {
122 return true;
123 }
124 }
125
126 return false;
127}
128
129bool DEG_id_type_any_exists(const Depsgraph *depsgraph, short id_type)
130{
131 const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(depsgraph);
132 return deg_graph->id_type_exist[BKE_idtype_idcode_to_index(id_type)] != 0;
133}
134
135uint32_t DEG_get_eval_flags_for_id(const Depsgraph *graph, const ID *id)
136{
137 if (graph == nullptr) {
138 /* Happens when converting objects to mesh from a python script
139 * after modifying scene graph.
140 *
141 * Currently harmless because it's only called for temporary
142 * objects which are out of the DAG anyway. */
143 return 0;
144 }
145
146 const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph);
147 const deg::IDNode *id_node = deg_graph->find_id_node(deg::get_original_id(id));
148 if (id_node == nullptr) {
149 /* TODO(sergey): Does it mean we need to check set scene? */
150 return 0;
151 }
152
153 return id_node->eval_flags;
154}
155
156void DEG_get_customdata_mask_for_object(const Depsgraph *graph,
157 Object *ob,
158 CustomData_MeshMasks *r_mask)
159{
160 if (graph == nullptr) {
161 /* Happens when converting objects to mesh from a python script
162 * after modifying scene graph.
163 *
164 * Currently harmless because it's only called for temporary
165 * objects which are out of the DAG anyway. */
166 return;
167 }
168
169 const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph);
170 const deg::IDNode *id_node = deg_graph->find_id_node(DEG_get_original(&ob->id));
171 if (id_node == nullptr) {
172 /* TODO(sergey): Does it mean we need to check set scene? */
173 return;
174 }
175
176 r_mask->vmask |= id_node->customdata_masks.vert_mask;
177 r_mask->emask |= id_node->customdata_masks.edge_mask;
178 r_mask->fmask |= id_node->customdata_masks.face_mask;
179 r_mask->lmask |= id_node->customdata_masks.loop_mask;
180 r_mask->pmask |= id_node->customdata_masks.poly_mask;
181}
182
183Scene *DEG_get_evaluated_scene(const Depsgraph *graph)
184{
185 const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph);
186 Scene *scene_cow = deg_graph->scene_cow;
187 /* TODO(sergey): Shall we expand data-block here? Or is it OK to assume
188 * that caller is OK with just a pointer in case scene is not updated yet? */
189 BLI_assert(scene_cow != nullptr && deg::deg_eval_copy_is_expanded(&scene_cow->id));
190 return scene_cow;
191}
192
194{
195 const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(graph);
196 Scene *scene_cow = DEG_get_evaluated_scene(graph);
197 if (scene_cow == nullptr) {
198 return nullptr; /* Happens with new, not-yet-built/evaluated graphs. */
199 }
200 /* Do name-based lookup. */
201 /* TODO(sergey): Can this be optimized? */
202 ViewLayer *view_layer_orig = deg_graph->view_layer;
203 ViewLayer *view_layer_cow = (ViewLayer *)BLI_findstring(
204 &scene_cow->view_layers, view_layer_orig->name, offsetof(ViewLayer, name));
205 BLI_assert(view_layer_cow != nullptr);
206 return view_layer_cow;
207}
208
209ID *DEG_get_evaluated_id(const Depsgraph *depsgraph, ID *id)
210{
211 return deg::get_evaluated_id(reinterpret_cast<const deg::Depsgraph *>(depsgraph), id);
212}
213
214const ID *DEG_get_evaluated_id(const Depsgraph *depsgraph, const ID *id)
215{
216 return DEG_get_evaluated_id(depsgraph, const_cast<ID *>(id));
217}
218
221 PointerRNA *r_ptr_eval)
222{
223 if ((ptr == nullptr) || (r_ptr_eval == nullptr)) {
224 return;
225 }
226 ID *orig_id = ptr->owner_id;
227 ID *cow_id = DEG_get_evaluated_id(depsgraph, orig_id);
228 if (ptr->owner_id == ptr->data) {
229 /* For ID pointers, it's easy... */
230 r_ptr_eval->owner_id = cow_id;
231 r_ptr_eval->data = (void *)cow_id;
232 r_ptr_eval->type = ptr->type;
233 }
234 else if (ptr->type == &RNA_PoseBone) {
235 /* HACK: Since bone keyframing is quite commonly used,
236 * speed things up for this case by doing a special lookup
237 * for bones */
238 const Object *ob_eval = (Object *)cow_id;
239 bPoseChannel *pchan = (bPoseChannel *)ptr->data;
240 const bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name);
241 r_ptr_eval->owner_id = cow_id;
242 r_ptr_eval->data = (void *)pchan_eval;
243 r_ptr_eval->type = ptr->type;
244 }
245 else {
246 /* For everything else, try to get RNA Path of the BMain-pointer,
247 * then use that to look up what the evaluated one should be
248 * given the evaluated ID pointer as the new lookup point */
249 /* TODO: Find a faster alternative, or implement support for other
250 * common types too above (e.g. modifiers) */
251 if (const std::optional<std::string> path = RNA_path_from_ID_to_struct(ptr)) {
252 PointerRNA cow_id_ptr = RNA_id_pointer_create(cow_id);
253 if (!RNA_path_resolve(&cow_id_ptr, path->c_str(), r_ptr_eval, nullptr)) {
254 /* Couldn't find evaluated copy of data */
255 fprintf(stderr,
256 "%s: Couldn't resolve RNA path ('%s') relative to evaluated ID (%p) for '%s'\n",
257 __func__,
258 path->c_str(),
259 (void *)cow_id,
260 orig_id->name);
261 }
262 }
263 else {
264 /* Path resolution failed - XXX: Hide this behind a debug flag */
265 fprintf(stderr,
266 "%s: Couldn't get RNA path for %s relative to %s\n",
267 __func__,
269 orig_id->name);
270 }
271 }
272}
273
275{
276 return deg::get_original_id(id);
277}
278
279const ID *DEG_get_original_id(const ID *id)
280{
281 return deg::get_original_id(id);
282}
283
284Depsgraph *DEG_get_depsgraph_by_id(const ID &id)
285{
286 return id.runtime.depsgraph;
287}
288
289bool DEG_is_original_id(const ID *id)
290{
291 /* Some explanation of the logic.
292 *
293 * What we want here is to be able to tell whether given ID is a result of dependency graph
294 * evaluation or not.
295 *
296 * All the data-blocks which are created by copy-on-evaluation mechanism will have will be tagged
297 * with ID_TAG_COPIED_ON_EVAL tag. Those data-blocks can not be original.
298 *
299 * Modifier stack evaluation might create special data-blocks which have all the modifiers
300 * applied, and those will be tagged with ID_TAG_COPIED_ON_EVAL_FINAL_RESULT. Such data-blocks
301 * can not be original as well.
302 *
303 * Localization is usually happening from evaluated data-block, or will have some special pointer
304 * magic which will make them to act as evaluated.
305 *
306 * NOTE: We consider ID evaluated if ANY of those flags is set. We do NOT require ALL of them. */
308 return false;
309 }
310 return true;
311}
312
313bool DEG_is_evaluated_id(const ID *id)
314{
315 return !DEG_is_original_id(id);
316}
317
318bool DEG_is_fully_evaluated(const Depsgraph *depsgraph)
319{
320 const deg::Depsgraph *deg_graph = (const deg::Depsgraph *)depsgraph;
321 /* Check whether relations are up to date. */
322 if (deg_graph->need_update_relations) {
323 return false;
324 }
325 /* Check whether IDs are up to date. */
326 if (!deg_graph->entry_tags.is_empty()) {
327 return false;
328 }
329 return true;
330}
331
332bool DEG_id_is_fully_evaluated(const Depsgraph *depsgraph, const ID *id_eval)
333{
334 const deg::Depsgraph *deg_graph = reinterpret_cast<const deg::Depsgraph *>(depsgraph);
335 /* Only us the original ID pointer to look up the IDNode, do not dereference it. */
336 const ID *id_orig = deg::get_original_id(id_eval);
337 const deg::IDNode *id_node = deg_graph->find_id_node(id_orig);
338 if (!id_node) {
339 return false;
340 }
341 for (deg::ComponentNode *component : id_node->components.values()) {
342 for (deg::OperationNode *operation : component->operations) {
343 if (operation->flag & deg::DEPSOP_FLAG_NEEDS_UPDATE) {
344 return false;
345 }
346 }
347 }
348 return true;
349}
350
351static bool operation_needs_update(const ID &id,
352 const deg::NodeType component_type,
353 const deg::OperationCode opcode)
354{
355 const Depsgraph *depsgraph = DEG_get_depsgraph_by_id(id);
356 if (!depsgraph) {
357 return false;
358 }
359 const deg::Depsgraph &deg_graph = *reinterpret_cast<const deg::Depsgraph *>(depsgraph);
360 /* Only us the original ID pointer to look up the IDNode, do not dereference it. */
361 const ID *id_orig = deg::get_original_id(&id);
362 if (!id_orig) {
363 return false;
364 }
365 const deg::IDNode *id_node = deg_graph.find_id_node(id_orig);
366 if (!id_node) {
367 return false;
368 };
369 const deg::ComponentNode *component_node = id_node->find_component(component_type);
370 if (!component_node) {
371 return false;
372 }
373 const deg::OperationNode *operation_node = component_node->find_operation(opcode);
374 if (!operation_node) {
375 return false;
376 }
377 /* Technically, there is potential for a race condition here, because the depsgraph evaluation
378 * might update this flag, but it's very unlikely to cause issues right now. Maybe this should
379 * become an atomic eventually. */
380 const bool needs_update = operation_node->flag & deg::DEPSOP_FLAG_NEEDS_UPDATE;
381 return needs_update;
382}
383
389
395
Blender kernel action and pose functionality.
bPoseChannel * BKE_pose_channel_find_name(const bPose *pose, const char *name)
int BKE_idtype_idcode_to_index(short idcode)
Definition idtype.cc:229
#define BLI_assert(a)
Definition BLI_assert.h:46
void * BLI_findstring(const ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:608
eEvaluationMode
T * DEG_get_original(T *id)
@ ID_TAG_COPIED_ON_EVAL
Definition DNA_ID.h:905
@ ID_TAG_LOCALIZED
Definition DNA_ID.h:895
@ ID_TAG_COPIED_ON_EVAL_FINAL_RESULT
Definition DNA_ID.h:915
Object is a sort of wrapper for general info.
BPy_StructRNA * depsgraph
float DEG_get_ctime(const Depsgraph *graph)
bool DEG_object_transform_is_evaluated(const Object &object)
uint32_t DEG_get_eval_flags_for_id(const Depsgraph *graph, const ID *id)
bool DEG_id_is_fully_evaluated(const Depsgraph *depsgraph, const ID *id_eval)
bool DEG_is_fully_evaluated(const Depsgraph *depsgraph)
bool DEG_is_evaluated_id(const ID *id)
void DEG_get_customdata_mask_for_object(const Depsgraph *graph, Object *ob, CustomData_MeshMasks *r_mask)
Scene * DEG_get_evaluated_scene(const Depsgraph *graph)
eEvaluationMode DEG_get_mode(const Depsgraph *graph)
bool DEG_is_original_id(const ID *id)
ID * DEG_get_original_id(ID *id)
Depsgraph * DEG_get_depsgraph_by_id(const ID &id)
bool DEG_object_geometry_is_evaluated(const Object &object)
ViewLayer * DEG_get_evaluated_view_layer(const Depsgraph *graph)
ViewLayer * DEG_get_input_view_layer(const Depsgraph *graph)
Main * DEG_get_bmain(const Depsgraph *graph)
static bool operation_needs_update(const ID &id, const deg::NodeType component_type, const deg::OperationCode opcode)
Scene * DEG_get_input_scene(const Depsgraph *graph)
bool DEG_id_type_any_exists(const Depsgraph *depsgraph, short id_type)
void DEG_get_evaluated_rna_pointer(const Depsgraph *depsgraph, PointerRNA *ptr, PointerRNA *r_ptr_eval)
ID * DEG_get_evaluated_id(const Depsgraph *depsgraph, ID *id)
bool DEG_collection_geometry_is_evaluated(const Collection &collection)
bool DEG_id_type_updated(const Depsgraph *graph, short id_type)
bool DEG_id_type_any_updated(const Depsgraph *graph)
#define offsetof(t, d)
bool deg_eval_copy_is_expanded(const ID *id_cow)
static const ID * get_evaluated_id(const Depsgraph *deg_graph, const ID *id)
static const ID * get_original_id(const ID *id)
const char * RNA_struct_identifier(const StructRNA *type)
PointerRNA RNA_id_pointer_create(ID *id)
std::optional< std::string > RNA_path_from_ID_to_struct(const PointerRNA *ptr)
Definition rna_path.cc:1014
bool RNA_path_resolve(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
Definition rna_path.cc:532
Definition DNA_ID.h:404
int tag
Definition DNA_ID.h:424
struct ID * orig_id
Definition DNA_ID.h:466
char name[66]
Definition DNA_ID.h:415
struct bPose * pose
ID * owner_id
Definition RNA_types.hh:51
StructRNA * type
Definition RNA_types.hh:52
void * data
Definition RNA_types.hh:53
ListBase view_layers
char name[64]
OperationNode * find_operation(OperationIDKey key) const
IDNode * find_id_node(const ID *id) const
Definition depsgraph.cc:101
char id_type_updated[INDEX_ID_MAX]
Definition depsgraph.hh:117
eEvaluationMode mode
Definition depsgraph.hh:143
char id_type_exist[INDEX_ID_MAX]
Definition depsgraph.hh:122
Set< OperationNode * > entry_tags
Definition depsgraph.hh:127
DEGCustomDataMeshMasks customdata_masks
Map< ComponentIDKey, ComponentNode * > components
ComponentNode * find_component(NodeType type, StringRef name="") const
PointerRNA * ptr
Definition wm_files.cc:4226