Commit: 133dde41bb5bbbbd083b12723f1ec9053764348a Author: Bastien Montagne Date: Wed Nov 30 11:13:37 2022 +0100 Branches: master https://developer.blender.org/rB133dde41bb5bbbbd083b12723f1ec9053764348a
Improve handling of (in)direclty linked status for linked IDs. This commit essentially ensures before writing .blend file that only actualy locally used linked IDs are tagged as `LIB_TAG_EXTERN` (and therefore get a reference stored in the .blend file). Previously, a linked ID tagged as directly linked would never get back to the indirectly linked status. Consequence was a lot of 'needless' references to linked data in .blend files. This commit also introduces a new flag for lib_query ID usage types, `IDWALK_CB_DIRECT_WEAK_LINK`, used currently for base's Object pointer, and for LayerCollection's Collection pointer. NOTE: A side-effect of this patch is that even IDs explicitely linked by the user won't be kept anymore when writing files, i.e. they will not be there anymore after a file reload, if they are not actually used. Overhead of new process is below 0.1% in whole file saving process in a Heist production file e.g. Reviewed By: brecht Differential Revision: https://developer.blender.org/D16605 =================================================================== M source/blender/blenkernel/BKE_lib_query.h M source/blender/blenkernel/intern/scene.cc M source/blender/blenloader/intern/writefile.cc M tests/python/bl_blendfile_liblink.py =================================================================== diff --git a/source/blender/blenkernel/BKE_lib_query.h b/source/blender/blenkernel/BKE_lib_query.h index a70d128cd95..69e8f58178a 100644 --- a/source/blender/blenkernel/BKE_lib_query.h +++ b/source/blender/blenkernel/BKE_lib_query.h @@ -38,44 +38,53 @@ enum { * Indicates whether this is direct (i.e. by local data) or indirect (i.e. by linked data) usage. */ IDWALK_CB_INDIRECT_USAGE = (1 << 2), + /** + * Indicates that this is a direct weak link usage, i.e. if the user is a local ID, and is using + * (pointing to) a linked ID, that usage does not make the linked ID directly linked. + * + * E.g. usages of linked collections or objects by ViewLayerCollections or Bases in scenes. + * + * See also #LIB_INDIRECT_WEAK_LINK in DNA_ID.h + */ + IDWALK_CB_DIRECT_WEAK_LINK = (1 << 3), /** * That ID is used as mere sub-data by its owner (only case currently: those root nodetrees in * materials etc., and the Scene's master collections). * This means callback shall not *do* anything, only use this as informative data if it needs it. */ - IDWALK_CB_EMBEDDED = (1 << 3), + IDWALK_CB_EMBEDDED = (1 << 4), /** * That ID is not really used by its owner, it's just an internal hint/helper. * This marks the 'from' pointers issue, like Key->from. * How to handle that kind of cases totally depends on what caller code is doing... */ - IDWALK_CB_LOOPBACK = (1 << 4), + IDWALK_CB_LOOPBACK = (1 << 5), /** That ID is used as library override's reference by its owner. */ - IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE = (1 << 5), + IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE = (1 << 6), /** That ID pointer is not overridable. */ - IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE = (1 << 6), + IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE = (1 << 7), /** * Indicates that this is an internal runtime ID pointer, like e.g. `ID.newid` or `ID.original`. * \note Those should be ignored in most cases, and won't be processed/generated anyway unless * `IDWALK_DO_INTERNAL_RUNTIME_POINTERS` option is enabled. */ - IDWALK_CB_INTERNAL = (1 << 7), + IDWALK_CB_INTERNAL = (1 << 8), /** * This ID usage is fully refcounted. * Callback is responsible to deal accordingly with #ID.us if needed. */ - IDWALK_CB_USER = (1 << 8), + IDWALK_CB_USER = (1 << 9), /** * This ID usage is not refcounted, but at least one user should be generated by it (to avoid * e.g. losing the used ID on save/reload). * Callback is responsible to deal accordingly with #ID.us if needed. */ - IDWALK_CB_USER_ONE = (1 << 9), + IDWALK_CB_USER_ONE = (1 << 10), }; enum { diff --git a/source/blender/blenkernel/intern/scene.cc b/source/blender/blenkernel/intern/scene.cc index c921cf603de..830122474e1 100644 --- a/source/blender/blenkernel/intern/scene.cc +++ b/source/blender/blenkernel/intern/scene.cc @@ -761,7 +761,8 @@ static void scene_foreach_layer_collection(LibraryForeachIDData *data, ListBase (lc->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ? IDWALK_CB_EMBEDDED : IDWALK_CB_NOP; - BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, lc->collection, cb_flag); + BKE_LIB_FOREACHID_PROCESS_IDSUPER( + data, lc->collection, cb_flag | IDWALK_CB_DIRECT_WEAK_LINK); scene_foreach_layer_collection(data, &lc->layer_collections); } } @@ -834,8 +835,11 @@ static void scene_foreach_id(ID *id, LibraryForeachIDData *data) BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, view_layer->mat_override, IDWALK_CB_USER); BKE_view_layer_synced_ensure(scene, view_layer); LISTBASE_FOREACH (Base *, base, BKE_view_layer_object_bases_get(view_layer)) { - BKE_LIB_FOREACHID_PROCESS_IDSUPER( - data, base->object, IDWALK_CB_NOP | IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE); + BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, + base->object, + IDWALK_CB_NOP | + IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE | + IDWALK_CB_DIRECT_WEAK_LINK); } BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( diff --git a/source/blender/blenloader/intern/writefile.cc b/source/blender/blenloader/intern/writefile.cc index 6e48b65eb25..3a776a6c7ba 100644 --- a/source/blender/blenloader/intern/writefile.cc +++ b/source/blender/blenloader/intern/writefile.cc @@ -102,6 +102,7 @@ #include "BKE_layer.h" #include "BKE_lib_id.h" #include "BKE_lib_override.h" +#include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_node.h" #include "BKE_packedFile.h" @@ -1083,6 +1084,30 @@ static void write_thumb(WriteData *wd, const BlendThumbnail *thumb) /** \name File Writing (Private) * \{ */ +/* Helper callback for checking linked IDs used by given ID (assumed local), to ensure directly + * linked data is tagged accordingly. */ +static int write_id_direct_linked_data_process_cb(LibraryIDLinkCallbackData *cb_data) +{ + ID *id_self = cb_data->id_self; + ID *id = *cb_data->id_pointer; + const int cb_flag = cb_data->cb_flag; + + if (id == nullptr || !ID_IS_LINKED(id)) { + return IDWALK_RET_NOP; + } + BLI_assert(!ID_IS_LINKED(id_self)); + BLI_assert((cb_flag & IDWALK_CB_INDIRECT_USAGE) == 0); + + if (cb_flag & IDWALK_CB_DIRECT_WEAK_LINK) { + id_lib_indirect_weak_link(id); + } + else { + id_lib_extern(id); + } + + return IDWALK_RET_NOP; +} + /* if MemFile * there's filesave to memory */ static bool write_file_handle(Main *mainvar, WriteWrap *ww, @@ -1097,11 +1122,24 @@ static bool write_file_handle(Main *mainvar, char buf[16]; WriteData *wd; - blo_split_main(&mainlist, mainvar); - wd = mywrite_begin(ww, compare, current); BlendWriter writer = {wd}; + /* Clear 'directly linked' flag for all linked data, these are not necessarily valid/up-to-date + * info, they will be re-generated while write code is processing local IDs below. */ + if (!wd->use_memfile) { + ID *id_iter; + FOREACH_MAIN_ID_BEGIN (mainvar, id_iter) { + if (ID_IS_LINKED(id_iter)) { + id_iter->tag |= LIB_TAG_INDIRECT; + id_iter->tag &= ~LIB_TAG_EXTERN; + } + } + FOREACH_MAIN_ID_END; + } + + blo_split_main(&mainlist, mainvar); + BLI_snprintf(buf, sizeof(buf), "BLENDER%c%c%.3d", @@ -1169,6 +1207,12 @@ static bool write_file_handle(Main *mainvar, const bool do_override = !ELEM(override_storage, nullptr, bmain) && ID_IS_OVERRIDE_LIBRARY_REAL(id); + /* If not writing undo data, properly set directly linked IDs as `LIB_TAG_EXTERN`. */ + if (!wd->use_memfile) { + BKE_library_foreach_ID_link( + bmain, id, write_id_direct_linked_data_process_cb, nullptr, IDWALK_READONLY); + } + if (do_override) { BKE_lib_override_library_operations_store_start(bmain, override_storage, id); } diff --git a/tests/python/bl_blendfile_liblink.py b/tests/python/bl_blendfile_liblink.py index c0ca18e1b1e..f3c2a3c9e17 100644 --- a/tests/python/bl_blendfile_liblink.py +++ b/tests/python/bl_blendfile_liblink.py @@ -247,7 +247,7 @@ class TestBlendLibLinkIndirect(TestBlendLibLinkHelper): assert material.users == 2 # Currently linked data which has no more local user never gets reset to indirectly linked status. - # ~ assert material.is_library_indirect == True + assert material.is_library_indirect == True bpy.ops.wm.open_mainfile(filepath=output_work_path, load_ui=False) @@ -264,7 +264,7 @@ class TestBlendLibLinkIndirect(TestBlendLibLinkHelper): assert material.users == 2 # Fake user is not cleared when linking. # Currently even re-reading the .blend file will not properly reset tag for indirectly linked data, # if their reference was written in the .blend file. - # ~ assert material.is_library_indirect == True + assert material.is_library_indirect == True assert mesh.library is not None assert mesh.use_fake_user is False _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs