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:
-rw-r--r--source/blender/blenkernel/BKE_image.h6
-rw-r--r--source/blender/blenkernel/intern/image.c407
-rw-r--r--source/blender/blenkernel/intern/seqcache.c2
-rw-r--r--source/blender/blenloader/intern/readfile.c43
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c11
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c4
-rw-r--r--source/blender/editors/space_image/image_ops.c40
-rw-r--r--source/blender/editors/space_info/info_ops.c2
-rw-r--r--source/blender/gpu/intern/gpu_draw.c8
-rw-r--r--source/blender/imbuf/IMB_moviecache.h12
-rw-r--r--source/blender/imbuf/intern/moviecache.c44
-rw-r--r--source/blender/makesdna/DNA_image_types.h3
-rw-r--r--source/blender/makesrna/intern/rna_image.c30
-rw-r--r--source/blender/render/intern/source/imagetexture.c8
14 files changed, 397 insertions, 223 deletions
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index 7b5abbba7f8..b5171f8e0c2 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -235,6 +235,12 @@ float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame);
/* Guess offset for the first frame in the sequence */
int BKE_image_sequence_guess_offset(struct Image *image);
+
+bool BKE_image_is_dirty(struct Image *image);
+void BKE_image_file_format_set(struct Image *image, int ftype);
+bool BKE_image_has_loaded_ibuf(struct Image *image);
+struct ImBuf *BKE_image_get_ibuf_with_name(struct Image *image, const char *name);
+struct ImBuf *BKE_image_get_first_ibuf(struct Image *image);
#ifdef __cplusplus
}
#endif
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;
+}
diff --git a/source/blender/blenkernel/intern/seqcache.c b/source/blender/blenkernel/intern/seqcache.c
index 33a76d0c03d..919d38be9e0 100644
--- a/source/blender/blenkernel/intern/seqcache.c
+++ b/source/blender/blenkernel/intern/seqcache.c
@@ -195,7 +195,7 @@ void BKE_sequencer_cache_cleanup(void)
BKE_sequencer_preprocessed_cache_cleanup();
}
-static int seqcache_key_check_seq(void *userkey, void *userdata)
+static bool seqcache_key_check_seq(ImBuf *UNUSED(ibuf), void *userkey, void *userdata)
{
SeqCacheKey *key = (SeqCacheKey *) userkey;
Sequence *seq = (Sequence *) userdata;
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 37d2ec787ed..6e64dcc0560 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -1317,9 +1317,8 @@ void blo_make_image_pointer_map(FileData *fd, Main *oldmain)
fd->imamap = oldnewmap_new();
for (; ima; ima = ima->id.next) {
- Link *ibuf = ima->ibufs.first;
- for (; ibuf; ibuf = ibuf->next)
- oldnewmap_insert(fd->imamap, ibuf, ibuf, 0);
+ if (ima->cache)
+ oldnewmap_insert(fd->imamap, ima->cache, ima->cache, 0);
if (ima->gputexture)
oldnewmap_insert(fd->imamap, ima->gputexture, ima->gputexture, 0);
if (ima->rr)
@@ -1355,19 +1354,7 @@ void blo_end_image_pointer_map(FileData *fd, Main *oldmain)
}
for (; ima; ima = ima->id.next) {
- Link *ibuf, *next;
-
- /* this mirrors direct_link_image */
- for (ibuf = ima->ibufs.first; ibuf; ibuf = next) {
- next = ibuf->next;
- if (NULL == newimaadr(fd, ibuf)) { /* so was restored */
- BLI_remlink(&ima->ibufs, ibuf);
- ima->bindcode = 0;
- ima->tpageflag &= ~IMA_GLBIND_IS_DATA;
- ima->gputexture = NULL;
- ima->rr = NULL;
- }
- }
+ ima->cache = newmclipadr(fd, ima->cache);
for (i = 0; i < IMA_MAX_RENDER_SLOT; i++)
ima->renders[i] = newimaadr(fd, ima->renders[i]);
@@ -3281,34 +3268,16 @@ static void lib_link_image(FileData *fd, Main *main)
}
}
-static void link_ibuf_list(FileData *fd, ListBase *lb)
-{
- Link *ln, *prev;
-
- if (lb->first == NULL) return;
-
- lb->first = newimaadr(fd, lb->first);
- ln = lb->first;
- prev = NULL;
- while (ln) {
- ln->next = newimaadr(fd, ln->next);
- ln->prev = prev;
- prev = ln;
- ln = ln->next;
- }
- lb->last = prev;
-}
-
static void direct_link_image(FileData *fd, Image *ima)
{
/* for undo system, pointers could be restored */
if (fd->imamap)
- link_ibuf_list(fd, &ima->ibufs);
+ ima->cache = newmclipadr(fd, ima->cache);
else
- ima->ibufs.first = ima->ibufs.last = NULL;
+ ima->cache = NULL;
/* if not restored, we keep the binded opengl index */
- if (ima->ibufs.first == NULL) {
+ if (!fd->imamap) {
ima->bindcode = 0;
ima->tpageflag &= ~IMA_GLBIND_IS_DATA;
ima->gputexture = NULL;
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index 47ca3e5ce0c..5b323a0a396 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -250,6 +250,7 @@ void ED_image_undo_restore(bContext *C, ListBase *lb)
for (tile = lb->first; tile; tile = tile->next) {
short use_float;
+ bool need_release = true;
/* find image based on name, pointer becomes invalid with global undo */
if (ima && strcmp(tile->idname, ima->id.name) == 0) {
@@ -268,8 +269,9 @@ void ED_image_undo_restore(bContext *C, ListBase *lb)
* matched file name in list of already loaded images */
BKE_image_release_ibuf(ima, ibuf, NULL);
+ need_release = false;
- ibuf = BLI_findstring(&ima->ibufs, tile->ibufname, offsetof(ImBuf, name));
+ ibuf = BKE_image_get_ibuf_with_name(ima, tile->ibufname);
}
if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) {
@@ -298,7 +300,12 @@ void ED_image_undo_restore(bContext *C, ListBase *lb)
ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
- BKE_image_release_ibuf(ima, ibuf, NULL);
+ if (need_release) {
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ }
+ else {
+ IMB_freeImBuf(ibuf);
+ }
}
IMB_freeImBuf(tmpibuf);
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index d6989c082a1..4b402bc1741 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -542,8 +542,7 @@ static bool project_paint_PickColor(const ProjPaintState *ps, const float pt[2],
}
ima = project_paint_face_image(ps, ps->dm_mtface, face_index);
- ibuf = ima->ibufs.first; /* we must have got the imbuf before getting here */
- if (!ibuf) return 0;
+ ibuf = BKE_image_get_first_ibuf(ima); /* we must have got the imbuf before getting here */
if (interp) {
float x, y;
@@ -599,6 +598,7 @@ static bool project_paint_PickColor(const ProjPaintState *ps, const float pt[2],
}
}
}
+ IMB_freeImBuf(ibuf);
return 1;
}
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index bda4be40c5c..a2f49af1730 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -63,6 +63,7 @@
#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
+#include "IMB_moviecache.h"
#include "RE_pipeline.h"
@@ -1628,9 +1629,10 @@ static int image_save_sequence_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
SpaceImage *sima = CTX_wm_space_image(C);
- ImBuf *ibuf;
+ ImBuf *ibuf, *first_ibuf = NULL;
int tot = 0;
char di[FILE_MAX];
+ struct MovieCacheIter *iter;
if (sima->image == NULL)
return OPERATOR_CANCELLED;
@@ -1645,10 +1647,22 @@ static int image_save_sequence_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- /* get total */
- for (ibuf = sima->image->ibufs.first; ibuf; ibuf = ibuf->next)
- if (ibuf->userflags & IB_BITMAPDIRTY)
- tot++;
+ /* get total dirty buffers and first dirty buffer which is used for menu */
+ ibuf = NULL;
+ if (sima->image->cache != NULL) {
+ iter = IMB_moviecacheIter_new(sima->image->cache);
+ while (!IMB_moviecacheIter_done(iter)) {
+ ibuf = IMB_moviecacheIter_getImBuf(iter);
+ if (ibuf->userflags & IB_BITMAPDIRTY) {
+ if (first_ibuf == NULL) {
+ first_ibuf = ibuf;
+ }
+ tot++;
+ }
+ IMB_moviecacheIter_step(iter);
+ }
+ IMB_moviecacheIter_free(iter);
+ }
if (tot == 0) {
BKE_report(op->reports, RPT_WARNING, "No images have been changed");
@@ -1656,18 +1670,17 @@ static int image_save_sequence_exec(bContext *C, wmOperator *op)
}
/* get a filename for menu */
- for (ibuf = sima->image->ibufs.first; ibuf; ibuf = ibuf->next)
- if (ibuf->userflags & IB_BITMAPDIRTY)
- break;
-
- BLI_split_dir_part(ibuf->name, di, sizeof(di));
+ BLI_split_dir_part(first_ibuf->name, di, sizeof(di));
BKE_reportf(op->reports, RPT_INFO, "%d image(s) will be saved in %s", tot, di);
- for (ibuf = sima->image->ibufs.first; ibuf; ibuf = ibuf->next) {
+ iter = IMB_moviecacheIter_new(sima->image->cache);
+ while (!IMB_moviecacheIter_done(iter)) {
+ ibuf = IMB_moviecacheIter_getImBuf(iter);
+
if (ibuf->userflags & IB_BITMAPDIRTY) {
char name[FILE_MAX];
BLI_strncpy(name, ibuf->name, sizeof(name));
-
+
BLI_path_abs(name, bmain->name);
if (0 == IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat)) {
@@ -1678,7 +1691,10 @@ static int image_save_sequence_exec(bContext *C, wmOperator *op)
BKE_reportf(op->reports, RPT_INFO, "Saved %s", ibuf->name);
ibuf->userflags &= ~IB_BITMAPDIRTY;
}
+
+ IMB_moviecacheIter_step(iter);
}
+ IMB_moviecacheIter_free(iter);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c
index 4e367c1d48d..6c76ba64893 100644
--- a/source/blender/editors/space_info/info_ops.c
+++ b/source/blender/editors/space_info/info_ops.c
@@ -145,7 +145,7 @@ static int pack_all_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(ev
// first check for dirty images
for (ima = bmain->image.first; ima; ima = ima->id.next) {
- if (ima->ibufs.first) { /* XXX FIX */
+ if (BKE_image_has_loaded_ibuf(ima)) { /* XXX FIX */
ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
if (ibuf && (ibuf->userflags & IB_BITMAPDIRTY)) {
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index 0dba2cd50e8..ee59cf418bf 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -93,6 +93,7 @@ void GPU_render_text(MTFace *tface, int mode,
{
if ((mode & GEMAT_TEXT) && (textlen>0) && tface->tpage) {
Image* ima = (Image *)tface->tpage;
+ ImBuf *first_ibuf;
int index, character;
float centerx, centery, sizex, sizey, transx, transy, movex, movey, advance;
float advance_tab;
@@ -117,7 +118,8 @@ void GPU_render_text(MTFace *tface, int mode,
glPushMatrix();
/* get the tab width */
- matrixGlyph((ImBuf *)ima->ibufs.first, ' ', & centerx, &centery,
+ first_ibuf = BKE_image_get_first_ibuf(ima);
+ matrixGlyph(first_ibuf, ' ', &centerx, &centery,
&sizex, &sizey, &transx, &transy, &movex, &movey, &advance);
advance_tab= advance * 4; /* tab width could also be an option */
@@ -143,7 +145,7 @@ void GPU_render_text(MTFace *tface, int mode,
// space starts at offset 1
// character = character - ' ' + 1;
- matrixGlyph((ImBuf *)ima->ibufs.first, character, & centerx, &centery,
+ matrixGlyph(first_ibuf, character, & centerx, &centery,
&sizex, &sizey, &transx, &transy, &movex, &movey, &advance);
uv[0][0] = (tface->uv[0][0] - centerx) * sizex + transx;
@@ -184,6 +186,8 @@ void GPU_render_text(MTFace *tface, int mode,
line_start -= advance; /* so we can go back to the start of the line */
}
glPopMatrix();
+
+ IMB_freeImBuf(first_ibuf);
}
}
diff --git a/source/blender/imbuf/IMB_moviecache.h b/source/blender/imbuf/IMB_moviecache.h
index 1c569712968..3432741596f 100644
--- a/source/blender/imbuf/IMB_moviecache.h
+++ b/source/blender/imbuf/IMB_moviecache.h
@@ -63,8 +63,18 @@ struct ImBuf *IMB_moviecache_get(struct MovieCache *cache, void *userkey);
int IMB_moviecache_has_frame(struct MovieCache *cache, void *userkey);
void IMB_moviecache_free(struct MovieCache *cache);
-void IMB_moviecache_cleanup(struct MovieCache *cache, int (cleanup_check_cb) (void *userkey, void *userdata), void *userdata);
+void IMB_moviecache_cleanup(struct MovieCache *cache,
+ bool (cleanup_check_cb) (struct ImBuf *ibuf, void *userkey, void *userdata),
+ void *userdata);
void IMB_moviecache_get_cache_segments(struct MovieCache *cache, int proxy, int render_flags, int *totseg_r, int **points_r);
+struct MovieCacheIter;
+struct MovieCacheIter *IMB_moviecacheIter_new(struct MovieCache *cache);
+void IMB_moviecacheIter_free(struct MovieCacheIter *iter);
+bool IMB_moviecacheIter_done(struct MovieCacheIter *iter);
+void IMB_moviecacheIter_step(struct MovieCacheIter *iter);
+struct ImBuf *IMB_moviecacheIter_getImBuf(struct MovieCacheIter *iter);
+void *IMB_moviecacheIter_getUserKey(struct MovieCacheIter *iter);
+
#endif
diff --git a/source/blender/imbuf/intern/moviecache.c b/source/blender/imbuf/intern/moviecache.c
index 90eea438c5e..c287cf4c005 100644
--- a/source/blender/imbuf/intern/moviecache.c
+++ b/source/blender/imbuf/intern/moviecache.c
@@ -443,23 +443,18 @@ void IMB_moviecache_free(MovieCache *cache)
MEM_freeN(cache);
}
-void IMB_moviecache_cleanup(MovieCache *cache, int (cleanup_check_cb) (void *userkey, void *userdata), void *userdata)
+void IMB_moviecache_cleanup(MovieCache *cache, bool (cleanup_check_cb) (ImBuf *ibuf, void *userkey, void *userdata), void *userdata)
{
GHashIterator *iter;
iter = BLI_ghashIterator_new(cache->hash);
while (!BLI_ghashIterator_done(iter)) {
MovieCacheKey *key = BLI_ghashIterator_getKey(iter);
- int remove;
+ MovieCacheItem *item = BLI_ghashIterator_getValue(iter);
BLI_ghashIterator_step(iter);
- remove = cleanup_check_cb(key->userkey, userdata);
-
- if (remove) {
- MovieCacheItem *item = BLI_ghashIterator_getValue(iter);
- (void) item; /* silence unused variable when not using debug */
-
+ if (cleanup_check_cb(item->ibuf, key->userkey, userdata)) {
PRINT("%s: cache '%s' remove item %p\n", __func__, cache->name, item);
BLI_ghash_remove(cache->hash, key, moviecache_keyfree, moviecache_valfree);
@@ -556,3 +551,36 @@ void IMB_moviecache_get_cache_segments(MovieCache *cache, int proxy, int render_
MEM_freeN(frames);
}
}
+
+struct MovieCacheIter *IMB_moviecacheIter_new(MovieCache *cache)
+{
+ GHashIterator *iter = BLI_ghashIterator_new(cache->hash);
+ return (struct MovieCacheIter *) iter;
+}
+
+void IMB_moviecacheIter_free(struct MovieCacheIter *iter)
+{
+ BLI_ghashIterator_free((GHashIterator *) iter);
+}
+
+bool IMB_moviecacheIter_done(struct MovieCacheIter *iter)
+{
+ return BLI_ghashIterator_done((GHashIterator *) iter);
+}
+
+void IMB_moviecacheIter_step(struct MovieCacheIter *iter)
+{
+ BLI_ghashIterator_step((GHashIterator *) iter);
+}
+
+ImBuf *IMB_moviecacheIter_getImBuf(struct MovieCacheIter *iter)
+{
+ MovieCacheItem *item = BLI_ghashIterator_getValue((GHashIterator *) iter);
+ return item->ibuf;
+}
+
+void *IMB_moviecacheIter_getUserKey(struct MovieCacheIter *iter)
+{
+ MovieCacheKey *key = BLI_ghashIterator_getKey((GHashIterator *) iter);
+ return key->userkey;
+}
diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h
index 6b0299e6d50..0b9dddd0ea5 100644
--- a/source/blender/makesdna/DNA_image_types.h
+++ b/source/blender/makesdna/DNA_image_types.h
@@ -40,6 +40,7 @@ struct PackedFile;
struct Scene;
struct anim;
struct ImBuf;
+struct MovieCache;
struct RenderResult;
struct GPUTexture;
@@ -74,7 +75,7 @@ typedef struct Image {
char name[1024]; /* file path, 1024 = FILE_MAX */
- ListBase ibufs; /* not written in file */
+ struct MovieCache *cache; /* not written in file */
struct GPUTexture *gputexture; /* not written in file */
/* sources from: */
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index c901abc834e..69b2d2d0227 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -79,14 +79,7 @@ static void rna_Image_animated_update(Main *UNUSED(bmain), Scene *UNUSED(scene),
static int rna_Image_dirty_get(PointerRNA *ptr)
{
- Image *ima = (Image *)ptr->data;
- ImBuf *ibuf;
-
- for (ibuf = ima->ibufs.first; ibuf; ibuf = ibuf->next)
- if (ibuf->userflags & IB_BITMAPDIRTY)
- return 1;
-
- return 0;
+ return BKE_image_is_dirty((Image *)ptr->data);
}
static void rna_Image_source_set(PointerRNA *ptr, int value)
@@ -210,31 +203,16 @@ static void rna_Image_file_format_set(PointerRNA *ptr, int value)
{
Image *image = (Image *)ptr->data;
if (BKE_imtype_is_movie(value) == 0) { /* should be able to throw an error here */
- ImBuf *ibuf;
int ftype = BKE_imtype_to_ftype(value);
-
-#if 0
- ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
- if (ibuf)
- ibuf->ftype = ftype;
-#endif
-
- /* to be safe change all buffer file types */
- /* TODO: this is never threadsafe */
- for (ibuf = image->ibufs.first; ibuf; ibuf = ibuf->next) {
- ibuf->ftype = ftype;
- }
+ BKE_image_file_format_set(image, ftype);
}
}
static int rna_Image_has_data_get(PointerRNA *ptr)
{
- Image *im = (Image *)ptr->data;
-
- if (im->ibufs.first)
- return 1;
+ Image *image = (Image *)ptr->data;
- return 0;
+ return BKE_image_has_loaded_ibuf(image);
}
static void rna_Image_size_get(PointerRNA *ptr, int *values)
diff --git a/source/blender/render/intern/source/imagetexture.c b/source/blender/render/intern/source/imagetexture.c
index bfc13bf6151..37c6a5ffdd1 100644
--- a/source/blender/render/intern/source/imagetexture.c
+++ b/source/blender/render/intern/source/imagetexture.c
@@ -127,7 +127,7 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul
if (ima) {
/* hack for icon render */
- if (ima->ibufs.first==NULL && (R.r.scemode & R_NO_IMAGE_LOAD))
+ if ((R.r.scemode & R_NO_IMAGE_LOAD) && !BKE_image_has_loaded_ibuf(ima))
return retval;
ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, pool);
@@ -1094,7 +1094,9 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex
if (ibuf==NULL && ima==NULL) return retval;
if (ima) { /* hack for icon render */
- if ((ima->ibufs.first == NULL) && (R.r.scemode & R_NO_IMAGE_LOAD)) return retval;
+ if ((R.r.scemode & R_NO_IMAGE_LOAD) && !BKE_image_has_loaded_ibuf(ima)) {
+ return retval;
+ }
ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, pool);
}
@@ -1515,7 +1517,7 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
if (ima) {
/* hack for icon render */
- if (ima->ibufs.first==NULL && (R.r.scemode & R_NO_IMAGE_LOAD))
+ if ((R.r.scemode & R_NO_IMAGE_LOAD) && !BKE_image_has_loaded_ibuf(ima))
return retval;
ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, pool);