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