[Bf-blender-cvs] [72d660443bd] master: LibOverride: add recursive resync.

Bastien Montagne noreply at git.blender.org
Wed May 26 17:50:47 CEST 2021


Commit: 72d660443bdb8ed0b8ab34fdfe068d4e065d7c58
Author: Bastien Montagne
Date:   Wed May 26 16:53:59 2021 +0200
Branches: master
https://developer.blender.org/rB72d660443bdb8ed0b8ab34fdfe068d4e065d7c58

LibOverride: add recursive resync.

Recursive resync means also resyncing overrides that are linked from
other library files into current working file.

Note that this allows to get 'working' files even when their
dependencies are out of sync. However, since linked data is never
written/saved, this has to be re-done every time the working file is
loaded, until said dependencies are updated properly.

NOTE: This is still missing the 'report' side of things, which is part
of a larger task to enhance reports regarding both linking, and
liboverrides (see T88393).

----------

Technical notes:

Implementing this proved to be slightly more challenging than expected,
mainly because one of the key aspects of the feature was never done in
Blender before: manipulating, re-creating linked data.

This ended up moving the whole resync code to use temp IDs out of bmain,
which is better in the long run anyway (and more aligned with what we
generally want to do when manipulating temp ID data). It should also
give a marginal improvement in performances for regular resync.

This commit also had to carefully 'sort' libraries by level of indirect
usage, as we want to resync first the libraries that are the least directly
used, i.e. libraries that are most used by other libraries.

===================================================================

M	source/blender/blenkernel/BKE_lib_override.h
M	source/blender/blenkernel/intern/lib_override.c
M	source/blender/makesdna/DNA_ID.h

===================================================================

diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h
index f1ed5a453ba..0275c2c235c 100644
--- a/source/blender/blenkernel/BKE_lib_override.h
+++ b/source/blender/blenkernel/BKE_lib_override.h
@@ -47,6 +47,7 @@ struct ID;
 struct IDOverrideLibrary;
 struct IDOverrideLibraryProperty;
 struct IDOverrideLibraryPropertyOperation;
+struct Library;
 struct Main;
 struct Object;
 struct PointerRNA;
@@ -68,7 +69,9 @@ bool BKE_lib_override_library_is_user_edited(struct ID *id);
 struct ID *BKE_lib_override_library_create_from_id(struct Main *bmain,
                                                    struct ID *reference_id,
                                                    const bool do_tagged_remap);
