[Bf-blender-cvs] [93b33b63d4b] undo-experiments-swap-reread-datablocks: Undo: initial attempt to use ID swap to address pointers remapping issue.

Bastien Montagne noreply at git.blender.org
Fri Nov 29 16:59:24 CET 2019


Commit: 93b33b63d4b82910de8a5483278030b0cfff1986
Author: Bastien Montagne
Date:   Fri Nov 29 16:47:41 2019 +0100
Branches: undo-experiments-swap-reread-datablocks
https://developer.blender.org/rB93b33b63d4b82910de8a5483278030b0cfff1986

Undo: initial attempt to use ID swap to address pointers remapping issue.

Not really working right now...

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

M	source/blender/blenkernel/intern/library.c
M	source/blender/blenloader/intern/readfile.c

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

diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index e312522b508..41e0b43807c 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -800,6 +800,7 @@ bool BKE_id_copy(Main *bmain, const ID *id, ID **newid)
 /**
  * Does a mere memory swap over the whole IDs data (including type-specific memory).
  * \note Most internal ID data itself is not swapped (only IDProperties are).
+ * \note bmain may be NULL, in which case no internal pointers to itself remapping will be done.
  */
 void BKE_id_swap(Main *bmain, ID *id_a, ID *id_b)
 {
@@ -863,9 +864,11 @@ void BKE_id_swap(Main *bmain, ID *id_a, ID *id_b)
   id_a->properties = id_b_back.properties;
   id_b->properties = id_a_back.properties;
 
-  /* Swap will have broken internal references to itself, restore them. */
-  BKE_libblock_relink_ex(bmain, id_a, id_b, id_a, ID_REMAP_SKIP_NEVER_NULL_USAGE);
-  BKE_libblock_relink_ex(bmain, id_b, id_a, id_b, ID_REMAP_SKIP_NEVER_NULL_USAGE);
+  if (bmain != NULL) {
+    /* Swap will have broken internal references to itself, restore them. */
+    BKE_libblock_relink_ex(bmain, id_a, id_b, id_a, ID_REMAP_SKIP_NEVER_NULL_USAGE);
+    BKE_libblock_relink_ex(bmain, id_b, id_a, id_b, ID_REMAP_SKIP_NEVER_NULL_USAGE);
+  }
 }
 
 /** Does *not* set ID->newid pointer. */
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index a8358a97732..f0018f2ff19 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -9204,7 +9204,6 @@ static BHead *read_libblock(FileData *fd,
   /* this routine reads a libblock and its direct data. Use link functions to connect it all
    */
   ID *id;
-  ListBase *lb;
   const char *allocname;
   bool wrong_id = false;
 
@@ -9278,10 +9277,22 @@ static BHead *read_libblock(FileData *fd,
                id ? id->name : "NONE",
                fd->are_memchunks_identical);
 
+  Main *old_bmain = fd->old_mainlist != NULL ? fd->old_mainlist->first : NULL;
+  ID *old_id = NULL;
+  bool do_swap_id_with_old_pointer = false;
+
   BHead *id_bhead = bhead;
 
   if (id) {
     const short idcode = GS(id->name);
+    ListBase *new_lb = which_libbase(main, idcode);
+
+    if (new_lb == NULL) {
+      /* unknown ID type */
+      printf("%s: unknown id code '%c%c'\n", __func__, (idcode & 0xff), (idcode >> 8));
+      MEM_freeN(id);
+      id = NULL;
+    }
 
     if (id_bhead->code != ID_LINK_PLACEHOLDER) {
       /* need a name for the mallocN, just for debugging and sane prints on leaks */
@@ -9297,56 +9308,77 @@ static BHead *read_libblock(FileData *fd,
                    id->name,
                    fd->are_memchunks_identical);
 
-      if (fd->are_memchunks_identical && !ELEM(idcode, ID_WM, ID_SCR, ID_WS)) {
-        BLI_assert(fd->memfile);
-
+      if (fd->memfile != NULL && !ELEM(idcode, ID_WM, ID_SCR, ID_WS)) {
         /* Find the 'current' existing ID we want to reuse instead of the one we would read from
          * the undo memfile. */
-        Main *old_bmain = fd->old_mainlist->first;
         ListBase *old_lb = which_libbase(old_bmain, idcode);
         BLI_assert(old_lb != NULL);
         if (BLI_findindex(old_lb, id_bhead->old) != -1) {
-          MEM_freeN(id);
-          id = (ID *)id_bhead->old;
+          old_id = (ID *)id_bhead->old;
+        }
 
-          id->tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_NEW;
-          id->lib = main->curlib;
-          id->us = ID_FAKE_USERS(id);
-          id->icon_id = 0;
-          id->newid = NULL; /* Needed because .blend may have been saved with crap value here... */
-          id->orig_id = NULL;
+        if (old_id != NULL) {
+          /* If identical, we can simply re-use existing memory, MEM_freeN the read ID (as we did
+           * not do any direct link, nothing else has been linked to it yet), and move old id from
+           * old bmain to new bmain. */
+          if (fd->are_memchunks_identical) {
+            MEM_freeN(id);
+            id = (ID *)id_bhead->old;
 
-          oldnewmap_insert(fd->libmap, id_bhead->old, id, id_bhead->code);
+            id->tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_NEW;
+            id->lib = main->curlib;
+            id->us = ID_FAKE_USERS(id);
+            id->icon_id = 0;
+            id->newid =
+                NULL; /* Needed because .blend may have been saved with crap value here... */
+            id->orig_id = NULL;
 
-          ListBase *new_lb = which_libbase(main, idcode);
-          BLI_remlink(old_lb, id);
-          BLI_addtail(new_lb, id);
+            oldnewmap_insert(fd->libmap, id_bhead->old, id, id_bhead->code);
 
-          if (r_id) {
-            *r_id = id;
+            BLI_remlink(old_lb, id);
+            BLI_addtail(new_lb, id);
+
+            if (r_id) {
+              *r_id = id;
+            }
+
+            oldnewmap_free_unused(fd->datamap);
+            oldnewmap_clear(fd->datamap);
+
+            return bhead;
           }
+          /* ID are not identical, we need to do proper full read, and once everything is done to
+           * swap content of new id and old id, so that we can keep using old id pointer
+           * everywhere, but with updated content from read file. */
+          else {
+            oldnewmap_insert(fd->libmap, id_bhead->old, old_id, id_bhead->code);
 
-          oldnewmap_free_unused(fd->datamap);
-          oldnewmap_clear(fd->datamap);
+            BLI_remlink(old_lb, old_id);
+            BLI_addtail(new_lb, old_id);
+            BLI_addtail(old_lb, id);
+
+            do_swap_id_with_old_pointer = true;
+          }
+        }
+        /* We did not find a matching ID pointer in current bmain, no choice but to do full
+         * reading... In theory this should only happen for created/deleted IDs? */
+        else {
+          oldnewmap_insert(fd->libmap, id_bhead->old, id, id_bhead->code);
 
-          return bhead;
+          BLI_addtail(new_lb, id);
         }
       }
-    }
+      else {
+        oldnewmap_insert(fd->libmap, id_bhead->old, id, id_bhead->code);
 
-    /* do after read_struct, for dna reconstruct */
-    lb = which_libbase(main, idcode);
-    if (lb) {
+        BLI_addtail(new_lb, id);
+      }
+    }
+    else {
       /* for ID_LINK_PLACEHOLDER check */
       oldnewmap_insert(fd->libmap, id_bhead->old, id, id_bhead->code);
 
-      BLI_addtail(lb, id);
-    }
-    else {
-      /* unknown ID type */
-      printf("%s: unknown id code '%c%c'\n", __func__, (idcode & 0xff), (idcode >> 8));
-      MEM_freeN(id);
-      id = NULL;
+      BLI_addtail(new_lb, id);
     }
   }
 
@@ -9514,7 +9546,20 @@ static BHead *read_libblock(FileData *fd,
   oldnewmap_clear(fd->datamap);
 
   if (wrong_id) {
-    BKE_id_free(main, id);
+    if (do_swap_id_with_old_pointer) {
+      BKE_id_free(old_bmain, id);
+    }
+    else {
+      BKE_id_free(main, id);
+    }
+  }
+  else if (do_swap_id_with_old_pointer) {
+    /* We need to do the swapping after all sub-data has been properly read, that way old_id now
+     * contains the full up-to-date data from .blend read, and id contains all old 'current' data
+     * that will be freed together with old bmain.
+     * Note that we do not care about internal self-ID pointers remapping here, this wil be take
+     * care of by liblinking process later on in the reading code. */
+    BKE_id_swap(NULL, id, old_id);
   }
 
   return (bhead);



More information about the Bf-blender-cvs mailing list