[Bf-blender-cvs] [b6db147c18d] undo-caches: Initial Refactor of code preserving caches during undo.

Bastien Montagne noreply at git.blender.org
Thu Jul 2 17:44:44 CEST 2020


Commit: b6db147c18d89ed7f308fe93fddd66a1c4d96682
Author: Bastien Montagne
Date:   Thu Jul 2 16:16:55 2020 +0200
Branches: undo-caches
https://developer.blender.org/rBb6db147c18d89ed7f308fe93fddd66a1c4d96682

Initial Refactor of code preserving caches during undo.

This is a proof od concept, it only implements new system for bSound
data-block as test subject.

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

M	source/blender/blenkernel/BKE_idtype.h
M	source/blender/blenkernel/intern/sound.c
M	source/blender/blenloader/BLO_readfile.h
M	source/blender/blenloader/intern/readblenentry.c
M	source/blender/blenloader/intern/readfile.c
M	source/blender/blenloader/intern/readfile.h
A	source/blender/blenloader/intern/readfile.h.autosave

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

diff --git a/source/blender/blenkernel/BKE_idtype.h b/source/blender/blenkernel/BKE_idtype.h
index b6dfadd3b2a..89082c99c2d 100644
--- a/source/blender/blenkernel/BKE_idtype.h
+++ b/source/blender/blenkernel/BKE_idtype.h
@@ -33,6 +33,7 @@ extern "C" {
 #endif
 
 struct ID;
+struct BLOCacheStorageKey;
 struct LibraryForeachIDData;
 struct Main;
 
@@ -63,6 +64,14 @@ typedef void (*IDTypeMakeLocalFunction)(struct Main *bmain, struct ID *id, const
 
 typedef void (*IDTypeForeachIDFunction)(struct ID *id, struct LibraryForeachIDData *data);
 
+typedef void (*IDTypeForeachCacheFunctionCallback)(struct ID *id,
+                                                   const struct BLOCacheStorageKey *cache_key,
+                                                   void **cache_p,
+                                                   void *user_data);
+typedef void (*IDTypeForeachCacheFunction)(struct ID *id,
+                                           IDTypeForeachCacheFunctionCallback function_callback,
+                                           void *user_data);
+
 typedef struct IDTypeInfo {
   /* ********** General IDType data. ********** */
 
@@ -130,6 +139,11 @@ typedef struct IDTypeInfo {
    * pointers) of given data-block.
    */
   IDTypeForeachIDFunction foreach_id;
+
+  /**
+   * Iterator over all cache pointers of given ID.
+   */
+  IDTypeForeachCacheFunction foreach_cache;
 } IDTypeInfo;
 
 /* ********** Declaration of each IDTypeInfo. ********** */
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index a293bc55073..84299818845 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -60,6 +60,8 @@
 #include "BKE_sequencer.h"
 #include "BKE_sound.h"
 
+#include "BLO_readfile.h"
+
 #include "DEG_depsgraph.h"
 #include "DEG_depsgraph_query.h"
 
@@ -112,6 +114,20 @@ static void sound_free_data(ID *id)
   }
 }
 
