From 8e0f8bb3e153d5cae0050ceb90e6b561069fe05b Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 3 Jul 2020 12:34:20 +0200 Subject: New undo cache management: Add Image IDs. Some notes: * `Image.cache` acts as some kind of 'main' cache, when it is NULL (could not be restored), other caches should also be cleared. Oddly enough, previous code was not clearing **all** caches, could not find any reason for that behavior, so new code does a full clear. * `imamap` is still used for Node previews from scenes' compositor, however this is actually fully disabled in `direct_link_node()`. * For render slots we cannot use offsetof as third part of the cache key, so we are using a hash of the slot's name instead. As far as I can tell, this fixes T76989: Visual glitches when undo after reload multiple images by script (in Material Preview). --- source/blender/blenkernel/intern/image.c | 32 ++++++++++ source/blender/blenloader/intern/readfile.c | 95 +++-------------------------- 2 files changed, 41 insertions(+), 86 deletions(-) diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index bb793b58a1d..e1d055512f0 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -185,6 +185,37 @@ static void image_free_data(ID *id) BLI_freelistN(&image->tiles); } +static void image_foreach_cache(ID *id, + IDTypeForeachCacheFunctionCallback function_callback, + void *user_data) +{ + Image *image = (Image *)id; + IDCacheKey key = { + .id_session_uuid = id->session_uuid, + .offset_in_ID = offsetof(Image, cache), + .cache_v = image->cache, + }; + function_callback(id, &key, (void **)&image->cache, user_data); + + for (int eye = 0; eye < 2; eye++) { + for (int a = 0; a < TEXTARGET_COUNT; a++) { + key.offset_in_ID = offsetof(Image, gputexture[a][eye]); + key.cache_v = image->gputexture[a][eye]; + function_callback(id, &key, (void **)&image->gputexture[a][eye], user_data); + } + } + + key.offset_in_ID = offsetof(Image, rr); + key.cache_v = image->rr; + function_callback(id, &key, (void **)&image->rr, user_data); + + LISTBASE_FOREACH (RenderSlot *, slot, &image->renderslots) { + key.offset_in_ID = (size_t)BLI_ghashutil_strhash_p(slot->name); + key.cache_v = slot->render; + function_callback(id, &key, (void **)&slot->render, user_data); + } +} + IDTypeInfo IDType_ID_IM = { .id_code = ID_IM, .id_filter = FILTER_ID_IM, @@ -200,6 +231,7 @@ IDTypeInfo IDType_ID_IM = { .free_data = image_free_data, .make_local = NULL, .foreach_id = NULL, + .foreach_cache = image_foreach_cache, }; /* prototypes */ diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index db530b749ad..28bab96cc6d 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -1959,32 +1959,9 @@ void blo_end_scene_pointer_map(FileData *fd, Main *oldmain) void blo_make_image_pointer_map(FileData *fd, Main *oldmain) { - Image *ima = oldmain->images.first; Scene *sce = oldmain->scenes.first; - int a; - fd->imamap = oldnewmap_new(); - for (; ima; ima = ima->id.next) { - if (ima->cache) { - oldnewmap_insert(fd->imamap, ima->cache, ima->cache, 0); - } - for (int eye = 0; eye < 2; eye++) { - for (a = 0; a < TEXTARGET_COUNT; a++) { - if (ima->gputexture[a][eye] != NULL) { - oldnewmap_insert(fd->imamap, ima->gputexture[a][eye], ima->gputexture[a][eye], 0); - } - } - } - if (ima->rr) { - oldnewmap_insert(fd->imamap, ima->rr, ima->rr, 0); - } - LISTBASE_FOREACH (RenderSlot *, slot, &ima->renderslots) { - if (slot->render) { - oldnewmap_insert(fd->imamap, slot->render, slot->render, 0); - } - } - } for (; sce; sce = sce->id.next) { if (sce->nodetree && sce->nodetree->previews) { bNodeInstanceHashIterator iter; @@ -2001,7 +1978,6 @@ void blo_make_image_pointer_map(FileData *fd, Main *oldmain) void blo_end_image_pointer_map(FileData *fd, Main *oldmain) { OldNew *entry = fd->imamap->entries; - Image *ima = oldmain->images.first; Scene *sce = oldmain->scenes.first; int i; @@ -2012,29 +1988,6 @@ void blo_end_image_pointer_map(FileData *fd, Main *oldmain) } } - for (; ima; ima = ima->id.next) { - ima->cache = newimaadr(fd, ima->cache); - if (ima->cache == NULL) { - ima->gpuflag = 0; - ima->gpuframenr = INT_MAX; - for (int eye = 0; eye < 2; eye++) { - for (i = 0; i < TEXTARGET_COUNT; i++) { - ima->gputexture[i][eye] = NULL; - } - } - ima->rr = NULL; - } - LISTBASE_FOREACH (RenderSlot *, slot, &ima->renderslots) { - slot->render = newimaadr(fd, slot->render); - } - - for (int eye = 0; eye < 2; eye++) { - for (i = 0; i < TEXTARGET_COUNT; i++) { - ima->gputexture[i][eye] = newimaadr(fd, ima->gputexture[i][eye]); - } - } - ima->rr = newimaadr(fd, ima->rr); - } for (; sce; sce = sce->id.next) { if (sce->nodetree && sce->nodetree->previews) { bNodeInstanceHash *new_previews = BKE_node_instance_hash_new("node previews"); @@ -4404,55 +4357,25 @@ static void direct_link_text(BlendDataReader *reader, Text *text) /** \name Read ID: Image * \{ */ -static void lib_link_image(BlendLibReader *UNUSED(reader), Image *UNUSED(ima)) +static void lib_link_image(BlendLibReader *UNUSED(reader), Image *ima) { + /* Images have some kind of 'main' cache, when NULL we should also clear all others. + * XXX It is not ideal to do that from here, but for now it will do. We have to do it after all + * cache pointers have been potentially remapped (in undo case) or NULL-ified. */ + if (ima->cache == NULL) { + BKE_image_free_buffers(ima); + } } static void direct_link_image(BlendDataReader *reader, Image *ima) { ImagePackedFile *imapf; - /* for undo system, pointers could be restored */ - if (reader->fd->imamap) { - ima->cache = newimaadr(reader->fd, ima->cache); - } - else { - ima->cache = NULL; - } - BLO_read_list(reader, &ima->tiles); - /* if not restored, we keep the binded opengl index */ - if (!ima->cache) { - ima->gpuflag = 0; - ima->gpuframenr = INT_MAX; - for (int eye = 0; eye < 2; eye++) { - for (int i = 0; i < TEXTARGET_COUNT; i++) { - ima->gputexture[i][eye] = NULL; - } - } - ima->rr = NULL; - } - else { - for (int eye = 0; eye < 2; eye++) { - for (int i = 0; i < TEXTARGET_COUNT; i++) { - ima->gputexture[i][eye] = newimaadr(reader->fd, ima->gputexture[i][eye]); - } - } - ima->rr = newimaadr(reader->fd, ima->rr); - } - - /* undo system, try to restore render buffers */ BLO_read_list(reader, &(ima->renderslots)); - if (reader->fd->imamap) { - LISTBASE_FOREACH (RenderSlot *, slot, &ima->renderslots) { - slot->render = newimaadr(reader->fd, slot->render); - } - } - else { - LISTBASE_FOREACH (RenderSlot *, slot, &ima->renderslots) { - slot->render = NULL; - } + if (reader->fd->memfile == NULL) { + /* We reset this last render slot index only when actually reading a file, not for undo. */ ima->last_render_slot = ima->render_slot; } -- cgit v1.2.3