Blender V2.61 - r43446
|
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 }