Fix #121733: Linked masks/moviclips/images used by editors get lost on file reload.

This was a consequence of the work done in #106321, where this specific
'active in UI' case was not identified and properly handled.

Now, consider most ID usages from UI (editors) as 'weak links', i.e.
keep a reference to these IDs even if they are only indirectly used.

Note that missing weak links will not create placeholders if the source
data is not found in the library anymore on load. they are just silently
dropped.

Pull Request: https://projects.blender.org/blender/blender/pulls/122207
This commit is contained in:
Bastien Montagne
2024-05-24 13:28:34 +02:00
committed by Gitea
parent 446a653cb7
commit 435b6743fd
15 changed files with 48 additions and 31 deletions

View File

@@ -46,6 +46,9 @@ enum {
*
* E.g. usages of linked collections or objects by ViewLayerCollections or Bases in scenes.
*
* Also used for most Editors ID usages (active node tree in the Node editor, shown image in the
* Image editor, and so on).
*
* See also #LIB_INDIRECT_WEAK_LINK in DNA_ID.h
*/
IDWALK_CB_DIRECT_WEAK_LINK = (1 << 3),

View File

@@ -128,7 +128,7 @@ void BKE_viewer_path_foreach_id(LibraryForeachIDData *data, ViewerPath *viewer_p
switch (ViewerPathElemType(elem->type)) {
case VIEWER_PATH_ELEM_TYPE_ID: {
auto *typed_elem = reinterpret_cast<IDViewerPathElem *>(elem);
BKE_LIB_FOREACHID_PROCESS_ID(data, typed_elem->id, IDWALK_CB_NOP);
BKE_LIB_FOREACHID_PROCESS_ID(data, typed_elem->id, IDWALK_CB_DIRECT_WEAK_LINK);
break;
}
case VIEWER_PATH_ELEM_TYPE_MODIFIER:

View File

@@ -1348,8 +1348,11 @@ static bool write_file_handle(Main *mainvar,
/* 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);
BKE_library_foreach_ID_link(bmain,
id,
write_id_direct_linked_data_process_cb,
nullptr,
IDWALK_READONLY | IDWALK_INCLUDE_UI);
}
if (do_override) {

View File

@@ -821,11 +821,11 @@ static void action_foreach_id(SpaceLink *space_link, LibraryForeachIDData *data)
const int data_flags = BKE_lib_query_foreachid_process_flags_get(data);
const bool is_readonly = (data_flags & IDWALK_READONLY) != 0;
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sact->action, IDWALK_CB_NOP);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sact->action, IDWALK_CB_DIRECT_WEAK_LINK);
/* NOTE: Could be deduplicated with the #bDopeSheet handling of #SpaceNla and #SpaceGraph. */
BKE_LIB_FOREACHID_PROCESS_ID(data, sact->ads.source, IDWALK_CB_NOP);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sact->ads.filter_grp, IDWALK_CB_NOP);
BKE_LIB_FOREACHID_PROCESS_ID(data, sact->ads.source, IDWALK_CB_DIRECT_WEAK_LINK);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sact->ads.filter_grp, IDWALK_CB_DIRECT_WEAK_LINK);
if (!is_readonly) {
/* Force recalc of list of channels, potentially updating the active action while we're

View File

@@ -915,7 +915,7 @@ static void buttons_foreach_id(SpaceLink *space_link, LibraryForeachIDData *data
const int data_flags = BKE_lib_query_foreachid_process_flags_get(data);
const bool is_readonly = (data_flags & IDWALK_READONLY) != 0;
BKE_LIB_FOREACHID_PROCESS_ID(data, sbuts->pinid, IDWALK_CB_NOP);
BKE_LIB_FOREACHID_PROCESS_ID(data, sbuts->pinid, IDWALK_CB_DIRECT_WEAK_LINK);
if (!is_readonly) {
if (sbuts->pinid == nullptr) {
sbuts->flag &= ~SB_PIN_CONTEXT;
@@ -927,7 +927,7 @@ static void buttons_foreach_id(SpaceLink *space_link, LibraryForeachIDData *data
if (sbuts->texuser) {
ButsContextTexture *ct = static_cast<ButsContextTexture *>(sbuts->texuser);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, ct->texture, IDWALK_CB_NOP);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, ct->texture, IDWALK_CB_DIRECT_WEAK_LINK);
if (!is_readonly) {
BLI_freelistN(&ct->users);

View File

@@ -1171,8 +1171,10 @@ static void clip_foreach_id(SpaceLink *space_link, LibraryForeachIDData *data)
const int data_flags = BKE_lib_query_foreachid_process_flags_get(data);
const bool is_readonly = (data_flags & IDWALK_READONLY) != 0;
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sclip->clip, IDWALK_CB_USER_ONE);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sclip->mask_info.mask, IDWALK_CB_USER_ONE);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(
data, sclip->clip, IDWALK_CB_USER_ONE | IDWALK_CB_DIRECT_WEAK_LINK);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(
data, sclip->mask_info.mask, IDWALK_CB_USER_ONE | IDWALK_CB_DIRECT_WEAK_LINK);
if (!is_readonly) {
sclip->scopes.ok = 0;

View File

@@ -838,8 +838,8 @@ static void graph_foreach_id(SpaceLink *space_link, LibraryForeachIDData *data)
return;
}
BKE_LIB_FOREACHID_PROCESS_ID(data, sgraph->ads->source, IDWALK_CB_NOP);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sgraph->ads->filter_grp, IDWALK_CB_NOP);
BKE_LIB_FOREACHID_PROCESS_ID(data, sgraph->ads->source, IDWALK_CB_DIRECT_WEAK_LINK);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sgraph->ads->filter_grp, IDWALK_CB_DIRECT_WEAK_LINK);
if (!is_readonly) {
/* Force recalc of list of channels (i.e. including calculating F-Curve colors) to

View File

@@ -1034,10 +1034,12 @@ static void image_foreach_id(SpaceLink *space_link, LibraryForeachIDData *data)
const int data_flags = BKE_lib_query_foreachid_process_flags_get(data);
const bool is_readonly = (data_flags & IDWALK_READONLY) != 0;
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, simg->image, IDWALK_CB_USER_ONE);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, simg->iuser.scene, IDWALK_CB_NOP);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, simg->mask_info.mask, IDWALK_CB_USER_ONE);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, simg->gpd, IDWALK_CB_USER);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(
data, simg->image, IDWALK_CB_USER_ONE | IDWALK_CB_DIRECT_WEAK_LINK);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, simg->iuser.scene, IDWALK_CB_DIRECT_WEAK_LINK);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(
data, simg->mask_info.mask, IDWALK_CB_USER_ONE | IDWALK_CB_DIRECT_WEAK_LINK);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, simg->gpd, IDWALK_CB_USER | IDWALK_CB_DIRECT_WEAK_LINK);
if (!is_readonly) {
simg->scopes.ok = 0;
}

View File

@@ -582,8 +582,8 @@ static void nla_foreach_id(SpaceLink *space_link, LibraryForeachIDData *data)
return;
}
BKE_LIB_FOREACHID_PROCESS_ID(data, snla->ads->source, IDWALK_CB_NOP);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, snla->ads->filter_grp, IDWALK_CB_NOP);
BKE_LIB_FOREACHID_PROCESS_ID(data, snla->ads->source, IDWALK_CB_DIRECT_WEAK_LINK);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, snla->ads->filter_grp, IDWALK_CB_DIRECT_WEAK_LINK);
}
static void nla_space_blend_read_data(BlendDataReader *reader, SpaceLink *sl)

View File

@@ -1241,8 +1241,8 @@ static void node_foreach_id(SpaceLink *space_link, LibraryForeachIDData *data)
bool is_embedded_nodetree = snode->id != nullptr && allow_pointer_access &&
bke::ntreeFromID(snode->id) == snode->nodetree;
BKE_LIB_FOREACHID_PROCESS_ID(data, snode->id, IDWALK_CB_NOP);
BKE_LIB_FOREACHID_PROCESS_ID(data, snode->from, IDWALK_CB_NOP);
BKE_LIB_FOREACHID_PROCESS_ID(data, snode->id, IDWALK_CB_DIRECT_WEAK_LINK);
BKE_LIB_FOREACHID_PROCESS_ID(data, snode->from, IDWALK_CB_DIRECT_WEAK_LINK);
bNodeTreePath *path = static_cast<bNodeTreePath *>(snode->treepath.first);
BLI_assert(path == nullptr || path->nodetree == snode->nodetree);
@@ -1264,13 +1264,16 @@ static void node_foreach_id(SpaceLink *space_link, LibraryForeachIDData *data)
}
}
else {
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, snode->nodetree, IDWALK_CB_USER_ONE);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(
data, snode->nodetree, IDWALK_CB_USER_ONE | IDWALK_CB_DIRECT_WEAK_LINK);
if (path != nullptr) {
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, path->nodetree, IDWALK_CB_USER_ONE);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(
data, path->nodetree, IDWALK_CB_USER_ONE | IDWALK_CB_DIRECT_WEAK_LINK);
}
}
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, snode->geometry_nodes_tool_tree, IDWALK_CB_USER_ONE);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(
data, snode->geometry_nodes_tool_tree, IDWALK_CB_USER_ONE | IDWALK_CB_DIRECT_WEAK_LINK);
/* Both `snode->id` and `snode->nodetree` have been remapped now, so their data can be
* accessed. */
@@ -1296,7 +1299,8 @@ static void node_foreach_id(SpaceLink *space_link, LibraryForeachIDData *data)
BLI_assert((path->nodetree->id.flag & LIB_EMBEDDED_DATA) == 0);
}
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, path->nodetree, IDWALK_CB_USER_ONE);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(
data, path->nodetree, IDWALK_CB_USER_ONE | IDWALK_CB_DIRECT_WEAK_LINK);
if (path->nodetree == nullptr) {
BLI_assert(!is_readonly);
@@ -1330,7 +1334,7 @@ static void node_foreach_id(SpaceLink *space_link, LibraryForeachIDData *data)
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, snode->edittree, IDWALK_CB_EMBEDDED_NOT_OWNING);
}
else {
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, snode->edittree, IDWALK_CB_NOP);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, snode->edittree, IDWALK_CB_DIRECT_WEAK_LINK);
}
}
}

