From 6426de4489fb21a79e4c18f2c3fbedefad3a4a4c Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 24 May 2024 17:39:09 +0200 Subject: [PATCH] Core: IDManagement: Refactor how 'never unused' IDs are defined. A few ID types are considered as 'never unused' in Blender (UI related ones, the Libraries and the Scenes). Local IDs of this type are always considered as used, even if no other ID links to them. This was previously fairly weekly defined and implemented (mainly in the writefile code and the 'tag unused' libquery functions). This commit formalize this characteristic of ID types by adding a new `IDTYPE_FLAGS_NEVER_UNUSED` flag, and using this in the few places in the code that handle unused IDs. --- source/blender/blenkernel/BKE_idtype.hh | 14 ++++++++++++++ source/blender/blenkernel/intern/lib_query.cc | 3 ++- source/blender/blenkernel/intern/library.cc | 3 ++- source/blender/blenkernel/intern/scene.cc | 2 +- source/blender/blenkernel/intern/screen.cc | 2 +- source/blender/blenkernel/intern/workspace.cc | 2 +- source/blender/blenloader/intern/writefile.cc | 7 ++++--- .../space_outliner/tree/tree_display_orphaned.cc | 10 ++++++++++ source/blender/windowmanager/intern/wm.cc | 2 +- 9 files changed, 36 insertions(+), 9 deletions(-) diff --git a/source/blender/blenkernel/BKE_idtype.hh b/source/blender/blenkernel/BKE_idtype.hh index 4147204d24c..0eb322f9df9 100644 --- a/source/blender/blenkernel/BKE_idtype.hh +++ b/source/blender/blenkernel/BKE_idtype.hh @@ -48,6 +48,20 @@ enum { * data-blocks. */ IDTYPE_FLAGS_NO_MEMFILE_UNDO = 1 << 5, + /** + * Indicates that the given IDType is considered as unused. + * + * This is used for some 'root' ID types which typically do not have any actual user (WM. + * Scene...). It prevents e.g. their deletion through the 'Purge' operation. + * + * \note This applies to local IDs. Linked data should essentially ignore this flag. In practice, + * currently, only the Scene ID can be linked among the `never unused` types. + * + * \note The implementation of the expected behaviors related to this characteristic is somewhat + * fragile and inconsistent currently. In most case though, code is expected to ensure that such + * IDs have at least an 'extra user' (#LIB_TAG_EXTRAUSER). + */ + IDTYPE_FLAGS_NEVER_UNUSED = 1 << 6, }; struct IDCacheKey { diff --git a/source/blender/blenkernel/intern/lib_query.cc b/source/blender/blenkernel/intern/lib_query.cc index bfb0995c149..f79e231a009 100644 --- a/source/blender/blenkernel/intern/lib_query.cc +++ b/source/blender/blenkernel/intern/lib_query.cc @@ -753,7 +753,8 @@ static bool lib_query_unused_ids_tag_recurse(ID *id, UnusedIDsData &data) return false; } - if (ELEM(GS(id->name), ID_WM, ID_WS, ID_SCE, ID_SCR, ID_LI)) { + const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id); + if (id_type->flags & IDTYPE_FLAGS_NEVER_UNUSED) { /* Some 'root' ID types are never unused (even though they may not have actual users), unless * their actual user-count is set to 0. */ id_relations->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED; diff --git a/source/blender/blenkernel/intern/library.cc b/source/blender/blenkernel/intern/library.cc index 5a631c937ba..b1150d91f49 100644 --- a/source/blender/blenkernel/intern/library.cc +++ b/source/blender/blenkernel/intern/library.cc @@ -86,7 +86,8 @@ IDTypeInfo IDType_ID_LI = { /*name*/ "Library", /*name_plural*/ N_("libraries"), /*translation_context*/ BLT_I18NCONTEXT_ID_LIBRARY, - /*flags*/ IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_LIBLINKING | IDTYPE_FLAGS_NO_ANIMDATA, + /*flags*/ IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_LIBLINKING | IDTYPE_FLAGS_NO_ANIMDATA | + IDTYPE_FLAGS_NEVER_UNUSED, /*asset_type_info*/ nullptr, /*init_data*/ nullptr, diff --git a/source/blender/blenkernel/intern/scene.cc b/source/blender/blenkernel/intern/scene.cc index d7c383bae56..8323248e7bc 100644 --- a/source/blender/blenkernel/intern/scene.cc +++ b/source/blender/blenkernel/intern/scene.cc @@ -1594,7 +1594,7 @@ constexpr IDTypeInfo get_type_info() info.name = "Scene"; info.name_plural = "scenes"; info.translation_context = BLT_I18NCONTEXT_ID_SCENE; - info.flags = 0; + info.flags = IDTYPE_FLAGS_NEVER_UNUSED; info.asset_type_info = nullptr; info.init_data = scene_init_data; diff --git a/source/blender/blenkernel/intern/screen.cc b/source/blender/blenkernel/intern/screen.cc index 7efc51aa979..f192c7a60bb 100644 --- a/source/blender/blenkernel/intern/screen.cc +++ b/source/blender/blenkernel/intern/screen.cc @@ -168,7 +168,7 @@ IDTypeInfo IDType_ID_SCR = { /*name_plural*/ N_("screens"), /*translation_context*/ BLT_I18NCONTEXT_ID_SCREEN, /*flags*/ IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_ONLY_APPEND | IDTYPE_FLAGS_NO_ANIMDATA | - IDTYPE_FLAGS_NO_MEMFILE_UNDO, + IDTYPE_FLAGS_NO_MEMFILE_UNDO | IDTYPE_FLAGS_NEVER_UNUSED, /*asset_type_info*/ nullptr, /*init_data*/ nullptr, diff --git a/source/blender/blenkernel/intern/workspace.cc b/source/blender/blenkernel/intern/workspace.cc index ea4d07825c8..26a154159e8 100644 --- a/source/blender/blenkernel/intern/workspace.cc +++ b/source/blender/blenkernel/intern/workspace.cc @@ -180,7 +180,7 @@ IDTypeInfo IDType_ID_WS = { /*name_plural*/ N_("workspaces"), /*translation_context*/ BLT_I18NCONTEXT_ID_WORKSPACE, /*flags*/ IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_ONLY_APPEND | IDTYPE_FLAGS_NO_ANIMDATA | - IDTYPE_FLAGS_NO_MEMFILE_UNDO, + IDTYPE_FLAGS_NO_MEMFILE_UNDO | IDTYPE_FLAGS_NEVER_UNUSED, /*asset_type_info*/ nullptr, /*init_data*/ workspace_init_data, diff --git a/source/blender/blenloader/intern/writefile.cc b/source/blender/blenloader/intern/writefile.cc index 4d53e2d3553..1bd25a1f56d 100644 --- a/source/blender/blenloader/intern/writefile.cc +++ b/source/blender/blenloader/intern/writefile.cc @@ -1311,10 +1311,11 @@ static bool write_file_handle(Main *mainvar, /* We only write unused IDs in undo case. */ if (!wd->use_memfile) { - /* NOTE: All Scenes, WindowManagers and WorkSpaces should always be written to disk, so - * their user-count should never be zero currently. */ + /* NOTE: All 'never unused' local IDs (Scenes, WindowManagers, ...) should always be + * written to disk, so their user-count should never be zero currently. Note that + * libraries have already been skipped above, as they need a specific handling. */ if (id->us == 0) { - BLI_assert(!ELEM(GS(id->name), ID_SCE, ID_WM, ID_WS)); + BLI_assert((id_type->flags & IDTYPE_FLAGS_NEVER_UNUSED) == 0); continue; } diff --git a/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc b/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc index 4715918196b..0f737172d59 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc @@ -13,6 +13,7 @@ #include "BLI_listbase_wrapper.hh" #include "BLI_utildefines.h" +#include "BKE_idtype.hh" #include "BKE_main.hh" #include "../outliner_intern.hh" @@ -75,6 +76,15 @@ ListBase TreeDisplayIDOrphans::build_tree(const TreeSourceData &source_data) bool TreeDisplayIDOrphans::datablock_has_orphans(ListBase &lb) const { + if (BLI_listbase_is_empty(&lb)) { + return false; + } + const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(static_cast(lb.first)); + if (id_type->flags & IDTYPE_FLAGS_NEVER_UNUSED) { + /* These ID types are never unused. */ + return false; + } + for (ID *id : List(lb)) { if (ID_REFCOUNTING_USERS(id) <= 0) { return true; diff --git a/source/blender/windowmanager/intern/wm.cc b/source/blender/windowmanager/intern/wm.cc index ca987249351..df3a645a78a 100644 --- a/source/blender/windowmanager/intern/wm.cc +++ b/source/blender/windowmanager/intern/wm.cc @@ -254,7 +254,7 @@ IDTypeInfo IDType_ID_WM = { /*name_plural*/ N_("window_managers"), /*translation_context*/ BLT_I18NCONTEXT_ID_WINDOWMANAGER, /*flags*/ IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_LIBLINKING | IDTYPE_FLAGS_NO_ANIMDATA | - IDTYPE_FLAGS_NO_MEMFILE_UNDO, + IDTYPE_FLAGS_NO_MEMFILE_UNDO | IDTYPE_FLAGS_NEVER_UNUSED, /*asset_type_info*/ nullptr, /*init_data*/ nullptr,