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