Blender V4.3
lib_query.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2014 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cstdlib>
10
11#include "DNA_anim_types.h"
12
13#include "BLI_function_ref.hh"
14#include "BLI_ghash.h"
15#include "BLI_linklist_stack.h"
16#include "BLI_listbase.h"
17#include "BLI_set.hh"
18#include "BLI_utildefines.h"
19
20#include "BKE_anim_data.hh"
21#include "BKE_idprop.hh"
22#include "BKE_idtype.hh"
23#include "BKE_lib_id.hh"
24#include "BKE_lib_query.hh"
25#include "BKE_main.hh"
26#include "BKE_node.hh"
27
28/* status */
29enum {
30 IDWALK_STOP = 1 << 0,
31};
32
45
47 int flag;
52
53 /* Function to call for every ID pointers of current processed data, and its opaque user data
54 * pointer. */
56 void *user_data;
59 int status;
60
61 /* To handle recursion. */
62 GSet *ids_handled; /* All IDs that are either already done, or still in ids_todo stack. */
64};
65
67{
68 return (data->status & IDWALK_STOP) != 0;
69}
70
72{
74 return;
75 }
76
77 const int flag = data->flag;
78 ID *old_id = *id_pp;
79
80 /* Update the callback flags with the ones defined (or forbidden) in `data` by the generic
81 * caller code. */
82 cb_flag = ((cb_flag | data->cb_flag) & ~data->cb_flag_clear);
83
84 /* Update the callback flags with some extra information regarding overrides: all 'loopback',
85 * 'internal', 'embedded' etc. ID pointers are never overridable. */
88 }
89
90 LibraryIDLinkCallbackData callback_data{};
91 callback_data.user_data = data->user_data;
92 callback_data.bmain = data->bmain;
93 callback_data.owner_id = data->owner_id;
94 callback_data.self_id = data->self_id;
95 callback_data.id_pointer = id_pp;
96 callback_data.cb_flag = cb_flag;
97 const int callback_return = data->callback(&callback_data);
98
99 if (flag & IDWALK_READONLY) {
100 BLI_assert(*(id_pp) == old_id);
101 }
102 else {
104 "Iteration over ID usages should not be interrupted by the callback in "
105 "non-readonly cases");
106 }
107
108 if (old_id && (flag & IDWALK_RECURSE)) {
109 if (BLI_gset_add((data)->ids_handled, old_id)) {
110 if (!(callback_return & IDWALK_RET_STOP_RECURSION)) {
111 BLI_LINKSTACK_PUSH(data->ids_todo, old_id);
112 }
113 }
114 }
115 if (callback_return & IDWALK_RET_STOP_ITER) {
116 data->status |= IDWALK_STOP;
117 }
118}
119
121{
122 return data->flag;
123}
124
126{
127 return data->bmain;
128}
129
131 const int cb_flag,
132 const bool do_replace)
133{
134 const int cb_flag_backup = data->cb_flag;
135 if (do_replace) {
136 data->cb_flag = cb_flag;
137 }
138 else {
139 data->cb_flag |= cb_flag;
140 }
141 return cb_flag_backup;
142}
143
144static bool library_foreach_ID_link(Main *bmain,
145 ID *owner_id,
146 ID *id,
148 void *user_data,
149 int flag,
150 LibraryForeachIDData *inherit_data);
151
153{
154 BLI_assert(id_prop->type == IDP_ID);
155
156 LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
157 const int cb_flag = IDWALK_CB_USER | ((id_prop->flag & IDP_FLAG_OVERRIDABLE_LIBRARY) ?
158 0 :
160 BKE_LIB_FOREACHID_PROCESS_ID(data, id_prop->data.pointer, cb_flag);
161}
162
164{
165 /* Needed e.g. for callbacks handling relationships. This call should be absolutely read-only. */
166 ID *id = *id_pp;
167 const int flag = data->flag;
168
171 return;
172 }
173 BLI_assert(id == *id_pp);
174
175 if (id == nullptr) {
176 return;
177 }
178
180 /* Do Nothing. */
181 }
182 else if (flag & IDWALK_RECURSE) {
183 /* Defer handling into main loop, recursively calling BKE_library_foreach_ID_link in
184 * IDWALK_RECURSE case is troublesome, see #49553. */
185 if (BLI_gset_add(data->ids_handled, id)) {
186 BLI_LINKSTACK_PUSH(data->ids_todo, id);
187 }
188 }
189 else {
191 data->bmain, data->owner_id, id, data->callback, data->user_data, data->flag, data))
192 {
193 data->status |= IDWALK_STOP;
194 return;
195 }
196 }
197}
198
200{
201 if (data->ids_handled != nullptr) {
202 BLI_gset_free(data->ids_handled, nullptr);
203 BLI_LINKSTACK_FREE(data->ids_todo);
204 }
205}
206
208static bool library_foreach_ID_link(Main *bmain,
209 ID *owner_id,
210 ID *id,
212 void *user_data,
213 int flag,
214 LibraryForeachIDData *inherit_data)
215{
217 data.bmain = bmain;
218
219 BLI_assert(inherit_data == nullptr || data.bmain == inherit_data->bmain);
220 /* `IDWALK_NO_ORIG_POINTERS_ACCESS` is mutually exclusive with `IDWALK_RECURSE`. */
223
226 }
227
228 if (flag & IDWALK_RECURSE) {
229 /* For now, recursion implies read-only, and no internal pointers. */
231 flag &= ~IDWALK_DO_INTERNAL_RUNTIME_POINTERS;
232
233 /* NOTE: This function itself should never be called recursively when IDWALK_RECURSE is set,
234 * see also comments in #BKE_library_foreach_ID_embedded.
235 * This is why we can always create this data here, and do not need to try and re-use it from
236 * `inherit_data`. */
237 data.ids_handled = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
238 BLI_LINKSTACK_INIT(data.ids_todo);
239
240 BLI_gset_add(data.ids_handled, id);
241 }
242 else {
243 data.ids_handled = nullptr;
244 }
245 data.flag = flag;
246 data.status = 0;
247 data.callback = callback;
248 data.user_data = user_data;
249
250#define CALLBACK_INVOKE_ID(check_id, cb_flag) \
251 { \
252 CHECK_TYPE_ANY((check_id), ID *, void *); \
253 BKE_lib_query_foreachid_process(&data, (ID **)&(check_id), (cb_flag)); \
254 if (BKE_lib_query_foreachid_iter_stop(&data)) { \
255 library_foreach_ID_data_cleanup(&data); \
256 return false; \
257 } \
258 } \
259 ((void)0)
260
261#define CALLBACK_INVOKE(check_id_super, cb_flag) \
262 { \
263 CHECK_TYPE(&((check_id_super)->id), ID *); \
264 BKE_lib_query_foreachid_process(&data, (ID **)&(check_id_super), (cb_flag)); \
265 if (BKE_lib_query_foreachid_iter_stop(&data)) { \
266 library_foreach_ID_data_cleanup(&data); \
267 return false; \
268 } \
269 } \
270 ((void)0)
271
272 for (; id != nullptr; id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : nullptr,
273 owner_id = nullptr)
274 {
275 data.self_id = id;
276 /* owner ID is same as self ID, except for embedded ID case. */
277 if (id->flag & ID_FLAG_EMBEDDED_DATA) {
279 data.owner_id = owner_id ? owner_id : id;
280 }
281 else {
282 /* NOTE: Unfortunately it is not possible to ensure validity of the set owner_id pointer
283 * here. `foreach_id` is used a lot by code remapping pointers, and in such cases the
284 * current owner ID of the processed embedded ID is indeed invalid - and the given one is
285 * to be assumed valid for the purpose of the current process.
286 *
287 * In other words, it is the responsibility of the code calling this `foreach_id` process
288 * to ensure that the given owner ID is valid for its own purpose, or that it is not used.
289 */
290 // BLI_assert(owner_id == nullptr || BKE_id_owner_get(id) == owner_id);
291 if (!owner_id) {
292 owner_id = BKE_id_owner_get(id, false);
293 }
294 data.owner_id = owner_id;
295 }
296 }
297 else {
298 BLI_assert(ELEM(owner_id, nullptr, id));
299 data.owner_id = id;
300 }
301
302 /* inherit_data is non-nullptr when this function is called for some sub-data ID
303 * (like root node-tree of a material).
304 * In that case, we do not want to generate those 'generic flags' from our current sub-data ID
305 * (the node tree), but re-use those generated for the 'owner' ID (the material). */
306 if (inherit_data == nullptr) {
307 data.cb_flag = ID_IS_LINKED(id) ? IDWALK_CB_INDIRECT_USAGE : 0;
308 /* When an ID is defined as not reference-counting its ID usages, it should never do it. */
309 data.cb_flag_clear = (id->tag & ID_TAG_NO_USER_REFCOUNT) ?
311 0;
312 }
313 else {
314 data.cb_flag = inherit_data->cb_flag;
315 data.cb_flag_clear = inherit_data->cb_flag_clear;
316 }
317
318 bool use_bmain_relations = bmain != nullptr && bmain->relations != nullptr &&
320 /* Including UI-related ID pointers should match with the relevant setting in Main relations
321 * cache. */
322 if (use_bmain_relations && (((bmain->relations->flag & MAINIDRELATIONS_INCLUDE_UI) == 0) !=
323 ((data.flag & IDWALK_INCLUDE_UI) == 0)))
324 {
325 use_bmain_relations = false;
326 }
327 /* No special 'internal' handling of ID pointers is covered by Main relations cache. */
328 if (use_bmain_relations &&
331 {
332 use_bmain_relations = false;
333 }
334 if (use_bmain_relations) {
335 /* Note that this is minor optimization, even in worst cases (like id being an object with
336 * lots of drivers and constraints and modifiers, or material etc. with huge node tree),
337 * but we might as well use it (Main->relations is always assumed valid,
338 * it's responsibility of code creating it to free it,
339 * especially if/when it starts modifying Main database). */
340 MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(
342 for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != nullptr;
343 to_id_entry = to_id_entry->next)
344 {
346 &data, to_id_entry->id_pointer.to, to_id_entry->usage_flag);
349 return false;
350 }
351 }
352 continue;
353 }
354
357 }
358
362 }
363
364 if (id->override_library != nullptr) {
365 CALLBACK_INVOKE_ID(id->override_library->reference,
367 CALLBACK_INVOKE_ID(id->override_library->storage,
369
370 CALLBACK_INVOKE_ID(id->override_library->hierarchy_root, IDWALK_CB_LOOPBACK);
371 LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &id->override_library->properties) {
372 LISTBASE_FOREACH (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
373 CALLBACK_INVOKE_ID(opop->subitem_reference_id,
375 CALLBACK_INVOKE_ID(opop->subitem_local_id,
377 }
378 }
379 }
380
381 IDP_foreach_property(id->properties, IDP_TYPE_FILTER_ID, [&](IDProperty *prop) {
382 BKE_lib_query_idpropertiesForeachIDLink_callback(prop, &data);
383 });
386 return false;
387 }
388
390 if (adt) {
391 BKE_animdata_foreach_id(adt, &data);
394 return false;
395 }
396 }
397
398 const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
399 if (id_type->foreach_id != nullptr) {
400 id_type->foreach_id(id, &data);
401
404 return false;
405 }
406 }
407 }
408
410 return true;
411
412#undef CALLBACK_INVOKE_ID
413#undef CALLBACK_INVOKE
414}
415
417 ID *id,
419 void *user_data,
420 int flag)
421{
422 library_foreach_ID_link(bmain, nullptr, id, callback, user_data, flag, nullptr);
423}
424
425void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cb_flag)
426{
427 if (cb_flag & IDWALK_CB_USER) {
428 id_us_min(id_src);
429 id_us_plus(id_dst);
430 }
431 else if (cb_flag & IDWALK_CB_USER_ONE) {
432 id_us_ensure_real(id_dst);
433 }
434}
435
437 Main *bmain,
438 ID *owner_id,
439 ID *self_id,
440 blender::FunctionRef<void(LibraryForeachIDData *data)> subdata_foreach_id,
442 void *user_data,
443 const int flag)
444{
447
449 data.bmain = bmain;
450 data.owner_id = owner_id;
451 data.self_id = self_id;
452 data.ids_handled = nullptr;
453 data.flag = flag;
454 data.status = 0;
455 data.callback = callback;
456 data.user_data = user_data;
457
458 subdata_foreach_id(&data);
459}
460
462 const bool include_ui,
463 const IDTypeInfo *owner_id_type)
464{
465 /* any type of ID can be used in custom props. */
466 if (owner_id->properties) {
467 return FILTER_ID_ALL;
468 }
469 /* When including UI data (i.e. editors), Screen UI IDs can also link to virtually any ID
470 * (through e.g. the Outliner). */
471 if (include_ui && GS(owner_id->name) == ID_SCR) {
472 return FILTER_ID_ALL;
473 }
474
475 /* Casting to non const.
476 * TODO(jbakker): We should introduce a ntree_id_has_tree function as we are actually not
477 * interested in the result. */
478 if (blender::bke::node_tree_from_id(const_cast<ID *>(owner_id))) {
479 return FILTER_ID_ALL;
480 }
481
482 if (BKE_animdata_from_id(owner_id)) {
483 /* AnimationData can use virtually any kind of data-blocks, through drivers especially. */
484 return FILTER_ID_ALL;
485 }
486
487 if (ID_IS_OVERRIDE_LIBRARY_REAL(owner_id)) {
488 /* LibOverride data 'hierarchy root' can virtually point back to any type of ID. */
489 return FILTER_ID_ALL;
490 }
491
492 if (!owner_id_type) {
493 owner_id_type = BKE_idtype_get_info_from_id(owner_id);
494 }
495 if (owner_id_type) {
496 return owner_id_type->dependencies_id_types;
497 }
499 return 0;
500}
501
502bool BKE_library_id_can_use_idtype(ID *owner_id, const short id_type_used)
503{
504 const IDTypeInfo *owner_id_type = BKE_idtype_get_info_from_id(owner_id);
505 const uint64_t filter_id_type_used = BKE_idtype_idcode_to_idfilter(id_type_used);
506 const uint64_t can_be_used = BKE_library_id_can_use_filter_id(owner_id, false, owner_id_type);
507 return (can_be_used & filter_id_type_used) != 0;
508}
509
510/* ***** ID users iterator. ***** */
513
514 // ListBase *lb_array[INDEX_ID_MAX]; /* UNUSED. */
515 // int lb_idx; /* UNUSED. */
516
518 int count_direct, count_indirect; /* Set by callback. */
519};
520
522{
523 ID **id_p = cb_data->id_pointer;
524 const int cb_flag = cb_data->cb_flag;
525 IDUsersIter *iter = static_cast<IDUsersIter *>(cb_data->user_data);
526
527 if (*id_p) {
528 /* 'Loopback' ID pointers (the ugly 'from' ones, like Key->from).
529 * Those are not actually ID usage, we can ignore them here.
530 */
531 if (cb_flag & IDWALK_CB_LOOPBACK) {
532 return IDWALK_RET_NOP;
533 }
534
535 if (*id_p == iter->id) {
536#if 0
537 printf(
538 "%s uses %s (refcounted: %d, userone: %d, used_one: %d, used_one_active: %d, "
539 "indirect_usage: %d)\n",
540 iter->curr_id->name,
541 iter->id->name,
542 (cb_flag & IDWALK_USER) ? 1 : 0,
543 (cb_flag & IDWALK_USER_ONE) ? 1 : 0,
544 (iter->id->tag & ID_TAG_EXTRAUSER) ? 1 : 0,
545 (iter->id->tag & ID_TAG_EXTRAUSER_SET) ? 1 : 0,
546 (cb_flag & IDWALK_INDIRECT_USAGE) ? 1 : 0);
547#endif
548 if (cb_flag & IDWALK_CB_INDIRECT_USAGE) {
549 iter->count_indirect++;
550 }
551 else {
552 iter->count_direct++;
553 }
554 }
555 }
556
557 return IDWALK_RET_NOP;
558}
559
560int BKE_library_ID_use_ID(ID *id_user, ID *id_used)
561{
562 IDUsersIter iter;
563
564 /* We do not care about iter.lb_array/lb_idx here... */
565 iter.id = id_used;
566 iter.curr_id = id_user;
567 iter.count_direct = iter.count_indirect = 0;
568
570 nullptr, iter.curr_id, foreach_libblock_id_users_callback, (void *)&iter, IDWALK_READONLY);
571
572 return iter.count_direct + iter.count_indirect;
573}
574
575static bool library_ID_is_used(Main *bmain, void *idv, const bool check_linked)
576{
577 IDUsersIter iter;
578 ListBase *lb_array[INDEX_ID_MAX];
579 ID *id = static_cast<ID *>(idv);
580 int i = set_listbasepointers(bmain, lb_array);
581 bool is_defined = false;
582
583 iter.id = id;
584 iter.count_direct = iter.count_indirect = 0;
585 while (i-- && !is_defined) {
586 ID *id_curr = static_cast<ID *>(lb_array[i]->first);
587
588 if (!id_curr || !BKE_library_id_can_use_idtype(id_curr, GS(id->name))) {
589 continue;
590 }
591
592 for (; id_curr && !is_defined; id_curr = static_cast<ID *>(id_curr->next)) {
593 if (id_curr == id) {
594 /* We are not interested in self-usages (mostly from drivers or bone constraints...). */
595 continue;
596 }
597 iter.curr_id = id_curr;
600
601 is_defined = ((check_linked ? iter.count_indirect : iter.count_direct) != 0);
602 }
603 }
604
605 return is_defined;
606}
607
609{
610 return library_ID_is_used(bmain, idv, false);
611}
612
614{
615 return library_ID_is_used(bmain, idv, true);
616}
617
619 void *idv,
620 bool *r_is_used_local,
621 bool *r_is_used_linked)
622{
623 IDUsersIter iter;
624 ListBase *lb_array[INDEX_ID_MAX];
625 ID *id = static_cast<ID *>(idv);
626 int i = set_listbasepointers(bmain, lb_array);
627 bool is_defined = false;
628
629 iter.id = id;
630 iter.count_direct = iter.count_indirect = 0;
631 while (i-- && !is_defined) {
632 ID *id_curr = static_cast<ID *>(lb_array[i]->first);
633
634 if (!id_curr || !BKE_library_id_can_use_idtype(id_curr, GS(id->name))) {
635 continue;
636 }
637
638 for (; id_curr && !is_defined; id_curr = static_cast<ID *>(id_curr->next)) {
639 if (id_curr == id) {
640 /* We are not interested in self-usages (mostly from drivers or bone constraints...). */
641 continue;
642 }
643 iter.curr_id = id_curr;
646
647 is_defined = (iter.count_direct != 0 && iter.count_indirect != 0);
648 }
649 }
650
651 *r_is_used_local = (iter.count_direct != 0);
652 *r_is_used_linked = (iter.count_indirect != 0);
653}
654
655/* ***** IDs usages.checking/tagging. ***** */
656
657/* Internal data for the common processing of the 'unused IDs' query functions.
658 *
659 * While #LibQueryUnusedIDsData is a subset of this internal struct, they need to be kept separate,
660 * since this struct is used with partially 'enforced' values for some parameters by the
661 * #BKE_lib_query_unused_ids_amounts code. This allows the computation of predictive amounts for
662 * user feedback ('what would be the amounts of IDs detected as unused if this option was
663 * enabled').
664 */
667
668 const int id_tag;
669
673
675
676 std::array<int, INDEX_ID_MAX> *num_total;
677 std::array<int, INDEX_ID_MAX> *num_local;
678 std::array<int, INDEX_ID_MAX> *num_linked;
679
681
694
695 void reset(const bool do_local_ids,
696 const bool do_linked_ids,
697 const bool do_recursive,
698 std::array<int, INDEX_ID_MAX> &num_total,
699 std::array<int, INDEX_ID_MAX> &num_local,
700 std::array<int, INDEX_ID_MAX> &num_linked)
701 {
703 this->do_local_ids = do_local_ids;
704 this->do_linked_ids = do_linked_ids;
705 this->do_recursive = do_recursive;
706 this->num_total = &num_total;
707 this->num_local = &num_local;
708 this->num_linked = &num_linked;
709 }
710};
711
713{
714 if (data.filter_fn && !data.filter_fn(id)) {
715 return;
716 }
717 id->tag |= data.id_tag;
718 data.unused_ids.add(id);
719
720 const int id_code = BKE_idtype_idcode_to_index(GS(id->name));
721 (*data.num_total)[INDEX_ID_NULL]++;
722 (*data.num_total)[id_code]++;
723 if (ID_IS_LINKED(id)) {
724 (*data.num_linked)[INDEX_ID_NULL]++;
725 (*data.num_linked)[id_code]++;
726 }
727 else {
728 (*data.num_local)[INDEX_ID_NULL]++;
729 (*data.num_local)[id_code]++;
730 }
731}
732
733/* Returns `true` if given ID is detected as part of at least one dependency loop, false otherwise.
734 */
736{
737 /* We should never deal with embedded, not-in-main IDs here. */
738 BLI_assert((id->flag & ID_FLAG_EMBEDDED_DATA) == 0);
739
740 MainIDRelationsEntry *id_relations = static_cast<MainIDRelationsEntry *>(
741 BLI_ghash_lookup(data.bmain->relations->relations_from_pointers, id));
742
743 if ((id_relations->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) != 0) {
744 return false;
745 }
746 if ((id_relations->tags & MAINIDRELATIONS_ENTRY_TAGS_INPROGRESS) != 0) {
747 /* This ID has not yet been fully processed. If this condition is reached, it means this is a
748 * dependency loop case. */
749 return true;
750 }
751
752 if ((!data.do_linked_ids && ID_IS_LINKED(id)) || (!data.do_local_ids && !ID_IS_LINKED(id))) {
754 return false;
755 }
756
757 if (data.unused_ids.contains(id)) {
759 return false;
760 }
761
762 if ((id->flag & ID_FLAG_FAKEUSER) != 0) {
763 /* This ID is forcefully kept around, and therefore never unused, no need to check it further.
764 */
766 return false;
767 }
768
769 const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
770 if (id_type->flags & IDTYPE_FLAGS_NEVER_UNUSED) {
771 /* Some 'root' ID types are never unused (even though they may not have actual users), unless
772 * their actual user-count is set to 0. */
774 return false;
775 }
776
777 if (ELEM(GS(id->name), ID_IM)) {
778 /* Images which have a 'viewer' source (e.g. render results) should not be considered as
779 * orphaned/unused data. */
780 const Image *image = (Image *)id;
781 if (image->source == IMA_SRC_VIEWER) {
783 return false;
784 }
785 }
786
787 /* An ID user is 'valid' (i.e. may affect the 'used'/'not used' status of the ID it uses) if it
788 * does not match `ignored_usages`, and does match `required_usages`. */
789 const int ignored_usages = (IDWALK_CB_LOOPBACK | IDWALK_CB_EMBEDDED |
791 const int required_usages = (IDWALK_CB_USER | IDWALK_CB_USER_ONE);
792
793 /* This ID may be tagged as unused if none of its users are 'valid', as defined above.
794 *
795 * First recursively check all its valid users, if all of them can be tagged as
796 * unused, then we can tag this ID as such too. */
797 bool has_valid_from_users = false;
798 bool is_part_of_dependency_loop = false;
800 for (MainIDRelationsEntryItem *id_from_item = id_relations->from_ids; id_from_item != nullptr;
801 id_from_item = id_from_item->next)
802 {
803 if ((id_from_item->usage_flag & ignored_usages) != 0 ||
804 (id_from_item->usage_flag & required_usages) == 0)
805 {
806 continue;
807 }
808
809 ID *id_from = id_from_item->id_pointer.from;
810 if ((id_from->flag & ID_FLAG_EMBEDDED_DATA) != 0) {
811 /* Directly 'by-pass' to actual real ID owner. */
812 id_from = BKE_id_owner_get(id_from);
813 BLI_assert(id_from != nullptr);
814 }
815
816 if (lib_query_unused_ids_tag_recurse(id_from, data)) {
817 /* Dependency loop case, ignore the `id_from` tag value here (as it should not be considered
818 * as valid yet), and presume that this is a 'valid user' case for now. */
819 is_part_of_dependency_loop = true;
820 continue;
821 }
822 if (!data.unused_ids.contains(id_from)) {
823 has_valid_from_users = true;
824 break;
825 }
826 }
827 if (!has_valid_from_users && !is_part_of_dependency_loop) {
828 /* Tag the ID as unused, only in case it is not part of a dependency loop. */
830 }
831
832 /* This ID is not being processed anymore.
833 *
834 * However, we can only tag is as successfully processed if either it was detected as part of a
835 * valid usage hierarchy, or, if detected as unused, if it was not part of a dependency loop.
836 *
837 * Otherwise, this is an undecided state, it will be resolved at the entry point of this
838 * recursive process for the root id (see below in #BKE_lib_query_unused_ids_tag calling code).
839 */
840 id_relations->tags &= ~MAINIDRELATIONS_ENTRY_TAGS_INPROGRESS;
841 if (has_valid_from_users || !is_part_of_dependency_loop) {
843 }
844
845 return is_part_of_dependency_loop;
846}
847
849{
851
852 /* First loop, to only check for immediately unused IDs (those with 0 user count).
853 * NOTE: It also takes care of clearing given tag for used IDs. */
854 ID *id;
855 FOREACH_MAIN_ID_BEGIN (data.bmain, id) {
856 if ((!data.do_linked_ids && ID_IS_LINKED(id)) || (!data.do_local_ids && !ID_IS_LINKED(id))) {
857 id->tag &= ~data.id_tag;
858 }
859 else if (id->us == 0) {
861 }
862 else {
863 id->tag &= ~data.id_tag;
864 }
865 }
867
868 if (!data.do_recursive) {
869 return;
870 }
871 BLI_assert(data.bmain->relations != nullptr);
872
873 FOREACH_MAIN_ID_BEGIN (data.bmain, id) {
874 if (lib_query_unused_ids_tag_recurse(id, data)) {
875 /* This root processed ID is part of one or more dependency loops.
876 *
877 * If it was not tagged, and its matching relations entry is not marked as processed, it
878 * means that it's the first encountered entry point of an 'unused archipelago' (i.e. the
879 * entry point to a set of IDs with relationships to each other, but no 'valid usage'
880 * relations to the current Blender file (like being part of a scene, etc.).
881 *
882 * So the entry can be tagged as processed, and the ID tagged as unused. */
883 if (!data.unused_ids.contains(id)) {
884 MainIDRelationsEntry *id_relations = static_cast<MainIDRelationsEntry *>(
885 BLI_ghash_lookup(data.bmain->relations->relations_from_pointers, id));
886 if ((id_relations->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) == 0) {
889 }
890 }
891 }
892
893#ifndef NDEBUG
894 /* Relation entry for the root processed ID should always be marked as processed now. */
895 MainIDRelationsEntry *id_relations = static_cast<MainIDRelationsEntry *>(
896 BLI_ghash_lookup(data.bmain->relations->relations_from_pointers, id));
899#endif
900 }
902}
903
905{
906 std::array<int, INDEX_ID_MAX> num_dummy{0};
907 if (parameters.do_recursive) {
909 }
910
911 parameters.num_total.fill(0);
912 parameters.num_local.fill(0);
913 parameters.num_linked.fill(0);
914
915 /* The complex fiddling with the two calls, which data they each get, based on the `do_local_ids`
916 * and `do_linked_ids`, is here to reduce as much as possible the extra processing:
917 *
918 * If both local and linked options are enabled, a single call with all given parameters gives
919 * all required data about unused IDs.
920 *
921 * If both local and linked options are disabled, total amount is left at zero, and each local
922 * and linked amounts are computed separately.
923 *
924 * If local is disabled and linked is enabled, the first call will compute the amount of local
925 * IDs that would be unused if the local option was enabled. Therefore, only the local amount can
926 * be kept from this call. The second call will compute valid values for both linked, and total
927 * data.
928 *
929 * If local is enabled and linked is disabled, the first call will compute valid values for both
930 * local, and total data. The second call will compute the amount of linked IDs that would be
931 * unused if the linked option was enabled. Therefore, only the linked amount can be kept from
932 * this call.
933 */
934
935 UnusedIDsData data(bmain, 0, parameters);
936 data.do_local_ids = true;
937 if (!parameters.do_local_ids) {
938 data.num_total = &num_dummy;
939 }
940 if (!(parameters.do_local_ids && parameters.do_linked_ids)) {
941 data.num_linked = &num_dummy;
942 }
944
945 if (!(parameters.do_local_ids && parameters.do_linked_ids)) {
946 /* In case a second run is required, clear runtime data and update settings for linked data. */
947 data.reset(parameters.do_local_ids,
948 true,
949 parameters.do_recursive,
950 (!parameters.do_local_ids && parameters.do_linked_ids) ? parameters.num_total :
951 num_dummy,
952 num_dummy,
953 parameters.num_linked);
955 }
956
957 if (parameters.do_recursive) {
959 }
960}
961
963{
964 BLI_assert(tag != 0);
965
966 parameters.num_total.fill(0);
967 parameters.num_local.fill(0);
968 parameters.num_linked.fill(0);
969
970 UnusedIDsData data(bmain, tag, parameters);
971
972 if (parameters.do_recursive) {
974 }
976 if (parameters.do_recursive) {
978 }
979}
980
982{
983 ID *self_id = cb_data->self_id;
984 ID **id_p = cb_data->id_pointer;
985 const int cb_flag = cb_data->cb_flag;
986 bool *is_changed = static_cast<bool *>(cb_data->user_data);
987
988 if (*id_p) {
989 /* The infamous 'from' pointers (Key.from, ...).
990 * those are not actually ID usage, so we ignore them here. */
991 if (cb_flag & IDWALK_CB_LOOPBACK) {
992 return IDWALK_RET_NOP;
993 }
994
995 /* If checked id is used by an assumed used ID,
996 * then it is also used and not part of any linked archipelago. */
997 if (!(self_id->tag & ID_TAG_DOIT) && ((*id_p)->tag & ID_TAG_DOIT)) {
998 (*id_p)->tag &= ~ID_TAG_DOIT;
999 *is_changed = true;
1000 }
1001 }
1002
1003 return IDWALK_RET_NOP;
1004}
1005
1006void BKE_library_unused_linked_data_set_tag(Main *bmain, const bool do_init_tag)
1007{
1008 ID *id;
1009
1010 if (do_init_tag) {
1011 FOREACH_MAIN_ID_BEGIN (bmain, id) {
1012 if (id->lib && (id->tag & ID_TAG_INDIRECT) != 0) {
1013 id->tag |= ID_TAG_DOIT;
1014 }
1015 else {
1016 id->tag &= ~ID_TAG_DOIT;
1017 }
1018 }
1020 }
1021
1022 for (bool do_loop = true; do_loop;) {
1023 do_loop = false;
1024 FOREACH_MAIN_ID_BEGIN (bmain, id) {
1025 /* We only want to check that ID if it is currently known as used... */
1026 if ((id->tag & ID_TAG_DOIT) == 0) {
1029 }
1030 }
1032 }
1033}
1034
1036{
1037 ListBase *lb_array[INDEX_ID_MAX];
1038
1039 bool do_loop = true;
1040 while (do_loop) {
1041 int i = set_listbasepointers(bmain, lb_array);
1042 do_loop = false;
1043
1044 while (i--) {
1045 LISTBASE_FOREACH (ID *, id, lb_array[i]) {
1046 if (!ID_IS_LINKED(id) || id->tag & ID_TAG_DOIT) {
1047 /* Local or non-indirectly-used ID (so far), no need to check it further. */
1048 continue;
1049 }
1052 }
1053 }
1054 }
1055}
void BKE_animdata_foreach_id(AnimData *adt, LibraryForeachIDData *data)
Definition anim_data.cc:346
AnimData * BKE_animdata_from_id(const ID *id)
Definition anim_data.cc:89
void IDP_foreach_property(IDProperty *id_property_root, int type_filter, blender::FunctionRef< void(IDProperty *id_property)> callback)
@ IDTYPE_FLAGS_NEVER_UNUSED
Definition BKE_idtype.hh:64
const IDTypeInfo * BKE_idtype_get_info_from_id(const ID *id)
Definition idtype.cc:150
uint64_t BKE_idtype_idcode_to_idfilter(short idcode)
Definition idtype.cc:369
int BKE_idtype_idcode_to_index(short idcode)
Definition idtype.cc:232
void id_us_plus(ID *id)
Definition lib_id.cc:351
ID * BKE_id_owner_get(ID *id, const bool debug_relationship_assert=true)
Definition lib_id.cc:2444
void id_us_ensure_real(ID *id)
Definition lib_id.cc:306
void id_us_min(ID *id)
Definition lib_id.cc:359
@ IDWALK_RET_STOP_RECURSION
@ IDWALK_RET_STOP_ITER
@ IDWALK_RET_NOP
@ IDWALK_CB_LOOPBACK
@ IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE
@ IDWALK_CB_NEVER_SELF
@ IDWALK_CB_USER_ONE
@ IDWALK_CB_USER
@ IDWALK_CB_INTERNAL
@ IDWALK_CB_EMBEDDED_NOT_OWNING
@ IDWALK_CB_EMBEDDED
@ IDWALK_CB_DIRECT_WEAK_LINK
@ IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE
@ IDWALK_CB_INDIRECT_USAGE
@ IDWALK_DO_DEPRECATED_POINTERS
@ IDWALK_RECURSE
@ IDWALK_INCLUDE_UI
@ IDWALK_IGNORE_MISSING_OWNER_ID
@ IDWALK_DO_LIBRARY_POINTER
@ IDWALK_READONLY
@ IDWALK_DO_INTERNAL_RUNTIME_POINTERS
@ IDWALK_NO_ORIG_POINTERS_ACCESS
@ IDWALK_IGNORE_EMBEDDED_ID
#define BKE_LIB_FOREACHID_PROCESS_ID(data_, id_, cb_flag_)
#define FOREACH_MAIN_ID_END
Definition BKE_main.hh:500
@ MAINIDRELATIONS_INCLUDE_UI
Definition BKE_main.hh:119
@ MAINIDRELATIONS_ENTRY_TAGS_PROCESSED
Definition BKE_main.hh:90
@ MAINIDRELATIONS_ENTRY_TAGS_INPROGRESS
Definition BKE_main.hh:101
int set_listbasepointers(Main *bmain, ListBase *lb[])
Definition main.cc:929
void BKE_main_relations_tag_set(Main *bmain, eMainIDRelationsEntryTags tag, bool value)
Definition main.cc:592
void BKE_main_relations_create(Main *bmain, short flag)
Definition main.cc:544
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id)
Definition BKE_main.hh:494
void BKE_main_relations_free(Main *bmain)
Definition main.cc:580
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
struct GSet GSet
Definition BLI_ghash.h:341
unsigned int BLI_ghashutil_ptrhash(const void *key)
GSet * BLI_gset_new(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:944
bool BLI_ghashutil_ptrcmp(const void *a, const void *b)
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:731
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition BLI_ghash.c:1034
bool BLI_gset_add(GSet *gs, void *key)
Definition BLI_ghash.c:966
#define LISTBASE_FOREACH(type, var, list)
#define ELEM(...)
#define FILTER_ID_ALL
Definition DNA_ID.h:1206
#define ID_IS_OVERRIDE_LIBRARY_REAL(_id)
Definition DNA_ID.h:676
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:654
@ ID_FLAG_FAKEUSER
Definition DNA_ID.h:720
@ ID_FLAG_EMBEDDED_DATA
Definition DNA_ID.h:725
@ ID_TAG_EXTRAUSER
Definition DNA_ID.h:824
@ ID_TAG_NO_USER_REFCOUNT
Definition DNA_ID.h:985
@ ID_TAG_INDIRECT
Definition DNA_ID.h:794
@ ID_TAG_DOIT
Definition DNA_ID.h:1003
@ ID_TAG_EXTRAUSER_SET
Definition DNA_ID.h:830
#define INDEX_ID_MAX
Definition DNA_ID.h:1328
@ INDEX_ID_NULL
Definition DNA_ID.h:1325
@ ID_IM
@ ID_SCR
@ IDP_ID
@ IDP_FLAG_OVERRIDABLE_LIBRARY
@ IDP_TYPE_FILTER_ID
@ IMA_SRC_VIEWER
void clear()
Definition BLI_set.hh:532
#define printf
DEGForeachIDComponentCallback callback
#define GS(x)
Definition iris.cc:202
void BKE_lib_query_foreachid_process(LibraryForeachIDData *data, ID **id_pp, int cb_flag)
Definition lib_query.cc:71
void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *r_is_used_local, bool *r_is_used_linked)
Definition lib_query.cc:618
void BKE_library_unused_linked_data_set_tag(Main *bmain, const bool do_init_tag)
bool BKE_library_ID_is_indirectly_used(Main *bmain, void *idv)
Definition lib_query.cc:613
void BKE_library_foreach_ID_embedded(LibraryForeachIDData *data, ID **id_pp)
Definition lib_query.cc:163
static bool library_ID_is_used(Main *bmain, void *idv, const bool check_linked)
Definition lib_query.cc:575
int BKE_lib_query_foreachid_process_flags_get(const LibraryForeachIDData *data)
Definition lib_query.cc:120
Main * BKE_lib_query_foreachid_process_main_get(const LibraryForeachIDData *data)
Definition lib_query.cc:125
void BKE_library_foreach_subdata_id(Main *bmain, ID *owner_id, ID *self_id, blender::FunctionRef< void(LibraryForeachIDData *data)> subdata_foreach_id, blender::FunctionRef< LibraryIDLinkCallback > callback, void *user_data, const int flag)
Definition lib_query.cc:436
#define CALLBACK_INVOKE(check_id_super, cb_flag)
void BKE_lib_query_unused_ids_amounts(Main *bmain, LibQueryUnusedIDsData &parameters)
Definition lib_query.cc:904
static bool lib_query_unused_ids_tag_recurse(ID *id, UnusedIDsData &data)
Definition lib_query.cc:735
void BKE_library_foreach_ID_link(Main *bmain, ID *id, blender::FunctionRef< LibraryIDLinkCallback > callback, void *user_data, int flag)
Definition lib_query.cc:416
int BKE_library_ID_use_ID(ID *id_user, ID *id_used)
Definition lib_query.cc:560
static void lib_query_unused_ids_tag_id(ID *id, UnusedIDsData &data)
Definition lib_query.cc:712
static void library_foreach_ID_data_cleanup(LibraryForeachIDData *data)
Definition lib_query.cc:199
void BKE_lib_query_unused_ids_tag(Main *bmain, const int tag, LibQueryUnusedIDsData &parameters)
Definition lib_query.cc:962
bool BKE_library_id_can_use_idtype(ID *owner_id, const short id_type_used)
Definition lib_query.cc:502
int BKE_lib_query_foreachid_process_callback_flag_override(LibraryForeachIDData *data, const int cb_flag, const bool do_replace)
Definition lib_query.cc:130
#define CALLBACK_INVOKE_ID(check_id, cb_flag)
void BKE_lib_query_idpropertiesForeachIDLink_callback(IDProperty *id_prop, void *user_data)
Definition lib_query.cc:152
bool BKE_lib_query_foreachid_iter_stop(const LibraryForeachIDData *data)
Definition lib_query.cc:66
static int foreach_libblock_id_users_callback(LibraryIDLinkCallbackData *cb_data)
Definition lib_query.cc:521
static bool library_foreach_ID_link(Main *bmain, ID *owner_id, ID *id, blender::FunctionRef< LibraryIDLinkCallback > callback, void *user_data, int flag, LibraryForeachIDData *inherit_data)
Definition lib_query.cc:208
void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cb_flag)
Definition lib_query.cc:425
static void lib_query_unused_ids_tag(UnusedIDsData &data)
Definition lib_query.cc:848
void BKE_library_indirectly_used_data_tag_clear(Main *bmain)
@ IDWALK_STOP
Definition lib_query.cc:30
uint64_t BKE_library_id_can_use_filter_id(const ID *owner_id, const bool include_ui, const IDTypeInfo *owner_id_type)
Definition lib_query.cc:461
bool BKE_library_ID_is_locally_used(Main *bmain, void *idv)
Definition lib_query.cc:608
static int foreach_libblock_used_linked_data_tag_clear_cb(LibraryIDLinkCallbackData *cb_data)
Definition lib_query.cc:981
double parameters[NUM_PARAMETERS]
bNodeTree * node_tree_from_id(ID *id)
Definition node.cc:3732
unsigned __int64 uint64_t
Definition stdint.h:90
void * pointer
Definition DNA_ID.h:145
short flag
Definition DNA_ID.h:161
IDPropertyData data
Definition DNA_ID.h:168
char type
Definition DNA_ID.h:154
uint64_t dependencies_id_types
IDTypeForeachIDFunction foreach_id
uint32_t flags
int count_indirect
Definition lib_query.cc:518
Definition DNA_ID.h:413
int tag
Definition DNA_ID.h:434
IDProperty * properties
Definition DNA_ID.h:456
short flag
Definition DNA_ID.h:430
void * next
Definition DNA_ID.h:416
char name[66]
Definition DNA_ID.h:425
blender::FunctionRef< LibraryIDLinkCallback > callback
Definition lib_query.cc:55
BLI_LINKSTACK_DECLARE(ids_todo, ID *)
void * first
MainIDRelationsEntryItem * from_ids
Definition BKE_main.hh:67
MainIDRelationsEntryItem * to_ids
Definition BKE_main.hh:69
GHash * relations_from_pointers
Definition BKE_main.hh:108
MainIDRelations * relations
Definition BKE_main.hh:260
blender::FunctionRef< bool(ID *id)> filter_fn
Definition lib_query.cc:674
std::array< int, INDEX_ID_MAX > * num_total
Definition lib_query.cc:676
const int id_tag
Definition lib_query.cc:668
blender::Set< ID * > unused_ids
Definition lib_query.cc:680
void reset(const bool do_local_ids, const bool do_linked_ids, const bool do_recursive, std::array< int, INDEX_ID_MAX > &num_total, std::array< int, INDEX_ID_MAX > &num_local, std::array< int, INDEX_ID_MAX > &num_linked)
Definition lib_query.cc:695
UnusedIDsData(Main *bmain, const int id_tag, LibQueryUnusedIDsData &parameters)
Definition lib_query.cc:682
std::array< int, INDEX_ID_MAX > * num_linked
Definition lib_query.cc:678
std::array< int, INDEX_ID_MAX > * num_local
Definition lib_query.cc:677
uint8_t flag
Definition wm_window.cc:138