Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Montagne <mont29>2022-03-16 19:52:16 +0300
committerBastien Montagne <bastien@blender.org>2022-03-16 20:34:20 +0300
commit7e06fc11b7cbf532bd8017b270f53e3a11f21523 (patch)
treeb4ae479c1c11701083bbede23c670629eb71bb10 /source/blender/blenkernel/intern/lib_remap.c
parent2564d152d6edf65afcb573598a1303483c62eb06 (diff)
Add 'multiple' variant of ID relink function.
Similar to other changes to ID remapping, gives huge speedups in some cases, like certain types of liboverride creation. Case from {T96092} goes from 1725 seconds (almost 30 minutes) to 45 seconds to generate the liboverride, on my machine. Reviewed By: jbakker Maniphest Tasks: T96092 Differential Revision: https://developer.blender.org/D14240
Diffstat (limited to 'source/blender/blenkernel/intern/lib_remap.c')
-rw-r--r--source/blender/blenkernel/intern/lib_remap.c175
1 files changed, 127 insertions, 48 deletions
diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c
index 24e7178dd63..468bc491a83 100644
--- a/source/blender/blenkernel/intern/lib_remap.c
+++ b/source/blender/blenkernel/intern/lib_remap.c
@@ -8,6 +8,7 @@
#include "CLG_log.h"
+#include "BLI_linklist.h"
#include "BLI_utildefines.h"
#include "DNA_collection_types.h"
@@ -681,6 +682,126 @@ void BKE_libblock_unlink(Main *bmain,
* ... sigh
*/
+typedef struct LibblockRelinkMultipleUserData {
+ Main *bmain;
+ LinkNode *ids;
+} LibBlockRelinkMultipleUserData;
+
+static void libblock_relink_foreach_idpair_cb(ID *old_id, ID *new_id, void *user_data)
+{
+ LibBlockRelinkMultipleUserData *data = user_data;
+ Main *bmain = data->bmain;
+ LinkNode *ids = data->ids;
+
+ BLI_assert(old_id != NULL);
+ BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name));
+ BLI_assert(old_id != new_id);
+
+ bool is_object_update_processed = false;
+ for (LinkNode *ln_iter = ids; ln_iter != NULL; ln_iter = ln_iter->next) {
+ ID *id_iter = ln_iter->link;
+
+ /* Some after-process updates.
+ * This is a bit ugly, but cannot see a way to avoid it.
+ * Maybe we should do a per-ID callback for this instead?
+ */
+ switch (GS(id_iter->name)) {
+ case ID_SCE:
+ case ID_GR: {
+ /* NOTE: here we know which collection we have affected, so at lest for NULL children
+ * detection we can only process that one.
+ * This is also a required fix in case `id` would not be in Main anymore, which can happen
+ * e.g. when called from `id_delete`. */
+ Collection *owner_collection = (GS(id_iter->name) == ID_GR) ?
+ (Collection *)id_iter :
+ ((Scene *)id_iter)->master_collection;
+ switch (GS(old_id->name)) {
+ case ID_OB:
+ if (!is_object_update_processed) {
+ libblock_remap_data_postprocess_object_update(
+ bmain, (Object *)old_id, (Object *)new_id);
+ is_object_update_processed = true;
+ }
+ break;
+ case ID_GR:
+ libblock_remap_data_postprocess_collection_update(
+ bmain, owner_collection, (Collection *)old_id, (Collection *)new_id);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ case ID_OB:
+ if (new_id != NULL) { /* Only affects us in case obdata was relinked (changed). */
+ libblock_remap_data_postprocess_obdata_relink(bmain, (Object *)id_iter, new_id);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void BKE_libblock_relink_multiple(Main *bmain,
+ LinkNode *ids,
+ const eIDRemapType remap_type,
+ struct IDRemapper *id_remapper,
+ const short remap_flags)
+{
+ BLI_assert(remap_type == ID_REMAP_TYPE_REMAP || BKE_id_remapper_is_empty(id_remapper));
+
+ for (LinkNode *ln_iter = ids; ln_iter != NULL; ln_iter = ln_iter->next) {
+ ID *id_iter = ln_iter->link;
+ libblock_remap_data(bmain, id_iter, remap_type, id_remapper, remap_flags);
+ }
+
+ switch (remap_type) {
+ case ID_REMAP_TYPE_REMAP: {
+ LibBlockRelinkMultipleUserData user_data = {0};
+ user_data.bmain = bmain;
+ user_data.ids = ids;
+
+ BKE_id_remapper_iter(id_remapper, libblock_relink_foreach_idpair_cb, &user_data);
+ break;
+ }
+ case ID_REMAP_TYPE_CLEANUP: {
+ bool is_object_update_processed = false;
+ for (LinkNode *ln_iter = ids; ln_iter != NULL; ln_iter = ln_iter->next) {
+ ID *id_iter = ln_iter->link;
+
+ switch (GS(id_iter->name)) {
+ case ID_SCE:
+ case ID_GR: {
+ /* NOTE: here we know which collection we have affected, so at lest for NULL children
+ * detection we can only process that one.
+ * This is also a required fix in case `id` would not be in Main anymore, which can
+ * happen e.g. when called from `id_delete`. */
+ Collection *owner_collection = (GS(id_iter->name) == ID_GR) ?
+ (Collection *)id_iter :
+ ((Scene *)id_iter)->master_collection;
+ /* No choice but to check whole objects once, and all children collections. */
+ libblock_remap_data_postprocess_collection_update(bmain, owner_collection, NULL, NULL);
+ if (!is_object_update_processed) {
+ libblock_remap_data_postprocess_object_update(bmain, NULL, NULL);
+ is_object_update_processed = true;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
+ }
+
+ DEG_relations_tag_update(bmain);
+}
+
void BKE_libblock_relink_ex(
Main *bmain, void *idv, void *old_idv, void *new_idv, const short remap_flags)
{
@@ -690,13 +811,15 @@ void BKE_libblock_relink_ex(
ID *id = idv;
ID *old_id = old_idv;
ID *new_id = new_idv;
+ LinkNode ids = {.next = NULL, .link = idv};
/* No need to lock here, we are only affecting given ID, not bmain database. */
struct IDRemapper *id_remapper = BKE_id_remapper_create();
eIDRemapType remap_type = ID_REMAP_TYPE_REMAP;
- BLI_assert(id);
- if (old_id) {
+ BLI_assert(id != NULL);
+ UNUSED_VARS_NDEBUG(id);
+ if (old_id != NULL) {
BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name));
BLI_assert(old_id != new_id);
BKE_id_remapper_add(id_remapper, old_id, new_id);
@@ -706,53 +829,9 @@ void BKE_libblock_relink_ex(
remap_type = ID_REMAP_TYPE_CLEANUP;
}
- libblock_remap_data(bmain, id, remap_type, id_remapper, remap_flags);
- BKE_id_remapper_free(id_remapper);
-
- /* Some after-process updates.
- * This is a bit ugly, but cannot see a way to avoid it.
- * Maybe we should do a per-ID callback for this instead?
- */
- switch (GS(id->name)) {
- case ID_SCE:
- case ID_GR: {
- /* NOTE: here we know which collection we have affected, so at lest for NULL children
- * detection we can only process that one.
- * This is also a required fix in case `id` would not be in Main anymore, which can happen
- * e.g. when called from `id_delete`. */
- Collection *owner_collection = (GS(id->name) == ID_GR) ? (Collection *)id :
- ((Scene *)id)->master_collection;
- if (old_id) {
- switch (GS(old_id->name)) {
- case ID_OB:
- libblock_remap_data_postprocess_object_update(
- bmain, (Object *)old_id, (Object *)new_id);
- break;
- case ID_GR:
- libblock_remap_data_postprocess_collection_update(
- bmain, owner_collection, (Collection *)old_id, (Collection *)new_id);
- break;
- default:
- break;
- }
- }
- else {
- /* No choice but to check whole objects/collections. */
- libblock_remap_data_postprocess_collection_update(bmain, owner_collection, NULL, NULL);
- libblock_remap_data_postprocess_object_update(bmain, NULL, NULL);
- }
- break;
- }
- case ID_OB:
- if (new_id) { /* Only affects us in case obdata was relinked (changed). */
- libblock_remap_data_postprocess_obdata_relink(bmain, (Object *)id, new_id);
- }
- break;
- default:
- break;
- }
+ BKE_libblock_relink_multiple(bmain, &ids, remap_type, id_remapper, remap_flags);
- DEG_relations_tag_update(bmain);
+ BKE_id_remapper_free(id_remapper);
}
static void libblock_relink_to_newid(Main *bmain, ID *id, const int remap_flag);