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