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