Send sequencer render context as const pointer rather than as value
[blender.git] / source / blender / blenkernel / intern / seqcache.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  * Peter Schlaile <peter [at] schlaile [dot] de> 2010
19  *
20  * Contributor(s): Sergey Sharybin
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 /** \file blender/blenkernel/intern/seqcache.c
26  *  \ingroup bke
27  */
28
29 #include <stddef.h>
30
31 #include "BLI_sys_types.h"  /* for intptr_t */
32
33 #include "MEM_guardedalloc.h"
34
35 #include "DNA_sequence_types.h"
36
37 #include "IMB_moviecache.h"
38 #include "IMB_imbuf.h"
39 #include "IMB_imbuf_types.h"
40
41 #include "BLI_listbase.h"
42
43 #include "BKE_sequencer.h"
44
45 typedef struct SeqCacheKey {
46         struct Sequence *seq;
47         SeqRenderData context;
48         float cfra;
49         seq_stripelem_ibuf_t type;
50 } SeqCacheKey;
51
52 typedef struct SeqPreprocessCacheElem {
53         struct SeqPreprocessCacheElem *next, *prev;
54
55         struct Sequence *seq;
56         SeqRenderData context;
57         seq_stripelem_ibuf_t type;
58
59         ImBuf *ibuf;
60 } SeqPreprocessCacheElem;
61
62 typedef struct SeqPreprocessCache {
63         int cfra;
64         ListBase elems;
65 } SeqPreprocessCache;
66
67 static struct MovieCache *moviecache = NULL;
68 static struct SeqPreprocessCache *preprocess_cache = NULL;
69
70 static void preprocessed_cache_destruct(void);
71
72 static int seq_cmp_render_data(const SeqRenderData *a, const SeqRenderData *b)
73 {
74         if (a->preview_render_size < b->preview_render_size) {
75                 return -1;
76         }
77         if (a->preview_render_size > b->preview_render_size) {
78                 return 1;
79         }
80
81         if (a->rectx < b->rectx) {
82                 return -1;
83         }
84         if (a->rectx > b->rectx) {
85                 return 1;
86         }
87
88         if (a->recty < b->recty) {
89                 return -1;
90         }
91         if (a->recty > b->recty) {
92                 return 1;
93         }
94
95         if (a->bmain < b->bmain) {
96                 return -1;
97         }
98         if (a->bmain > b->bmain) {
99                 return 1;
100         }
101
102         if (a->scene < b->scene) {
103                 return -1;
104         }
105         if (a->scene > b->scene) {
106                 return 1;
107         }
108
109         if (a->motion_blur_shutter < b->motion_blur_shutter) {
110                 return -1;
111         }
112         if (a->motion_blur_shutter > b->motion_blur_shutter) {
113                 return 1;
114         }
115
116         if (a->motion_blur_samples < b->motion_blur_samples) {
117                 return -1;
118         }
119         if (a->motion_blur_samples > b->motion_blur_samples) {
120                 return 1;
121         }
122
123         return 0;
124 }
125
126 static unsigned int seq_hash_render_data(const SeqRenderData *a)
127 {
128         unsigned int rval = a->rectx + a->recty;
129
130         rval ^= a->preview_render_size;
131         rval ^= ((intptr_t) a->bmain) << 6;
132         rval ^= ((intptr_t) a->scene) << 6;
133         rval ^= (int)(a->motion_blur_shutter * 100.0f) << 10;
134         rval ^= a->motion_blur_samples << 24;
135
136         return rval;
137 }
138
139 static unsigned int seqcache_hashhash(const void *key_)
140 {
141         const SeqCacheKey *key = (SeqCacheKey *) key_;
142         unsigned int rval = seq_hash_render_data(&key->context);
143
144         rval ^= *(unsigned int *) &key->cfra;
145         rval += key->type;
146         rval ^= ((intptr_t) key->seq) << 6;
147
148         return rval;
149 }
150
151 static int seqcache_hashcmp(const void *a_, const void *b_)
152 {
153         const SeqCacheKey *a = (SeqCacheKey *) a_;
154         const SeqCacheKey *b = (SeqCacheKey *) b_;
155
156         if (a->seq < b->seq) {
157                 return -1;
158         }
159         if (a->seq > b->seq) {
160                 return 1;
161         }
162
163         if (a->cfra < b->cfra) {
164                 return -1;
165         }
166         if (a->cfra > b->cfra) {
167                 return 1;
168         }
169
170         if (a->type < b->type) {
171                 return -1;
172         }
173         if (a->type > b->type) {
174                 return 1;
175         }
176
177         return seq_cmp_render_data(&a->context, &b->context);
178 }
179
180 void BKE_sequencer_cache_destruct(void)
181 {
182         if (moviecache)
183                 IMB_moviecache_free(moviecache);
184
185         preprocessed_cache_destruct();
186 }
187
188 void BKE_sequencer_cache_cleanup(void)
189 {
190         if (moviecache) {
191                 IMB_moviecache_free(moviecache);
192                 moviecache = IMB_moviecache_create("seqcache", sizeof(SeqCacheKey), seqcache_hashhash, seqcache_hashcmp);
193         }
194
195         BKE_sequencer_preprocessed_cache_cleanup();
196 }
197
198 static bool seqcache_key_check_seq(ImBuf *UNUSED(ibuf), void *userkey, void *userdata)
199 {
200         SeqCacheKey *key = (SeqCacheKey *) userkey;
201         Sequence *seq = (Sequence *) userdata;
202
203         return key->seq == seq;
204 }
205
206 void BKE_sequencer_cache_cleanup_sequence(Sequence *seq)
207 {
208         if (moviecache)
209                 IMB_moviecache_cleanup(moviecache, seqcache_key_check_seq, seq);
210 }
211
212 struct ImBuf *BKE_sequencer_cache_get(const SeqRenderData *context, Sequence *seq, float cfra, seq_stripelem_ibuf_t type)
213 {
214         if (moviecache && seq) {
215                 SeqCacheKey key;
216
217                 key.seq = seq;
218                 key.context = *context;
219                 key.cfra = cfra - seq->start;
220                 key.type = type;
221
222                 return IMB_moviecache_get(moviecache, &key);
223         }
224
225         return NULL;
226 }
227
228 void BKE_sequencer_cache_put(const SeqRenderData *context, Sequence *seq, float cfra, seq_stripelem_ibuf_t type, ImBuf *i)
229 {
230         SeqCacheKey key;
231
232         if (i == NULL || context->skip_cache) {
233                 return;
234         }
235
236         if (!moviecache) {
237                 moviecache = IMB_moviecache_create("seqcache", sizeof(SeqCacheKey), seqcache_hashhash, seqcache_hashcmp);
238         }
239
240         key.seq = seq;
241         key.context = *context;
242         key.cfra = cfra - seq->start;
243         key.type = type;
244
245         IMB_moviecache_put(moviecache, &key, i);
246 }
247
248 void BKE_sequencer_preprocessed_cache_cleanup(void)
249 {
250         SeqPreprocessCacheElem *elem;
251
252         if (!preprocess_cache)
253                 return;
254
255         for (elem = preprocess_cache->elems.first; elem; elem = elem->next) {
256                 IMB_freeImBuf(elem->ibuf);
257         }
258         BLI_freelistN(&preprocess_cache->elems);
259
260         preprocess_cache->elems.first = preprocess_cache->elems.last = NULL;
261 }
262
263 static void preprocessed_cache_destruct(void)
264 {
265         if (!preprocess_cache)
266                 return;
267
268         BKE_sequencer_preprocessed_cache_cleanup();
269
270         MEM_freeN(preprocess_cache);
271         preprocess_cache = NULL;
272 }
273
274 ImBuf *BKE_sequencer_preprocessed_cache_get(const SeqRenderData *context, Sequence *seq, float cfra, seq_stripelem_ibuf_t type)
275 {
276         SeqPreprocessCacheElem *elem;
277
278         if (!preprocess_cache)
279                 return NULL;
280
281         if (preprocess_cache->cfra != cfra)
282                 return NULL;
283
284         for (elem = preprocess_cache->elems.first; elem; elem = elem->next) {
285                 if (elem->seq != seq)
286                         continue;
287
288                 if (elem->type != type)
289                         continue;
290
291                 if (seq_cmp_render_data(&elem->context, context) != 0)
292                         continue;
293
294                 IMB_refImBuf(elem->ibuf);
295                 return elem->ibuf;
296         }
297
298         return NULL;
299 }
300
301 void BKE_sequencer_preprocessed_cache_put(const SeqRenderData *context, Sequence *seq, float cfra, seq_stripelem_ibuf_t type, ImBuf *ibuf)
302 {
303         SeqPreprocessCacheElem *elem;
304
305         if (!preprocess_cache) {
306                 preprocess_cache = MEM_callocN(sizeof(SeqPreprocessCache), "sequencer preprocessed cache");
307         }
308         else {
309                 if (preprocess_cache->cfra != cfra)
310                         BKE_sequencer_preprocessed_cache_cleanup();
311         }
312
313         elem = MEM_callocN(sizeof(SeqPreprocessCacheElem), "sequencer preprocessed cache element");
314
315         elem->seq = seq;
316         elem->type = type;
317         elem->context = *context;
318         elem->ibuf = ibuf;
319
320         preprocess_cache->cfra = cfra;
321
322         IMB_refImBuf(ibuf);
323
324         BLI_addtail(&preprocess_cache->elems, elem);
325 }
326
327 void BKE_sequencer_preprocessed_cache_cleanup_sequence(Sequence *seq)
328 {
329         SeqPreprocessCacheElem *elem, *elem_next;
330
331         if (!preprocess_cache)
332                 return;
333
334         for (elem = preprocess_cache->elems.first; elem; elem = elem_next) {
335                 elem_next = elem->next;
336
337                 if (elem->seq == seq) {
338                         IMB_freeImBuf(elem->ibuf);
339
340                         BLI_freelinkN(&preprocess_cache->elems, elem);
341                 }
342         }
343 }