[Bf-blender-cvs] [c786f958712] master: Cleanup: split partial undo code off into functions, tweak debug prints

Brecht Van Lommel noreply at git.blender.org
Tue Apr 7 13:23:37 CEST 2020


Commit: c786f9587123b55afc412d1645977c29865ba9c6
Author: Brecht Van Lommel
Date:   Fri Apr 3 14:31:05 2020 +0200
Branches: master
https://developer.blender.org/rBc786f9587123b55afc412d1645977c29865ba9c6

Cleanup: split partial undo code off into functions, tweak debug prints

Differential Revision: https://developer.blender.org/D7331

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

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

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

diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 06f53a6c640..d23d61b4d20 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -9424,6 +9424,7 @@ static bool read_libblock_is_identical(FileData *fd, BHead *bhead)
   return true;
 }
 
+/* For undo, restore matching library datablock from the old main. */
 static bool read_libblock_undo_restore_library(FileData *fd, Main *main, const ID *id)
 {
   /* In undo case, most libs and linked data should be kept as is from previous state
@@ -9460,6 +9461,7 @@ static bool read_libblock_undo_restore_library(FileData *fd, Main *main, const I
   return false;
 }
 
+/* For undo, restore existing linked datablock from the old main. */
 static bool read_libblock_undo_restore_linked(FileData *fd, Main *main, const ID *id, BHead *bhead)
 {
   DEBUG_PRINTF("UNDO: restore linked datablock %s\n", id->name);
@@ -9467,17 +9469,17 @@ static bool read_libblock_undo_restore_linked(FileData *fd, Main *main, const ID
                main->curlib ? main->curlib->id.name : "<NULL>",
                main->curlib ? main->curlib->name : "<NULL>");
 
-  ID *existing_id = BKE_libblock_find_name(main, GS(id->name), id->name + 2);
-  if (existing_id != NULL) {
+  ID *id_old = BKE_libblock_find_name(main, GS(id->name), id->name + 2);
+  if (id_old != NULL) {
     DEBUG_PRINTF("  found!\n");
-    /* Even though we found our linked ID,
-     * there is no guarantee its address is still the same. */
-    if (existing_id != bhead->old) {
-      oldnewmap_insert(fd->libmap, bhead->old, existing_id, GS(existing_id->name));
+    /* Even though we found our linked ID, there is no guarantee its address
+     * is still the same. */
+    if (id_old != bhead->old) {
+      oldnewmap_insert(fd->libmap, bhead->old, id_old, GS(id_old->name));
     }
 
-    /* No need to do anything else for ID_LINK_PLACEHOLDER,
-     * it's assumed already present in its lib's main. */
+    /* No need to do anything else for ID_LINK_PLACEHOLDER, it's assumed
+     * already present in its lib's main. */
     return true;
   }
 
@@ -9485,6 +9487,94 @@ static bool read_libblock_undo_restore_linked(FileData *fd, Main *main, const ID
   return false;
 }
 
+/* For undo, restore unchanged datablock from old main. */
+static void read_libblock_undo_restore_identical(
+    FileData *fd, Main *main, const ID *id, ID *id_old, const int tag)
+{
+  BLI_assert((fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0);
+  BLI_assert(id_old != NULL);
+
+  id_old->tag = tag;
+  id_old->lib = main->curlib;
+  id_old->us = ID_FAKE_USERS(id_old);
+  /* Do not reset id->icon_id here, memory allocated for it remains valid. */
+  /* Needed because .blend may have been saved with crap value here... */
+  id_old->newid = NULL;
+  id_old->orig_id = NULL;
+
+  /* About recalc: since that ID did not change at all, we know that its recalc fields also
+   * remained unchanged, so no need to handle neither recalc nor recalc_undo_future here.
+   */
+
+  const short idcode = GS(id_old->name);
+  Main *old_bmain = fd->old_mainlist->first;
+  ListBase *old_lb = which_libbase(old_bmain, idcode);
+  ListBase *new_lb = which_libbase(main, idcode);
+  BLI_remlink(old_lb, id_old);
+  BLI_addtail(new_lb, id_old);
+
+  /* Even though we re-use the old ID as-is, it does not mean that we are 100% safe from
+   * needing some depsgraph updates for it (it could depend on another ID which address
+   * did not change, but which actual content might have been re-read from the memfile).
+   * IMPORTANT: Do not fully overwrite recalc flag here, depsgraph may not have been ran
+   * yet for previous undo step(s), we do not want to erase flags set by those.
+   */
+  if (fd->undo_direction < 0) {
+    /* We are coming from the future (i.e. do an actual undo, and not a redo), we use our
+     * old reused ID's 'accumulated recalc flags since last memfile undo step saving' as
+     * recalc flags. */
+    id_old->recalc |= id_old->recalc_undo_accumulated;
+  }
+  else {
+    /* We are coming from the past (i.e. do a redo), we use the saved 'accumulated recalc
+     * flags since last memfile undo step saving' from the newly read ID as recalc flags.
+     */
+    id_old->recalc |= id->recalc_undo_accumulated;
+  }
+  /* There is no need to flush the depsgraph's CoWs here, since that ID's data itself did
+   * not change. */
+
+  /* We need to 'accumulate' the accumulated recalc flags of all undo steps until we
+   * actually perform a depsgraph update, otherwise we'd only ever use the flags from one
+   * of the steps, and never get proper flags matching all others. */
+  id_old->recalc_undo_accumulated |= id->recalc_undo_accumulated;
+}
+
+/* For undo, store changed datablock at old address. */
+static void read_libblock_undo_restore_at_old_address(FileData *fd, Main *main, ID *id, ID *id_old)
+{
+  /* During memfile undo, if an ID changed and we cannot directly re-use existing one from old
+   * bmain, we do a full read of the new id from the memfile, and then fully swap its content
+   * with the old id. This allows us to keep the same pointer even for modified data, which
+   * helps reducing further detected changes by the depsgraph (since unchanged IDs remain fully
+   * unchanged, even if they are using/pointing to a changed one). */
+  BLI_assert((fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0);
+  BLI_assert(id_old != NULL);
+
+  const short idcode = GS(id->name);
+
+  Main *old_bmain = fd->old_mainlist->first;
+  ListBase *old_lb = which_libbase(old_bmain, idcode);
+  ListBase *new_lb = which_libbase(main, idcode);
+  BLI_remlink(old_lb, id_old);
+  BLI_remlink(new_lb, id);
+
+  /* We do not need any remapping from this call here, since no ID pointer is valid in the data
+   * currently (they are all pointing to old addresses, and need to go through `lib_link`
+   * process). So we can pass NULL for the Main pointer parameter. */
+  BKE_lib_id_swap_full(NULL, id, id_old);
+
+  BLI_addtail(new_lb, id_old);
+  BLI_addtail(old_lb, id);
+}
+
+/* This routine reads a datablock and its direct data, and advances bhead to
+ * the next datablock. For library linked datablocks, only a placeholder will
+ * be generated, to be replaced in read_library_linked_ids.
+ *
+ * When reading for undo, libraries, linked datablocks and unchanged datablocks
+ * will be restored from the old database. Only new or changed datablocks will
+ * actually be read. */
 static BHead *read_libblock(FileData *fd,
                             Main *main,
                             BHead *bhead,
@@ -9492,10 +9582,9 @@ static BHead *read_libblock(FileData *fd,
                             const bool placeholder_set_indirect_extern,
                             ID **r_id)
 {
-  /* This routine reads a libblock and its direct data. Lib link functions will
-   * set points between datablocks. */
+  /* Initialize in case of early return. */
   if (r_id) {
-    *r_id = NULL; /* In case of early return. */
+    *r_id = NULL;
   }
 
   /* Read libblock struct. */
@@ -9515,15 +9604,21 @@ static BHead *read_libblock(FileData *fd,
     return blo_bhead_next(fd, bhead);
   }
 
-  /* Restore library and linked datablocks for undo. */
+  /* Used when undoing from memfile, we swap changed IDs into their old addresses when found. */
+  ID *id_old = NULL;
+  bool restore_at_old_address = false;
+
+  /* Restore existing datablocks for undo. */
   if (fd->memfile != NULL) {
     if (bhead->code == ID_LI) {
+      /* Restore library datablock. */
       if (read_libblock_undo_restore_library(fd, main, id)) {
         MEM_freeN(id);
         return blo_bhead_next(fd, bhead);
       }
     }
     else if (bhead->code == ID_LINK_PLACEHOLDER) {
+      /* Restore linked datablock. */
       if (read_libblock_undo_restore_linked(fd, main, id, bhead)) {
         MEM_freeN(id);
         return blo_bhead_next(fd, bhead);
@@ -9536,55 +9631,33 @@ static BHead *read_libblock(FileData *fd,
       MEM_freeN(id);
       return blo_bhead_next(fd, bhead);
     }
-  }
 
-  /* Restore existing datablocks for undo. */
-  const bool do_partial_undo = (fd->memfile != NULL) &&
-                               (fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0 &&
-                               (bhead->code != ID_LINK_PLACEHOLDER);
+    /* Restore local datablocks. */
+    DEBUG_PRINTF("UNDO: read %s (uuid %d) -> ", id->name, id->session_uuid);
 
-  /* Used when undoing from memfile, we swap changed IDs into their old addresses when found. */
-  ID *id_old = NULL;
-  bool do_id_swap = false;
+    const bool do_partial_undo = (fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0;
+    if (do_partial_undo && (bhead->code != ID_LINK_PLACEHOLDER)) {
+      /* This code should only ever be reached for local data-blocks. */
+      BLI_assert(main->curlib == NULL);
 
-  if (do_partial_undo) {
-    const bool is_identical = read_libblock_is_identical(fd, id_bhead);
-    DEBUG_PRINTF("%s: ID %s is unchanged: %d\n", __func__, id->name, is_identical);
-
-    BLI_assert(fd->old_idmap != NULL || !do_partial_undo);
-    /* This code should only ever be reached for local data-blocks. */
-    BLI_assert(main->curlib == NULL);
+      /* Find the 'current' existing ID we want to reuse instead of the one we
+       * would read from the undo memfile. */
+      BLI_assert(fd->old_idmap != NULL);
+      id_old = BKE_main_idmap_lookup_uuid(fd->old_idmap, id->session_uuid);
+    }
 
-    /* Find the 'current' existing ID we want to reuse instead of the one we would read from
-     * the undo memfile. */
-    DEBUG_PRINTF("\t Looking for ID %s with uuid %u instead of newly read one\n",
-                 id->name,
-                 id->session_uuid);
-    id_old = BKE_main_idmap_lookup_uuid(fd->old_idmap, id->session_uuid);
+    if (id_old != NULL && read_libblock_is_identical(fd, id_bhead)) {
+      /* Local datablock was unchanged, restore from the old main. */
+      DEBUG_PRINTF("keep identical datablock\n");
 
-    if (id_old != NULL && is_identical) {
       /* Do not add LIB_TAG_NEW here, this should not be needed/used in undo case anyway (as
        * this is only for do_version-like co

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list