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:
authorBastien Montagne <bastien@blender.org>2020-07-03 12:36:27 +0300
committerBastien Montagne <bastien@blender.org>2020-07-03 13:56:21 +0300
commit5fa6bd8a8ddbd13ef58d127546af2f57d1905be4 (patch)
treeea667c7a746f71fcabb0e25e626dc6b520cc1591 /source/blender/blenloader
parent6cb796e98e63aa859f5de762e4d542debfd932eb (diff)
Readfile/Undo: initial refactor of cache preservation code.
Main goal here is to have better specificity using cache keys, to avoid same memroy address being re-used messing up with cache pointers restoration after undo had to re-read a data-block. Once all caches handling are ported to this new system, it should fix random issues like the one reported in T76989. Part of D8183, refactoring how we preserve caches across undo steps in readfile code.
Diffstat (limited to 'source/blender/blenloader')
-rw-r--r--source/blender/blenloader/intern/readblenentry.c4
-rw-r--r--source/blender/blenloader/intern/readfile.c143
-rw-r--r--source/blender/blenloader/intern/readfile.h6
3 files changed, 153 insertions, 0 deletions
diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c
index 1309b3e3c33..a6fe99b2974 100644
--- a/source/blender/blenloader/intern/readblenentry.c
+++ b/source/blender/blenloader/intern/readblenentry.c
@@ -407,8 +407,12 @@ BlendFileData *BLO_read_from_memfile(Main *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);
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 1e855228875..db530b749ad 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,140 @@ 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 IDCacheKey *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));
+
+ IDCacheKey *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 IDCacheKey *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 IDCacheKey *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;
+}
+
+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(
+ BKE_idtype_cache_key_hash, BKE_idtype_cache_key_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;
+ }
+
+ 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_clear_in_old, fd->cache_storage);
+ }
+ FOREACH_MAIN_LISTBASE_ID_END;
+ }
+ FOREACH_MAIN_LISTBASE_END;
+ }
+}
+
+void blo_cache_storage_end(FileData *fd)
+{
+ if (fd->cache_storage != NULL) {
+ BLI_ghash_free(fd->cache_storage->cache_map, NULL, NULL);
+ BLI_memarena_free(fd->cache_storage->memarena);
+ MEM_freeN(fd->cache_storage);
+ fd->cache_storage = NULL;
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -9079,6 +9215,8 @@ static bool direct_link_id(FileData *fd, Main *main, const int tag, ID *id, ID *
return true;
}
+ const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
+
/* XXX Very weakly handled currently, see comment in read_libblock() before trying to
* use it for anything new. */
bool success = true;
@@ -9206,6 +9344,11 @@ static bool direct_link_id(FileData *fd, Main *main, const int tag, ID *id, ID *
break;
}
+ /* try to restore (when undoing) or clear ID's cache pointers. */
+ if (id_type->foreach_cache != NULL) {
+ id_type->foreach_cache(id, blo_cache_storage_entry_restore_in_new, reader.fd->cache_storage);
+ }
+
return success;
}
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index f698d642e33..57c86f7128c 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -30,6 +30,7 @@
#include "DNA_windowmanager_types.h" /* for ReportType */
#include "zlib.h"
+struct BLOCacheStorage;
struct GSet;
struct IDNameLib_Map;
struct Key;
@@ -121,6 +122,7 @@ typedef struct FileData {
struct OldNewMap *soundmap;
struct OldNewMap *volumemap;
struct OldNewMap *packedmap;
+ struct BLOCacheStorage *cache_storage;
struct BHeadSort *bheadmap;
int tot_bheadmap;
@@ -167,6 +169,10 @@ void blo_end_packed_pointer_map(FileData *fd, struct Main *oldmain);
void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd);
void blo_make_old_idmap_from_main(FileData *fd, struct Main *bmain);
+void blo_cache_storage_init(FileData *fd, struct Main *bmain);
+void blo_cache_storage_old_bmain_clear(FileData *fd, struct Main *bmain_old);
+void blo_cache_storage_end(FileData *fd);
+
void blo_filedata_free(FileData *fd);
BHead *blo_bhead_first(FileData *fd);