[Bf-blender-cvs] [fbe5254ff3e] uuid-undo-experiments: Merge branch 'master' into uuid-undo-experiments
Bastien Montagne
noreply at git.blender.org
Tue Apr 7 14:31:00 CEST 2020
Commit: fbe5254ff3e2c01bd3e6214b802fe9acdb249726
Author: Bastien Montagne
Date: Tue Apr 7 14:30:01 2020 +0200
Branches: uuid-undo-experiments
https://developer.blender.org/rBfbe5254ff3e2c01bd3e6214b802fe9acdb249726
Merge branch 'master' into uuid-undo-experiments
Conflicts:
source/blender/blenloader/intern/readfile.c
Not really a merge, accepting changes from master and loosing most of
recently added debug prints here... Not a big deal, those are easy to
add back once needed.
===================================================================
===================================================================
diff --cc source/blender/blenloader/intern/readfile.c
index 8f73ce48b37,d4799404ef2..e9015391d1e
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@@ -9688,55 -9380,299 +9392,299 @@@ static bool direct_link_id(FileData *fd
break;
}
- oldnewmap_free_unused(fd->datamap);
- oldnewmap_clear(fd->datamap);
+ return success;
+ }
- if (wrong_id) {
- /* XXX This is probably working OK currently given the very limited scope of that flag.
- * However, it is absolutely **not** handled correctly: it is freeing an ID pointer that has
- * been added to the fd->libmap mapping, which in theory could lead to nice crashes...
- * This should be properly solved at some point. */
- BKE_id_free(main, id);
- if (r_id != NULL) {
- *r_id = NULL;
+ /* Read all data associated with a datablock into datamap. */
+ static BHead *read_data_into_datamap(FileData *fd, BHead *bhead, const char *allocname)
+ {
+ bhead = blo_bhead_next(fd, bhead);
+
+ while (bhead && bhead->code == DATA) {
+ void *data;
+ #if 0
+ /* XXX DUMB DEBUGGING OPTION TO GIVE NAMES for guarded malloc errors */
+ short* sp = fd->filesdna->structs[bhead->SDNAnr];
+ char* tmp = malloc(100);
+ allocname = fd->filesdna->types[sp[0]];
+ strcpy(tmp, allocname);
+ data = read_struct(fd, bhead, tmp);
+ #else
+ data = read_struct(fd, bhead, allocname);
+ #endif
+
+ if (data) {
+ oldnewmap_insert(fd->datamap, bhead->old, data, 0);
}
+
+ bhead = blo_bhead_next(fd, bhead);
}
- else if (do_id_swap) {
- /* 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);
+ return bhead;
+ }
- Main *old_bmain = fd->old_mainlist->first;
- BLI_assert(id_old != NULL);
+ /* Verify if the datablock and all associated data is identical. */
+ static bool read_libblock_is_identical(FileData *fd, BHead *bhead)
+ {
+ /* Test ID itself. */
+ if (bhead->len && !BHEADN_FROM_BHEAD(bhead)->is_memchunk_identical) {
+ return false;
+ }
- 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);
+ /* Test any other data that is part of ID (logic must match read_data_into_datamap). */
+ bhead = blo_bhead_next(fd, bhead);
- /* 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);
+ while (bhead && bhead->code == DATA) {
+ if (bhead->len && !BHEADN_FROM_BHEAD(bhead)->is_memchunk_identical) {
+ return false;
+ }
- BLI_addtail(new_lb, id_old);
- BLI_addtail(old_lb, id);
+ bhead = blo_bhead_next(fd, 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
+ * (see BLO_read_from_memfile).
+ * However, some needed by the snapshot being read may have been removed in previous one,
+ * and would go missing.
+ * This leads e.g. to disappearing objects in some undo/redo case, see T34446.
+ * That means we have to carefully check whether current lib or
+ * libdata already exits in old main, if it does we merely copy it over into new main area,
+ * otherwise we have to do a full read of that bhead... */
+ DEBUG_PRINTF("UNDO: restore library %s\n", id->name);
+
+ Main *libmain = fd->old_mainlist->first;
+ /* Skip oldmain itself... */
+ for (libmain = libmain->next; libmain; libmain = libmain->next) {
+ DEBUG_PRINTF(" compare with %s -> ", libmain->curlib ? libmain->curlib->id.name : "<NULL>");
+ if (libmain->curlib && STREQ(id->name, libmain->curlib->id.name)) {
+ Main *oldmain = fd->old_mainlist->first;
+ DEBUG_PRINTF("match!\n");
+ /* In case of a library, we need to re-add its main to fd->mainlist,
+ * because if we have later a missing ID_LINK_PLACEHOLDER,
+ * we need to get the correct lib it is linked to!
+ * Order is crucial, we cannot bulk-add it in BLO_read_from_memfile()
+ * like it used to be. */
+ BLI_remlink(fd->old_mainlist, libmain);
+ BLI_remlink_safe(&oldmain->libraries, libmain->curlib);
+ BLI_addtail(fd->mainlist, libmain);
+ BLI_addtail(&main->libraries, libmain->curlib);
+ return true;
+ }
+ DEBUG_PRINTF("no match\n");
+ }
- if (DEBUG_CHECK_ID_FOR_UNDO(id_old)) {
- printf("ID %s will have recalc flags: ", id_old->name);
- DEG_id_recalc_print(id_old);
- printf("\n\n");
+ 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);
+ DEBUG_PRINTF(" from %s (%s): ",
+ main->curlib ? main->curlib->id.name : "<NULL>",
+ main->curlib ? main->curlib->name : "<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 (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. */
+ return true;
+ }
+
+ DEBUG_PRINTF(" not found\n");
+ 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,
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list