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/imbuf/intern/moviecache.c')
-rw-r--r--source/blender/imbuf/intern/moviecache.c382
1 files changed, 382 insertions, 0 deletions
diff --git a/source/blender/imbuf/intern/moviecache.c b/source/blender/imbuf/intern/moviecache.c
new file mode 100644
index 00000000000..7492b6aec44
--- /dev/null
+++ b/source/blender/imbuf/intern/moviecache.c
@@ -0,0 +1,382 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2011 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation,
+ * Sergey Sharybin,
+ * Peter Schlaile
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/moviecache.c
+ * \ingroup bke
+ */
+
+#include <stdlib.h> /* for qsort */
+#include <memory.h>
+
+#include "MEM_guardedalloc.h"
+#include "MEM_CacheLimiterC-Api.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+#include "BLI_mempool.h"
+
+#include "IMB_moviecache.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+static MEM_CacheLimiterC *limitor= NULL;
+
+typedef struct MovieCache {
+ GHash *hash;
+ GHashHashFP hashfp;
+ GHashCmpFP cmpfp;
+ MovieCacheGetKeyDataFP getdatafp;
+
+ struct BLI_mempool *keys_pool;
+ struct BLI_mempool *items_pool;
+ struct BLI_mempool *userkeys_pool;
+
+ int keysize;
+ unsigned long curtime;
+
+ int totseg, *points, proxy, render_flags; /* for visual statistics optimization */
+ int pad;
+} MovieCache;
+
+typedef struct MovieCacheKey {
+ MovieCache *cache_owner;
+ void *userkey;
+} MovieCacheKey;
+
+typedef struct MovieCacheItem {
+ MovieCache *cache_owner;
+ ImBuf *ibuf;
+ MEM_CacheLimiterHandleC * c_handle;
+ unsigned long last_access;
+} MovieCacheItem;
+
+static unsigned int moviecache_hashhash(const void *keyv)
+{
+ MovieCacheKey *key= (MovieCacheKey*)keyv;
+
+ return key->cache_owner->hashfp(key->userkey);
+}
+
+static int moviecache_hashcmp(const void *av, const void *bv)
+{
+ const MovieCacheKey *a= (MovieCacheKey*)av;
+ const MovieCacheKey *b= (MovieCacheKey*)bv;
+
+ return a->cache_owner->cmpfp(a->userkey, b->userkey);
+}
+
+static void moviecache_keyfree(void *val)
+{
+ MovieCacheKey *key= (MovieCacheKey*)val;
+
+ BLI_mempool_free(key->cache_owner->keys_pool, key);
+}
+
+static void moviecache_valfree(void *val)
+{
+ MovieCacheItem *item= (MovieCacheItem*)val;
+
+ if (item->ibuf) {
+ MEM_CacheLimiter_unmanage(item->c_handle);
+ IMB_freeImBuf(item->ibuf);
+ }
+
+ BLI_mempool_free(item->cache_owner->items_pool, item);
+}
+
+static void check_unused_keys(MovieCache *cache)
+{
+ GHashIterator *iter;
+
+ iter= BLI_ghashIterator_new(cache->hash);
+ while(!BLI_ghashIterator_isDone(iter)) {
+ MovieCacheKey *key= BLI_ghashIterator_getKey(iter);
+ MovieCacheItem *item= BLI_ghashIterator_getValue(iter);
+
+ BLI_ghashIterator_step(iter);
+
+ if(!item->ibuf)
+ BLI_ghash_remove(cache->hash, key, moviecache_keyfree, moviecache_valfree);
+ }
+
+ BLI_ghashIterator_free(iter);
+}
+
+static int compare_int(const void *av, const void *bv)
+{
+ const int *a= (int *)av;
+ const int *b= (int *)bv;
+ return *a-*b;
+}
+
+static void IMB_moviecache_destructor(void *p)
+{
+ MovieCacheItem *item= (MovieCacheItem *) p;
+
+ if (item && item->ibuf) {
+ IMB_freeImBuf(item->ibuf);
+
+ item->ibuf= NULL;
+ item->c_handle= NULL;
+ }
+}
+
+/* approximate size of ImBuf in memory */
+static intptr_t IMB_get_size_in_memory(ImBuf *ibuf)
+{
+ int a;
+ intptr_t size= 0, channel_size= 0;
+
+ size+= sizeof(ImBuf);
+
+ if(ibuf->rect)
+ channel_size+= sizeof(char);
+
+ if(ibuf->rect_float)
+ channel_size+= sizeof(float);
+
+ size+= channel_size*ibuf->x*ibuf->y*ibuf->channels;
+
+ if(ibuf->miptot) {
+ for(a= 0; a<ibuf->miptot; a++) {
+ if(ibuf->mipmap[a])
+ size+= IMB_get_size_in_memory(ibuf->mipmap[a]);
+ }
+ }
+
+ if(ibuf->tiles) {
+ size+= sizeof(unsigned int)*ibuf->ytiles*ibuf->xtiles;
+ }
+
+ return size;
+}
+
+static intptr_t get_item_size (void *p)
+{
+ intptr_t size= sizeof(MovieCacheItem);
+ MovieCacheItem *item= (MovieCacheItem *) p;
+
+ if(item->ibuf)
+ size+= IMB_get_size_in_memory(item->ibuf);
+
+ return size;
+}
+
+void IMB_moviecache_init(void)
+{
+ limitor= new_MEM_CacheLimiter(IMB_moviecache_destructor, get_item_size);
+}
+
+void IMB_moviecache_destruct(void)
+{
+ if(limitor)
+ delete_MEM_CacheLimiter(limitor);
+}
+
+struct MovieCache *IMB_moviecache_create(int keysize, GHashHashFP hashfp, GHashCmpFP cmpfp,
+ MovieCacheGetKeyDataFP getdatafp)
+{
+ MovieCache *cache;
+
+ cache= MEM_callocN(sizeof(MovieCache), "MovieCache");
+ cache->keys_pool= BLI_mempool_create(sizeof(MovieCacheKey), 64, 64, 0);
+ cache->items_pool= BLI_mempool_create(sizeof(MovieCacheItem), 64, 64, 0);
+ cache->userkeys_pool= BLI_mempool_create(keysize, 64, 64, 0);
+ cache->hash= BLI_ghash_new(moviecache_hashhash, moviecache_hashcmp, "MovieClip ImBuf cache hash");
+
+ cache->keysize= keysize;
+ cache->hashfp= hashfp;
+ cache->cmpfp= cmpfp;
+ cache->getdatafp= getdatafp;
+ cache->proxy= -1;
+
+ return cache;
+}
+
+void IMB_moviecache_put(MovieCache *cache, void *userkey, ImBuf *ibuf)
+{
+ MovieCacheKey *key;
+ MovieCacheItem *item;
+
+ if(!limitor)
+ IMB_moviecache_init();
+
+ IMB_refImBuf(ibuf);
+
+ key= BLI_mempool_alloc(cache->keys_pool);
+ key->cache_owner= cache;
+ key->userkey= BLI_mempool_alloc(cache->userkeys_pool);;
+ memcpy(key->userkey, userkey, cache->keysize);
+
+ item= BLI_mempool_alloc(cache->items_pool);
+ item->ibuf= ibuf;
+ item->cache_owner= cache;
+ item->last_access= cache->curtime++;
+ item->c_handle= NULL;
+
+ BLI_ghash_remove(cache->hash, key, moviecache_keyfree, moviecache_valfree);
+ BLI_ghash_insert(cache->hash, key, item);
+
+ item->c_handle= MEM_CacheLimiter_insert(limitor, item);
+
+ MEM_CacheLimiter_ref(item->c_handle);
+ MEM_CacheLimiter_enforce_limits(limitor);
+ MEM_CacheLimiter_unref(item->c_handle);
+
+ /* cache limiter can't remove unused keys which points to destoryed values */
+ check_unused_keys(cache);
+
+ if(cache->points) {
+ MEM_freeN(cache->points);
+ cache->points= NULL;
+ }
+}
+
+ImBuf* IMB_moviecache_get(MovieCache *cache, void *userkey)
+{
+ MovieCacheKey key;
+ MovieCacheItem *item;
+
+ key.cache_owner= cache;
+ key.userkey= userkey;
+ item= (MovieCacheItem*)BLI_ghash_lookup(cache->hash, &key);
+
+ if(item) {
+ item->last_access= cache->curtime++;
+
+ if(item->ibuf) {
+ MEM_CacheLimiter_touch(item->c_handle);
+ IMB_refImBuf(item->ibuf);
+
+ return item->ibuf;
+ }
+ }
+
+ return NULL;
+}
+
+void IMB_moviecache_free(MovieCache *cache)
+{
+ BLI_ghash_free(cache->hash, moviecache_keyfree, moviecache_valfree);
+
+ BLI_mempool_destroy(cache->keys_pool);
+ BLI_mempool_destroy(cache->items_pool);
+ BLI_mempool_destroy(cache->userkeys_pool);
+
+ if(cache->points)
+ MEM_freeN(cache->points);
+
+ MEM_freeN(cache);
+}
+
+/* get segments of cached frames. useful for debugging cache policies */
+void IMB_moviecache_get_cache_segments(MovieCache *cache, int proxy, int render_flags, int *totseg_r, int **points_r)
+{
+ *totseg_r= 0;
+ *points_r= NULL;
+
+ if(!cache->getdatafp)
+ return;
+
+ if(cache->proxy!=proxy || cache->render_flags!=render_flags) {
+ if(cache->points)
+ MEM_freeN(cache->points);
+
+ cache->points= NULL;
+ }
+
+ if(cache->points) {
+ *totseg_r= cache->totseg;
+ *points_r= cache->points;
+ } else {
+ int totframe= BLI_ghash_size(cache->hash);
+ int *frames= MEM_callocN(totframe*sizeof(int), "movieclip cache frames");
+ int a, totseg= 0;
+ GHashIterator *iter;
+
+ iter= BLI_ghashIterator_new(cache->hash);
+ a= 0;
+ while(!BLI_ghashIterator_isDone(iter)) {
+ MovieCacheKey *key= BLI_ghashIterator_getKey(iter);
+ MovieCacheItem *item= BLI_ghashIterator_getValue(iter);
+ int framenr, curproxy, curflags;
+
+ if(item->ibuf) {
+ cache->getdatafp(key->userkey, &framenr, &curproxy, &curflags);
+
+ if(curproxy==proxy && curflags==render_flags)
+ frames[a++]= framenr;
+ }
+
+ BLI_ghashIterator_step(iter);
+ }
+
+ BLI_ghashIterator_free(iter);
+
+ qsort(frames, totframe, sizeof(int), compare_int);
+
+ /* count */
+ for(a= 0; a<totframe; a++) {
+ if(a && frames[a]-frames[a-1]!=1)
+ totseg++;
+
+ if(a==totframe-1)
+ totseg++;
+ }
+
+ if(totseg) {
+ int b, *points;
+
+ points= MEM_callocN(2*sizeof(int)*totseg, "movieclip cache segments");
+
+ /* fill */
+ for(a= 0, b= 0; a<totframe; a++) {
+ if(a==0)
+ points[b++]= frames[a];
+
+ if(a && frames[a]-frames[a-1]!=1) {
+ points[b++]= frames[a-1];
+ points[b++]= frames[a];
+ }
+
+ if(a==totframe-1)
+ points[b++]= frames[a];
+ }
+
+ *totseg_r= totseg;
+ *points_r= points;
+
+ cache->totseg= totseg;
+ cache->points= points;
+ cache->proxy= proxy;
+ cache->render_flags= render_flags;
+ }
+
+ MEM_freeN(frames);
+ }
+}