diff options
author | Bastien Montagne <bastien@blender.org> | 2020-07-03 12:36:27 +0300 |
---|---|---|
committer | Bastien Montagne <bastien@blender.org> | 2020-07-03 13:56:21 +0300 |
commit | 5fa6bd8a8ddbd13ef58d127546af2f57d1905be4 (patch) | |
tree | ea667c7a746f71fcabb0e25e626dc6b520cc1591 /source/blender/blenloader/intern | |
parent | 6cb796e98e63aa859f5de762e4d542debfd932eb (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/intern')
-rw-r--r-- | source/blender/blenloader/intern/readblenentry.c | 4 | ||||
-rw-r--r-- | source/blender/blenloader/intern/readfile.c | 143 | ||||
-rw-r--r-- | source/blender/blenloader/intern/readfile.h | 6 |
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); |