Cleanup: style, use braces for blenkernel
[blender.git] / source / blender / blenkernel / intern / seqcache.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * Peter Schlaile <peter [at] schlaile [dot] de> 2010
17  */
18
19 /** \file
20  * \ingroup bke
21  */
22
23 #include <stddef.h>
24
25 #include "BLI_sys_types.h" /* for intptr_t */
26
27 #include "MEM_guardedalloc.h"
28
29 #include "DNA_sequence_types.h"
30 #include "DNA_scene_types.h"
31
32 #include "IMB_moviecache.h"
33 #include "IMB_imbuf.h"
34 #include "IMB_imbuf_types.h"
35
36 #include "BLI_listbase.h"
37
38 #include "BKE_sequencer.h"
39 #include "BKE_scene.h"
40
41 typedef struct SeqCacheKey {
42   struct Sequence *seq;
43   SeqRenderData context;
44   float cfra;
45   eSeqStripElemIBuf type;
46 } SeqCacheKey;
47
48 typedef struct SeqPreprocessCacheElem {
49   struct SeqPreprocessCacheElem *next, *prev;
50
51   struct Sequence *seq;
52   SeqRenderData context;
53   eSeqStripElemIBuf type;
54
55   ImBuf *ibuf;
56 } SeqPreprocessCacheElem;
57
58 typedef struct SeqPreprocessCache {
59   int cfra;
60   ListBase elems;
61 } SeqPreprocessCache;
62
63 static struct MovieCache *moviecache = NULL;
64 static struct SeqPreprocessCache *preprocess_cache = NULL;
65
66 static void preprocessed_cache_destruct(void);
67
68 static bool seq_cmp_render_data(const SeqRenderData *a, const SeqRenderData *b)
69 {
70   return ((a->preview_render_size != b->preview_render_size) || (a->rectx != b->rectx) ||
71           (a->recty != b->recty) || (a->bmain != b->bmain) || (a->scene != b->scene) ||
72           (a->motion_blur_shutter != b->motion_blur_shutter) ||
73           (a->motion_blur_samples != b->motion_blur_samples) ||
74           (a->scene->r.views_format != b->scene->r.views_format) || (a->view_id != b->view_id));
75 }
76
77 static unsigned int seq_hash_render_data(const SeqRenderData *a)
78 {
79   unsigned int rval = a->rectx + a->recty;
80
81   rval ^= a->preview_render_size;
82   rval ^= ((intptr_t)a->bmain) << 6;
83   rval ^= ((intptr_t)a->scene) << 6;
84   rval ^= (int)(a->motion_blur_shutter * 100.0f) << 10;
85   rval ^= a->motion_blur_samples << 16;
86   rval ^= ((a->scene->r.views_format * 2) + a->view_id) << 24;
87
88   return rval;
89 }
90
91 static unsigned int seqcache_hashhash(const void *key_)
92 {
93   const SeqCacheKey *key = key_;
94   unsigned int rval = seq_hash_render_data(&key->context);
95
96   rval ^= *(const unsigned int *)&key->cfra;
97   rval += key->type;
98   rval ^= ((intptr_t)key->seq) << 6;
99
100   return rval;
101 }
102
103 static bool seqcache_hashcmp(const void *a_, const void *b_)
104 {
105   const SeqCacheKey *a = a_;
106   const SeqCacheKey *b = b_;
107
108   return ((a->seq != b->seq) || (a->cfra != b->cfra) || (a->type != b->type) ||
109           seq_cmp_render_data(&a->context, &b->context));
110 }
111
112 void BKE_sequencer_cache_destruct(void)
113 {
114   if (moviecache) {
115     IMB_moviecache_free(moviecache);
116   }
117
118   preprocessed_cache_destruct();
119 }
120
121 void BKE_sequencer_cache_cleanup(void)
122 {
123   if (moviecache) {
124     IMB_moviecache_free(moviecache);
125     moviecache = IMB_moviecache_create(
126         "seqcache", sizeof(SeqCacheKey), seqcache_hashhash, seqcache_hashcmp);
127   }
128
129   BKE_sequencer_preprocessed_cache_cleanup();
130 }
131
132 static bool seqcache_key_check_seq(ImBuf *UNUSED(ibuf), void *userkey, void *userdata)
133 {
134   SeqCacheKey *key = (SeqCacheKey *)userkey;
135   Sequence *seq = (Sequence *)userdata;
136
137   return key->seq == seq;
138 }
139
140 void BKE_sequencer_cache_cleanup_sequence(Sequence *seq)
141 {
142   if (moviecache) {
143     IMB_moviecache_cleanup(moviecache, seqcache_key_check_seq, seq);
144   }
145 }
146
147 struct ImBuf *BKE_sequencer_cache_get(const SeqRenderData *context,
148                                       Sequence *seq,
149                                       float cfra,
150                                       eSeqStripElemIBuf type)
151 {
152   if (moviecache && seq) {
153     SeqCacheKey key;
154
155     key.seq = seq;
156     key.context = *context;
157     key.cfra = cfra - seq->start;
158     key.type = type;
159
160     return IMB_moviecache_get(moviecache, &key);
161   }
162
163   return NULL;
164 }
165
166 void BKE_sequencer_cache_put(
167     const SeqRenderData *context, Sequence *seq, float cfra, eSeqStripElemIBuf type, ImBuf *i)
168 {
169   SeqCacheKey key;
170
171   if (i == NULL || context->skip_cache) {
172     return;
173   }
174
175   if (!moviecache) {
176     moviecache = IMB_moviecache_create(
177         "seqcache", sizeof(SeqCacheKey), seqcache_hashhash, seqcache_hashcmp);
178   }
179
180   key.seq = seq;
181   key.context = *context;
182   key.cfra = cfra - seq->start;
183   key.type = type;
184
185   IMB_moviecache_put(moviecache, &key, i);
186 }
187
188 void BKE_sequencer_preprocessed_cache_cleanup(void)
189 {
190   SeqPreprocessCacheElem *elem;
191
192   if (!preprocess_cache) {
193     return;
194   }
195
196   for (elem = preprocess_cache->elems.first; elem; elem = elem->next) {
197     IMB_freeImBuf(elem->ibuf);
198   }
199   BLI_freelistN(&preprocess_cache->elems);
200
201   BLI_listbase_clear(&preprocess_cache->elems);
202 }
203
204 static void preprocessed_cache_destruct(void)
205 {
206   if (!preprocess_cache) {
207     return;
208   }
209
210   BKE_sequencer_preprocessed_cache_cleanup();
211
212   MEM_freeN(preprocess_cache);
213   preprocess_cache = NULL;
214 }
215
216 ImBuf *BKE_sequencer_preprocessed_cache_get(const SeqRenderData *context,
217                                             Sequence *seq,
218                                             float cfra,
219                                             eSeqStripElemIBuf type)
220 {
221   SeqPreprocessCacheElem *elem;
222
223   if (!preprocess_cache) {
224     return NULL;
225   }
226
227   if (preprocess_cache->cfra != cfra) {
228     return NULL;
229   }
230
231   for (elem = preprocess_cache->elems.first; elem; elem = elem->next) {
232     if (elem->seq != seq) {
233       continue;
234     }
235
236     if (elem->type != type) {
237       continue;
238     }
239
240     if (seq_cmp_render_data(&elem->context, context) != 0) {
241       continue;
242     }
243
244     IMB_refImBuf(elem->ibuf);
245     return elem->ibuf;
246   }
247
248   return NULL;
249 }
250
251 void BKE_sequencer_preprocessed_cache_put(
252     const SeqRenderData *context, Sequence *seq, float cfra, eSeqStripElemIBuf type, ImBuf *ibuf)
253 {
254   SeqPreprocessCacheElem *elem;
255
256   if (!preprocess_cache) {
257     preprocess_cache = MEM_callocN(sizeof(SeqPreprocessCache), "sequencer preprocessed cache");
258   }
259   else {
260     if (preprocess_cache->cfra != cfra) {
261       BKE_sequencer_preprocessed_cache_cleanup();
262     }
263   }
264
265   elem = MEM_callocN(sizeof(SeqPreprocessCacheElem), "sequencer preprocessed cache element");
266
267   elem->seq = seq;
268   elem->type = type;
269   elem->context = *context;
270   elem->ibuf = ibuf;
271
272   preprocess_cache->cfra = cfra;
273
274   IMB_refImBuf(ibuf);
275
276   BLI_addtail(&preprocess_cache->elems, elem);
277 }
278
279 void BKE_sequencer_preprocessed_cache_cleanup_sequence(Sequence *seq)
280 {
281   SeqPreprocessCacheElem *elem, *elem_next;
282
283   if (!preprocess_cache) {
284     return;
285   }
286
287   for (elem = preprocess_cache->elems.first; elem; elem = elem_next) {
288     elem_next = elem->next;
289
290     if (elem->seq == seq) {
291       IMB_freeImBuf(elem->ibuf);
292
293       BLI_freelinkN(&preprocess_cache->elems, elem);
294     }
295   }
296 }