merge with/from trunk at r35190
[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 #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_utildefines.h"
36 #include "BLI_ghash.h"
37 #include "BLI_mempool.h"
38 #include <pthread.h>
39
40 #include "IMB_imbuf.h"
41 #include "IMB_imbuf_types.h"
42
43 typedef struct seqCacheKey 
44 {
45         struct Sequence * seq;
46         SeqRenderData context;
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 = NULL;
58 static MEM_CacheLimiterC * limitor = NULL;
59 static struct BLI_mempool * entrypool = NULL;
60 static struct BLI_mempool * keypool = NULL;
61 static int ibufs_in  = 0;
62 static int ibufs_rem = 0;
63
64 static unsigned int HashHash(const void *key_)
65 {
66         const seqCacheKey *key = (seqCacheKey*) key_;
67         unsigned int rval = seq_hash_render_data(&key->context);
68
69         rval ^= *(unsigned int*) &key->cfra;
70         rval += key->type;
71         rval ^= ((intptr_t) key->seq) << 6;
72
73         return rval;
74 }
75
76 static int HashCmp(const void *a_, const void *b_)
77 {
78         const seqCacheKey * a = (seqCacheKey*) a_;
79         const 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         return seq_cmp_render_data(&a->context, &b->context);
103 }
104
105 static void HashKeyFree(void *key)
106 {
107         BLI_mempool_free(keypool, key);
108 }
109
110 static void HashValFree(void *val)
111 {
112         seqCacheEntry* e = (seqCacheEntry*) val;
113
114         if (e->ibuf) {
115                 /* fprintf(stderr, "Removing: %p, cnt: %d\n", e->ibuf, 
116                    e->ibuf->refcounter); */
117                 IMB_freeImBuf(e->ibuf);
118                 MEM_CacheLimiter_unmanage(e->c_handle);
119                 ibufs_rem++;
120         }
121
122         e->ibuf = NULL;
123         e->c_handle = NULL;
124
125         BLI_mempool_free(entrypool, e);
126 }
127
128 static void IMB_seq_cache_destructor(void * p)
129 {
130         seqCacheEntry* e = (seqCacheEntry*) p;
131         
132         if (e && e->ibuf) {
133                 /* fprintf(stderr, "Removing: %p, cnt: %d\n", e->ibuf,
134                    e->ibuf->refcounter); */
135                 IMB_freeImBuf(e->ibuf);
136                 ibufs_rem++;
137
138                 e->ibuf = NULL;
139                 e->c_handle = NULL;
140         }
141 }
142
143 void seq_stripelem_cache_init(void)
144 {
145         hash = BLI_ghash_new(HashHash, HashCmp, "seq stripelem cache hash");
146         limitor = new_MEM_CacheLimiter( IMB_seq_cache_destructor );
147
148         entrypool = BLI_mempool_create(sizeof(seqCacheEntry), 64, 64, 0, 0);
149         keypool = BLI_mempool_create(sizeof(seqCacheKey), 64, 64, 0, 0);
150 }
151
152 void seq_stripelem_cache_destruct(void)
153 {
154         if (!entrypool) {
155                 return;
156         }
157         BLI_ghash_free(hash, HashKeyFree, HashValFree);
158         delete_MEM_CacheLimiter(limitor);
159         BLI_mempool_destroy(entrypool);
160         BLI_mempool_destroy(keypool);
161 }
162
163 void seq_stripelem_cache_cleanup(void)
164 {
165         if (!entrypool) {
166                 seq_stripelem_cache_init();
167         }
168
169         /* fprintf(stderr, "Stats before cleanup: in: %d rem: %d\n",
170            ibufs_in, ibufs_rem); */
171
172         BLI_ghash_free(hash, HashKeyFree, HashValFree);
173         hash = BLI_ghash_new(HashHash, HashCmp, "seq stripelem cache hash");
174
175         /* fprintf(stderr, "Stats after cleanup: in: %d rem: %d\n",
176            ibufs_in, ibufs_rem); */
177
178 }
179
180 struct ImBuf * seq_stripelem_cache_get(
181         SeqRenderData context, struct Sequence * seq, 
182         float cfra, seq_stripelem_ibuf_t type)
183 {
184         seqCacheKey key;
185         seqCacheEntry * e;
186
187         if (!seq) {
188                 return NULL;
189         }
190
191         if (!entrypool) {
192                 seq_stripelem_cache_init();
193         }
194
195         key.seq = seq;
196         key.context = context;
197         key.cfra = cfra - seq->start;
198         key.type = type;
199         
200         e = (seqCacheEntry*) BLI_ghash_lookup(hash, &key);
201
202         if (e && e->ibuf) {
203                 IMB_refImBuf(e->ibuf);
204
205                 MEM_CacheLimiter_touch(e->c_handle);
206                 return e->ibuf;
207         }
208         return NULL;
209 }
210
211 void seq_stripelem_cache_put(
212         SeqRenderData context, struct Sequence * seq, 
213         float cfra, seq_stripelem_ibuf_t type, struct ImBuf * i)
214 {
215         seqCacheKey * key;
216         seqCacheEntry * e;
217
218         if (!i) {
219                 return;
220         }
221
222         ibufs_in++;
223
224         if (!entrypool) {
225                 seq_stripelem_cache_init();
226         }
227
228         key = (seqCacheKey*) BLI_mempool_alloc(keypool);
229
230         key->seq = seq;
231         key->context = context;
232         key->cfra = cfra - seq->start;
233         key->type = type;
234
235         /* Normally we want our own version, but start and end stills are duplicates of the original. */
236         if(ELEM(type, SEQ_STRIPELEM_IBUF_STARTSTILL, SEQ_STRIPELEM_IBUF_ENDSTILL)==0)
237                 IMB_refImBuf(i);
238
239         e = (seqCacheEntry*) BLI_mempool_alloc(entrypool);
240
241         e->ibuf = i;
242         e->c_handle = NULL;
243
244         BLI_ghash_remove(hash, key, HashKeyFree, HashValFree);
245         BLI_ghash_insert(hash, key, e);
246
247         e->c_handle = MEM_CacheLimiter_insert(limitor, e);
248
249         MEM_CacheLimiter_ref(e->c_handle);
250         MEM_CacheLimiter_enforce_limits(limitor);
251         MEM_CacheLimiter_unref(e->c_handle);
252 }