aa02fd7d71187f2df6246bdb949df43c3f8b9e1a
[blender.git] / source / blender / blenkernel / intern / moviecache.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2011 Blender Foundation.
21  * All rights reserved.
22  *
23  * Contributor(s): Blender Foundation,
24  *                 Sergey Sharybin,
25  *                 Peter Schlaile
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 /** \file blender/blenkernel/intern/moviecache.c
31  *  \ingroup bke
32  */
33
34 #include "MEM_guardedalloc.h"
35 #include "MEM_CacheLimiterC-Api.h"
36
37 #include "BLI_utildefines.h"
38 #include "BLI_ghash.h"
39 #include "BLI_mempool.h"
40
41 #include "BKE_moviecache.h"
42
43 #include "IMB_imbuf_types.h"
44 #include "IMB_imbuf.h"
45
46 static MEM_CacheLimiterC *limitor= NULL;
47
48 typedef struct MovieCache {
49         GHash *hash;
50         GHashHashFP hashfp;
51         GHashCmpFP cmpfp;
52         MovieCacheGetKeyDataFP getdatafp;
53
54         struct BLI_mempool *keys_pool;
55         struct BLI_mempool *items_pool;
56         struct BLI_mempool *userkeys_pool;
57
58         int keysize;
59         unsigned long curtime;
60
61         int totseg, *points;    /* for visual statistics optimization */
62 } MovieCache;
63
64 typedef struct MovieCacheKey {
65         MovieCache *cache_owner;
66         void *userkey;
67 } MovieCacheKey;
68
69 typedef struct MovieCacheItem {
70         MovieCache *cache_owner;
71         ImBuf *ibuf;
72         MEM_CacheLimiterHandleC * c_handle;
73         unsigned long last_access;
74 } MovieCacheItem;
75
76 static unsigned int moviecache_hashhash(const void *keyv)
77 {
78         MovieCacheKey *key= (MovieCacheKey*)keyv;
79
80         return key->cache_owner->hashfp(key->userkey);
81 }
82
83 static int moviecache_hashcmp(const void *av, const void *bv)
84 {
85         const MovieCacheKey *a= (MovieCacheKey*)av;
86         const MovieCacheKey *b= (MovieCacheKey*)bv;
87
88         return a->cache_owner->cmpfp(a->userkey, b->userkey);
89 }
90
91 static void moviecache_keyfree(void *val)
92 {
93         MovieCacheKey *key= (MovieCacheKey*)val;
94
95         BLI_mempool_free(key->cache_owner->keys_pool, key);
96 }
97
98 static void moviecache_valfree(void *val)
99 {
100         MovieCacheItem *item= (MovieCacheItem*)val;
101
102         if (item->ibuf) {
103                 MEM_CacheLimiter_unmanage(item->c_handle);
104                 IMB_freeImBuf(item->ibuf);
105         }
106
107         BLI_mempool_free(item->cache_owner->items_pool, item);
108 }
109
110 static void check_unused_keys(MovieCache *cache)
111 {
112         GHashIterator *iter;
113
114         iter= BLI_ghashIterator_new(cache->hash);
115         while(!BLI_ghashIterator_isDone(iter)) {
116                 MovieCacheKey *key= BLI_ghashIterator_getKey(iter);
117                 MovieCacheItem *item= BLI_ghashIterator_getValue(iter);
118
119                 BLI_ghashIterator_step(iter);
120
121                 if(!item->ibuf)
122                         BLI_ghash_remove(cache->hash, key, moviecache_keyfree, moviecache_valfree);
123         }
124
125         BLI_ghashIterator_free(iter);
126 }
127
128 static int compare_int(const void *av, const void *bv)
129 {
130         const int *a= (int *)av;
131         const int *b= (int *)bv;
132         return *a-*b;
133 }
134
135 static void IMB_moviecache_destructor(void *p)
136 {
137         MovieCacheItem *item= (MovieCacheItem *) p;
138
139         if (item && item->ibuf) {
140                 IMB_freeImBuf(item->ibuf);
141
142                 item->ibuf= NULL;
143                 item->c_handle= NULL;
144         }
145 }
146
147 /* approximate size of ImBuf in memory */
148 static intptr_t IMB_get_size_in_memory(ImBuf *ibuf)
149 {
150         int a;
151         intptr_t size= 0, channel_size= 0;
152
153         size+= sizeof(ImBuf);
154
155         if(ibuf->rect)
156                 channel_size+= sizeof(char);
157
158         if(ibuf->rect_float)
159                 channel_size= sizeof(float);
160
161         size+= channel_size*ibuf->x*ibuf->y*ibuf->channels;
162
163         if(ibuf->miptot) {
164                 for(a= 0; a<ibuf->miptot; a++) {
165                         if(ibuf->mipmap[a])
166                                 size+= IMB_get_size_in_memory(ibuf->mipmap[a]);
167                 }
168         }
169
170         if(ibuf->tiles) {
171                 size+= sizeof(unsigned int)*ibuf->ytiles*ibuf->xtiles;
172         }
173
174         return size;
175 }
176
177 static intptr_t get_item_size (void *p)
178 {
179         intptr_t size= sizeof(MovieCacheItem);
180         MovieCacheItem *item= (MovieCacheItem *) p;
181
182         if(item->ibuf)
183                 size+= IMB_get_size_in_memory(item->ibuf);
184
185         return size;
186 }
187
188 void BKE_moviecache_init(void)
189 {
190         limitor= new_MEM_CacheLimiter(IMB_moviecache_destructor, get_item_size);
191 }
192
193 void BKE_moviecache_destruct(void)
194 {
195         if(limitor)
196                 delete_MEM_CacheLimiter(limitor);
197 }
198
199 struct MovieCache *BKE_moviecache_create(int keysize, GHashHashFP hashfp, GHashCmpFP cmpfp,
200                 MovieCacheGetKeyDataFP getdatafp)
201 {
202         MovieCache *cache;
203
204         cache= MEM_callocN(sizeof(MovieCache), "MovieCache");
205         cache->keys_pool= BLI_mempool_create(sizeof(MovieCacheKey), 64, 64, 0);
206         cache->items_pool= BLI_mempool_create(sizeof(MovieCacheItem), 64, 64, 0);
207         cache->userkeys_pool= BLI_mempool_create(keysize, 64, 64, 0);
208         cache->hash= BLI_ghash_new(moviecache_hashhash, moviecache_hashcmp, "MovieClip ImBuf cache hash");
209
210         cache->keysize= keysize;
211         cache->hashfp= hashfp;
212         cache->cmpfp= cmpfp;
213         cache->getdatafp= getdatafp;
214
215         return cache;
216 }
217
218 void BKE_moviecache_put(MovieCache *cache, void *userkey, ImBuf *ibuf)
219 {
220         MovieCacheKey *key;
221         MovieCacheItem *item;
222
223         if(!limitor)
224                 BKE_moviecache_init();
225
226         IMB_refImBuf(ibuf);
227
228         key= BLI_mempool_alloc(cache->keys_pool);
229         key->cache_owner= cache;
230         key->userkey= BLI_mempool_alloc(cache->userkeys_pool);;
231         memcpy(key->userkey, userkey, cache->keysize);
232
233         item= BLI_mempool_alloc(cache->items_pool);
234         item->ibuf= ibuf;
235         item->cache_owner= cache;
236         item->last_access= cache->curtime++;
237         item->c_handle= NULL;
238
239         BLI_ghash_remove(cache->hash, key, moviecache_keyfree, moviecache_valfree);
240         BLI_ghash_insert(cache->hash, key, item);
241
242         item->c_handle= MEM_CacheLimiter_insert(limitor, item);
243
244         MEM_CacheLimiter_ref(item->c_handle);
245         MEM_CacheLimiter_enforce_limits(limitor);
246         MEM_CacheLimiter_unref(item->c_handle);
247
248         /* cache limiter can't remove unused keys which points to destoryed values */
249         check_unused_keys(cache);
250
251         if(cache->points) {
252                 MEM_freeN(cache->points);
253                 cache->points= NULL;
254         }
255 }
256
257 ImBuf* BKE_moviecache_get(MovieCache *cache, void *userkey)
258 {
259         MovieCacheKey key;
260         MovieCacheItem *item;
261
262         key.cache_owner= cache;
263         key.userkey= userkey;
264         item= (MovieCacheItem*)BLI_ghash_lookup(cache->hash, &key);
265
266         if(item) {
267                 item->last_access= cache->curtime++;
268
269                 if(item->ibuf) {
270                         MEM_CacheLimiter_touch(item->c_handle);
271                         IMB_refImBuf(item->ibuf);
272                         return item->ibuf;
273                 }
274         }
275
276         return NULL;
277 }
278
279 void BKE_moviecache_free(MovieCache *cache)
280 {
281         BLI_ghash_free(cache->hash, moviecache_keyfree, moviecache_valfree);
282
283         BLI_mempool_destroy(cache->keys_pool);
284         BLI_mempool_destroy(cache->items_pool);
285         BLI_mempool_destroy(cache->userkeys_pool);
286
287         if(cache->points)
288                 MEM_freeN(cache->points);
289
290         MEM_freeN(cache);
291 }
292
293 /* get segments of cached frames. useful for debugging cache policies */
294 void BKE_moviecache_get_cache_segments(MovieCache *cache, int *totseg_r, int **points_r)
295 {
296         *totseg_r= 0;
297         *points_r= NULL;
298
299         if(!cache->getdatafp)
300                 return;
301
302         if(cache->points) {
303                 *totseg_r= cache->totseg;
304                 *points_r= cache->points;
305         } else if(cache) {
306                 int totframe= BLI_ghash_size(cache->hash);
307                 int *frames= MEM_callocN(totframe*sizeof(int), "movieclip cache frames");
308                 int a, totseg= 0;
309                 GHashIterator *iter;
310
311                 iter= BLI_ghashIterator_new(cache->hash);
312                 a= 0;
313                 while(!BLI_ghashIterator_isDone(iter)) {
314                         MovieCacheKey *key= BLI_ghashIterator_getKey(iter);
315                         MovieCacheItem *item= BLI_ghashIterator_getValue(iter);
316                         int framenr;
317
318                         if(item->ibuf) {
319                                 cache->getdatafp(key->userkey, &framenr);
320
321                                 frames[a++]= framenr;
322                         }
323
324                         BLI_ghashIterator_step(iter);
325                 }
326
327                 BLI_ghashIterator_free(iter);
328
329                 qsort(frames, totframe, sizeof(int), compare_int);
330
331                 /* count */
332                 for(a= 0; a<totframe; a++) {
333                         if(a && frames[a]-frames[a-1]!=1)
334                                 totseg++;
335
336                         if(a==totframe-1)
337                                 totseg++;
338                 }
339
340                 if(totseg) {
341                         int b, *points;
342
343                         points= MEM_callocN(2*sizeof(int)*totseg, "movieclip cache segments");
344
345                         /* fill */
346                         for(a= 0, b= 0; a<totframe; a++) {
347                                 if(a==0)
348                                         points[b++]= frames[a];
349
350                                 if(a && frames[a]-frames[a-1]!=1) {
351                                         points[b++]= frames[a-1];
352                                         points[b++]= frames[a];
353                                 }
354
355                                 if(a==totframe-1)
356                                         points[b++]= frames[a];
357                         }
358
359                         MEM_freeN(frames);
360
361                         *totseg_r= totseg;
362                         *points_r= points;
363
364                         cache->totseg= totseg;
365                         cache->points= points;
366                 }
367         }
368 }