Blender V2.61 - r43446

moviecache.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2011 Blender Foundation.
00019  * All rights reserved.
00020  *
00021  * Contributor(s): Blender Foundation,
00022  *                 Sergey Sharybin,
00023  *                 Peter Schlaile
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00032 #include <stdlib.h> /* for qsort */
00033 #include <memory.h>
00034 
00035 #include "MEM_guardedalloc.h"
00036 #include "MEM_CacheLimiterC-Api.h"
00037 
00038 #include "BLI_utildefines.h"
00039 #include "BLI_ghash.h"
00040 #include "BLI_mempool.h"
00041 
00042 #include "IMB_moviecache.h"
00043 
00044 #include "IMB_imbuf_types.h"
00045 #include "IMB_imbuf.h"
00046 
00047 static MEM_CacheLimiterC *limitor= NULL;
00048 
00049 typedef struct MovieCache {
00050     GHash *hash;
00051     GHashHashFP hashfp;
00052     GHashCmpFP cmpfp;
00053     MovieCacheGetKeyDataFP getdatafp;
00054 
00055     struct BLI_mempool *keys_pool;
00056     struct BLI_mempool *items_pool;
00057     struct BLI_mempool *userkeys_pool;
00058 
00059     int keysize;
00060     unsigned long curtime;
00061 
00062     int totseg, *points, proxy, render_flags;   /* for visual statistics optimization */
00063     int pad;
00064 } MovieCache;
00065 
00066 typedef struct MovieCacheKey {
00067     MovieCache *cache_owner;
00068     void *userkey;
00069 } MovieCacheKey;
00070 
00071 typedef struct MovieCacheItem {
00072     MovieCache *cache_owner;
00073     ImBuf *ibuf;
00074     MEM_CacheLimiterHandleC * c_handle;
00075     unsigned long last_access;
00076 } MovieCacheItem;
00077 
00078 static unsigned int moviecache_hashhash(const void *keyv)
00079 {
00080     MovieCacheKey *key= (MovieCacheKey*)keyv;
00081 
00082     return key->cache_owner->hashfp(key->userkey);
00083 }
00084 
00085 static int moviecache_hashcmp(const void *av, const void *bv)
00086 {
00087     const MovieCacheKey *a= (MovieCacheKey*)av;
00088     const MovieCacheKey *b= (MovieCacheKey*)bv;
00089 
00090     return a->cache_owner->cmpfp(a->userkey, b->userkey);
00091 }
00092 
00093 static void moviecache_keyfree(void *val)
00094 {
00095     MovieCacheKey *key= (MovieCacheKey*)val;
00096 
00097     BLI_mempool_free(key->cache_owner->keys_pool, key);
00098 }
00099 
00100 static void moviecache_valfree(void *val)
00101 {
00102     MovieCacheItem *item= (MovieCacheItem*)val;
00103 
00104     if (item->ibuf) {
00105         MEM_CacheLimiter_unmanage(item->c_handle);
00106         IMB_freeImBuf(item->ibuf);
00107     }
00108 
00109     BLI_mempool_free(item->cache_owner->items_pool, item);
00110 }
00111 
00112 static void check_unused_keys(MovieCache *cache)
00113 {
00114     GHashIterator *iter;
00115 
00116     iter= BLI_ghashIterator_new(cache->hash);
00117     while(!BLI_ghashIterator_isDone(iter)) {
00118         MovieCacheKey *key= BLI_ghashIterator_getKey(iter);
00119         MovieCacheItem *item= BLI_ghashIterator_getValue(iter);
00120 
00121         BLI_ghashIterator_step(iter);
00122 
00123         if(!item->ibuf)
00124             BLI_ghash_remove(cache->hash, key, moviecache_keyfree, moviecache_valfree);
00125     }
00126 
00127     BLI_ghashIterator_free(iter);
00128 }
00129 
00130 static int compare_int(const void *av, const void *bv)
00131 {
00132     const int *a= (int *)av;
00133     const int *b= (int *)bv;
00134     return *a-*b;
00135 }
00136 
00137 static void IMB_moviecache_destructor(void *p)
00138 {
00139     MovieCacheItem *item= (MovieCacheItem *) p;
00140 
00141     if (item && item->ibuf) {
00142         IMB_freeImBuf(item->ibuf);
00143 
00144         item->ibuf= NULL;
00145         item->c_handle= NULL;
00146     }
00147 }
00148 
00149 /* approximate size of ImBuf in memory */
00150 static intptr_t IMB_get_size_in_memory(ImBuf *ibuf)
00151 {
00152     int a;
00153     intptr_t size= 0, channel_size= 0;
00154 
00155     size+= sizeof(ImBuf);
00156 
00157     if(ibuf->rect)
00158         channel_size+= sizeof(char);
00159 
00160     if(ibuf->rect_float)
00161         channel_size+= sizeof(float);
00162 
00163     size+= channel_size*ibuf->x*ibuf->y*ibuf->channels;
00164 
00165     if(ibuf->miptot) {
00166         for(a= 0; a<ibuf->miptot; a++) {
00167             if(ibuf->mipmap[a])
00168                 size+= IMB_get_size_in_memory(ibuf->mipmap[a]);
00169         }
00170     }
00171 
00172     if(ibuf->tiles) {
00173         size+= sizeof(unsigned int)*ibuf->ytiles*ibuf->xtiles;
00174     }
00175 
00176     return size;
00177 }
00178 
00179 static intptr_t get_item_size (void *p)
00180 {
00181     intptr_t size= sizeof(MovieCacheItem);
00182     MovieCacheItem *item= (MovieCacheItem *) p;
00183 
00184     if(item->ibuf)
00185         size+= IMB_get_size_in_memory(item->ibuf);
00186 
00187     return size;
00188 }
00189 
00190 void IMB_moviecache_init(void)
00191 {
00192     limitor= new_MEM_CacheLimiter(IMB_moviecache_destructor, get_item_size);
00193 }
00194 
00195 void IMB_moviecache_destruct(void)
00196 {
00197     if(limitor)
00198         delete_MEM_CacheLimiter(limitor);
00199 }
00200 
00201 struct MovieCache *IMB_moviecache_create(int keysize, GHashHashFP hashfp, GHashCmpFP cmpfp,
00202         MovieCacheGetKeyDataFP getdatafp)
00203 {
00204     MovieCache *cache;
00205 
00206     cache= MEM_callocN(sizeof(MovieCache), "MovieCache");
00207     cache->keys_pool= BLI_mempool_create(sizeof(MovieCacheKey), 64, 64, FALSE, FALSE);
00208     cache->items_pool= BLI_mempool_create(sizeof(MovieCacheItem), 64, 64, FALSE, FALSE);
00209     cache->userkeys_pool= BLI_mempool_create(keysize, 64, 64, FALSE, FALSE);
00210     cache->hash= BLI_ghash_new(moviecache_hashhash, moviecache_hashcmp, "MovieClip ImBuf cache hash");
00211 
00212     cache->keysize= keysize;
00213     cache->hashfp= hashfp;
00214     cache->cmpfp= cmpfp;
00215     cache->getdatafp= getdatafp;
00216     cache->proxy= -1;
00217 
00218     return cache;
00219 }
00220 
00221 void IMB_moviecache_put(MovieCache *cache, void *userkey, ImBuf *ibuf)
00222 {
00223     MovieCacheKey *key;
00224     MovieCacheItem *item;
00225 
00226     if(!limitor)
00227         IMB_moviecache_init();
00228 
00229     IMB_refImBuf(ibuf);
00230 
00231     key= BLI_mempool_alloc(cache->keys_pool);
00232     key->cache_owner= cache;
00233     key->userkey= BLI_mempool_alloc(cache->userkeys_pool);
00234     memcpy(key->userkey, userkey, cache->keysize);
00235 
00236     item= BLI_mempool_alloc(cache->items_pool);
00237     item->ibuf= ibuf;
00238     item->cache_owner= cache;
00239     item->last_access= cache->curtime++;
00240     item->c_handle= NULL;
00241 
00242     BLI_ghash_remove(cache->hash, key, moviecache_keyfree, moviecache_valfree);
00243     BLI_ghash_insert(cache->hash, key, item);
00244 
00245     item->c_handle= MEM_CacheLimiter_insert(limitor, item);
00246 
00247     MEM_CacheLimiter_ref(item->c_handle);
00248     MEM_CacheLimiter_enforce_limits(limitor);
00249     MEM_CacheLimiter_unref(item->c_handle);
00250 
00251     /* cache limiter can't remove unused keys which points to destoryed values */
00252     check_unused_keys(cache);
00253 
00254     if(cache->points) {
00255         MEM_freeN(cache->points);
00256         cache->points= NULL;
00257     }
00258 }
00259 
00260 ImBuf* IMB_moviecache_get(MovieCache *cache, void *userkey)
00261 {
00262     MovieCacheKey key;
00263     MovieCacheItem *item;
00264 
00265     key.cache_owner= cache;
00266     key.userkey= userkey;
00267     item= (MovieCacheItem*)BLI_ghash_lookup(cache->hash, &key);
00268 
00269     if(item) {
00270         item->last_access= cache->curtime++;
00271 
00272         if(item->ibuf) {
00273             MEM_CacheLimiter_touch(item->c_handle);
00274             IMB_refImBuf(item->ibuf);
00275 
00276             return item->ibuf;
00277         }
00278     }
00279 
00280     return NULL;
00281 }
00282 
00283 void IMB_moviecache_free(MovieCache *cache)
00284 {
00285     BLI_ghash_free(cache->hash, moviecache_keyfree, moviecache_valfree);
00286 
00287     BLI_mempool_destroy(cache->keys_pool);
00288     BLI_mempool_destroy(cache->items_pool);
00289     BLI_mempool_destroy(cache->userkeys_pool);
00290 
00291     if(cache->points)
00292         MEM_freeN(cache->points);
00293 
00294     MEM_freeN(cache);
00295 }
00296 
00297 /* get segments of cached frames. useful for debugging cache policies */
00298 void IMB_moviecache_get_cache_segments(MovieCache *cache, int proxy, int render_flags, int *totseg_r, int **points_r)
00299 {
00300     *totseg_r= 0;
00301     *points_r= NULL;
00302 
00303     if(!cache->getdatafp)
00304         return;
00305 
00306     if(cache->proxy!=proxy || cache->render_flags!=render_flags) {
00307         if(cache->points)
00308             MEM_freeN(cache->points);
00309 
00310         cache->points= NULL;
00311     }
00312 
00313     if(cache->points) {
00314         *totseg_r= cache->totseg;
00315         *points_r= cache->points;
00316     } else {
00317         int totframe= BLI_ghash_size(cache->hash);
00318         int *frames= MEM_callocN(totframe*sizeof(int), "movieclip cache frames");
00319         int a, totseg= 0;
00320         GHashIterator *iter;
00321 
00322         iter= BLI_ghashIterator_new(cache->hash);
00323         a= 0;
00324         while(!BLI_ghashIterator_isDone(iter)) {
00325             MovieCacheKey *key= BLI_ghashIterator_getKey(iter);
00326             MovieCacheItem *item= BLI_ghashIterator_getValue(iter);
00327             int framenr, curproxy, curflags;
00328 
00329             if(item->ibuf) {
00330                 cache->getdatafp(key->userkey, &framenr, &curproxy, &curflags);
00331 
00332                 if(curproxy==proxy && curflags==render_flags)
00333                     frames[a++]= framenr;
00334             }
00335 
00336             BLI_ghashIterator_step(iter);
00337         }
00338 
00339         BLI_ghashIterator_free(iter);
00340 
00341         qsort(frames, totframe, sizeof(int), compare_int);
00342 
00343         /* count */
00344         for(a= 0; a<totframe; a++) {
00345             if(a && frames[a]-frames[a-1]!=1)
00346                 totseg++;
00347 
00348             if(a==totframe-1)
00349                 totseg++;
00350         }
00351 
00352         if(totseg) {
00353             int b, *points;
00354 
00355             points= MEM_callocN(2*sizeof(int)*totseg, "movieclip cache segments");
00356 
00357             /* fill */
00358             for(a= 0, b= 0; a<totframe; a++) {
00359                 if(a==0)
00360                     points[b++]= frames[a];
00361 
00362                 if(a && frames[a]-frames[a-1]!=1) {
00363                     points[b++]= frames[a-1];
00364                     points[b++]= frames[a];
00365                 }
00366 
00367                 if(a==totframe-1)
00368                     points[b++]= frames[a];
00369             }
00370 
00371             *totseg_r= totseg;
00372             *points_r= points;
00373 
00374             cache->totseg= totseg;
00375             cache->points= points;
00376             cache->proxy= proxy;
00377             cache->render_flags= render_flags;
00378         }
00379 
00380         MEM_freeN(frames);
00381     }
00382 }