diff options
Diffstat (limited to 'source/blender/blenkernel/intern/image.c')
-rw-r--r-- | source/blender/blenkernel/intern/image.c | 407 |
1 files changed, 280 insertions, 127 deletions
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 82ea3cb80b1..1e55b5ee962 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -50,6 +50,7 @@ #include "IMB_colormanagement.h" #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" +#include "IMB_moviecache.h" #ifdef WITH_OPENEXR # include "intern/openexr/openexr_multi.h" @@ -109,6 +110,51 @@ static SpinLock image_spin; #define IMA_INDEX_FRAME(index) (index >> 10) #define IMA_INDEX_PASS(index) (index & ~1023) +/* ******** IMAGE CACHE ************* */ + +typedef struct ImageCacheKey { + int index; +} ImageCacheKey; + +static unsigned int imagecache_hashhash(const void *key_v) +{ + const ImageCacheKey *key = (ImageCacheKey *) key_v; + return key->index; +} + +static int imagecache_hashcmp(const void *a_v, const void *b_v) +{ + const ImageCacheKey *a = (ImageCacheKey *) a_v; + const ImageCacheKey *b = (ImageCacheKey *) b_v; + + return a->index - b->index; +} + +static void imagecache_put(Image *image, int index, ImBuf *ibuf) +{ + ImageCacheKey key; + + if (image->cache == NULL) { + image->cache = IMB_moviecache_create("Image Datablock Cache", sizeof(ImageCacheKey), + imagecache_hashhash, imagecache_hashcmp); + } + + key.index = index; + + IMB_moviecache_put(image->cache, &key, ibuf); +} + +static struct ImBuf* imagecache_get(Image *image, int index) +{ + if (image->cache) { + ImageCacheKey key; + key.index = index; + return IMB_moviecache_get(image->cache, &key); + } + + return NULL; +} + void BKE_images_init(void) { BLI_spin_init(&image_spin); @@ -193,13 +239,9 @@ void BKE_image_de_interlace(Image *ima, int odd) static void image_free_cahced_frames(Image *image) { - ImBuf *ibuf; - while ((ibuf = BLI_pophead(&image->ibufs))) { - if (ibuf->userdata) { - MEM_freeN(ibuf->userdata); - ibuf->userdata = NULL; - } - IMB_freeImBuf(ibuf); + if (image->cache) { + IMB_moviecache_free(image->cache); + image->cache = NULL; } } @@ -268,59 +310,30 @@ static Image *image_alloc(Main *bmain, const char *name, short source, short typ return ima; } -/* get the ibuf from an image cache, local use here only */ -static ImBuf *image_get_ibuf(Image *ima, int index, int frame) +/* Get the ibuf from an image cache by it's index and frame. + * Local use here only. + * + * Returns referenced image buffer if it exists, callee is to + * call IMB_freeImBuf to de-reference the image buffer after + * it's done handling it. + */ +static ImBuf *image_get_cached_ibuf_for_index_frame(Image *ima, int index, int frame) { - /* this function is intended to be thread safe. with IMA_NO_INDEX this - * should be OK, but when iterating over the list this is more tricky - * */ - if (index == IMA_NO_INDEX) { - return ima->ibufs.first; - } - else { - ImBuf *ibuf; - + if (index != IMA_NO_INDEX) { index = IMA_MAKE_INDEX(frame, index); - for (ibuf = ima->ibufs.first; ibuf; ibuf = ibuf->next) - if (ibuf->index == index) - return ibuf; } - return NULL; -} - -/* no ima->ibuf anymore, but listbase */ -static void image_remove_ibuf(Image *ima, ImBuf *ibuf) -{ - if (ibuf) { - BLI_remlink(&ima->ibufs, ibuf); - IMB_freeImBuf(ibuf); - } + return imagecache_get(ima, index); } - /* no ima->ibuf anymore, but listbase */ static void image_assign_ibuf(Image *ima, ImBuf *ibuf, int index, int frame) { if (ibuf) { - ImBuf *link; - if (index != IMA_NO_INDEX) index = IMA_MAKE_INDEX(frame, index); - /* insert based on index */ - for (link = ima->ibufs.first; link; link = link->next) - if (link->index >= index) - break; - - ibuf->index = index; - - /* this function accepts (link == NULL) */ - BLI_insertlinkbefore(&ima->ibufs, link, ibuf); - - /* now we don't want copies? */ - if (link && ibuf->index == link->index) - image_remove_ibuf(ima, link); + imagecache_put(ima, index, ibuf); } } @@ -521,14 +534,21 @@ void BKE_image_make_local(struct Image *ima) void BKE_image_merge(Image *dest, Image *source) { - ImBuf *ibuf; - /* sanity check */ if (dest && source && dest != source) { - - while ((ibuf = BLI_pophead(&source->ibufs))) { - image_assign_ibuf(dest, ibuf, IMA_INDEX_PASS(ibuf->index), IMA_INDEX_FRAME(ibuf->index)); + BLI_spin_lock(&image_spin); + if (source->cache != NULL) { + struct MovieCacheIter *iter; + iter = IMB_moviecacheIter_new(source->cache); + while (!IMB_moviecacheIter_done(iter)) { + ImBuf *ibuf = IMB_moviecacheIter_getImBuf(iter); + ImageCacheKey *key = IMB_moviecacheIter_getUserKey(iter); + imagecache_put(dest, key->index, ibuf); + IMB_moviecacheIter_step(iter); + } + IMB_moviecacheIter_free(iter); } + BLI_spin_unlock(&image_spin); BKE_libblock_free(&G.main->image, source); } @@ -729,6 +749,9 @@ Image *BKE_image_add_generated(Main *bmain, unsigned int width, unsigned int hei ibuf = add_ibuf_size(width, height, ima->name, depth, floatbuf, gen_type, color, &ima->colorspace_settings); image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0); + /* image_assign_ibuf puts buffer to the cache, which increments user counter. */ + IMB_freeImBuf(ibuf); + ima->ok = IMA_OK_LOADED; } @@ -755,7 +778,7 @@ Image *BKE_image_add_from_imbuf(ImBuf *ibuf) /* packs rect from memory as PNG */ void BKE_image_memorypack(Image *ima) { - ImBuf *ibuf = image_get_ibuf(ima, IMA_NO_INDEX, 0); + ImBuf *ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0); if (ibuf == NULL) return; @@ -786,6 +809,8 @@ void BKE_image_memorypack(Image *ima) ima->type = IMA_TYPE_IMAGE; } } + + IMB_freeImBuf(ibuf); } void BKE_image_tag_time(Image *ima) @@ -838,7 +863,7 @@ void free_old_images(void) ima->lastused = ctime; } /* Otherwise, just kill the buffers */ - else if (ima->ibufs.first) { + else { image_free_buffers(ima); } } @@ -846,30 +871,47 @@ void free_old_images(void) } } -static uintptr_t image_mem_size(Image *ima) +static uintptr_t image_mem_size(Image *image) { - ImBuf *ibuf, *ibufm; - int level; uintptr_t size = 0; - size = 0; - /* viewers have memory depending on other rules, has no valid rect pointer */ - if (ima->source == IMA_SRC_VIEWER) + if (image->source == IMA_SRC_VIEWER) return 0; - for (ibuf = ima->ibufs.first; ibuf; ibuf = ibuf->next) { - if (ibuf->rect) size += MEM_allocN_len(ibuf->rect); - else if (ibuf->rect_float) size += MEM_allocN_len(ibuf->rect_float); + BLI_spin_lock(&image_spin); + if (image->cache != NULL) { + struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache); + + while (!IMB_moviecacheIter_done(iter)) { + ImBuf *ibuf = IMB_moviecacheIter_getImBuf(iter); + ImBuf *ibufm; + int level; - for (level = 0; level < IB_MIPMAP_LEVELS; level++) { - ibufm = ibuf->mipmap[level]; - if (ibufm) { - if (ibufm->rect) size += MEM_allocN_len(ibufm->rect); - else if (ibufm->rect_float) size += MEM_allocN_len(ibufm->rect_float); + if (ibuf->rect) { + size += MEM_allocN_len(ibuf->rect); + } + if (ibuf->rect_float) { + size += MEM_allocN_len(ibuf->rect_float); } + + for (level = 0; level < IB_MIPMAP_LEVELS; level++) { + ibufm = ibuf->mipmap[level]; + if (ibufm) { + if (ibufm->rect) { + size += MEM_allocN_len(ibufm->rect); + } + if (ibufm->rect_float) { + size += MEM_allocN_len(ibufm->rect_float); + } + } + } + + IMB_moviecacheIter_step(iter); } + IMB_moviecacheIter_free(iter); } + BLI_spin_unlock(&image_spin); return size; } @@ -892,11 +934,20 @@ void BKE_image_print_memlist(void) } } +static bool imagecache_check_dirty(ImBuf *ibuf, void *UNUSED(userkey), void *UNUSED(userdata)) +{ + return (ibuf->userflags & IB_BITMAPDIRTY) == 0; +} + void BKE_image_free_all_textures(void) { +#undef CHECK_FREED_SIZE + Tex *tex; Image *ima; - /* unsigned int totsize = 0; */ +#ifdef CHECK_FREED_SIZE + uintptr_t tot_freed_size = 0; +#endif for (ima = G.main->image.first; ima; ima = ima->id.next) ima->id.flag &= ~LIB_DOIT; @@ -906,49 +957,35 @@ void BKE_image_free_all_textures(void) tex->ima->id.flag |= LIB_DOIT; for (ima = G.main->image.first; ima; ima = ima->id.next) { - if (ima->ibufs.first && (ima->id.flag & LIB_DOIT)) { - ImBuf *ibuf; + if (ima->cache && (ima->id.flag & LIB_DOIT)) { +#ifdef CHECK_FREED_SIZE + uintptr_t old_size = image_mem_size(ima); +#endif - for (ibuf = ima->ibufs.first; ibuf; ibuf = ibuf->next) { - /* escape when image is painted on */ - if (ibuf->userflags & IB_BITMAPDIRTY) - break; + IMB_moviecache_cleanup(ima->cache, imagecache_check_dirty, NULL); -#if 0 - if (ibuf->mipmap[0]) - totsize += 1.33 * ibuf->x * ibuf->y * 4; - else - totsize += ibuf->x * ibuf->y * 4; +#ifdef CHECK_FREED_SIZE + tot_freed_size += old_size - image_mem_size(ima); #endif - } - if (ibuf == NULL) - image_free_buffers(ima); } } - /* printf("freed total %d MB\n", totsize / (1024 * 1024)); */ +#ifdef CHECK_FREED_SIZE + printf("%s: freed total %lu MB\n", __func__, tot_freed_size / (1024 * 1024)); +#endif +} + +static bool imagecache_check_free_anim(ImBuf *ibuf, void *UNUSED(userkey), void *userdata) +{ + int except_frame = *(int *)userdata; + return (ibuf->userflags & IB_BITMAPDIRTY) == 0 && + (ibuf->index != IMA_NO_INDEX) && + (except_frame != IMA_INDEX_FRAME(ibuf->index)); } /* except_frame is weak, only works for seqs without offset... */ void BKE_image_free_anim_ibufs(Image *ima, int except_frame) { - ImBuf *ibuf, *nbuf; - - for (ibuf = ima->ibufs.first; ibuf; ibuf = nbuf) { - nbuf = ibuf->next; - if (ibuf->userflags & IB_BITMAPDIRTY) - continue; - if (ibuf->index == IMA_NO_INDEX) - continue; - if (except_frame != IMA_INDEX_FRAME(ibuf->index)) { - BLI_remlink(&ima->ibufs, ibuf); - - if (ibuf->userdata) { - MEM_freeN(ibuf->userdata); - ibuf->userdata = NULL; - } - IMB_freeImBuf(ibuf); - } - } + IMB_moviecache_cleanup(ima->cache, imagecache_check_free_anim, &except_frame); } void BKE_image_all_free_anim_ibufs(int cfra) @@ -2219,10 +2256,11 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal) if (ima->source == IMA_SRC_GENERATED) { if (ima->gen_x == 0 || ima->gen_y == 0) { - ImBuf *ibuf = image_get_ibuf(ima, IMA_NO_INDEX, 0); + ImBuf *ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0); if (ibuf) { ima->gen_x = ibuf->x; ima->gen_y = ibuf->y; + IMB_freeImBuf(ibuf); } } } @@ -2784,7 +2822,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_ } } - ibuf = image_get_ibuf(ima, IMA_NO_INDEX, 0); + ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0); /* make ibuf if needed, and initialize it */ if (ibuf == NULL) { @@ -2870,7 +2908,13 @@ static void image_get_frame_and_index(Image *ima, ImageUser *iuser, int *frame_r *index_r = index; } -static ImBuf *image_get_ibuf_threadsafe(Image *ima, ImageUser *iuser, int *frame_r, int *index_r) +/* Get the ibuf from an image cache for a given image user. + * + * Returns referenced image buffer if it exists, callee is to + * call IMB_freeImBuf to de-reference the image buffer after + * it's done handling it. + */ +static ImBuf *image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *frame_r, int *index_r) { ImBuf *ibuf = NULL; int frame = 0, index = 0; @@ -2878,7 +2922,7 @@ static ImBuf *image_get_ibuf_threadsafe(Image *ima, ImageUser *iuser, int *frame /* see if we already have an appropriate ibuf, with image source and type */ if (ima->source == IMA_SRC_MOVIE) { frame = iuser ? iuser->framenr : ima->lastframe; - ibuf = image_get_ibuf(ima, 0, frame); + ibuf = image_get_cached_ibuf_for_index_frame(ima, 0, frame); /* XXX temp stuff? */ if (ima->lastframe != frame) ima->tpageflag |= IMA_TPAGE_REFRESH; @@ -2887,7 +2931,7 @@ static ImBuf *image_get_ibuf_threadsafe(Image *ima, ImageUser *iuser, int *frame else if (ima->source == IMA_SRC_SEQUENCE) { if (ima->type == IMA_TYPE_IMAGE) { frame = iuser ? iuser->framenr : ima->lastframe; - ibuf = image_get_ibuf(ima, 0, frame); + ibuf = image_get_cached_ibuf_for_index_frame(ima, 0, frame); /* XXX temp stuff? */ if (ima->lastframe != frame) { @@ -2898,17 +2942,17 @@ static ImBuf *image_get_ibuf_threadsafe(Image *ima, ImageUser *iuser, int *frame else if (ima->type == IMA_TYPE_MULTILAYER) { frame = iuser ? iuser->framenr : ima->lastframe; index = iuser ? iuser->multi_index : IMA_NO_INDEX; - ibuf = image_get_ibuf(ima, index, frame); + ibuf = image_get_cached_ibuf_for_index_frame(ima, index, frame); } } else if (ima->source == IMA_SRC_FILE) { if (ima->type == IMA_TYPE_IMAGE) - ibuf = image_get_ibuf(ima, IMA_NO_INDEX, 0); + ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0); else if (ima->type == IMA_TYPE_MULTILAYER) - ibuf = image_get_ibuf(ima, iuser ? iuser->multi_index : IMA_NO_INDEX, 0); + ibuf = image_get_cached_ibuf_for_index_frame(ima, iuser ? iuser->multi_index : IMA_NO_INDEX, 0); } else if (ima->source == IMA_SRC_GENERATED) { - ibuf = image_get_ibuf(ima, IMA_NO_INDEX, 0); + ibuf = image_get_cached_ibuf_for_index_frame(ima, IMA_NO_INDEX, 0); } else if (ima->source == IMA_SRC_VIEWER) { /* always verify entirely, not that this shouldn't happen @@ -2957,7 +3001,7 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r) if (!image_quick_test(ima, iuser)) return NULL; - ibuf = image_get_ibuf_threadsafe(ima, iuser, &frame, &index); + ibuf = image_get_cached_ibuf(ima, iuser, &frame, &index); if (ibuf == NULL) { /* we are sure we have to load the ibuf, using source and type */ @@ -3012,7 +3056,7 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r) /* XXX anim play for viewer nodes not yet supported */ frame = 0; // XXX iuser ? iuser->framenr : 0; - ibuf = image_get_ibuf(ima, 0, frame); + ibuf = image_get_cached_ibuf_for_index_frame(ima, 0, frame); if (!ibuf) { /* Composite Viewer, all handled in compositor */ @@ -3045,9 +3089,6 @@ ImBuf *BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r) ibuf = image_acquire_ibuf(ima, iuser, lock_r); - if (ibuf) - IMB_refImBuf(ibuf); - BLI_spin_unlock(&image_spin); return ibuf; @@ -3082,18 +3123,16 @@ int BKE_image_has_ibuf(Image *ima, ImageUser *iuser) if (!image_quick_test(ima, iuser)) return FALSE; - ibuf = image_get_ibuf_threadsafe(ima, iuser, NULL, NULL); + BLI_spin_lock(&image_spin); - if (!ibuf) { - BLI_spin_lock(&image_spin); + ibuf = image_get_cached_ibuf(ima, iuser, NULL, NULL); - ibuf = image_get_ibuf_threadsafe(ima, iuser, NULL, NULL); + if (!ibuf) + ibuf = image_acquire_ibuf(ima, iuser, NULL); - if (!ibuf) - ibuf = image_acquire_ibuf(ima, iuser, NULL); + BLI_spin_unlock(&image_spin); - BLI_spin_unlock(&image_spin); - } + IMB_freeImBuf(ibuf); return ibuf != NULL; } @@ -3187,9 +3226,6 @@ ImBuf *BKE_image_pool_acquire_ibuf(Image *ima, ImageUser *iuser, ImagePool *pool ibuf = image_acquire_ibuf(ima, iuser, NULL); - if (ibuf) - IMB_refImBuf(ibuf); - entry = MEM_callocN(sizeof(ImagePoolEntry), "Image Pool Entry"); entry->image = ima; entry->frame = frame; @@ -3455,3 +3491,120 @@ int BKE_image_sequence_guess_offset(Image *image) return atoi(num); } + +bool BKE_image_is_dirty(Image *image) +{ + bool is_dirty = false; + + BLI_spin_lock(&image_spin); + if (image->cache != NULL) { + struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache); + + while (!IMB_moviecacheIter_done(iter)) { + ImBuf *ibuf = IMB_moviecacheIter_getImBuf(iter); + if (ibuf->userflags & IB_BITMAPDIRTY) { + is_dirty = true; + break; + } + IMB_moviecacheIter_step(iter); + } + IMB_moviecacheIter_free(iter); + } + BLI_spin_unlock(&image_spin); + + return is_dirty; +} + +void BKE_image_file_format_set(Image *image, int ftype) +{ +#if 0 + ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL); + if (ibuf) { + ibuf->ftype = ftype; + } + BKE_image_release_ibuf(image, ibuf, NULL); +#endif + + BLI_spin_lock(&image_spin); + if (image->cache != NULL) { + struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache); + + while (!IMB_moviecacheIter_done(iter)) { + ImBuf *ibuf = IMB_moviecacheIter_getImBuf(iter); + ibuf->ftype = ftype; + IMB_moviecacheIter_step(iter); + } + IMB_moviecacheIter_free(iter); + } + BLI_spin_unlock(&image_spin); +} + +bool BKE_image_has_loaded_ibuf(Image *image) +{ + bool has_loaded_ibuf = false; + + BLI_spin_lock(&image_spin); + if (image->cache != NULL) { + struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache); + + while (!IMB_moviecacheIter_done(iter)) { + has_loaded_ibuf = true; + break; + } + IMB_moviecacheIter_free(iter); + } + BLI_spin_unlock(&image_spin); + + return has_loaded_ibuf; +} + +/* References the result, IMB_freeImBuf is to be called to de-reference. */ +ImBuf *BKE_image_get_ibuf_with_name(Image *image, const char *name) +{ + ImBuf *ibuf = NULL; + + BLI_spin_lock(&image_spin); + if (image->cache != NULL) { + struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache); + + while (!IMB_moviecacheIter_done(iter)) { + ImBuf *current_ibuf = IMB_moviecacheIter_getImBuf(iter); + if (STREQ(current_ibuf->name, name)) { + ibuf = current_ibuf; + IMB_refImBuf(ibuf); + break; + } + } + IMB_moviecacheIter_free(iter); + } + BLI_spin_unlock(&image_spin); + + return ibuf; +} + +/* References the result, IMB_freeImBuf is to be called to de-reference. + * + * TODO(sergey): This is actually "get first entry from the cache", which is + * not so much predictable. But using first loaded image buffer + * was also malicious logic and all the areas which uses this + * function are to be re-considered. + */ +ImBuf *BKE_image_get_first_ibuf(Image *image) +{ + ImBuf *ibuf = NULL; + + BLI_spin_lock(&image_spin); + if (image->cache != NULL) { + struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache); + + while (!IMB_moviecacheIter_done(iter)) { + ibuf = IMB_moviecacheIter_getImBuf(iter); + IMB_refImBuf(ibuf); + break; + } + IMB_moviecacheIter_free(iter); + } + BLI_spin_unlock(&image_spin); + + return ibuf; +} |