4b49076dcd655d062d6cbd8d717fab59025ce042
[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         const MovieCacheKey *key = keyv;
103
104         return key->cache_owner->hashfp(key->userkey);
105 }
106
107 static bool moviecache_hashcmp(const void *av, const void *bv)
108 {
109         const MovieCacheKey *a = av;
110         const MovieCacheKey *b = 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 = 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 gh_iter;
146
147         BLI_ghashIterator_init(&gh_iter, cache->hash);
148
149         while (!BLI_ghashIterator_done(&gh_iter)) {
150                 const MovieCacheKey *key = BLI_ghashIterator_getKey(&gh_iter);
151                 const MovieCacheItem *item = BLI_ghashIterator_getValue(&gh_iter);
152                 bool remove;
153
154                 BLI_ghashIterator_step(&gh_iter);
155
156                 remove = !item->ibuf;
157
158                 if (remove) {
159                         PRINT("%s: cache '%s' remove item %p without buffer\n", __func__, cache->name, item);
160                 }
161
162                 if (remove)
163                         BLI_ghash_remove(cache->hash, key, moviecache_keyfree, moviecache_valfree);
164         }
165 }
166
167 static int compare_int(const void *av, const void *bv)
168 {
169         const int *a = av;
170         const int *b = bv;
171         return *a - *b;
172 }
173
174 static void IMB_moviecache_destructor(void *p)
175 {
176         MovieCacheItem *item = (MovieCacheItem *)p;
177
178         if (item && item->ibuf) {
179                 MovieCache *cache = item->cache_owner;
180
181                 PRINT("%s: cache '%s' destroy item %p buffer %p\n", __func__, cache->name, item, item->ibuf);
182
183                 IMB_freeImBuf(item->ibuf);
184
185                 item->ibuf = NULL;
186                 item->c_handle = NULL;
187
188                 /* force cached segments to be updated */
189                 if (cache->points) {
190                         MEM_freeN(cache->points);
191                         cache->points = NULL;
192                 }
193         }
194 }
195
196 /* approximate size of ImBuf in memory */
197 static size_t IMB_get_size_in_memory(ImBuf *ibuf)
198 {
199         int a;
200         size_t size = 0, channel_size = 0;
201
202         /* Persistent images should have no affect on how "normal"
203          * images are cached.
204          *
205          * This is a bit arbitrary, but would make it so only movies
206          * and sequences are memory limited, keeping textures in the
207          * memory in order to avoid constant file reload on viewport
208          * update.
209          */
210         if (ibuf->userflags & IB_PERSISTENT) {
211                 return 0;
212         }
213
214         size += sizeof(ImBuf);
215
216         if (ibuf->rect)
217                 channel_size += sizeof(char);
218
219         if (ibuf->rect_float)
220                 channel_size += sizeof(float);
221
222         size += channel_size * ibuf->x * ibuf->y * ibuf->channels;
223
224         if (ibuf->miptot) {
225                 for (a = 0; a < ibuf->miptot; a++) {
226                         if (ibuf->mipmap[a])
227                                 size += IMB_get_size_in_memory(ibuf->mipmap[a]);
228                 }
229         }
230
231         if (ibuf->tiles) {
232                 size += sizeof(unsigned int) * ibuf->ytiles * ibuf->xtiles;
233         }
234
235         return size;
236 }
237
238 static size_t get_item_size(void *p)
239 {
240         size_t size = sizeof(MovieCacheItem);
241         MovieCacheItem *item = (MovieCacheItem *) p;
242
243         if (item->ibuf)
244                 size += IMB_get_size_in_memory(item->ibuf);
245
246         return size;
247 }
248
249 static int get_item_priority(void *item_v, int default_priority)
250 {
251         MovieCacheItem *item = (MovieCacheItem *) item_v;
252         MovieCache *cache = item->cache_owner;
253         int priority;
254
255         if (!cache->getitempriorityfp) {
256                 PRINT("%s: cache '%s' item %p use default priority %d\n", __func__, cache-> name, item, default_priority);
257
258                 return default_priority;
259         }
260
261         priority = cache->getitempriorityfp(cache->last_userkey, item->priority_data);
262
263         PRINT("%s: cache '%s' item %p priority %d\n", __func__, cache-> name, item, priority);
264
265         return priority;
266 }
267
268 static bool get_item_destroyable(void *item_v)
269 {
270         MovieCacheItem *item = (MovieCacheItem *) item_v;
271         /* IB_BITMAPDIRTY means image was modified from inside blender and
272          * changes are not saved to disk.
273          *
274          * Such buffers are never to be freed.
275          */
276         if ((item->ibuf->userflags & IB_BITMAPDIRTY) ||
277             (item->ibuf->userflags & IB_PERSISTENT))
278         {
279                 return false;
280         }
281         return true;
282 }
283
284 void IMB_moviecache_init(void)
285 {
286         limitor = new_MEM_CacheLimiter(IMB_moviecache_destructor, get_item_size);
287
288         MEM_CacheLimiter_ItemPriority_Func_set(limitor, get_item_priority);
289         MEM_CacheLimiter_ItemDestroyable_Func_set(limitor, get_item_destroyable);
290 }
291
292 void IMB_moviecache_destruct(void)
293 {
294         if (limitor)
295                 delete_MEM_CacheLimiter(limitor);
296 }
297
298 MovieCache *IMB_moviecache_create(const char *name, int keysize, GHashHashFP hashfp, GHashCmpFP cmpfp)
299 {
300         MovieCache *cache;
301
302         PRINT("%s: cache '%s' create\n", __func__, name);
303
304         cache = MEM_callocN(sizeof(MovieCache), "MovieCache");
305
306         BLI_strncpy(cache->name, name, sizeof(cache->name));
307
308         cache->keys_pool = BLI_mempool_create(sizeof(MovieCacheKey), 0, 64, BLI_MEMPOOL_NOP);
309         cache->items_pool = BLI_mempool_create(sizeof(MovieCacheItem), 0, 64, BLI_MEMPOOL_NOP);
310         cache->userkeys_pool = BLI_mempool_create(keysize, 0, 64, BLI_MEMPOOL_NOP);
311         cache->hash = BLI_ghash_new(moviecache_hashhash, moviecache_hashcmp, "MovieClip ImBuf cache hash");
312
313         cache->keysize = keysize;
314         cache->hashfp = hashfp;
315         cache->cmpfp = cmpfp;
316         cache->proxy = -1;
317
318         return cache;
319 }
320
321 void IMB_moviecache_set_getdata_callback(MovieCache *cache, MovieCacheGetKeyDataFP getdatafp)
322 {
323         cache->getdatafp = getdatafp;
324 }
325
326 void IMB_moviecache_set_priority_callback(struct MovieCache *cache, MovieCacheGetPriorityDataFP getprioritydatafp,
327                                           MovieCacheGetItemPriorityFP getitempriorityfp,
328                                           MovieCachePriorityDeleterFP prioritydeleterfp)
329 {
330         cache->last_userkey = MEM_mallocN(cache->keysize, "movie cache last user key");
331
332         cache->getprioritydatafp = getprioritydatafp;
333         cache->getitempriorityfp = getitempriorityfp;
334         cache->prioritydeleterfp = prioritydeleterfp;
335 }
336
337 static void do_moviecache_put(MovieCache *cache, void *userkey, ImBuf *ibuf, bool need_lock)
338 {
339         MovieCacheKey *key;
340         MovieCacheItem *item;
341
342         if (!limitor)
343                 IMB_moviecache_init();
344
345         IMB_refImBuf(ibuf);
346
347         key = BLI_mempool_alloc(cache->keys_pool);
348         key->cache_owner = cache;
349         key->userkey = BLI_mempool_alloc(cache->userkeys_pool);
350         memcpy(key->userkey, userkey, cache->keysize);
351
352         item = BLI_mempool_alloc(cache->items_pool);
353
354         PRINT("%s: cache '%s' put %p, item %p\n", __func__, cache-> name, ibuf, item);
355
356         item->ibuf = ibuf;
357         item->cache_owner = cache;
358         item->c_handle = NULL;
359         item->priority_data = NULL;
360
361         if (cache->getprioritydatafp) {
362                 item->priority_data = cache->getprioritydatafp(userkey);
363         }
364
365         BLI_ghash_reinsert(cache->hash, key, item, moviecache_keyfree, moviecache_valfree);
366
367         if (cache->last_userkey) {
368                 memcpy(cache->last_userkey, userkey, cache->keysize);
369         }
370
371         if (need_lock)
372                 BLI_mutex_lock(&limitor_lock);
373
374         item->c_handle = MEM_CacheLimiter_insert(limitor, item);
375
376         MEM_CacheLimiter_ref(item->c_handle);
377         MEM_CacheLimiter_enforce_limits(limitor);
378         MEM_CacheLimiter_unref(item->c_handle);
379
380         if (need_lock)
381                 BLI_mutex_unlock(&limitor_lock);
382
383         /* cache limiter can't remove unused keys which points to destoryed values */
384         check_unused_keys(cache);
385
386         if (cache->points) {
387                 MEM_freeN(cache->points);
388                 cache->points = NULL;
389         }
390 }
391
392 void IMB_moviecache_put(MovieCache *cache, void *userkey, ImBuf *ibuf)
393 {
394         do_moviecache_put(cache, userkey, ibuf, true);
395 }
396
397 bool IMB_moviecache_put_if_possible(MovieCache *cache, void *userkey, ImBuf *ibuf)
398 {
399         size_t mem_in_use, mem_limit, elem_size;
400         bool result = false;
401
402         elem_size = IMB_get_size_in_memory(ibuf);
403         mem_limit = MEM_CacheLimiter_get_maximum();
404
405         BLI_mutex_lock(&limitor_lock);
406         mem_in_use = MEM_CacheLimiter_get_memory_in_use(limitor);
407
408         if (mem_in_use + elem_size <= mem_limit) {
409                 do_moviecache_put(cache, userkey, ibuf, false);
410                 result = true;
411         }
412
413         BLI_mutex_unlock(&limitor_lock);
414
415         return result;
416 }
417
418 ImBuf *IMB_moviecache_get(MovieCache *cache, void *userkey)
419 {
420         MovieCacheKey key;
421         MovieCacheItem *item;
422
423         key.cache_owner = cache;
424         key.userkey = userkey;
425         item = (MovieCacheItem *)BLI_ghash_lookup(cache->hash, &key);
426
427         if (item) {
428                 if (item->ibuf) {
429                         BLI_mutex_lock(&limitor_lock);
430                         MEM_CacheLimiter_touch(item->c_handle);
431                         BLI_mutex_unlock(&limitor_lock);
432
433                         IMB_refImBuf(item->ibuf);
434
435                         return item->ibuf;
436                 }
437         }
438
439         return NULL;
440 }
441
442 bool IMB_moviecache_has_frame(MovieCache *cache, void *userkey)
443 {
444         MovieCacheKey key;
445         MovieCacheItem *item;
446
447         key.cache_owner = cache;
448         key.userkey = userkey;
449         item = (MovieCacheItem *)BLI_ghash_lookup(cache->hash, &key);
450
451         return item != NULL;
452 }
453
454 void IMB_moviecache_free(MovieCache *cache)
455 {
456         PRINT("%s: cache '%s' free\n", __func__, cache->name);
457
458         BLI_ghash_free(cache->hash, moviecache_keyfree, moviecache_valfree);
459
460         BLI_mempool_destroy(cache->keys_pool);
461         BLI_mempool_destroy(cache->items_pool);
462         BLI_mempool_destroy(cache->userkeys_pool);
463
464         if (cache->points)
465                 MEM_freeN(cache->points);
466
467         if (cache->last_userkey)
468                 MEM_freeN(cache->last_userkey);
469
470         MEM_freeN(cache);
471 }
472
473 void IMB_moviecache_cleanup(MovieCache *cache, bool (cleanup_check_cb) (ImBuf *ibuf, void *userkey, void *userdata), void *userdata)
474 {
475         GHashIterator gh_iter;
476
477         check_unused_keys(cache);
478
479         BLI_ghashIterator_init(&gh_iter, cache->hash);
480
481         while (!BLI_ghashIterator_done(&gh_iter)) {
482                 MovieCacheKey *key = BLI_ghashIterator_getKey(&gh_iter);
483                 MovieCacheItem *item = BLI_ghashIterator_getValue(&gh_iter);
484
485                 BLI_ghashIterator_step(&gh_iter);
486
487                 if (cleanup_check_cb(item->ibuf, key->userkey, userdata)) {
488                         PRINT("%s: cache '%s' remove item %p\n", __func__, cache->name, item);
489
490                         BLI_ghash_remove(cache->hash, key, moviecache_keyfree, moviecache_valfree);
491                 }
492         }
493 }
494
495 /* get segments of cached frames. useful for debugging cache policies */
496 void IMB_moviecache_get_cache_segments(MovieCache *cache, int proxy, int render_flags, int *totseg_r, int **points_r)
497 {
498         *totseg_r = 0;
499         *points_r = NULL;
500
501         if (!cache->getdatafp)
502                 return;
503
504         if (cache->proxy != proxy || cache->render_flags != render_flags) {
505                 if (cache->points)
506                         MEM_freeN(cache->points);
507
508                 cache->points = NULL;
509         }
510
511         if (cache->points) {
512                 *totseg_r = cache->totseg;
513                 *points_r = cache->points;
514         }
515         else {
516                 int totframe = BLI_ghash_size(cache->hash);
517                 int *frames = MEM_callocN(totframe * sizeof(int), "movieclip cache frames");
518                 int a, totseg = 0;
519                 GHashIterator gh_iter;
520
521                 a = 0;
522                 GHASH_ITER(gh_iter, cache->hash) {
523                         MovieCacheKey *key = BLI_ghashIterator_getKey(&gh_iter);
524                         MovieCacheItem *item = BLI_ghashIterator_getValue(&gh_iter);
525                         int framenr, curproxy, curflags;
526
527                         if (item->ibuf) {
528                                 cache->getdatafp(key->userkey, &framenr, &curproxy, &curflags);
529
530                                 if (curproxy == proxy && curflags == render_flags)
531                                         frames[a++] = framenr;
532                         }
533                 }
534
535                 qsort(frames, totframe, sizeof(int), compare_int);
536
537                 /* count */
538                 for (a = 0; a < totframe; a++) {
539                         if (a && frames[a] - frames[a - 1] != 1)
540                                 totseg++;
541
542                         if (a == totframe - 1)
543                                 totseg++;
544                 }
545
546                 if (totseg) {
547                         int b, *points;
548
549                         points = MEM_callocN(2 * sizeof(int) * totseg, "movieclip cache segments");
550
551                         /* fill */
552                         for (a = 0, b = 0; a < totframe; a++) {
553                                 if (a == 0)
554                                         points[b++] = frames[a];
555
556                                 if (a && frames[a] - frames[a - 1] != 1) {
557                                         points[b++] = frames[a - 1];
558                                         points[b++] = frames[a];
559                                 }
560
561                                 if (a == totframe - 1)
562                                         points[b++] = frames[a];
563                         }
564
565                         *totseg_r = totseg;
566                         *points_r = points;
567
568                         cache->totseg = totseg;
569                         cache->points = points;
570                         cache->proxy = proxy;
571                         cache->render_flags = render_flags;
572                 }
573
574                 MEM_freeN(frames);
575         }
576 }
577
578 struct MovieCacheIter *IMB_moviecacheIter_new(MovieCache *cache)
579 {
580         GHashIterator *iter;
581
582         check_unused_keys(cache);
583         iter = BLI_ghashIterator_new(cache->hash);
584
585         return (struct MovieCacheIter *) iter;
586 }
587
588 void IMB_moviecacheIter_free(struct MovieCacheIter *iter)
589 {
590         BLI_ghashIterator_free((GHashIterator *) iter);
591 }
592
593 bool IMB_moviecacheIter_done(struct MovieCacheIter *iter)
594 {
595         return BLI_ghashIterator_done((GHashIterator *) iter);
596 }
597
598 void IMB_moviecacheIter_step(struct MovieCacheIter *iter)
599 {
600         BLI_ghashIterator_step((GHashIterator *) iter);
601 }
602
603 ImBuf *IMB_moviecacheIter_getImBuf(struct MovieCacheIter *iter)
604 {
605         MovieCacheItem *item = BLI_ghashIterator_getValue((GHashIterator *) iter);
606         return item->ibuf;
607 }
608
609 void *IMB_moviecacheIter_getUserKey(struct MovieCacheIter *iter)
610 {
611         MovieCacheKey *key = BLI_ghashIterator_getKey((GHashIterator *) iter);
612         return key->userkey;
613 }