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:
Diffstat (limited to 'source/blender/blenkernel/intern/image.c')
-rw-r--r--source/blender/blenkernel/intern/image.c407
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;
+}