Refactor: Move 'need link' and 'need expand' ID tags to runtime readfile data.

Also adds a new `BLO_readfile_id_runtime_tags_for_write` accessor to
ensure readfile data is created before assigning a tag value.

Followup to 2ec1b6887d. Should cover the last existing ID tags that
can be moved to temp runtime readfile ID data.

Pull Request: https://projects.blender.org/blender/blender/pulls/133715
This commit is contained in:
Bastien Montagne
2025-01-31 14:26:38 +01:00
committed by Bastien Montagne
parent 41e693c43c
commit 2612b27e42
4 changed files with 71 additions and 49 deletions

View File

@@ -489,7 +489,8 @@ using BLOExpandDoitCallback = void (*)(void *fdhandle, Main *mainvar, void *idv)
/**
* Loop over all ID data in Main to mark relations.
* Set (id->tag & ID_TAG_NEED_EXPAND) to mark expanding. Flags get cleared after expanding.
* Set #ID_Readfile_Data::Tags.needs_expanding to mark expanding. Flags get
* cleared after expanding.
*
* \param fdhandle: usually file-data, or own handle. May be nullptr.
* \param mainvar: the Main database to expand.
@@ -545,7 +546,24 @@ short BLO_version_from_file(const char *filepath);
*/
struct ID_Readfile_Data {
struct Tags {
bool is_id_link_placeholder : 1;
/* General ID reading related tags. */
/**
* Mark ID placeholders for linked data-blocks needing to be read from their library
* blendfiles.
*/
bool is_link_placeholder : 1;
/**
* Mark IDs needing to be expanded (only done once). See #BLO_expand_main.
*/
bool needs_expanding : 1;
/**
* Mark IDs needing to be 'lib-linked', i.e. to get their pointers to other data-blocks
* updated from the 'UID' values stored in `.blend` files to the new, actual pointers.
*/
bool needs_linking : 1;
/* Specific ID-type reading/versioning related tags. */
/**
* Set when this ID used a legacy Action, in which case it also should pick
@@ -563,6 +581,13 @@ struct ID_Readfile_Data {
*/
ID_Readfile_Data::Tags BLO_readfile_id_runtime_tags(ID &id);
/**
* Create the `readfile_data` if needed, and return `id->runtime.readfile_data->tags`.
*
* Use it instead of #BLO_readfile_id_runtime_tags when tags need to be set.
*/
ID_Readfile_Data::Tags &BLO_readfile_id_runtime_tags_for_write(ID &id);
/**
* Free the ID_Readfile_Data of all IDs in this bmain and all their embedded IDs.
*

View File

@@ -2140,6 +2140,12 @@ ID_Readfile_Data::Tags BLO_readfile_id_runtime_tags(ID &id)
return id.runtime.readfile_data->tags;
}
ID_Readfile_Data::Tags &BLO_readfile_id_runtime_tags_for_write(ID &id)
{
readfile_id_runtime_data_ensure(id);
return id.runtime.readfile_data->tags;
}
void BLO_readfile_id_runtime_data_free(ID &id)
{
MEM_SAFE_FREE(id.runtime.readfile_data);
@@ -2222,7 +2228,7 @@ static void direct_link_id_common(BlendDataReader *reader,
id->runtime.readfile_data->tags = id_read_tags;
}
if (BLO_readfile_id_runtime_tags(*id).is_id_link_placeholder) {
if (BLO_readfile_id_runtime_tags(*id).is_link_placeholder) {
/* For placeholder we only need to set the tag and properly initialize generic ID fields above,
* no further data to read. */
return;
@@ -2329,8 +2335,8 @@ static bool scene_validate_setscene__liblink(Scene *sce, const int totscene)
/* This runs per library (before each libraries #Main has been joined),
* so we can't step into other libraries since `totscene` is only for this library.
*
* Also, other libraries may not have been linked yet,
* while we could check #ID_TAG_NEED_LINK the library pointer check is sufficient. */
* Also, other libraries may not have been linked yet, while we could check for
* #ID_Readfile_Data::Tags.needs_linking the library pointer check is sufficient. */
if (sce->id.lib != sce_iter->id.lib) {
return true;
}
@@ -2534,7 +2540,7 @@ static bool direct_link_id(FileData *fd,
/* Read part of datablock that is common between real and embedded datablocks. */
direct_link_id_common(&reader, main->curlib, id, id_old, tag, id_read_tags);
if (BLO_readfile_id_runtime_tags(*id).is_id_link_placeholder) {
if (BLO_readfile_id_runtime_tags(*id).is_link_placeholder) {
/* For placeholder we only need to set the tag, no further data to read. */
id->tag = tag;
return true;
@@ -2789,8 +2795,8 @@ static void read_libblock_undo_restore_identical(
/* Do not add ID_TAG_NEW here, this should not be needed/used in undo case anyway (as
* this is only for do_version-like code), but for sake of consistency, and also because
* it will tell us which ID is re-used from old Main, and which one is actually newly read. */
/* Also do not add ID_TAG_NEED_LINK, this ID will never be re-liblinked, hence that tag will
* never be cleared, leading to critical issue in link/append code. */
/* Also do not set #ID_Readfile_Data::Tags.needs_linking, this ID will never be re-liblinked,
* hence that tag will never be cleared, leading to critical issue in link/append code. */
/* Some tags need to be preserved here. */
id_old->tag = ((id_tag | ID_TAG_UNDO_OLD_ID_REUSED_UNCHANGED) & ~ID_TAG_KEEP_ON_UNDO) |
(id_old->tag & ID_TAG_KEEP_ON_UNDO);
@@ -2863,7 +2869,8 @@ static void read_libblock_undo_restore_at_old_address(FileData *fd, Main *main,
* lib-linking to restore some data that should never be affected by undo, e.g. the 3D cursor of
* #Scene. */
id_old->orig_id = id;
id_old->tag |= ID_TAG_UNDO_OLD_ID_REREAD_IN_PLACE | ID_TAG_NEED_LINK;
id_old->tag |= ID_TAG_UNDO_OLD_ID_REREAD_IN_PLACE;
BLO_readfile_id_runtime_tags_for_write(*id_old).needs_linking = true;
BLI_addtail(new_lb, id_old);
BLI_addtail(old_lb, id);
@@ -2974,6 +2981,7 @@ static BHead *read_libblock(FileData *fd,
Main *main,
BHead *bhead,
int id_tag,
ID_Readfile_Data::Tags id_read_tags,
const bool placeholder_set_indirect_extern,
ID **r_id)
{
@@ -3042,13 +3050,12 @@ static BHead *read_libblock(FileData *fd,
/* Set tag for new datablock to indicate lib linking and versioning needs
* to be done still. */
id_tag |= (ID_TAG_NEED_LINK | ID_TAG_NEW);
ID_Readfile_Data::Tags id_read_tags{};
id_tag |= ID_TAG_NEW;
id_read_tags.needs_linking = true;
if (bhead->code == ID_LINK_PLACEHOLDER) {
/* Read placeholder for linked datablock. */
id_read_tags.is_id_link_placeholder = true;
id_read_tags.is_link_placeholder = true;
if (placeholder_set_indirect_extern) {
if (id->flag & ID_FLAG_INDIRECT_WEAK_LINK) {
@@ -3362,7 +3369,7 @@ static void lib_link_all(FileData *fd, Main *bmain)
/* This ID has been re-used from 'old' bmain. Since it was therefore unchanged across
* current undo step, and old IDs re-use their old memory address, we do not need to liblink
* it at all. */
BLI_assert((id->tag & ID_TAG_NEED_LINK) == 0);
BLI_assert(!BLO_readfile_id_runtime_tags(*id).needs_linking);
/* Some data that should be persistent, like the 3DCursor or the tool settings, are
* stored in IDs affected by undo, like Scene. So this requires some specific handling. */
@@ -3376,7 +3383,7 @@ static void lib_link_all(FileData *fd, Main *bmain)
continue;
}
if ((id->tag & ID_TAG_NEED_LINK) != 0) {
if (BLO_readfile_id_runtime_tags(*id).needs_linking) {
/* Not all original pointer values can be considered as valid.
* Handling of DNA deprecated data should never be needed in undo case. */
const LibraryForeachIDFlag flag = IDWALK_NO_ORIG_POINTERS_ACCESS | IDWALK_INCLUDE_UI |
@@ -3387,7 +3394,7 @@ static void lib_link_all(FileData *fd, Main *bmain)
after_liblink_id_process(&reader, id);
id->tag &= ~ID_TAG_NEED_LINK;
BLO_readfile_id_runtime_tags_for_write(*id).needs_linking = false;
}
/* Some data that should be persistent, like the 3DCursor or the tool settings, are
@@ -3409,7 +3416,7 @@ static void lib_link_all(FileData *fd, Main *bmain)
/* Double check we do not have any 'need link' tag remaining, this should never be the case once
* this function has run. */
FOREACH_MAIN_ID_BEGIN (bmain, id) {
BLI_assert((id->tag & ID_TAG_NEED_LINK) == 0);
BLI_assert(!BLO_readfile_id_runtime_tags(*id).needs_linking);
}
FOREACH_MAIN_ID_END;
#endif
@@ -3724,7 +3731,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
* to the file format definition. So we can use the entry at the
* end of mainlist, added in direct_link_library. */
Main *libmain = static_cast<Main *>(mainlist.last);
bhead = read_libblock(fd, libmain, bhead, 0, true, nullptr);
bhead = read_libblock(fd, libmain, bhead, 0, {}, true, nullptr);
}
break;
/* in 2.50+ files, the file identifier for screens is patched, forward compatibility */
@@ -3740,7 +3747,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
bhead = blo_bhead_next(fd, bhead);
}
else {
bhead = read_libblock(fd, bfd->main, bhead, ID_TAG_LOCAL, false, nullptr);
bhead = read_libblock(fd, bfd->main, bhead, ID_TAG_LOCAL, {}, false, nullptr);
}
}
else {
@@ -4148,7 +4155,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
if (id == nullptr) {
/* ID has not been read yet, add placeholder to the main of the
* library it belongs to, so that it will be read later. */
read_libblock(fd, libmain, bhead, fd->id_tag_extra | ID_TAG_INDIRECT, false, &id);
read_libblock(fd, libmain, bhead, fd->id_tag_extra | ID_TAG_INDIRECT, {}, false, &id);
BLI_assert(id != nullptr);
id_sort_by_name(which_libbase(libmain, GS(id->name)), id, static_cast<ID *>(id->prev));
@@ -4161,7 +4168,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
else {
/* Convert any previously read weak link to regular link
* to signal that we want to read this data-block. */
if (BLO_readfile_id_runtime_tags(*id).is_id_link_placeholder) {
if (BLO_readfile_id_runtime_tags(*id).is_link_placeholder) {
id->flag &= ~ID_FLAG_INDIRECT_WEAK_LINK;
}
@@ -4192,8 +4199,10 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
/* Data-block in same library. */
ID *id = library_id_is_yet_read(fd, mainvar, bhead);
if (id == nullptr) {
ID_Readfile_Data::Tags id_read_tags{};
id_read_tags.needs_expanding = true;
read_libblock(
fd, mainvar, bhead, fd->id_tag_extra | ID_TAG_NEED_EXPAND | ID_TAG_INDIRECT, false, &id);
fd, mainvar, bhead, fd->id_tag_extra | ID_TAG_INDIRECT, id_read_tags, false, &id);
BLI_assert(id != nullptr);
id_sort_by_name(which_libbase(mainvar, GS(id->name)), id, static_cast<ID *>(id->prev));
}
@@ -4201,7 +4210,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
/* Convert any previously read weak link to regular link to signal that we want to read this
* data-block. Note that this function also visits already-loaded data-blocks, and thus their
* `readfile_data` field might already have been freed. */
if (BLO_readfile_id_runtime_tags(*id).is_id_link_placeholder) {
if (BLO_readfile_id_runtime_tags(*id).is_link_placeholder) {
id->flag &= ~ID_FLAG_INDIRECT_WEAK_LINK;
}
@@ -4255,7 +4264,7 @@ void BLO_expand_main(void *fdhandle, Main *mainvar, BLOExpandDoitCallback callba
ID *id_iter;
FOREACH_MAIN_ID_BEGIN (mainvar, id_iter) {
if ((id_iter->tag & ID_TAG_NEED_EXPAND) == 0) {
if (!BLO_readfile_id_runtime_tags(*id_iter).needs_expanding) {
continue;
}
@@ -4271,7 +4280,7 @@ void BLO_expand_main(void *fdhandle, Main *mainvar, BLOExpandDoitCallback callba
BKE_library_foreach_ID_link(nullptr, id_iter, expand_cb, &expander, flag);
do_it = true;
id_iter->tag &= ~ID_TAG_NEED_EXPAND;
BLO_readfile_id_runtime_tags_for_write(*id_iter).needs_expanding = false;
}
FOREACH_MAIN_ID_END;
}
@@ -4301,7 +4310,9 @@ static ID *link_named_part(
if (id == nullptr) {
/* not read yet */
const int tag = ((force_indirect ? ID_TAG_INDIRECT : ID_TAG_EXTERN) | fd->id_tag_extra);
read_libblock(fd, mainl, bhead, tag | ID_TAG_NEED_EXPAND, false, &id);
ID_Readfile_Data::Tags id_read_tags{};
id_read_tags.needs_expanding = true;
read_libblock(fd, mainl, bhead, tag, id_read_tags, false, &id);
if (id) {
/* sort by name in list */
@@ -4615,7 +4626,7 @@ static int has_linked_ids_to_read(Main *mainvar)
while (a--) {
LISTBASE_FOREACH (ID *, id, lbarray[a]) {
if (BLO_readfile_id_runtime_tags(*id).is_id_link_placeholder &&
if (BLO_readfile_id_runtime_tags(*id).is_link_placeholder &&
!(id->flag & ID_FLAG_INDIRECT_WEAK_LINK))
{
return true;
@@ -4648,13 +4659,13 @@ static void read_library_linked_id(
library_parent_filepath(mainvar->curlib));
}
id->runtime.readfile_data->tags.is_id_link_placeholder = false;
BLO_readfile_id_runtime_tags_for_write(*id).is_link_placeholder = false;
id->flag &= ~ID_FLAG_INDIRECT_WEAK_LINK;
if (bhead) {
id->tag |= ID_TAG_NEED_EXPAND;
BLO_readfile_id_runtime_tags_for_write(*id).needs_expanding = true;
// printf("read lib block %s\n", id->name);
read_libblock(fd, mainvar, bhead, id->tag, false, r_id);
read_libblock(fd, mainvar, bhead, id->tag, BLO_readfile_id_runtime_tags(*id), false, r_id);
}
else {
CLOG_INFO(&LOG,
@@ -4693,7 +4704,7 @@ static void read_library_linked_ids(FileData *basefd,
while (id) {
ID *id_next = static_cast<ID *>(id->next);
if (BLO_readfile_id_runtime_tags(*id).is_id_link_placeholder &&
if (BLO_readfile_id_runtime_tags(*id).is_link_placeholder &&
!(id->flag & ID_FLAG_INDIRECT_WEAK_LINK))
{
BLI_remlink(lbarray[a], id);
@@ -4757,7 +4768,7 @@ static void read_library_clear_weak_links(FileData *basefd, ListBase *mainlist,
/* This function also visits already-loaded data-blocks, and thus their
* `readfile_data` field might already have been freed. */
if (BLO_readfile_id_runtime_tags(*id).is_id_link_placeholder &&
if (BLO_readfile_id_runtime_tags(*id).is_link_placeholder &&
(id->flag & ID_FLAG_INDIRECT_WEAK_LINK))
{
CLOG_INFO(&LOG, 3, "Dropping weak link to '%s'", id->name);

View File

@@ -488,8 +488,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
/* tex->extend and tex->imageflag have changed: */
Tex *tex = static_cast<Tex *>(bmain->textures.first);
while (tex) {
if (tex->id.tag & ID_TAG_NEED_LINK) {
if (BLO_readfile_id_runtime_tags(tex->id).needs_linking) {
if (tex->extend == 0) {
if (tex->xrepeat || tex->yrepeat) {
tex->extend = TEX_REPEAT;
@@ -2273,7 +2272,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
part->id.lib = ob->id.lib;
part->id.us--;
part->id.tag |= (ob->id.tag & ID_TAG_NEED_LINK);
BLO_readfile_id_runtime_tags_for_write(part->id).needs_linking =
BLO_readfile_id_runtime_tags(ob->id).needs_linking;
psys->totpart = 0;
psys->flag = PSYS_CURRENT;

View File

@@ -874,20 +874,6 @@ enum {
*/
ID_TAG_PRE_EXISTING = 1 << 13,
/**
* Tag used internally in `readfile.cc`, to mark IDs needing to be expanded (only done once).
*
* RESET_AFTER_USE
*/
ID_TAG_NEED_EXPAND = 1 << 14,
/**
* Tag used internally in `readfile.cc`, to mark IDs needing to be 'lib-linked', i.e. to get
* their pointers to other data-blocks updated from the 'UID' values stored in `.blend` files to
* the new, actual pointers.
*
* RESET_AFTER_USE
*/
ID_TAG_NEED_LINK = 1 << 16,
/**
* ID is being re-used from the old Main (instead of read from memfile), during memfile undo
* processing, because it was detected as unchanged.