+static void sound_foreach_cache(ID *id,
+                                IDTypeForeachCacheFunctionCallback function_callback,
+                                void *user_data)
+{
+  bSound *sound = (bSound *)id;
+  BLOCacheStorageKey key = {
+      .id_session_uuid = id->session_uuid,
+      .offset_in_ID = offsetof(bSound, waveform),
+      .cache_v = sound->waveform,
+  };
+
+  function_callback(id, &key, &sound->waveform, user_data);
+}
+
 IDTypeInfo IDType_ID_SO = {
     .id_code = ID_SO,
     .id_filter = FILTER_ID_SO,
@@ -128,6 +144,7 @@ IDTypeInfo IDType_ID_SO = {
     .free_data = sound_free_data,
     .make_local = NULL,
     .foreach_id = NULL,
+    .foreach_cache = sound_foreach_cache,
 };
 
 #ifdef WITH_AUDASPACE
diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h
index e4908eb7257..dfce23559d9 100644
--- a/source/blender/blenloader/BLO_readfile.h
+++ b/source/blender/blenloader/BLO_readfile.h
@@ -193,6 +193,18 @@ struct BlendThumbnail *BLO_thumbnail_from_file(const char *filepath);
 extern const struct bTheme U_theme_default;
 extern const struct UserDef U_default;
 
+/* Management of chaches that we want to preserve across undo's. */
+
+typedef struct BLOCacheStorageKey {
+  /* The session uuid of the ID owning the cached data. */
+  unsigned int id_session_uuid;
+  /* Value uniquely indentifying the cache whithin its ID.
+   * Typically the offset of its member in the data-block struct, but can be anything. */
+  size_t offset_in_ID;
+  /* Actual address of the cached data to save and restore. */
+  void *cache_v;
+} BLOCacheStorageKey;
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c
index 1309b3e3c33..74e91b6bdc5 100644
--- a/source/blender/blenloader/intern/readblenentry.c
+++ b/source/blender/blenloader/intern/readblenentry.c
@@ -400,15 +400,19 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain,
     blo_make_movieclip_pointer_map(fd, oldmain);
 
     /* make lookups of existing sound data in old main */
-    blo_make_sound_pointer_map(fd, oldmain);
+    //    blo_make_sound_pointer_map(fd, oldmain);
 
     /* make lookups of existing volume data in old main */
     blo_make_volume_pointer_map(fd, oldmain);
 
     /* removed packed data from this trick - it's internal data that needs saves */
 
+    blo_cache_storage_init(fd, oldmain);
+
     bfd = blo_read_file_internal(fd, filename);
 
+    blo_cache_storage_old_bmain_clear(fd, oldmain);
+
     /* ensures relinked light caches are not freed */
     blo_end_scene_pointer_map(fd, oldmain);
 
@@ -419,7 +423,7 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain,
     blo_end_movieclip_pointer_map(fd, oldmain);
 
     /* ensures relinked sounds are not freed */
-    blo_end_sound_pointer_map(fd, oldmain);
+    //    blo_end_sound_pointer_map(fd, oldmain);
 
     /* ensures relinked volumes are not freed */
     blo_end_volume_pointer_map(fd, oldmain);
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index e4822c4cb7f..1273aec4592 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -105,6 +105,7 @@
 #include "BLI_ghash.h"
 #include "BLI_linklist.h"
 #include "BLI_math.h"
+#include "BLI_memarena.h"
 #include "BLI_mempool.h"
 #include "BLI_threads.h"
 
@@ -1635,6 +1636,7 @@ void blo_filedata_free(FileData *fd)
     if (fd->old_idmap != NULL) {
       BKE_main_idmap_destroy(fd->old_idmap);
     }
+    blo_cache_storage_end(fd);
     if (fd->bheadmap) {
       MEM_freeN(fd->bheadmap);
     }
@@ -2316,6 +2318,157 @@ void blo_make_old_idmap_from_main(FileData *fd, Main *bmain)
   fd->old_idmap = BKE_main_idmap_create(bmain, false, NULL, MAIN_IDMAP_TYPE_UUID);
 }
 
