Change !BLI_ghashIterator_isDone to BLI_ghashIterator_notDone. It is
[blender.git] / source / blender / imbuf / intern / moviecache.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2011 Blender Foundation.
19  * All rights reserved.
20  *
21  * Contributor(s): Blender Foundation,
22  *                 Sergey Sharybin,
23  *                 Peter Schlaile
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/imbuf/intern/moviecache.c
29  *  \ingroup bke
30  */
31
32 #undef DEBUG_MESSAGES
33
34 #include <stdlib.h> /* for qsort */
35 #include <memory.h>
36
37 #include "MEM_guardedalloc.h"
38 #include "MEM_CacheLimiterC-Api.h"
39
40 #include "BLI_string.h"
41 #include "BLI_utildefines.h"
42 #include "BLI_ghash.h"
43 #include "BLI_mempool.h"
44 #include "BLI_threads.h"
45
46 #include "IMB_moviecache.h"
47
48 #include "IMB_imbuf_types.h"
49 #include "IMB_imbuf.h"
50
51 #ifdef DEBUG_MESSAGES
52 #  if defined __GNUC__ || defined __sun
53 #    define PRINT(format, args ...) printf(format, ##args)
54 #  else
55 #    define PRINT(format, ...) printf(__VA_ARGS__)
56 #  endif
57 #else
58 #  define PRINT(format, ...)
59 #endif
60
61 static MEM_CacheLimiterC *limitor = NULL;
62 static pthread_mutex_t limitor_lock = BLI_MUTEX_INITIALIZER;
63
64 typedef struct MovieCache {
65         char name[64];
66
67         GHash *hash;
68         GHashHashFP hashfp;
69         GHashCmpFP cmpfp;
70         MovieCacheGetKeyDataFP getdatafp;
71
72         MovieCacheGetPriorityDataFP getprioritydatafp;
73         MovieCacheGetItemPriorityFP getitempriorityfp;
74         MovieCachePriorityDeleterFP prioritydeleterfp;
75
76         struct BLI_mempool *keys_pool;
77         struct BLI_mempool *items_pool;
78         struct BLI_mempool *userkeys_pool;
79
80         int keysize;
81
82         void *last_userkey;
83
84         int totseg, *points, proxy, render_flags;  /* for visual statistics optimization */
85         int pad;
86 } MovieCache;
87
88 typedef struct MovieCacheKey {
89         MovieCache *cache_owner;
90         void *userkey;
91 } MovieCacheKey;
92
93 typedef struct MovieCacheItem {
94         MovieCache *cache_owner;
95         ImBuf *ibuf;
96         MEM_CacheLimiterHandleC *c_handle;
97         void *priority_data;
98 } MovieCacheItem;
99
100 static unsigned int moviecache_hashhash(const void *keyv)
101 {
102         MovieCacheKey *key = (MovieCacheKey *)keyv;
103
104         return key->cache_owner->hashfp(key->userkey);
105 }
106
107 static int moviecache_hashcmp(const void *av, const void *bv)
108 {
109         const MovieCacheKey *a = (MovieCacheKey *)av;
110         const MovieCacheKey *b = (MovieCacheKey *)bv;
111
112         return a->cache_owner->cmpfp(a->userkey, b->userkey);
113 }
114
115 static void moviecache_keyfree(void *val)
116 {
117         MovieCacheKey *key = (MovieCacheKey *)val;
118
119         BLI_mempool_free(key->cache_owner->userkeys_pool, key->userkey);
120
121         BLI_mempool_free(key->cache_owner->keys_pool, key);
122 }
123
124 static void moviecache_valfree(void *val)
125 {
126         MovieCacheItem *item = (MovieCacheItem *)val;
127         MovieCache *cache = item->cache_owner;
128
129         PRINT("%s: cache '%s' free item %p buffer %p\n", __func__, cache->name, item, item->ibuf);
130
131         if (item->ibuf) {
132                 MEM_CacheLimiter_unmanage(item->c_handle);
133                 IMB_freeImBuf(item->ibuf);
134         }
135
136         if (item->priority_data && cache->prioritydeleterfp) {
137                 cache->prioritydeleterfp(item->priority_data);
138         }
139
140         BLI_mempool_free(item->cache_owner->items_pool, item);
141 }
142
143 static void check_unused_keys(MovieCache *cache)
144 {
145         GHashIterator *iter;
146
147         iter = BLI_ghashIterator_new(cache->hash);
148         while (BLI_ghashIterator_notDone(iter)) {
149                 MovieCacheKey *key = BLI_ghashIterator_getKey(iter);
150                 MovieCacheItem *item = BLI_ghashIterator_getValue(iter);
151                 int remove = 0;
152
153                 BLI_ghashIterator_step(iter);
154
155                 remove = !item->ibuf;
156
157                 if (remove) {
158                         PRINT("%s: cache '%s' remove item %p without buffer\n", __func__, cache->name, item);
159                 }
160
161                 if (remove)
162                         BLI_ghash_remove(cache->hash, key, moviecache_keyfree, moviecache_valfree);
163         }
164
165         BLI_ghashIterator_free(iter);
166 }
167
168 static int compare_int(const void *av, const void *bv)
169 {
170         const int *a = (int *)av;
171         const int *b = (int *)bv;
172         return *a - *b;
173 }
174
175 static void IMB_moviecache_destructor(void *p)
176 {
177         MovieCacheItem *item = (MovieCacheItem *)p;
178
179         if (item && item->ibuf) {
180                 MovieCache *cache = item->cache_owner;
181
182                 PRINT("%s: cache '%s' destroy item %p buffer %p\n", __func__, cache->name, item, item->ibuf);
183
184                 IMB_freeImBuf(item->ibuf);
185
186                 item->ibuf = NULL;
187                 item->c_handle = NULL;
188
189                 /* force cached segments to be updated */
190                 if (cache->points) {
191                         MEM_freeN(cache->points);
192                         cache->points = NULL;
193                 }
194         }
195 }
196
197 /* approximate size of ImBuf in memory */
198 static size_t IMB_get_size_in_memory(ImBuf *ibuf)
199 {
200         int a;
201         size_t size = 0, channel_size = 0;
202
203         size += sizeof(ImBuf);
204
205         if (ibuf->rect)
206                 channel_size += sizeof(char);
207
208         if (ibuf->rect_float)
209                 channel_size += sizeof(float);
210
211         size += channel_size * ibuf->x * ibuf->y * ibuf->channels;
212
213         if (ibuf->miptot) {
214                 for (a = 0; a < ibuf->miptot; a++) {
215                         if (ibuf->mipmap[a])
216                                 size += IMB_get_size_in_memory(ibuf->mipmap[a]);
217                 }
218         }
219
220         if (ibuf->tiles) {
221                 size += sizeof(unsigned int) * ibuf->ytiles * ibuf->xtiles;
222         }
223
224         return size;
225 }
226
227 static size_t get_item_size(void *p)
228 {
229         size_t size = sizeof(MovieCacheItem);
230         MovieCacheItem *item = (MovieCacheItem *) p;
231
232         if (item->ibuf)
233                 size += IMB_get_size_in_memory(item->ibuf);
234
235         return size;
236 }
237
238 static int get_item_priority(void *item_v, int default_priority)
239 {
240         MovieCacheItem *item = (MovieCacheItem *) item_v;
241         MovieCache *cache = item->cache_owner;
242         int priority;
243
244         if (!cache->getitempriorityfp) {
245                 PRINT("%s: cache '%s' item %p use default priority %d\n", __func__, cache-> name, item, default_priority);
246
247                 return default_priority;
248         }
249
250         priority = cache->getitempriorityfp(cache->last_userkey, item->priority_data);
251
252         PRINT("%s: cache '%s' item %p priority %d\n", __func__, cache-> name, item, priority);
253
254         return priority;
255 }
256
257 void IMB_moviecache_init(void)
258 {
259         limitor = new_MEM_CacheLimiter(IMB_moviecache_destructor, get_item_size);
260
261         MEM_CacheLimiter_ItemPriority_Func_set(limitor, get_item_priority);
262 }
263
264 void IMB_moviecache_destruct(void)
265 {
266         if (limitor)
267                 delete_MEM_CacheLimiter(limitor);
268 }
269
270 MovieCache *IMB_moviecache_create(const char *name, int keysize, GHashHashFP hashfp, GHashCmpFP cmpfp)
271 {
272         MovieCache *cache;
273
274         PRINT("%s: cache '%s' create\n", __func__, name);
275
276         cache = MEM_callocN(sizeof(MovieCache), "MovieCache");
277
278         BLI_strncpy(cache->name, name, sizeof(cache->name));
279
280         cache->keys_pool = BLI_mempool_create(sizeof(MovieCacheKey), 64, 64, 0);
281         cache->items_pool = BLI_mempool_create(sizeof(MovieCacheItem), 64, 64, 0);
282         cache->userkeys_pool = BLI_mempool_create(keysize, 64, 64, 0);
283         cache->hash = BLI_ghash_new(moviecache_hashhash, moviecache_hashcmp, "MovieClip ImBuf cache hash");
284
285         cache->keysize = keysize;
286         cache->hashfp = hashfp;
287         cache->cmpfp = cmpfp;
288         cache->proxy = -1;
289
290         return cache;
291 }
292
293 void IMB_moviecache_set_getdata_callback(MovieCache *cache, MovieCacheGetKeyDataFP getdatafp)
294 {
295         cache->getdatafp = getdatafp;
296 }
297
298 void IMB_moviecache_set_priority_callback(struct MovieCache *cache, MovieCacheGetPriorityDataFP getprioritydatafp,
299                                           MovieCacheGetItemPriorityFP getitempriorityfp,
300                                           MovieCachePriorityDeleterFP prioritydeleterfp)
301 {
302         cache->last_userkey = MEM_mallocN(cache->keysize, "movie cache last user key");
303
304         cache->getprioritydatafp = getprioritydatafp;
305         cache->getitempriorityfp = getitempriorityfp;
306         cache->prioritydeleterfp = prioritydeleterfp;
307 }
308
309 void IMB_moviecache_put(MovieCache *cache, void *userkey, ImBuf *ibuf)
310 {
311         MovieCacheKey *key;
312         MovieCacheItem *item;
313
314         if (!limitor)
315                 IMB_moviecache_init();
316
317         IMB_refImBuf(ibuf);
318
319         key = BLI_mempool_alloc(cache->keys_pool);
320         key->cache_owner = cache;
321         key->userkey = BLI_mempool_alloc(cache->userkeys_pool);
322         memcpy(key->userkey, userkey, cache->keysize);
323
324         item = BLI_mempool_alloc(cache->items_pool);
325
326         PRINT("%s: cache '%s' put %p, item %p\n", __func__, cache-> name, ibuf, item);
327
328         item->ibuf = ibuf;
329         item->cache_owner = cache;
330         item->c_handle = NULL;
331         item->priority_data = NULL;
332
333         if (cache->getprioritydatafp) {
334                 item->priority_data = cache->getprioritydatafp(userkey);
335         }
336
337         BLI_ghash_remove(cache->hash, key, moviecache_keyfree, moviecache_valfree);
338         BLI_ghash_insert(cache->hash, key, item);
339
340         if (cache->last_userkey) {
341                 memcpy(cache->last_userkey, userkey, cache->keysize);
342         }
343
344         BLI_mutex_lock(&limitor_lock);
345
346         item->c_handle = MEM_CacheLimiter_insert(limitor, item);
347
348         MEM_CacheLimiter_ref(item->c_handle);
349         MEM_CacheLimiter_enforce_limits(limitor);
350         MEM_CacheLimiter_unref(item->c_handle);
351
352         BLI_mutex_unlock(&limitor_lock);
353
354         /* cache limiter can't remove unused keys which points to destoryed values */
355         check_unused_keys(cache);
356
357         if (cache->points) {
358                 MEM_freeN(cache->points);
359                 cache->points = NULL;
360         }
361 }
362
363 ImBuf *IMB_moviecache_get(MovieCache *cache, void *userkey)
364 {
365         MovieCacheKey key;
366         MovieCacheItem *item;
367
368         key.cache_owner = cache;
369         key.userkey = userkey;
370         item = (MovieCacheItem *)BLI_ghash_lookup(cache->hash, &key);
371
372         if (item) {
373                 if (item->ibuf) {
374                         BLI_mutex_lock(&limitor_lock);
375                         MEM_CacheLimiter_touch(item->c_handle);
376                         BLI_mutex_unlock(&limitor_lock);
377
378                         IMB_refImBuf(item->ibuf);
379
380                         return item->ibuf;
381                 }
382         }
383
384         return NULL;
385 }
386
387 void IMB_moviecache_free(MovieCache *cache)
388 {
389         PRINT("%s: cache '%s' free\n", __func__, cache->name);
390
391         BLI_ghash_free(cache->hash, moviecache_keyfree, moviecache_valfree);
392
393         BLI_mempool_destroy(cache->keys_pool);
394         BLI_mempool_destroy(cache->items_pool);
395         BLI_mempool_destroy(cache->userkeys_pool);
396
397         if (cache->points)
398                 MEM_freeN(cache->points);
399
400         if (cache->last_userkey)
401                 MEM_freeN(cache->last_userkey);
402
403         MEM_freeN(cache);
404 }
405
406 void IMB_moviecache_cleanup(MovieCache *cache, int (cleanup_check_cb) (void *userkey, void *userdata), void *userdata)
407 {
408         GHashIterator *iter;
409
410         iter = BLI_ghashIterator_new(cache->hash);
411         while (BLI_ghashIterator_notDone(iter)) {
412                 MovieCacheKey *key = BLI_ghashIterator_getKey(iter);
413                 int remove;
414
415                 BLI_ghashIterator_step(iter);
416
417                 remove = cleanup_check_cb(key->userkey, userdata);
418
419                 if (remove) {
420                         MovieCacheItem *item = BLI_ghashIterator_getValue(iter);
421                         (void) item;  /* silence unused variable when not using debug */
422
423                         PRINT("%s: cache '%s' remove item %p\n", __func__, cache->name, item);
424
425                         BLI_ghash_remove(cache->hash, key, moviecache_keyfree, moviecache_valfree);
426                 }
427         }
428
429         BLI_ghashIterator_free(iter);
430 }
431
432 /* get segments of cached frames. useful for debugging cache policies */
433 void IMB_moviecache_get_cache_segments(MovieCache *cache, int proxy, int render_flags, int *totseg_r, int **points_r)
434 {
435         *totseg_r = 0;
436         *points_r = NULL;
437
438         if (!cache->getdatafp)
439                 return;
440
441         if (cache->proxy != proxy || cache->render_flags != render_flags) {
442                 if (cache->points)
443                         MEM_freeN(cache->points);
444
445                 cache->points = NULL;
446         }
447
448         if (cache->points) {
449                 *totseg_r = cache->totseg;
450                 *points_r = cache->points;
451         }
452         else {
453                 int totframe = BLI_ghash_size(cache->hash);
454                 int *frames = MEM_callocN(totframe * sizeof(int), "movieclip cache frames");
455                 int a, totseg = 0;
456                 GHashIterator *iter;
457
458                 iter = BLI_ghashIterator_new(cache->hash);
459                 a = 0;
460                 while (BLI_ghashIterator_notDone(iter)) {
461                         MovieCacheKey *key = BLI_ghashIterator_getKey(iter);
462                         MovieCacheItem *item = BLI_ghashIterator_getValue(iter);
463                         int framenr, curproxy, curflags;
464
465                         if (item->ibuf) {
466                                 cache->getdatafp(key->userkey, &framenr, &curproxy, &curflags);
467
468                                 if (curproxy == proxy && curflags == render_flags)
469                                         frames[a++] = framenr;
470                         }
471
472                         BLI_ghashIterator_step(iter);
473                 }
474
475                 BLI_ghashIterator_free(iter);
476
477                 qsort(frames, totframe, sizeof(int), compare_int);
478
479                 /* count */
480                 for (a = 0; a < totframe; a++) {
481                         if (a && frames[a] - frames[a - 1] != 1)
482                                 totseg++;
483
484                         if (a == totframe - 1)
485                                 totseg++;
486                 }
487
488                 if (totseg) {
489                         int b, *points;
490
491                         points = MEM_callocN(2 * sizeof(int) * totseg, "movieclip cache segments");
492
493                         /* fill */
494                         for (a = 0, b = 0; a < totframe; a++) {
495                                 if (a == 0)
496                                         points[b++] = frames[a];
497
498                                 if (a && frames[a] - frames[a - 1] != 1) {
499                                         points[b++] = frames[a - 1];
500                                         points[b++] = frames[a];
501                                 }
502
503                                 if (a == totframe - 1)
504                                         points[b++] = frames[a];
505                         }
506
507                         *totseg_r = totseg;
508                         *points_r = points;
509
510                         cache->totseg = totseg;
511                         cache->points = points;
512                         cache->proxy = proxy;
513                         cache->render_flags = render_flags;
514                 }
515
516                 MEM_freeN(frames);
517         }
518 }