View File

@@ -472,6 +472,8 @@ static void outliner_foreach_id(SpaceLink *space_link, LibraryForeachIDData *dat
while (TreeStoreElem *tselem = static_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter))) {
/* Do not try to restore non-ID pointers (drivers/sequence/etc.). */
if (TSE_IS_REAL_ID(tselem)) {
/* NOTE: Outliner ID pointers are never `IDWALK_CB_DIRECT_WEAK_LINK`, they should never
* enforce keeping a reference to some linked data. */
const int cb_flag = (tselem->id != nullptr && allow_pointer_access &&
(tselem->id->flag & LIB_EMBEDDED_DATA) != 0) ?
IDWALK_CB_EMBEDDED_NOT_OWNING :

View File

@@ -148,7 +148,7 @@ static void script_main_region_listener(const wmRegionListenerParams * /*params*
static void script_foreach_id(SpaceLink *space_link, LibraryForeachIDData *data)
{
SpaceScript *scpt = reinterpret_cast<SpaceScript *>(space_link);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, scpt->script, IDWALK_CB_NOP);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, scpt->script, IDWALK_CB_DIRECT_WEAK_LINK);
}
static void script_space_blend_read_after_liblink(BlendLibReader * /*reader*/,

View File

@@ -920,7 +920,7 @@ static void sequencer_id_remap(ScrArea * /*area*/,
static void sequencer_foreach_id(SpaceLink *space_link, LibraryForeachIDData *data)
{
SpaceSeq *sseq = reinterpret_cast<SpaceSeq *>(space_link);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sseq->gpd, IDWALK_CB_USER);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sseq->gpd, IDWALK_CB_USER | IDWALK_CB_DIRECT_WEAK_LINK);
}
/* ************************************* */

View File

@@ -400,7 +400,8 @@ static void text_id_remap(ScrArea * /*area*/,
static void text_foreach_id(SpaceLink *space_link, LibraryForeachIDData *data)
{
SpaceText *st = reinterpret_cast<SpaceText *>(space_link);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, st->text, IDWALK_CB_USER_ONE);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(
data, st->text, IDWALK_CB_USER_ONE | IDWALK_CB_DIRECT_WEAK_LINK);
}
static void text_space_blend_read_data(BlendDataReader * /*reader*/, SpaceLink *sl)

View File

@@ -2073,10 +2073,10 @@ static void view3d_foreach_id(SpaceLink *space_link, LibraryForeachIDData *data)
{
View3D *v3d = reinterpret_cast<View3D *>(space_link);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, v3d->camera, IDWALK_CB_NOP);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, v3d->ob_center, IDWALK_CB_NOP);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, v3d->camera, IDWALK_CB_DIRECT_WEAK_LINK);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, v3d->ob_center, IDWALK_CB_DIRECT_WEAK_LINK);
if (v3d->localvd) {
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, v3d->localvd->camera, IDWALK_CB_NOP);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, v3d->localvd->camera, IDWALK_CB_DIRECT_WEAK_LINK);
}
BKE_viewer_path_foreach_id(data, &v3d->viewer_path);
}