Sequencer: per-sequence modifier stack for color grading
[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
30 #include <stddef.h>
31
32 #include "BLO_sys_types.h"  /* for intptr_t */
33
34 #include "MEM_guardedalloc.h"
35
36 #include "DNA_sequence_types.h"
37 #include "BKE_sequencer.h"
38
39 #include "IMB_moviecache.h"
40 #include "IMB_imbuf.h"
41 #include "IMB_imbuf_types.h"
42
43 #include "BLI_listbase.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
196 static int seqcache_key_check_seq(void *userkey, void *userdata)
197 {
198         SeqCacheKey *key = (SeqCacheKey *) userkey;
199         Sequence *seq = (Sequence *) userdata;
200
201         return key->seq == seq;
202 }
203
204 void BKE_sequencer_cache_cleanup_sequence(Sequence *seq)
205 {
206         if (moviecache)
207                 IMB_moviecache_cleanup(moviecache, seqcache_key_check_seq, seq);
208 }
209
210 struct ImBuf *BKE_sequencer_cache_get(SeqRenderData context, Sequence *seq, float cfra, seq_stripelem_ibuf_t type)
211 {
212         if (moviecache && seq) {
213                 SeqCacheKey key;
214
215                 key.seq = seq;
216                 key.context = context;
217                 key.cfra = cfra - seq->start;
218                 key.type = type;
219
220                 return IMB_moviecache_get(moviecache, &key);
221         }
222
223         return NULL;
224 }
225
226 void BKE_sequencer_cache_put(SeqRenderData context, Sequence *seq, float cfra, seq_stripelem_ibuf_t type, ImBuf *i)
227 {
228         SeqCacheKey key;
229
230         if (!i) {
231                 return;
232         }
233
234         if (!moviecache) {
235                 moviecache = IMB_moviecache_create("seqcache", sizeof(SeqCacheKey), seqcache_hashhash, seqcache_hashcmp);
236         }
237
238         key.seq = seq;
239         key.context = context;
240         key.cfra = cfra - seq->start;
241         key.type = type;
242
243         IMB_moviecache_put(moviecache, &key, i);
244 }
245
246 static void preprocessed_cache_clean(void)
247 {
248         SeqPreprocessCacheElem *elem;
249
250         if (!preprocess_cache)
251                 return;
252
253         for (elem = preprocess_cache->elems.first; elem; elem = elem->next) {
254                 IMB_freeImBuf(elem->ibuf);
255         }
256         BLI_freelistN(&preprocess_cache->elems);
257
258         preprocess_cache->elems.first = preprocess_cache->elems.last = NULL;
259 }
260
261 static void preprocessed_cache_destruct(void)
262 {
263         if (!preprocess_cache)
264                 return;
265
266         preprocessed_cache_clean();
267
268         MEM_freeN(preprocess_cache);
269         preprocess_cache = NULL;
270 }
271
272 ImBuf *BKE_sequencer_preprocessed_cache_get(SeqRenderData context, Sequence *seq, float cfra, seq_stripelem_ibuf_t type)
273 {
274         SeqPreprocessCacheElem *elem;
275
276         if (!preprocess_cache)
277                 return NULL;
278
279         if (preprocess_cache->cfra != cfra)
280                 return NULL;
281
282         for (elem = preprocess_cache->elems.first; elem; elem = elem->next) {
283                 if (elem->seq != seq)
284                         continue;
285
286                 if (elem->type != type)
287                         continue;
288
289                 if (seq_cmp_render_data(&elem->context, &context) != 0)
290                         continue;
291
292                 IMB_refImBuf(elem->ibuf);
293                 return elem->ibuf;
294         }
295
296         return NULL;
297 }
298
299 void BKE_sequencer_preprocessed_cache_put(SeqRenderData context, Sequence *seq, float cfra, seq_stripelem_ibuf_t type, ImBuf *ibuf)
300 {
301         SeqPreprocessCacheElem *elem;
302
303         if (!preprocess_cache) {
304                 preprocess_cache = MEM_callocN(sizeof(SeqPreprocessCache), "sequencer preprocessed cache");
305         }
306         else {
307                 if (preprocess_cache->cfra != cfra)
308                         preprocessed_cache_clean();
309         }
310
311         elem = MEM_callocN(sizeof(SeqPreprocessCacheElem), "sequencer preprocessed cache element");
312
313         elem->seq = seq;
314         elem->type = type;
315         elem->context = context;
316         elem->ibuf = ibuf;
317
318         preprocess_cache->cfra = cfra;
319
320         IMB_refImBuf(ibuf);
321
322         BLI_addtail(&preprocess_cache->elems, elem);
323 }
324
325 void BKE_sequencer_preprocessed_cache_cleanup_sequence(Sequence *seq)
326 {
327         SeqPreprocessCacheElem *elem, *elem_next;
328
329         if (!preprocess_cache)
330                 return;
331
332         for (elem = preprocess_cache->elems.first; elem; elem = elem_next) {
333                 elem_next = elem->next;
334
335                 if (elem->seq == seq) {
336                         IMB_freeImBuf(elem->ibuf);
337
338                         BLI_freelinkN(&preprocess_cache->elems, elem);
339                 }
340         }
341 }