== Sequencer ==
[blender.git] / source / blender / blenkernel / intern / seqcache.c
1 /*
2 * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * Peter Schlaile <peter [at] schlaile [dot] de> 2010
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 #include <stdlib.h>
32 #include <string.h>
33 #include <math.h>
34
35 #include "MEM_guardedalloc.h"
36 #include "MEM_CacheLimiterC-Api.h"
37
38 #include "DNA_sequence_types.h"
39 #include "BKE_sequencer.h"
40 #include "BLI_utildefines.h"
41 #include "BLI_ghash.h"
42 #include "BLI_mempool.h"
43 #include <pthread.h>
44
45 #include "IMB_imbuf.h"
46 #include "IMB_imbuf_types.h"
47
48 typedef struct seqCacheKey 
49 {
50         struct Sequence * seq;
51         SeqRenderData context;
52         float cfra;
53         seq_stripelem_ibuf_t type;
54 } seqCacheKey;
55
56 typedef struct seqCacheEntry
57 {
58         ImBuf * ibuf;
59         MEM_CacheLimiterHandleC * c_handle;
60 } seqCacheEntry;
61
62 static GHash * hash = NULL;
63 static MEM_CacheLimiterC * limitor = NULL;
64 static struct BLI_mempool * entrypool = NULL;
65 static struct BLI_mempool * keypool = NULL;
66 static int ibufs_in  = 0;
67 static int ibufs_rem = 0;
68
69 static unsigned int HashHash(const void *key_)
70 {
71         const seqCacheKey *key = (seqCacheKey*) key_;
72         unsigned int rval = seq_hash_render_data(&key->context);
73
74         rval ^= *(unsigned int*) &key->cfra;
75         rval += key->type;
76         rval ^= ((intptr_t) key->seq) << 6;
77
78         return rval;
79 }
80
81 static int HashCmp(const void *a_, const void *b_)
82 {
83         const seqCacheKey * a = (seqCacheKey*) a_;
84         const seqCacheKey * b = (seqCacheKey*) b_;
85
86         if (a->seq < b->seq) {
87                 return -1;              
88         }
89         if (a->seq > b->seq) {
90                 return 1;
91         }
92
93         if (a->cfra < b->cfra) {
94                 return -1;
95         }
96         if (a->cfra > b->cfra) {
97                 return 1;
98         }
99
100         if (a->type < b->type) {
101                 return -1;
102         }
103         if (a->type > b->type) {
104                 return 1;
105         }
106
107         return seq_cmp_render_data(&a->context, &b->context);
108 }
109
110 static void HashKeyFree(void *key)
111 {
112         BLI_mempool_free(keypool, key);
113 }
114
115 static void HashValFree(void *val)
116 {
117         seqCacheEntry* e = (seqCacheEntry*) val;
118
119         if (e->ibuf) {
120                 /* fprintf(stderr, "Removing: %p, cnt: %d\n", e->ibuf, 
121                    e->ibuf->refcounter); */
122                 IMB_freeImBuf(e->ibuf);
123                 MEM_CacheLimiter_unmanage(e->c_handle);
124                 ibufs_rem++;
125         }
126
127         e->ibuf = NULL;
128         e->c_handle = NULL;
129
130         BLI_mempool_free(entrypool, e);
131 }
132
133 static void IMB_seq_cache_destructor(void * p)
134 {
135         seqCacheEntry* e = (seqCacheEntry*) p;
136         
137         if (e && e->ibuf) {
138                 /* fprintf(stderr, "Removing: %p, cnt: %d\n", e->ibuf,
139                    e->ibuf->refcounter); */
140                 IMB_freeImBuf(e->ibuf);
141                 ibufs_rem++;
142
143                 e->ibuf = NULL;
144                 e->c_handle = NULL;
145         }
146 }
147
148 void seq_stripelem_cache_init(void)
149 {
150         hash = BLI_ghash_new(HashHash, HashCmp, "seq stripelem cache hash");
151         limitor = new_MEM_CacheLimiter( IMB_seq_cache_destructor );
152
153         entrypool = BLI_mempool_create(sizeof(seqCacheEntry), 64, 64, 0);
154         keypool = BLI_mempool_create(sizeof(seqCacheKey), 64, 64, 0);
155 }
156
157 void seq_stripelem_cache_destruct(void)
158 {
159         if (!entrypool) {
160                 return;
161         }
162         BLI_ghash_free(hash, HashKeyFree, HashValFree);
163         delete_MEM_CacheLimiter(limitor);
164         BLI_mempool_destroy(entrypool);
165         BLI_mempool_destroy(keypool);
166 }
167
168 void seq_stripelem_cache_cleanup(void)
169 {
170         if (!entrypool) {
171                 seq_stripelem_cache_init();
172         }
173
174         /* fprintf(stderr, "Stats before cleanup: in: %d rem: %d\n",
175            ibufs_in, ibufs_rem); */
176
177         BLI_ghash_free(hash, HashKeyFree, HashValFree);
178         hash = BLI_ghash_new(HashHash, HashCmp, "seq stripelem cache hash");
179
180         /* fprintf(stderr, "Stats after cleanup: in: %d rem: %d\n",
181            ibufs_in, ibufs_rem); */
182
183 }
184
185 struct ImBuf * seq_stripelem_cache_get(
186         SeqRenderData context, struct Sequence * seq, 
187         float cfra, seq_stripelem_ibuf_t type)
188 {
189         seqCacheKey key;
190         seqCacheEntry * e;
191
192         if (!seq) {
193                 return NULL;
194         }
195
196         if (!entrypool) {
197                 seq_stripelem_cache_init();
198         }
199
200         key.seq = seq;
201         key.context = context;
202         key.cfra = cfra - seq->start;
203         key.type = type;
204         
205         e = (seqCacheEntry*) BLI_ghash_lookup(hash, &key);
206
207         if (e && e->ibuf) {
208                 IMB_refImBuf(e->ibuf);
209
210                 MEM_CacheLimiter_touch(e->c_handle);
211                 return e->ibuf;
212         }
213         return NULL;
214 }
215
216 void seq_stripelem_cache_put(
217         SeqRenderData context, struct Sequence * seq, 
218         float cfra, seq_stripelem_ibuf_t type, struct ImBuf * i)
219 {
220         seqCacheKey * key;
221         seqCacheEntry * e;
222
223         if (!i) {
224                 return;
225         }
226
227         ibufs_in++;
228
229         if (!entrypool) {
230                 seq_stripelem_cache_init();
231         }
232
233         key = (seqCacheKey*) BLI_mempool_alloc(keypool);
234
235         key->seq = seq;
236         key->context = context;
237         key->cfra = cfra - seq->start;
238         key->type = type;
239
240         IMB_refImBuf(i);
241
242         e = (seqCacheEntry*) BLI_mempool_alloc(entrypool);
243
244         e->ibuf = i;
245         e->c_handle = NULL;
246
247         BLI_ghash_remove(hash, key, HashKeyFree, HashValFree);
248         BLI_ghash_insert(hash, key, e);
249
250         e->c_handle = MEM_CacheLimiter_insert(limitor, e);
251
252         MEM_CacheLimiter_ref(e->c_handle);
253         MEM_CacheLimiter_enforce_limits(limitor);
254         MEM_CacheLimiter_unref(e->c_handle);
255 }