merge from trunk at r31523
[blender.git] / source / blender / blenkernel / intern / seqcache.c
1 /**
2 * $Id: seqcache.c 30687 2010-07-24 08:47:14Z schlaile $
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 #include <stddef.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <math.h>
29
30 #include "MEM_guardedalloc.h"
31 #include "MEM_CacheLimiterC-Api.h"
32
33 #include "DNA_sequence_types.h"
34 #include "BKE_sequencer.h"
35 #include "BLI_ghash.h"
36 #include "BLI_mempool.h"
37 #include <pthread.h>
38
39 #include "IMB_imbuf.h"
40 #include "IMB_imbuf_types.h"
41
42 typedef struct seqCacheKey 
43 {
44         struct Sequence * seq;
45         int rectx;
46         int recty;
47         float cfra;
48         seq_stripelem_ibuf_t type;
49 } seqCacheKey;
50
51 typedef struct seqCacheEntry
52 {
53         ImBuf * ibuf;
54         MEM_CacheLimiterHandleC * c_handle;
55 } seqCacheEntry;
56
57 static GHash * hash = 0;
58 static MEM_CacheLimiterC * limitor = 0;
59 static struct BLI_mempool * entrypool = 0;
60 static struct BLI_mempool * keypool = 0;
61 static int ibufs_in  = 0;
62 static int ibufs_rem = 0;
63
64 static unsigned int HashHash(void *key_)
65 {
66         seqCacheKey * key = (seqCacheKey*) key_;
67         unsigned int rval = key->rectx + key->recty;
68
69         rval ^= *(unsigned int*) &key->cfra;
70         rval += key->type;
71         rval ^= ((unsigned int) key->seq) << 6;
72
73         return rval;
74 }
75
76 static int HashCmp(void *a_, void *b_)
77 {
78         seqCacheKey * a = (seqCacheKey*) a_;
79         seqCacheKey * b = (seqCacheKey*) b_;
80
81         if (a->seq < b->seq) {
82                 return -1;              
83         }
84         if (a->seq > b->seq) {
85                 return 1;
86         }
87
88         if (a->cfra < b->cfra) {
89                 return -1;
90         }
91         if (a->cfra > b->cfra) {
92                 return 1;
93         }
94
95         if (a->type < b->type) {
96                 return -1;
97         }
98         if (a->type > b->type) {
99                 return 1;
100         }
101
102         if (a->rectx < b->rectx) {
103                 return -1;
104         }
105         if (a->rectx > b->rectx) {
106                 return 1;
107         }
108
109         if (a->recty < b->recty) {
110                 return -1;
111         }
112         if (a->recty > b->recty) {
113                 return 1;
114         }
115
116         return 0;
117 }
118
119 static void HashKeyFree(void *key)
120 {
121         BLI_mempool_free(keypool, key);
122 }
123
124 static void HashValFree(void *val)
125 {
126         seqCacheEntry* e = (seqCacheEntry*) val;
127
128         if (e->ibuf) {
129                 /* fprintf(stderr, "Removing: %p, cnt: %d\n", e->ibuf, 
130                    e->ibuf->refcounter); */
131                 IMB_freeImBuf(e->ibuf);
132                 MEM_CacheLimiter_unmanage(e->c_handle);
133                 ibufs_rem++;
134         }
135
136         e->ibuf = 0;
137         e->c_handle = 0;
138
139         BLI_mempool_free(entrypool, e);
140 }
141
142 static void IMB_seq_cache_destructor(void * p)
143 {
144         seqCacheEntry* e = (seqCacheEntry*) p;
145         
146         if (e && e->ibuf) {
147                 /* fprintf(stderr, "Removing: %p, cnt: %d\n", e->ibuf,
148                    e->ibuf->refcounter); */
149                 IMB_freeImBuf(e->ibuf);
150                 ibufs_rem++;
151
152                 e->ibuf = 0;
153                 e->c_handle = 0;
154         }
155 }
156
157 void seq_stripelem_cache_init()
158 {
159         hash = BLI_ghash_new(HashHash, HashCmp, "seq stripelem cache hash");
160         limitor = new_MEM_CacheLimiter( IMB_seq_cache_destructor );
161
162         entrypool = BLI_mempool_create(sizeof(seqCacheEntry), 64, 64, 0, 0);
163         keypool = BLI_mempool_create(sizeof(seqCacheKey), 64, 64, 0, 0);
164 }
165
166 void seq_stripelem_cache_destruct()
167 {
168         if (!entrypool) {
169                 return;
170         }
171         BLI_ghash_free(hash, HashKeyFree, HashValFree);
172         delete_MEM_CacheLimiter(limitor);
173         BLI_mempool_destroy(entrypool);
174         BLI_mempool_destroy(keypool);
175 }
176
177 void seq_stripelem_cache_cleanup()
178 {
179         if (!entrypool) {
180                 seq_stripelem_cache_init();
181         }
182
183         /* fprintf(stderr, "Stats before cleanup: in: %d rem: %d\n",
184            ibufs_in, ibufs_rem); */
185
186         BLI_ghash_free(hash, HashKeyFree, HashValFree);
187         hash = BLI_ghash_new(HashHash, HashCmp, "seq stripelem cache hash");
188
189         /* fprintf(stderr, "Stats after cleanup: in: %d rem: %d\n",
190            ibufs_in, ibufs_rem); */
191
192 }
193
194 struct ImBuf * seq_stripelem_cache_get(
195         struct Sequence * seq, int rectx, int recty, 
196         float cfra, seq_stripelem_ibuf_t type)
197 {
198         seqCacheKey key;
199         seqCacheEntry * e;
200
201         if (!seq) {
202                 return 0;
203         }
204
205         if (!entrypool) {
206                 seq_stripelem_cache_init();
207         }
208
209         key.seq = seq;
210         key.rectx = rectx;
211         key.recty = recty;
212         key.cfra = cfra - seq->start;
213         key.type = type;
214         
215         e = (seqCacheEntry*) BLI_ghash_lookup(hash, &key);
216
217         if (e && e->ibuf) {
218                 IMB_refImBuf(e->ibuf);
219
220                 MEM_CacheLimiter_touch(e->c_handle);
221                 return e->ibuf;
222         }
223         return 0;
224 }
225
226 void seq_stripelem_cache_put(
227         struct Sequence * seq, int rectx, int recty, 
228         float cfra, seq_stripelem_ibuf_t type, struct ImBuf * i)
229 {
230         seqCacheKey * key;
231         seqCacheEntry * e;
232
233         if (!i) {
234                 return;
235         }
236
237         ibufs_in++;
238
239         if (!entrypool) {
240                 seq_stripelem_cache_init();
241         }
242
243         key = (seqCacheKey*) BLI_mempool_alloc(keypool);
244
245         key->seq = seq;
246         key->rectx = rectx;
247         key->recty = recty;
248         key->cfra = cfra - seq->start;
249         key->type = type;
250
251         /* we want our own version */
252         IMB_refImBuf(i);
253
254         e = (seqCacheEntry*) BLI_mempool_alloc(entrypool);
255
256         e->ibuf = i;
257         e->c_handle = 0;
258
259         BLI_ghash_remove(hash, key, HashKeyFree, HashValFree);
260         BLI_ghash_insert(hash, key, e);
261
262         e->c_handle = MEM_CacheLimiter_insert(limitor, e);
263
264         MEM_CacheLimiter_ref(e->c_handle);
265         MEM_CacheLimiter_enforce_limits(limitor);
266         MEM_CacheLimiter_unref(e->c_handle);
267 }