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:
authorBrecht Van Lommel <brecht@blender.org>2020-04-04 18:38:07 +0300
committerBrecht Van Lommel <brecht@blender.org>2020-04-07 14:19:52 +0300
commite953ada0bb9d22108e3a96b8faecfaa58c97caac (patch)
tree75d3f01c235e6bdd977d5108cb38a6e61227c182 /source/blender/blenloader
parentc786f9587123b55afc412d1645977c29865ba9c6 (diff)
Cleanup: avoid memory allocation for unchanged datablocks in undo
Differential Revision: https://developer.blender.org/D7336
Diffstat (limited to 'source/blender/blenloader')
-rw-r--r--source/blender/blenloader/intern/readfile.c190
1 files changed, 104 insertions, 86 deletions
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index d23d61b4d20..d4799404ef2 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -2384,6 +2384,15 @@ static void *read_struct(FileData *fd, BHead *bh, const char *blockname)
return temp;
}
+/* Like read_struct, but gets a pointer without allocating. Only works for
+ * undo since DNA must match. */
+static const void *peek_struct_undo(FileData *fd, BHead *bhead)
+{
+ BLI_assert(fd->memfile != NULL);
+ UNUSED_VARS_NDEBUG(fd);
+ return (bhead->len) ? (const void *)(bhead + 1) : NULL;
+}
+
typedef void (*link_list_cb)(FileData *fd, void *data);
static void link_list_ex(FileData *fd, ListBase *lb, link_list_cb callback) /* only direct data */
@@ -9568,6 +9577,78 @@ static void read_libblock_undo_restore_at_old_address(FileData *fd, Main *main,
BLI_addtail(old_lb, id);
}
+static bool read_libblock_undo_restore(
+ FileData *fd, Main *main, BHead *bhead, const int tag, ID **r_id_old)
+{
+ /* Get pointer to memory of new ID that we will be reading. */
+ const ID *id = peek_struct_undo(fd, bhead);
+ const short idcode = GS(id->name);
+
+ if (bhead->code == ID_LI) {
+ /* Restore library datablock. */
+ if (read_libblock_undo_restore_library(fd, main, id)) {
+ return true;
+ }
+ }
+ else if (bhead->code == ID_LINK_PLACEHOLDER) {
+ /* Restore linked datablock. */
+ if (read_libblock_undo_restore_linked(fd, main, id, bhead)) {
+ return true;
+ }
+ }
+ else if (ELEM(idcode, ID_WM, ID_SCR, ID_WS)) {
+ /* Skip reading any UI datablocks, existing ones are kept. We don't
+ * support pointers from other datablocks to UI datablocks so those
+ * we also don't put UI datablocks in fd->libmap. */
+ return true;
+ }
+
+ /* Restore local datablocks. */
+ DEBUG_PRINTF("UNDO: read %s (uuid %d) -> ", id->name, id->session_uuid);
+
+ ID *id_old = NULL;
+ 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);
+
+ /* 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);
+ }
+
+ if (id_old != NULL && read_libblock_is_identical(fd, bhead)) {
+ /* Local datablock was unchanged, restore from the old main. */
+ DEBUG_PRINTF("keep identical datablock\n");
+
+ /* 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 code), but for sake of consistency, and also because
+ * it will tell us which ID is re-used from old Main, and which one is actually new. */
+ const int id_tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_UNDO_OLD_ID_REUSED;
+ read_libblock_undo_restore_identical(fd, main, id, id_old, id_tag);
+
+ /* Insert into library map for lookup by newly read datablocks (with pointer
+ * value bhead->old) or existing datablocks in memory (pointer value id_old). */
+ oldnewmap_insert(fd->libmap, bhead->old, id_old, bhead->code);
+ oldnewmap_insert(fd->libmap, id_old, id_old, bhead->code);
+
+ *r_id_old = id_old;
+ return true;
+ }
+ else if (id_old != NULL) {
+ /* Local datablock was changed. Restore at the address of the old datablock. */
+ DEBUG_PRINTF("read to old existing address\n");
+ *r_id_old = id_old;
+ return false;
+ }
+ else {
+ /* Local datablock does not exist in the undo step, so read from scratch. */
+ DEBUG_PRINTF("read at new address\n");
+ return false;
+ }
+}
+
/* 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.
@@ -9582,107 +9663,48 @@ static BHead *read_libblock(FileData *fd,
const bool placeholder_set_indirect_extern,
ID **r_id)
{
- /* Initialize in case of early return. */
- if (r_id) {
- *r_id = NULL;
+ /* First attemp to restore existing datablocks for undo.
+ * When datablocks are changed but still exist, we restore them at the old
+ * address and inherit recalc flags for the dependency graph. */
+ ID *id_old = NULL;
+ if (fd->memfile != NULL) {
+ if (read_libblock_undo_restore(fd, main, bhead, tag, &id_old)) {
+ if (r_id) {
+ *r_id = id_old;
+ }
+ return blo_bhead_next(fd, bhead);
+ }
}
/* Read libblock struct. */
- BHead *id_bhead = bhead;
ID *id = read_struct(fd, bhead, "lib block");
if (id == NULL) {
+ if (r_id) {
+ *r_id = NULL;
+ }
return blo_bhead_next(fd, bhead);
}
- /* Determine ID type. */
+ /* Determine ID type and add to main database list. */
const short idcode = GS(id->name);
ListBase *lb = which_libbase(main, idcode);
if (lb == NULL) {
/* Unknown ID type. */
printf("%s: unknown id code '%c%c'\n", __func__, (idcode & 0xff), (idcode >> 8));
MEM_freeN(id);
+ if (r_id) {
+ *r_id = NULL;
+ }
return blo_bhead_next(fd, bhead);
}
- /* 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);
- }
- }
- else if (ELEM(idcode, ID_WM, ID_SCR, ID_WS)) {
- /* Skip reading any UI datablocks, existing ones are kept. We don't
- * support pointers from other datablocks to UI datablocks so those
- * we also don't put UI datablocks in fd->libmap. */
- MEM_freeN(id);
- return blo_bhead_next(fd, bhead);
- }
-
- /* Restore local datablocks. */
- DEBUG_PRINTF("UNDO: read %s (uuid %d) -> ", id->name, id->session_uuid);
-
- 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);
-
- /* 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);
- }
-
- 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");
-
- /* 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 code), but for sake of consistency, and also because
- * it will tell us which ID is re-used from old Main, and which one is actually new. */
- const int id_tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_UNDO_OLD_ID_REUSED;
- read_libblock_undo_restore_identical(fd, main, id, id_old, id_tag);
-
- /* Insert into library map for lookup by newly read datablocks (with pointer
- * value bhead->old) or existing datablocks in memory (pointer value id_old). */
- oldnewmap_insert(fd->libmap, bhead->old, id_old, bhead->code);
- oldnewmap_insert(fd->libmap, id_old, id_old, bhead->code);
-
- if (r_id) {
- *r_id = id_old;
- }
-
- MEM_freeN(id);
- return blo_bhead_next(fd, bhead);
- }
- else if (id_old != NULL) {
- /* Local datablock was changed. Restore at the address of the old datablock. */
- DEBUG_PRINTF("read to old existing address\n");
- BLI_assert(MEM_allocN_len(id) == MEM_allocN_len(id_old));
- restore_at_old_address = true;
- }
- else {
- /* Local datablock does not exist in the undo step, so read from scratch. */
- DEBUG_PRINTF("read at new address\n");
- }
- }
+ /* NOTE: id must be added to the list before direct_link_id(), since
+ * direct_link_library() may remove it from there in case of duplicates. */
+ BLI_addtail(lb, id);
/* Insert into library map for lookup by newly read datablocks (with pointer
* value bhead->old) or existing datablocks in memory (pointer value id_old). */
- ID *id_target = restore_at_old_address ? id_old : id;
+ ID *id_target = id_old ? id_old : id;
oldnewmap_insert(fd->libmap, bhead->old, id_target, bhead->code);
oldnewmap_insert(fd->libmap, id_old, id_target, bhead->code);
@@ -9690,10 +9712,6 @@ static BHead *read_libblock(FileData *fd,
*r_id = id_target;
}
- /* NOTE: id must be added to the list before direct_link_id(), since
- * direct_link_library() may remove it from there in case of duplicates. */
- BLI_addtail(lb, id);
-
/* Set tag for new datablock to indicate lib linking and versioning needs
* to be done still. */
int id_tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_NEW;
@@ -9732,7 +9750,7 @@ static BHead *read_libblock(FileData *fd,
*r_id = NULL;
}
}
- else if (restore_at_old_address) {
+ else if (id_old) {
/* For undo, store contents read into id at id_old. */
read_libblock_undo_restore_at_old_address(fd, main, id, id_old);
}