+typedef struct BLOCacheStorage {
+  GHash *cache_map;
+  MemArena *memarena;
+} BLOCacheStorage;
+
+/** Register a cache data entry to be preserved when reading some undo memfile. */
+static void blo_cache_storage_entry_register(ID *id,
+                                             const BLOCacheStorageKey *key,
+                                             void **UNUSED(cache_p),
+                                             void *cache_storage_v)
+{
+  BLI_assert(key->id_session_uuid == id->session_uuid);
+
+  BLOCacheStorage *cache_storage = cache_storage_v;
+  BLI_assert(!BLI_ghash_haskey(cache_storage->cache_map, key));
+
+  BLOCacheStorageKey *storage_key = BLI_memarena_alloc(cache_storage->memarena,
+                                                       sizeof(*storage_key));
+  *storage_key = *key;
+  BLI_ghash_insert(cache_storage->cache_map, storage_key, POINTER_FROM_UINT(0));
+}
+
+/** Restore a cache data entry from old ID into new one, when reading some undo memfile. */
+static void blo_cache_storage_entry_restore_in_new(ID *UNUSED(id),
+                                                   const BLOCacheStorageKey *key,
+                                                   void **cache_p,
+                                                   void *cache_storage_v)
+{
+  BLOCacheStorage *cache_storage = cache_storage_v;
+
+  if (cache_storage == NULL) {
+    *cache_p = NULL;
+    return;
+  }
+
+  void **value = BLI_ghash_lookup_p(cache_storage->cache_map, key);
+  if (value == NULL) {
+    *cache_p = NULL;
+    return;
+  }
+  *value = POINTER_FROM_UINT(POINTER_AS_UINT(*value) + 1);
+  *cache_p = key->cache_v;
+}
+
+/** Clear as needed a cache data entry from old ID, when reading some undo memfile. */
+static void blo_cache_storage_entry_clear_in_old(ID *UNUSED(id),
+                                                 const BLOCacheStorageKey *key,
+                                                 void **cache_p,
+                                                 void *cache_storage_v)
+{
+  BLOCacheStorage *cache_storage = cache_storage_v;
+
+  void **value = BLI_ghash_lookup_p(cache_storage->cache_map, key);
+  if (value == NULL) {
+    *cache_p = NULL;
+    return;
+  }
+  /* If that cache has been restored into some new ID, we want to remove it from old one, otherwise
+   * keep it there so that it gets properly freed together with its ID. */
+  *cache_p = POINTER_AS_UINT(*value) != 0 ? NULL : key->cache_v;
+}
+
+static uint blo_cache_storage_hash(const void *key_v)
+{
+  const BLOCacheStorageKey *key = key_v;
+  size_t hash = BLI_ghashutil_uinthash(key->id_session_uuid);
+  hash = BLI_ghashutil_combine_hash(hash, BLI_ghashutil_uinthash((uint)key->offset_in_ID));
+  return (uint)BLI_ghashutil_combine_hash(hash, BLI_ghashutil_ptrhash(key->cache_v));
+}
+
+static bool blo_cache_storage_cmp(const void *key_a_v, const void *key_b_v)
+{
+  const BLOCacheStorageKey *key_a = key_a_v;
+  const BLOCacheStorageKey *key_b = key_b_v;
+  return (key_a->id_session_uuid != key_b->id_session_uuid) ||
+         (key_a->offset_in_ID != key_b->offset_in_ID) || (key_a->cache_v != key_b->cache_v);
+}
+
+void blo_cache_storage_init(FileData *fd, Main *bmain)
+{
+  if (fd->memfile != NULL) {
+    BLI_assert(fd->cache_storage == NULL);
+    fd->cache_storage = MEM_mallocN(sizeof(*fd->cache_storage), __func__);
+    fd->cache_storage->memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+    fd->cache_storage->cache_map = BLI_ghash_new(
+        blo_cache_storage_hash, blo_cache_storage_cmp, __func__);
+
+    ListBase *lb;
+    FOREACH_MAIN_LISTBASE_BEGIN (bmain, lb) {
+      ID *id = lb->first;
+      if (id == NULL) {
+        continue;
+      }
+
+      const IDTypeInfo *type_info = BKE_idtype_get_info_from_id(id);
+      if (type_info->foreach_cache == NULL) {
+        continue;
+      }
+
+      FOREACH_MAIN_LISTBASE_ID_BEGIN (lb, id) {
+        if (ID_IS_LINKED(id)) {
+          continue;
+        }
+        type_info->foreach_cache(id, blo_cache_storage_entry_register, fd->cache_storage);
+      }
+      FOREACH_MAIN_LISTBASE_ID_END;
+    }
+    FOREACH_MAIN_LISTBASE_END;
+  }
+  else {
+    fd->cache_storage = NULL;
+  }
+}
+
+void blo_cache_storage_old_bmain_clear(FileData *fd, Main *bmain_old)
+{
+  if (fd->cache_storage != NULL) {
+    ListBase *lb;
+    FOREACH_MAIN_LISTBASE_BEGIN (bmain_old, lb) {
+      ID *id = lb->first;
+      if (id == NULL) {
+        continue

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list