-bool BKE_lib_override_library_create_from_tag(struct Main *bmain);
+bool BKE_lib_override_library_create_from_tag(struct Main *bmain,
+                                              const struct Library *reference_library,
+                                              const bool do_no_main);
 bool BKE_lib_override_library_create(struct Main *bmain,
                                      struct Scene *scene,
                                      struct ViewLayer *view_layer,
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index 1d7c4c3ef6b..36730a7baf7 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -48,6 +48,7 @@
 #include "BKE_lib_query.h"
 #include "BKE_lib_remap.h"
 #include "BKE_main.h"
+#include "BKE_node.h"
 #include "BKE_report.h"
 #include "BKE_scene.h"
 
@@ -207,12 +208,17 @@ void BKE_lib_override_library_free(struct IDOverrideLibrary **override, const bo
   *override = NULL;
 }
 
-static ID *lib_override_library_create_from(Main *bmain, ID *reference_id)
+static ID *lib_override_library_create_from(Main *bmain,
+                                            ID *reference_id,
+                                            const int lib_id_copy_flags)
 {
   /* Note: We do not want to copy possible override data from reference here (whether it is an
    * override template, or already an override of some other ref data). */
-  ID *local_id = BKE_id_copy_ex(
-      bmain, reference_id, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_NO_LIB_OVERRIDE);
+  ID *local_id = BKE_id_copy_ex(bmain,
+                                reference_id,
+                                NULL,
+                                LIB_ID_COPY_DEFAULT | LIB_ID_COPY_NO_LIB_OVERRIDE |
+                                    lib_id_copy_flags);
 
   if (local_id == NULL) {
     return NULL;
@@ -270,7 +276,7 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain,
   BLI_assert(reference_id != NULL);
   BLI_assert(reference_id->lib != NULL);
 
-  ID *local_id = lib_override_library_create_from(bmain, reference_id);
+  ID *local_id = lib_override_library_create_from(bmain, reference_id, 0);
 
   if (do_tagged_remap) {
     Key *reference_key, *local_key = NULL;
@@ -315,9 +321,17 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain,
  * main. You can add more local IDs to be remapped to use new overriding ones by setting their
  * LIB_TAG_DOIT tag.
  *
+ * \param reference_library the library from which the linked data being overridden come from
+ * (i.e. the library of the linked reference ID).
+ *
+ * \param do_no_main Create the new override data outside of Main database. Used for resyncing of
+ * linked overrides.
+ *
  * \return \a true on success, \a false otherwise.
  */
-bool BKE_lib_override_library_create_from_tag(Main *bmain)
+bool BKE_lib_override_library_create_from_tag(Main *bmain,
+                                              const Library *reference_library,
+                                              const bool do_no_main)
 {
   ID *reference_id;
   bool success = true;
@@ -327,7 +341,7 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain)
 
   /* Get all IDs we want to override. */
   FOREACH_MAIN_ID_BEGIN (bmain, reference_id) {
-    if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL &&
+    if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib == reference_library &&
         BKE_idtype_idcode_is_linkable(GS(reference_id->name))) {
       todo_id_iter = MEM_callocN(sizeof(*todo_id_iter), __func__);
       todo_id_iter->data = reference_id;
@@ -339,10 +353,16 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain)
   /* Override the IDs. */
   for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) {
     reference_id = todo_id_iter->data;
+
+    /* If `newid` is already set, assume it has been handled by calling code.
+     * Only current use case: re-using proxy ID when converting to liboverride. */
     if (reference_id->newid == NULL) {
-      /* If `newid` is already set, assume it has been handled by calling code.
-       * Only current use case: re-using proxy ID when converting to liboverride. */
-      if ((reference_id->newid = lib_override_library_create_from(bmain, reference_id)) == NULL) {
+      /* Note: `no main` case is used during resync procedure, to support recursive resync. This
+       * requires extra care further odwn the resync process, see
+       * `BKE_lib_override_library_resync`. */
+      reference_id->newid = lib_override_library_create_from(
+          bmain, reference_id, do_no_main ? LIB_ID_CREATE_NO_MAIN : 0);
+      if (reference_id->newid == NULL) {
         success = false;
         break;
       }
@@ -382,23 +402,42 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain)
 
       /* Still checking the whole Main, that way we can tag other local IDs as needing to be
        * remapped to use newly created overriding IDs, if needed. */
-      FOREACH_MAIN_ID_BEGIN (bmain, other_id) {
-        if ((other_id->tag & LIB_TAG_DOIT) != 0 && other_id->lib == NULL) {
-          /* Note that using ID_REMAP_SKIP_INDIRECT_USAGE below is superfluous, as we only remap
-           * local IDs usages anyway. */
+      ID *id;
+      FOREACH_MAIN_ID_BEGIN (bmain, id) {
+        /* In case we created new overrides as 'no main', they are not accessible directly in this
+         * loop, but we can get to them through their reference's `newid` pointer. */
+        if (do_no_main && id->lib == reference_id->lib && id->newid != NULL) {
+          other_id = id->newid;
+          /* Otherwise we cannot properly dinstinguish between IDs that are actually from the
+           * linked library (and should not be remapped), and IDs that are overrides re-generated
+           * from the reference from the linked library, and must therefore be remapped.
+           *
+           * This is reset afterwards at the end of this loop. */
+          other_id->lib = NULL;
+        }
+        else {
+          other_id = id;
+        }
+
+        /* If other ID is a linked one, but not from the same library as our reference, then we
+         * consider we should also remap it, as part of recursive resync. */
+        if ((other_id->tag & LIB_TAG_DOIT) != 0 && other_id->lib != reference_id->lib) {
           BKE_libblock_relink_ex(bmain,
                                  other_id,
                                  reference_id,
                                  local_id,
-                                 ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY);
+                                 ID_REMAP_SKIP_OVERRIDE_LIBRARY | ID_REMAP_FORCE_USER_REFCOUNT);
           if (reference_key != NULL) {
             BKE_libblock_relink_ex(bmain,
                                    other_id,
                                    &reference_key->id,
                                    &local_key->id,
-                                   ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY);
+                                   ID_REMAP_SKIP_OVERRIDE_LIBRARY | ID_REMAP_FORCE_USER_REFCOUNT);
           }
         }
+        if (other_id != id) {
+          other_id->lib = reference_id->lib;
+        }
       }
       FOREACH_MAIN_ID_END;
     }
@@ -598,26 +637,22 @@ static void lib_override_local_group_tag_recursive(LibOverrideGroupTagData *data
     if (ELEM(to_id, NULL, id_owner)) {
       continue;
     }
-    if (!ID_IS_OVERRIDE_LIBRARY(to_id) || ID_IS_LINKED(to_id)) {
+    if (!ID_IS_OVERRIDE_LIBRARY(to_id) || (to_id->lib != id_owner->lib)) {
       continue;
     }
 
-    /* Do not tag 'virtual' overrides (shape keys here, as we already rejected embedded case
-     * above). */
-    if (ID_IS_OVERRIDE_LIBRARY_REAL(to_id)) {
-      Library *reference_lib = lib_override_get(bmain, id_owner)->reference->lib;
-      ID *to_id_reference = lib_override_get(bmain, to_id)->reference;
-      if (to_id_reference->lib != reference_lib) {
-        /* We do not override data-blocks from other libraries, nor do we process them. */
-        continue;
-      }
+    Library *reference_lib = lib_override_get(bmain, id_owner)->reference->lib;
+    ID *to_id_reference = lib_override_get(bmain, to_id)->reference;
+    if (to_id_reference->lib != reference_lib) {
+      /* We do not override data-blocks from other libraries, nor do we process them. */
+      continue;
+    }
 
-      if (to_id_reference->tag & LIB_TAG_MISSING) {
-        to_id->tag |= missing_tag;
-      }
-      else {
-        to_id->tag |= tag;
-      }
+    if (to_id_reference->tag & LIB_TAG_MISSING) {
+      to_id->tag |= missing_tag;
+    }
+    else {
+      to_id->tag |= tag;
     }
 
     /* Recursively process the dependencies. */
@@ -631,7 +666,7 @@ static void lib_override_local_group_tag_recursive(LibOverrideGroupTagData *data
 static void lib_override_local_group_tag(LibOverrideGroupTagData *data)
 {
   ID *id_root = data->id_root;
-  BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root) && !ID_IS_LINKED(id_root));
+  BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root));
 
   if ((id_root->override_library->reference->tag & LIB_TAG_MISSING)) {
     id_root->tag |= data->missing_tag;
@@ -656,7 +691,7 @@ static bool lib_override_library_create_do(Main *bmain, ID *id_root)
 
   BKE_main_relations_free(bmain);
 
-  return BKE_lib_override_li

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list