Fix #136020: Linking: Improve performances of many linked IDs relocation.
The remapping from old to new linked IDs was done one by one, with all the related pre/post processing. In particular for objects, this could easily lead to quadratic cost (need to loop over all objects for each object)... Solved by reworking the remapping logic in relocation code to process all linked data in a single call. From quick tests locally, it makes relocating a library with 10k object got from 50s to about 5s. A 40k linked objects case goes from 'way too long to measure' to about 4 minutes. So there is likely still some things that could be improved here (processing time still does not seem to be O(n)), but at least it's usable now. Pull Request: https://projects.blender.org/blender/blender/pulls/144207
This commit is contained in:
committed by
Bastien Montagne
parent
87ec9fc4a7
commit
a1abf9a64e
@@ -1701,12 +1701,12 @@ void BKE_blendfile_override(BlendfileLinkAppendContext *lapp_context,
|
||||
/** \name Library relocating code.
|
||||
* \{ */
|
||||
|
||||
static void blendfile_library_relocate_id_remap_do(Main *bmain,
|
||||
ID *old_id,
|
||||
ID *new_id,
|
||||
ReportList *reports,
|
||||
const bool do_reload,
|
||||
const int remap_flags)
|
||||
static void blendfile_library_relocate_id_remap_prepare(
|
||||
id::IDRemapper &remapper,
|
||||
blender::Map<ID *, ID *> &old_owner_id_to_shapekey,
|
||||
ID *old_id,
|
||||
ID *new_id,
|
||||
const bool do_reload)
|
||||
{
|
||||
BLI_assert(old_id);
|
||||
if (do_reload) {
|
||||
@@ -1720,29 +1720,69 @@ static void blendfile_library_relocate_id_remap_do(Main *bmain,
|
||||
old_id->name,
|
||||
old_id->us,
|
||||
new_id->us);
|
||||
BKE_libblock_remap_locked(bmain, old_id, new_id, remap_flags);
|
||||
remapper.add(old_id, new_id);
|
||||
}
|
||||
|
||||
if (old_id->flag & ID_FLAG_FAKEUSER) {
|
||||
id_fake_user_clear(old_id);
|
||||
id_fake_user_set(new_id);
|
||||
}
|
||||
/* Usual special code for ShapeKeys snowflakes...
|
||||
*
|
||||
* NOTE: Unfortunately, actual reasons for why the old shapekeys needs to be removed from their
|
||||
* old owner ID was not documented in the initial commit. Suspect it's related to the fact that
|
||||
* the old ID should not end up using the new shapekeys? */
|
||||
Key **old_key_p = BKE_key_from_id_p(old_id);
|
||||
if (old_key_p == nullptr) {
|
||||
return;
|
||||
}
|
||||
Key *old_key = *old_key_p;
|
||||
Key *new_key = BKE_key_from_id(new_id);
|
||||
if (old_key != nullptr) {
|
||||
old_owner_id_to_shapekey.add(old_id, &old_key->id);
|
||||
*old_key_p = nullptr;
|
||||
id_us_min(&old_key->id);
|
||||
remapper.add(&old_key->id, &new_key->id);
|
||||
}
|
||||
}
|
||||
|
||||
CLOG_DEBUG(&LOG,
|
||||
"After remap of %s, old_id users: %d, new_id users: %d",
|
||||
old_id->name,
|
||||
old_id->us,
|
||||
new_id->us);
|
||||
|
||||
/* In some cases, new_id might become direct link, remove parent of library in this case. */
|
||||
if (new_id->lib->runtime->parent && (new_id->tag & ID_TAG_INDIRECT) == 0) {
|
||||
if (do_reload) {
|
||||
BLI_assert_unreachable(); /* Should not happen in 'pure' reload case... */
|
||||
}
|
||||
new_id->lib->runtime->parent = nullptr;
|
||||
static void blendfile_library_relocate_id_remap_finalize(
|
||||
Main *bmain,
|
||||
blender::Map<ID *, ID *> &old_owner_id_to_shapekey,
|
||||
ID *old_id,
|
||||
ID *new_id,
|
||||
ReportList *reports,
|
||||
const bool do_reload)
|
||||
{
|
||||
/* Restore old shapekey pointer in old id (see also
|
||||
* #blendfile_library_relocate_id_remap_prepare above). */
|
||||
Key **old_key_p = BKE_key_from_id_p(old_id);
|
||||
if (old_key_p) {
|
||||
Key *old_key = reinterpret_cast<Key *>(
|
||||
old_owner_id_to_shapekey.lookup_default_as(old_id, nullptr));
|
||||
if (old_key) {
|
||||
BLI_assert(GS(old_key->id.name) == ID_KE);
|
||||
*old_key_p = old_key;
|
||||
id_us_plus_no_lib(&old_key->id);
|
||||
}
|
||||
}
|
||||
|
||||
if (old_id->us > 0 && new_id && old_id->lib == new_id->lib) {
|
||||
if (old_id->flag & ID_FLAG_FAKEUSER) {
|
||||
id_fake_user_clear(old_id);
|
||||
id_fake_user_set(new_id);
|
||||
}
|
||||
|
||||
CLOG_DEBUG(&LOG,
|
||||
"After remap of %s, old_id users: %d, new_id users: %d",
|
||||
old_id->name,
|
||||
old_id->us,
|
||||
new_id->us);
|
||||
|
||||
/* In some cases, new_id might become direct link, remove parent of library in this case. */
|
||||
if (new_id->lib->runtime->parent && (new_id->tag & ID_TAG_INDIRECT) == 0) {
|
||||
if (do_reload) {
|
||||
BLI_assert_unreachable(); /* Should not happen in 'pure' reload case... */
|
||||
}
|
||||
new_id->lib->runtime->parent = nullptr;
|
||||
}
|
||||
|
||||
if (old_id->us > 0 && old_id->lib == new_id->lib) {
|
||||
/* Note that this *should* not happen - but better be safe than sorry in this area,
|
||||
* at least until we are 100% sure this cannot ever happen.
|
||||
* Also, we can safely assume names were unique so far,
|
||||
@@ -1785,31 +1825,36 @@ static void blendfile_library_relocate_id_remap_do(Main *bmain,
|
||||
}
|
||||
}
|
||||
|
||||
static void blendfile_library_relocate_id_remap(Main *bmain,
|
||||
ID *old_id,
|
||||
ID *new_id,
|
||||
static void blendfile_library_relocate_id_remap(BlendfileLinkAppendContext &lapp_context,
|
||||
ReportList *reports,
|
||||
const bool do_reload,
|
||||
const int remap_flags)
|
||||
{
|
||||
blendfile_library_relocate_id_remap_do(bmain, old_id, new_id, reports, do_reload, remap_flags);
|
||||
if (new_id == nullptr) {
|
||||
return;
|
||||
Main *bmain = lapp_context.params->bmain;
|
||||
|
||||
id::IDRemapper remapper;
|
||||
blender::Map<ID *, ID *> old_owner_id_to_shapekey;
|
||||
|
||||
for (BlendfileLinkAppendContextItem &item : lapp_context.items) {
|
||||
ID *old_id = static_cast<ID *>(item.userdata);
|
||||
if (!old_id) {
|
||||
continue;
|
||||
}
|
||||
ID *new_id = item.new_id;
|
||||
blendfile_library_relocate_id_remap_prepare(
|
||||
remapper, old_owner_id_to_shapekey, old_id, new_id, do_reload);
|
||||
}
|
||||
/* Usual special code for ShapeKeys snowflakes... */
|
||||
Key **old_key_p = BKE_key_from_id_p(old_id);
|
||||
if (old_key_p == nullptr) {
|
||||
return;
|
||||
}
|
||||
Key *old_key = *old_key_p;
|
||||
Key *new_key = BKE_key_from_id(new_id);
|
||||
if (old_key != nullptr) {
|
||||
*old_key_p = nullptr;
|
||||
id_us_min(&old_key->id);
|
||||
blendfile_library_relocate_id_remap_do(
|
||||
bmain, &old_key->id, &new_key->id, reports, do_reload, remap_flags);
|
||||
*old_key_p = old_key;
|
||||
id_us_plus_no_lib(&old_key->id);
|
||||
|
||||
BKE_libblock_remap_multiple_locked(bmain, remapper, remap_flags);
|
||||
|
||||
for (BlendfileLinkAppendContextItem &item : lapp_context.items) {
|
||||
ID *old_id = static_cast<ID *>(item.userdata);
|
||||
if (!old_id) {
|
||||
continue;
|
||||
}
|
||||
ID *new_id = item.new_id;
|
||||
blendfile_library_relocate_id_remap_finalize(
|
||||
bmain, old_owner_id_to_shapekey, old_id, new_id, reports, do_reload);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2040,18 +2085,21 @@ void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context,
|
||||
* new data. */
|
||||
blender::Map<Library *, Library *> new_to_old_libraries_map;
|
||||
|
||||
BKE_layer_collection_resync_forbid();
|
||||
/* Note that in reload case, we also want to replace indirect usages. */
|
||||
const int remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE |
|
||||
(do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE);
|
||||
for (BlendfileLinkAppendContextItem &item : lapp_context->items) {
|
||||
ID *old_id = static_cast<ID *>(item.userdata);
|
||||
ID *new_id = item.new_id;
|
||||
if (new_id) {
|
||||
new_to_old_libraries_map.add(new_id->lib, old_id->lib);
|
||||
}
|
||||
blendfile_library_relocate_id_remap(bmain, old_id, new_id, reports, do_reload, remap_flags);
|
||||
}
|
||||
|
||||
BKE_layer_collection_resync_forbid();
|
||||
|
||||
/* Note that in reload case, we also want to replace indirect usages. */
|
||||
const int remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE |
|
||||
(do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE);
|
||||
blendfile_library_relocate_id_remap(*lapp_context, reports, do_reload, remap_flags);
|
||||
|
||||
BKE_layer_collection_resync_allow();
|
||||
BKE_main_collection_sync_remap(bmain);
|
||||
|
||||
@@ -2117,7 +2165,7 @@ void BKE_blendfile_id_relocate(BlendfileLinkAppendContext &lapp_context, ReportL
|
||||
|
||||
/* Do not affect indirect usages. */
|
||||
const int remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE | ID_REMAP_SKIP_INDIRECT_USAGE;
|
||||
blendfile_library_relocate_id_remap(bmain, old_id, new_id, reports, false, remap_flags);
|
||||
blendfile_library_relocate_id_remap(lapp_context, reports, false, remap_flags);
|
||||
|
||||
BKE_layer_collection_resync_allow();
|
||||
BKE_main_collection_sync_remap(bmain);
|
||||
|
||||
Reference in New Issue
Block a user