comparison libass/ass_cache.c @ 30200:48d020c5ceca

Update internal libass copy to commit 8db4a5
author greg
date Fri, 08 Jan 2010 18:35:44 +0000
parents 0f1b5b68af32
children e64df5862cea
comparison
equal deleted inserted replaced
30199:f9984b2fc1b2 30200:48d020c5ceca
1 // -*- c-basic-offset: 8; indent-tabs-mode: t -*-
2 // vim:ts=8:sw=8:noet:ai:
3 /* 1 /*
4 * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com> 2 * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
5 * 3 *
6 * This file is part of libass. 4 * This file is part of libass.
7 * 5 *
27 #include FT_FREETYPE_H 25 #include FT_FREETYPE_H
28 #include FT_GLYPH_H 26 #include FT_GLYPH_H
29 27
30 #include <assert.h> 28 #include <assert.h>
31 29
32 #include "mputils.h" 30 #include "ass_utils.h"
33 #include "ass.h" 31 #include "ass.h"
34 #include "ass_fontconfig.h" 32 #include "ass_fontconfig.h"
35 #include "ass_font.h" 33 #include "ass_font.h"
36 #include "ass_bitmap.h" 34 #include "ass_bitmap.h"
37 #include "ass_cache.h" 35 #include "ass_cache.h"
38 36
39 37 static unsigned hashmap_hash(void *buf, size_t len)
40 typedef struct hashmap_item_s { 38 {
41 void* key; 39 return fnv_32a_buf(buf, len, FNV1_32A_INIT);
42 void* value; 40 }
43 struct hashmap_item_s* next; 41
44 } hashmap_item_t; 42 static int hashmap_key_compare(void *a, void *b, size_t size)
45 typedef hashmap_item_t* hashmap_item_p; 43 {
46 44 return memcmp(a, b, size) == 0;
47 struct hashmap_s { 45 }
48 int nbuckets; 46
49 size_t key_size, value_size; 47 static void hashmap_item_dtor(void *key, size_t key_size, void *value,
50 hashmap_item_p* root; 48 size_t value_size)
51 hashmap_item_dtor_t item_dtor; // a destructor for hashmap key/value pairs 49 {
52 hashmap_key_compare_t key_compare; 50 free(key);
53 hashmap_hash_t hash; 51 free(value);
54 // stats 52 }
55 int hit_count; 53
56 int miss_count; 54 Hashmap *hashmap_init(ASS_Library *library, size_t key_size,
57 int count; 55 size_t value_size, int nbuckets,
58 }; 56 HashmapItemDtor item_dtor,
59 57 HashmapKeyCompare key_compare,
60 #define FNV1_32A_INIT (unsigned)0x811c9dc5 58 HashmapHash hash)
61 59 {
62 static inline unsigned fnv_32a_buf(void* buf, size_t len, unsigned hval) 60 Hashmap *map = calloc(1, sizeof(Hashmap));
63 { 61 map->library = library;
64 unsigned char *bp = buf; 62 map->nbuckets = nbuckets;
65 unsigned char *be = bp + len; 63 map->key_size = key_size;
66 while (bp < be) { 64 map->value_size = value_size;
67 hval ^= (unsigned)*bp++; 65 map->root = calloc(nbuckets, sizeof(hashmap_item_p));
68 hval += (hval<<1) + (hval<<4) + (hval<<7) + (hval<<8) + (hval<<24); 66 map->item_dtor = item_dtor ? item_dtor : hashmap_item_dtor;
69 } 67 map->key_compare = key_compare ? key_compare : hashmap_key_compare;
70 return hval; 68 map->hash = hash ? hash : hashmap_hash;
71 } 69 return map;
72 static inline unsigned fnv_32a_str(char* str, unsigned hval) 70 }
73 { 71
74 unsigned char* s = (unsigned char*)str; 72 void hashmap_done(Hashmap *map)
75 while (*s) { 73 {
76 hval ^= (unsigned)*s++; 74 int i;
77 hval += (hval<<1) + (hval<<4) + (hval<<7) + (hval<<8) + (hval<<24); 75 // print stats
78 } 76 if (map->count > 0 || map->hit_count + map->miss_count > 0)
79 return hval; 77 ass_msg(map->library, MSGL_V,
80 } 78 "cache statistics: \n total accesses: %d\n hits: %d\n "
81 79 "misses: %d\n object count: %d",
82 static unsigned hashmap_hash(void* buf, size_t len) 80 map->hit_count + map->miss_count, map->hit_count,
83 { 81 map->miss_count, map->count);
84 return fnv_32a_buf(buf, len, FNV1_32A_INIT); 82
85 } 83 for (i = 0; i < map->nbuckets; ++i) {
86 84 HashmapItem *item = map->root[i];
87 static int hashmap_key_compare(void* a, void* b, size_t size) 85 while (item) {
88 { 86 HashmapItem *next = item->next;
89 return memcmp(a, b, size) == 0; 87 map->item_dtor(item->key, map->key_size, item->value,
90 } 88 map->value_size);
91 89 free(item);
92 static void hashmap_item_dtor(void* key, size_t key_size, void* value, size_t value_size) 90 item = next;
93 { 91 }
94 free(key); 92 }
95 free(value); 93 free(map->root);
96 } 94 free(map);
97
98 hashmap_t* hashmap_init(size_t key_size, size_t value_size, int nbuckets,
99 hashmap_item_dtor_t item_dtor, hashmap_key_compare_t key_compare,
100 hashmap_hash_t hash)
101 {
102 hashmap_t* map = calloc(1, sizeof(hashmap_t));
103 map->nbuckets = nbuckets;
104 map->key_size = key_size;
105 map->value_size = value_size;
106 map->root = calloc(nbuckets, sizeof(hashmap_item_p));
107 map->item_dtor = item_dtor ? item_dtor : hashmap_item_dtor;
108 map->key_compare = key_compare ? key_compare : hashmap_key_compare;
109 map->hash = hash ? hash : hashmap_hash;
110 return map;
111 }
112
113 void hashmap_done(hashmap_t* map)
114 {
115 int i;
116 // print stats
117 if (map->count > 0 || map->hit_count + map->miss_count > 0)
118 mp_msg(MSGT_ASS, MSGL_V, "cache statistics: \n total accesses: %d\n hits: %d\n misses: %d\n object count: %d\n",
119 map->hit_count + map->miss_count, map->hit_count, map->miss_count, map->count);
120
121 for (i = 0; i < map->nbuckets; ++i) {
122 hashmap_item_t* item = map->root[i];
123 while (item) {
124 hashmap_item_t* next = item->next;
125 map->item_dtor(item->key, map->key_size, item->value, map->value_size);
126 free(item);
127 item = next;
128 }
129 }
130 free(map->root);
131 free(map);
132 } 95 }
133 96
134 // does nothing if key already exists 97 // does nothing if key already exists
135 void* hashmap_insert(hashmap_t* map, void* key, void* value) 98 void *hashmap_insert(Hashmap *map, void *key, void *value)
136 { 99 {
137 unsigned hash = map->hash(key, map->key_size); 100 unsigned hash = map->hash(key, map->key_size);
138 hashmap_item_t** next = map->root + (hash % map->nbuckets); 101 HashmapItem **next = map->root + (hash % map->nbuckets);
139 while (*next) { 102 while (*next) {
140 if (map->key_compare(key, (*next)->key, map->key_size)) 103 if (map->key_compare(key, (*next)->key, map->key_size))
141 return (*next)->value; 104 return (*next)->value;
142 next = &((*next)->next); 105 next = &((*next)->next);
143 assert(next); 106 assert(next);
144 } 107 }
145 (*next) = malloc(sizeof(hashmap_item_t)); 108 (*next) = malloc(sizeof(HashmapItem));
146 (*next)->key = malloc(map->key_size); 109 (*next)->key = malloc(map->key_size);
147 (*next)->value = malloc(map->value_size); 110 (*next)->value = malloc(map->value_size);
148 memcpy((*next)->key, key, map->key_size); 111 memcpy((*next)->key, key, map->key_size);
149 memcpy((*next)->value, value, map->value_size); 112 memcpy((*next)->value, value, map->value_size);
150 (*next)->next = 0; 113 (*next)->next = 0;
151 114
152 map->count ++; 115 map->count++;
153 return (*next)->value; 116 return (*next)->value;
154 } 117 }
155 118
156 void* hashmap_find(hashmap_t* map, void* key) 119 void *hashmap_find(Hashmap *map, void *key)
157 { 120 {
158 unsigned hash = map->hash(key, map->key_size); 121 unsigned hash = map->hash(key, map->key_size);
159 hashmap_item_t* item = map->root[hash % map->nbuckets]; 122 HashmapItem *item = map->root[hash % map->nbuckets];
160 while (item) { 123 while (item) {
161 if (map->key_compare(key, item->key, map->key_size)) { 124 if (map->key_compare(key, item->key, map->key_size)) {
162 map->hit_count++; 125 map->hit_count++;
163 return item->value; 126 return item->value;
164 } 127 }
165 item = item->next; 128 item = item->next;
166 } 129 }
167 map->miss_count++; 130 map->miss_count++;
168 return 0; 131 return 0;
169 } 132 }
170 133
171 //--------------------------------- 134 //---------------------------------
172 // font cache 135 // font cache
173 136
174 hashmap_t* font_cache; 137 static unsigned font_desc_hash(void *buf, size_t len)
175 138 {
176 static unsigned font_desc_hash(void* buf, size_t len) 139 ASS_FontDesc *desc = buf;
177 { 140 unsigned hval;
178 ass_font_desc_t* desc = buf; 141 hval = fnv_32a_str(desc->family, FNV1_32A_INIT);
179 unsigned hval; 142 hval = fnv_32a_buf(&desc->bold, sizeof(desc->bold), hval);
180 hval = fnv_32a_str(desc->family, FNV1_32A_INIT); 143 hval = fnv_32a_buf(&desc->italic, sizeof(desc->italic), hval);
181 hval = fnv_32a_buf(&desc->bold, sizeof(desc->bold), hval); 144 return hval;
182 hval = fnv_32a_buf(&desc->italic, sizeof(desc->italic), hval); 145 }
183 return hval; 146
184 } 147 static int font_compare(void *key1, void *key2, size_t key_size)
185 148 {
186 static int font_compare(void* key1, void* key2, size_t key_size) { 149 ASS_FontDesc *a = key1;
187 ass_font_desc_t* a = key1; 150 ASS_FontDesc *b = key2;
188 ass_font_desc_t* b = key2; 151 if (strcmp(a->family, b->family) != 0)
189 if (strcmp(a->family, b->family) != 0) 152 return 0;
190 return 0; 153 if (a->bold != b->bold)
191 if (a->bold != b->bold) 154 return 0;
192 return 0; 155 if (a->italic != b->italic)
193 if (a->italic != b->italic) 156 return 0;
194 return 0; 157 if (a->treat_family_as_pattern != b->treat_family_as_pattern)
195 if (a->treat_family_as_pattern != b->treat_family_as_pattern) 158 return 0;
196 return 0; 159 return 1;
197 return 1; 160 }
198 } 161
199 162 static void font_hash_dtor(void *key, size_t key_size, void *value,
200 static void font_hash_dtor(void* key, size_t key_size, void* value, size_t value_size) 163 size_t value_size)
201 { 164 {
202 ass_font_free(value); 165 ass_font_free(value);
203 free(key); 166 free(key);
204 } 167 }
205 168
206 ass_font_t* ass_font_cache_find(ass_font_desc_t* desc) 169 ASS_Font *ass_font_cache_find(Hashmap *font_cache,
207 { 170 ASS_FontDesc *desc)
208 return hashmap_find(font_cache, desc); 171 {
172 return hashmap_find(font_cache, desc);
209 } 173 }
210 174
211 /** 175 /**
212 * \brief Add a face struct to cache. 176 * \brief Add a face struct to cache.
213 * \param font font struct 177 * \param font font struct
214 */ 178 */
215 void* ass_font_cache_add(ass_font_t* font) 179 void *ass_font_cache_add(Hashmap *font_cache, ASS_Font *font)
216 { 180 {
217 return hashmap_insert(font_cache, &(font->desc), font); 181 return hashmap_insert(font_cache, &(font->desc), font);
218 } 182 }
219 183
220 void ass_font_cache_init(void) 184 Hashmap *ass_font_cache_init(ASS_Library *library)
221 { 185 {
222 font_cache = hashmap_init(sizeof(ass_font_desc_t), 186 Hashmap *font_cache;
223 sizeof(ass_font_t), 187 font_cache = hashmap_init(library, sizeof(ASS_FontDesc),
224 1000, 188 sizeof(ASS_Font),
225 font_hash_dtor, font_compare, font_desc_hash); 189 1000,
226 } 190 font_hash_dtor, font_compare, font_desc_hash);
227 191 return font_cache;
228 void ass_font_cache_done(void) 192 }
229 { 193
230 hashmap_done(font_cache); 194 void ass_font_cache_done(Hashmap *font_cache)
231 } 195 {
196 hashmap_done(font_cache);
197 }
198
199
200 // Create hash/compare functions for bitmap and glyph
201 #define CREATE_HASH_FUNCTIONS
202 #include "ass_cache_template.h"
203 #define CREATE_COMPARISON_FUNCTIONS
204 #include "ass_cache_template.h"
232 205
233 //--------------------------------- 206 //---------------------------------
234 // bitmap cache 207 // bitmap cache
235 208
236 hashmap_t* bitmap_cache; 209 static void bitmap_hash_dtor(void *key, size_t key_size, void *value,
237 210 size_t value_size)
238 static void bitmap_hash_dtor(void* key, size_t key_size, void* value, size_t value_size) 211 {
239 { 212 BitmapHashValue *v = value;
240 bitmap_hash_val_t* v = value; 213 if (v->bm)
241 if (v->bm) ass_free_bitmap(v->bm); 214 ass_free_bitmap(v->bm);
242 if (v->bm_o) ass_free_bitmap(v->bm_o); 215 if (v->bm_o)
243 if (v->bm_s) ass_free_bitmap(v->bm_s); 216 ass_free_bitmap(v->bm_o);
244 free(key); 217 if (v->bm_s)
245 free(value); 218 ass_free_bitmap(v->bm_s);
246 } 219 free(key);
247 220 free(value);
248 void* cache_add_bitmap(bitmap_hash_key_t* key, bitmap_hash_val_t* val) 221 }
249 { 222
250 return hashmap_insert(bitmap_cache, key, val); 223 void *cache_add_bitmap(Hashmap *bitmap_cache, BitmapHashKey *key,
224 BitmapHashValue *val)
225 {
226 // Note: this is only an approximation
227 if (val->bm_o)
228 bitmap_cache->cache_size += val->bm_o->w * val->bm_o->h * 3;
229 else if (val->bm)
230 bitmap_cache->cache_size += val->bm->w * val->bm->h * 3;
231
232 return hashmap_insert(bitmap_cache, key, val);
251 } 233 }
252 234
253 /** 235 /**
254 * \brief Get a bitmap from bitmap cache. 236 * \brief Get a bitmap from bitmap cache.
255 * \param key hash key 237 * \param key hash key
256 * \return requested hash val or 0 if not found 238 * \return requested hash val or 0 if not found
257 */ 239 */
258 bitmap_hash_val_t* cache_find_bitmap(bitmap_hash_key_t* key) 240 BitmapHashValue *cache_find_bitmap(Hashmap *bitmap_cache,
259 { 241 BitmapHashKey *key)
260 return hashmap_find(bitmap_cache, key); 242 {
261 } 243 return hashmap_find(bitmap_cache, key);
262 244 }
263 void ass_bitmap_cache_init(void) 245
264 { 246 Hashmap *ass_bitmap_cache_init(ASS_Library *library)
265 bitmap_cache = hashmap_init(sizeof(bitmap_hash_key_t), 247 {
266 sizeof(bitmap_hash_val_t), 248 Hashmap *bitmap_cache;
267 0xFFFF + 13, 249 bitmap_cache = hashmap_init(library,
268 bitmap_hash_dtor, NULL, NULL); 250 sizeof(BitmapHashKey),
269 } 251 sizeof(BitmapHashValue),
270 252 0xFFFF + 13,
271 void ass_bitmap_cache_done(void) 253 bitmap_hash_dtor, bitmap_compare,
272 { 254 bitmap_hash);
273 hashmap_done(bitmap_cache); 255 return bitmap_cache;
274 } 256 }
275 257
276 void ass_bitmap_cache_reset(void) 258 void ass_bitmap_cache_done(Hashmap *bitmap_cache)
277 { 259 {
278 ass_bitmap_cache_done(); 260 hashmap_done(bitmap_cache);
279 ass_bitmap_cache_init(); 261 }
262
263 Hashmap *ass_bitmap_cache_reset(Hashmap *bitmap_cache)
264 {
265 ASS_Library *lib = bitmap_cache->library;
266
267 ass_bitmap_cache_done(bitmap_cache);
268 return ass_bitmap_cache_init(lib);
280 } 269 }
281 270
282 //--------------------------------- 271 //---------------------------------
283 // glyph cache 272 // glyph cache
284 273
285 hashmap_t* glyph_cache; 274 static void glyph_hash_dtor(void *key, size_t key_size, void *value,
286 275 size_t value_size)
287 static void glyph_hash_dtor(void* key, size_t key_size, void* value, size_t value_size) 276 {
288 { 277 GlyphHashValue *v = value;
289 glyph_hash_val_t* v = value; 278 if (v->glyph)
290 if (v->glyph) FT_Done_Glyph(v->glyph); 279 FT_Done_Glyph(v->glyph);
291 if (v->outline_glyph) FT_Done_Glyph(v->outline_glyph); 280 if (v->outline_glyph)
292 free(key); 281 FT_Done_Glyph(v->outline_glyph);
293 free(value); 282 free(key);
294 } 283 free(value);
295 284 }
296 void* cache_add_glyph(glyph_hash_key_t* key, glyph_hash_val_t* val) 285
297 { 286 void *cache_add_glyph(Hashmap *glyph_cache, GlyphHashKey *key,
298 return hashmap_insert(glyph_cache, key, val); 287 GlyphHashValue *val)
288 {
289 return hashmap_insert(glyph_cache, key, val);
299 } 290 }
300 291
301 /** 292 /**
302 * \brief Get a glyph from glyph cache. 293 * \brief Get a glyph from glyph cache.
303 * \param key hash key 294 * \param key hash key
304 * \return requested hash val or 0 if not found 295 * \return requested hash val or 0 if not found
305 */ 296 */
306 glyph_hash_val_t* cache_find_glyph(glyph_hash_key_t* key) 297 GlyphHashValue *cache_find_glyph(Hashmap *glyph_cache,
307 { 298 GlyphHashKey *key)
308 return hashmap_find(glyph_cache, key); 299 {
309 } 300 return hashmap_find(glyph_cache, key);
310 301 }
311 void ass_glyph_cache_init(void) 302
312 { 303 Hashmap *ass_glyph_cache_init(ASS_Library *library)
313 glyph_cache = hashmap_init(sizeof(glyph_hash_key_t), 304 {
314 sizeof(glyph_hash_val_t), 305 Hashmap *glyph_cache;
315 0xFFFF + 13, 306 glyph_cache = hashmap_init(library, sizeof(GlyphHashKey),
316 glyph_hash_dtor, NULL, NULL); 307 sizeof(GlyphHashValue),
317 } 308 0xFFFF + 13,
318 309 glyph_hash_dtor, glyph_compare, glyph_hash);
319 void ass_glyph_cache_done(void) 310 return glyph_cache;
320 { 311 }
321 hashmap_done(glyph_cache); 312
322 } 313 void ass_glyph_cache_done(Hashmap *glyph_cache)
323 314 {
324 void ass_glyph_cache_reset(void) 315 hashmap_done(glyph_cache);
325 { 316 }
326 ass_glyph_cache_done(); 317
327 ass_glyph_cache_init(); 318 Hashmap *ass_glyph_cache_reset(Hashmap *glyph_cache)
319 {
320 ASS_Library *lib = glyph_cache->library;
321
322 ass_glyph_cache_done(glyph_cache);
323 return ass_glyph_cache_init(lib);
328 } 324 }
329 325
330 326
331 //--------------------------------- 327 //---------------------------------
332 // composite cache 328 // composite cache
333 329
334 hashmap_t* composite_cache; 330 static void composite_hash_dtor(void *key, size_t key_size, void *value,
335 331 size_t value_size)
336 static void composite_hash_dtor(void* key, size_t key_size, void* value, size_t value_size) 332 {
337 { 333 CompositeHashValue *v = value;
338 composite_hash_val_t* v = value; 334 free(v->a);
339 free(v->a); 335 free(v->b);
340 free(v->b); 336 free(key);
341 free(key); 337 free(value);
342 free(value); 338 }
343 } 339
344 340 void *cache_add_composite(Hashmap *composite_cache,
345 void* cache_add_composite(composite_hash_key_t* key, composite_hash_val_t* val) 341 CompositeHashKey *key,
346 { 342 CompositeHashValue *val)
347 return hashmap_insert(composite_cache, key, val); 343 {
344 return hashmap_insert(composite_cache, key, val);
348 } 345 }
349 346
350 /** 347 /**
351 * \brief Get a composite bitmap from composite cache. 348 * \brief Get a composite bitmap from composite cache.
352 * \param key hash key 349 * \param key hash key
353 * \return requested hash val or 0 if not found 350 * \return requested hash val or 0 if not found
354 */ 351 */
355 composite_hash_val_t* cache_find_composite(composite_hash_key_t* key) 352 CompositeHashValue *cache_find_composite(Hashmap *composite_cache,
356 { 353 CompositeHashKey *key)
357 return hashmap_find(composite_cache, key); 354 {
358 } 355 return hashmap_find(composite_cache, key);
359 356 }
360 void ass_composite_cache_init(void) 357
361 { 358 Hashmap *ass_composite_cache_init(ASS_Library *library)
362 composite_cache = hashmap_init(sizeof(composite_hash_key_t), 359 {
363 sizeof(composite_hash_val_t), 360 Hashmap *composite_cache;
364 0xFFFF + 13, 361 composite_cache = hashmap_init(library, sizeof(CompositeHashKey),
365 composite_hash_dtor, NULL, NULL); 362 sizeof(CompositeHashValue),
366 } 363 0xFFFF + 13,
367 364 composite_hash_dtor, composite_compare,
368 void ass_composite_cache_done(void) 365 composite_hash);
369 { 366 return composite_cache;
370 hashmap_done(composite_cache); 367 }
371 } 368
372 369 void ass_composite_cache_done(Hashmap *composite_cache)
373 void ass_composite_cache_reset(void) 370 {
374 { 371 hashmap_done(composite_cache);
375 ass_composite_cache_done(); 372 }
376 ass_composite_cache_init(); 373
377 } 374 Hashmap *ass_composite_cache_reset(Hashmap *composite_cache)
378 375 {
376 ASS_Library *lib = composite_cache->library;
377
378 ass_composite_cache_done(composite_cache);
379 return ass_composite_cache_init(lib);
380 }