Sequencer: refactor clipboard copy to no longer increase user count.
[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 #include "DNA_scene_types.h"
37
38 #include "IMB_moviecache.h"
39 #include "IMB_imbuf.h"
40 #include "IMB_imbuf_types.h"
41
42 #include "BLI_listbase.h"
43
44 #include "BKE_sequencer.h"
45 #include "BKE_scene.h"
46
47 typedef struct SeqCacheKey {
48         struct Sequence *seq;
49         SeqRenderData context;
50         float cfra;
51         eSeqStripElemIBuf type;
52 } SeqCacheKey;
53
54 typedef struct SeqPreprocessCacheElem {
55         struct SeqPreprocessCacheElem *next, *prev;
56
57         struct Sequence *seq;
58         SeqRenderData context;
59         eSeqStripElemIBuf type;
60
61         ImBuf *ibuf;
62 } SeqPreprocessCacheElem;
63
64 typedef struct SeqPreprocessCache {
65         int cfra;
66         ListBase elems;
67 } SeqPreprocessCache;
68
69 static struct MovieCache *moviecache = NULL;
70 static struct SeqPreprocessCache *preprocess_cache = NULL;
71
72 static void preprocessed_cache_destruct(void);
73
74 static bool seq_cmp_render_data(const SeqRenderData *a, const SeqRenderData *b)
75 {
76         return ((a->preview_render_size != b->preview_render_size) ||
77                 (a->rectx != b->rectx) ||
78                 (a->recty != b->recty) ||
79                 (a->bmain != b->bmain) ||
80                 (a->scene != b->scene) ||
81                 (a->motion_blur_shutter != b->motion_blur_shutter) ||
82                 (a->motion_blur_samples != b->motion_blur_samples) ||
83                 (a->scene->r.views_format != b->scene->r.views_format) ||
84                 (a->view_id != b->view_id));
85 }
86
87 static unsigned int seq_hash_render_data(const SeqRenderData *a)
88 {
89         unsigned int rval = a->rectx + a->recty;
90
91         rval ^= a->preview_render_size;
92         rval ^= ((intptr_t) a->bmain) << 6;
93         rval ^= ((intptr_t) a->scene) << 6;
94         rval ^= (int)(a->motion_blur_shutter * 100.0f) << 10;
95         rval ^= a->motion_blur_samples << 16;
96         rval ^= ((a->scene->r.views_format * 2) + a->view_id) << 24;
97
98         return rval;
99 }
100
101 static unsigned int seqcache_hashhash(const void *key_)
102 {
103         const SeqCacheKey *key = key_;
104         unsigned int rval = seq_hash_render_data(&key->context);
105
106         rval ^= *(const unsigned int *) &key->cfra;
107         rval += key->type;
108         rval ^= ((intptr_t) key->seq) << 6;
109
110         return rval;
111 }
112
113 static bool seqcache_hashcmp(const void *a_, const void *b_)
114 {
115         const SeqCacheKey *a = a_;
116         const SeqCacheKey *b = b_;
117
118         return ((a->seq != b->seq) ||
119                 (a->cfra != b->cfra) ||
120                 (a->type != b->type) ||
121                 seq_cmp_render_data(&a->context, &b->context));
122 }
123
124 void BKE_sequencer_cache_destruct(void)
125 {
126         if (moviecache)
127                 IMB_moviecache_free(moviecache);
128
129         preprocessed_cache_destruct();
130 }
131
132 void BKE_sequencer_cache_cleanup(void)
133 {
134         if (moviecache) {
135                 IMB_moviecache_free(moviecache);
136                 moviecache = IMB_moviecache_create("seqcache", sizeof(SeqCacheKey), seqcache_hashhash, seqcache_hashcmp);
137         }
138
139         BKE_sequencer_preprocessed_cache_cleanup();
140 }
141
142 static bool seqcache_key_check_seq(ImBuf *UNUSED(ibuf), void *userkey, void *userdata)
143 {
144         SeqCacheKey *key = (SeqCacheKey *) userkey;
145         Sequence *seq = (Sequence *) userdata;
146
147         return key->seq == seq;
148 }
149
150 void BKE_sequencer_cache_cleanup_sequence(Sequence *seq)
151 {
152         if (moviecache)
153                 IMB_moviecache_cleanup(moviecache, seqcache_key_check_seq, seq);
154 }
155
156 struct ImBuf *BKE_sequencer_cache_get(const SeqRenderData *context, Sequence *seq, float cfra, eSeqStripElemIBuf type)
157 {
158         if (moviecache && seq) {
159                 SeqCacheKey key;
160
161                 key.seq = seq;
162                 key.context = *context;
163                 key.cfra = cfra - seq->start;
164                 key.type = type;
165
166                 return IMB_moviecache_get(moviecache, &key);
167         }
168
169         return NULL;
170 }
171
172 void BKE_sequencer_cache_put(const SeqRenderData *context, Sequence *seq, float cfra, eSeqStripElemIBuf type, ImBuf *i)
173 {
174         SeqCacheKey key;
175
176         if (i == NULL || context->skip_cache) {
177                 return;
178         }
179
180         if (!moviecache) {
181                 moviecache = IMB_moviecache_create("seqcache", sizeof(SeqCacheKey), seqcache_hashhash, seqcache_hashcmp);
182         }
183
184         key.seq = seq;
185         key.context = *context;
186         key.cfra = cfra - seq->start;
187         key.type = type;
188
189         IMB_moviecache_put(moviecache, &key, i);
190 }
191
192 void BKE_sequencer_preprocessed_cache_cleanup(void)
193 {
194         SeqPreprocessCacheElem *elem;
195
196         if (!preprocess_cache)
197                 return;
198
199         for (elem = preprocess_cache->elems.first; elem; elem = elem->next) {
200                 IMB_freeImBuf(elem->ibuf);
201         }
202         BLI_freelistN(&preprocess_cache->elems);
203
204         BLI_listbase_clear(&preprocess_cache->elems);
205 }
206
207 static void preprocessed_cache_destruct(void)
208 {
209         if (!preprocess_cache)
210                 return;
211
212         BKE_sequencer_preprocessed_cache_cleanup();
213
214         MEM_freeN(preprocess_cache);
215         preprocess_cache = NULL;
216 }
217
218 ImBuf *BKE_sequencer_preprocessed_cache_get(const SeqRenderData *context, Sequence *seq, float cfra, eSeqStripElemIBuf type)
219 {
220         SeqPreprocessCacheElem *elem;
221
222         if (!preprocess_cache)
223                 return NULL;
224
225         if (preprocess_cache->cfra != cfra)
226                 return NULL;
227
228         for (elem = preprocess_cache->elems.first; elem; elem = elem->next) {
229                 if (elem->seq != seq)
230                         continue;
231
232                 if (elem->type != type)
233                         continue;
234
235                 if (seq_cmp_render_data(&elem->context, context) != 0)
236                         continue;
237
238                 IMB_refImBuf(elem->ibuf);
239                 return elem->ibuf;
240         }
241
242         return NULL;
243 }
244
245 void BKE_sequencer_preprocessed_cache_put(const SeqRenderData *context, Sequence *seq, float cfra, eSeqStripElemIBuf type, ImBuf *ibuf)
246 {
247         SeqPreprocessCacheElem *elem;
248
249         if (!preprocess_cache) {
250                 preprocess_cache = MEM_callocN(sizeof(SeqPreprocessCache), "sequencer preprocessed cache");
251         }
252         else {
253                 if (preprocess_cache->cfra != cfra)
254                         BKE_sequencer_preprocessed_cache_cleanup();
255         }
256
257         elem = MEM_callocN(sizeof(SeqPreprocessCacheElem), "sequencer preprocessed cache element");
258
259         elem->seq = seq;
260         elem->type = type;
261         elem->context = *context;
262         elem->ibuf = ibuf;
263
264         preprocess_cache->cfra = cfra;
265
266         IMB_refImBuf(ibuf);
267
268         BLI_addtail(&preprocess_cache->elems, elem);
269 }
270
271 void BKE_sequencer_preprocessed_cache_cleanup_sequence(Sequence *seq)
272 {
273         SeqPreprocessCacheElem *elem, *elem_next;
274
275         if (!preprocess_cache)
276                 return;
277
278         for (elem = preprocess_cache->elems.first; elem; elem = elem_next) {
279                 elem_next = elem->next;
280
281                 if (elem->seq == seq) {
282                         IMB_freeImBuf(elem->ibuf);
283
284                         BLI_freelinkN(&preprocess_cache->elems, elem);
285                 }
286         }
287 }