writefile: avoid adding SDNA to every undo step
authorCampbell Barton <ideasman42@gmail.com>
Wed, 6 Jul 2016 12:23:50 +0000 (22:23 +1000)
committerCampbell Barton <ideasman42@gmail.com>
Wed, 6 Jul 2016 13:07:37 +0000 (23:07 +1000)
Since SDNA was allocated for each undo step,
the new address meant it was considered different and included again.

Add an option not to duplicate the DNA string when calling DNA_sdna_from_data,
as well as avoiding a redundant copy, it writes the same address each time.

source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/makesdna/DNA_genfile.h
source/blender/makesdna/DNA_sdna_types.h
source/blender/makesdna/intern/dna_genfile.c
source/blender/makesrna/intern/rna_define.c

index b09ea45469c6d60f89ef32d5c6dd73e6ca43efa7..0dd099df79be5027219476461a7f2e6bc43394e6 100644 (file)
@@ -918,7 +918,7 @@ static int read_file_dna(FileData *fd)
                if (bhead->code == DNA1) {
                        const bool do_endian_swap = (fd->flags & FD_FLAGS_SWITCH_ENDIAN) != 0;
                        
-                       fd->filesdna = DNA_sdna_from_data(&bhead[1], bhead->len, do_endian_swap);
+                       fd->filesdna = DNA_sdna_from_data(&bhead[1], bhead->len, do_endian_swap, true);
                        if (fd->filesdna) {
                                fd->compflags = DNA_struct_get_compareflags(fd->filesdna, fd->memsdna);
                                /* used to retrieve ID names from (bhead+1) */
@@ -1078,7 +1078,7 @@ static FileData *filedata_new(void)
         * but it keeps us re-entrant,  remove once we have
         * a lib that provides a nice lock. - zr
         */
-       fd->memsdna = DNA_sdna_from_data(DNAstr, DNAlen, false);
+       fd->memsdna = DNA_sdna_from_data(DNAstr, DNAlen, false, false);
        
        fd->datamap = oldnewmap_new();
        fd->globmap = oldnewmap_new();
index bbbe04dd24e485ad30b20e93db9623f9131f3b28..77df7ae04312d9f579f237aae400957ca25cec4f 100644 (file)
@@ -325,7 +325,7 @@ static WriteData *writedata_new(WriteWrap *ww)
 {
        WriteData *wd = MEM_callocN(sizeof(*wd), "writedata");
 
-       wd->sdna = DNA_sdna_from_data(DNAstr, DNAlen, false);
+       wd->sdna = DNA_sdna_from_data(DNAstr, DNAlen, false, false);
 
        wd->ww = ww;
 
@@ -4013,6 +4013,10 @@ static bool write_file_handle(
        write_thumb(wd, thumb);
        write_global(wd, write_flags, mainvar);
 
+       /* The windowmanager and screen often change,
+        * avoid thumbnail detecting changes because of this. */
+       mywrite(wd, MYWRITE_FLUSH, 0);
+
        write_windowmanagers(wd, &mainvar->wm);
        write_screens(wd, &mainvar->screen);
        write_movieclips(wd, &mainvar->movieclip);
@@ -4046,11 +4050,17 @@ static bool write_file_handle(
        write_linestyles(wd, &mainvar->linestyle);
        write_libraries(wd,  mainvar->next);
 
+       /* So changes above don't cause a 'DNA1' to be detected as changed on undo. */
+       mywrite(wd, MYWRITE_FLUSH, 0);
+
        if (write_flags & G_FILE_USERPREFS) {
                write_userdef(wd);
        }
 
-       /* dna as last, because (to be implemented) test for which structs are written */
+       /* Write DNA last, because (to be implemented) test for which structs are written.
+        *
+        * Note that we *borrow* the pointer to 'DNAstr',
+        * so writing each time uses the same address and doesn't cause unnecessary undo overhead. */
        writedata(wd, DNA1, wd->sdna->datalen, wd->sdna->data);
 
 #ifdef USE_NODE_COMPAT_CUSTOMNODES
index d62369803d658dcc99f55883764d83d51bbc1cce..77877f7bada982514c06ce81cf86c5f7d8cc8f41 100644 (file)
@@ -74,7 +74,9 @@ enum eSDNA_StructCompare {
        SDNA_CMP_NOT_EQUAL  = 2,
 };
 
-struct SDNA *DNA_sdna_from_data(const void *data, const int datalen, bool do_endian_swap);
+struct SDNA *DNA_sdna_from_data(
+        const void *data, const int datalen,
+        bool do_endian_swap, bool data_alloc);
 void DNA_sdna_free(struct SDNA *sdna);
 
 int DNA_struct_find_nr(struct SDNA *sdna, const char *str);
index cb7a371c7c5205d9a541276ce2c5901687aa0a61..791aca77558e434a4c490c5288f238c8329ccf50 100644 (file)
@@ -35,8 +35,9 @@
 #
 #
 typedef struct SDNA {
-       char *data;                     /* full copy of 'encoded' data */
+       const char *data;                       /* full copy of 'encoded' data */
        int datalen;            /* length of data */
+       bool data_alloc;
 
        int nr_names;           /* total number of struct members */
        const char **names;             /* struct member names */
index 99ab29fbdcc6bedc45e61378fbf771d102e06ace..9135d7bab7d7a6709100ffc757843e03b8a296b4 100644 (file)
@@ -196,7 +196,10 @@ int DNA_elem_array_size(const char *str)
 
 void DNA_sdna_free(SDNA *sdna)
 {
-       MEM_freeN(sdna->data);
+       if (sdna->data_alloc) {
+               MEM_freeN((void *)sdna->data);
+       }
+
        MEM_freeN((void *)sdna->names);
        MEM_freeN(sdna->types);
        MEM_freeN(sdna->structs);
@@ -549,15 +552,24 @@ static void init_structDNA(SDNA *sdna, bool do_endian_swap)
 /**
  * Constructs and returns a decoded SDNA structure from the given encoded SDNA data block.
  */
-SDNA *DNA_sdna_from_data(const void *data, const int datalen, bool do_endian_swap)
+SDNA *DNA_sdna_from_data(
+        const void *data, const int datalen,
+        bool do_endian_swap, bool data_alloc)
 {
        SDNA *sdna = MEM_mallocN(sizeof(*sdna), "sdna");
        
        sdna->lastfind = 0;
 
        sdna->datalen = datalen;
-       sdna->data = MEM_mallocN(datalen, "sdna_data");
-       memcpy(sdna->data, data, datalen);
+       if (data_alloc) {
+               char *data_copy = MEM_mallocN(datalen, "sdna_data");
+               memcpy(data_copy, data, datalen);
+               sdna->data = data_copy;
+       }
+       else {
+               sdna->data = data;
+       }
+       sdna->data_alloc = data_alloc;
        
        init_structDNA(sdna, do_endian_swap);
        
index 36e2b9b0572194645a33fa9d5eca669b26b19f01..bf2b091576e39c727e27135945ca311a4dcbece6 100644 (file)
@@ -532,7 +532,7 @@ BlenderRNA *RNA_create(void)
 
        brna = MEM_callocN(sizeof(BlenderRNA), "BlenderRNA");
 
-       DefRNA.sdna = DNA_sdna_from_data(DNAstr,  DNAlen, false);
+       DefRNA.sdna = DNA_sdna_from_data(DNAstr, DNAlen, false, false);
        BLI_listbase_clear(&DefRNA.structs);
        DefRNA.error = 0;
        DefRNA.preprocess = 1;