From f4d6e4b9af4cfe2fe684640f19682e4f954b7549 Mon Sep 17 00:00:00 2001 From: "Dr.Smile" Date: Fri, 18 Sep 2015 00:33:33 +0300 Subject: cache: remove ass_cache_cancel(), cache failures instead --- libass/ass_cache.c | 212 ++++++++++++++++++++++++++++++++-------------------- libass/ass_cache.h | 6 +- libass/ass_font.c | 15 ++-- libass/ass_render.c | 147 +++++++++++++++++------------------- libass/ass_shaper.c | 32 ++++---- 5 files changed, 228 insertions(+), 184 deletions(-) (limited to 'libass') diff --git a/libass/ass_cache.c b/libass/ass_cache.c index 44aaee9..87e6cc2 100644 --- a/libass/ass_cache.c +++ b/libass/ass_cache.c @@ -63,37 +63,20 @@ static unsigned font_compare(void *key1, void *key2, size_t key_size) return 1; } -static void font_destruct(void *key, void *value) +static bool font_key_copy(void *dst, void *src, size_t key_size) { - ass_font_clear(value); + memcpy(dst, src, key_size); + ASS_FontDesc *d = dst, *s = src; + d->family = strdup(s->family); + return d->family; } -// bitmap cache -static void bitmap_destruct(void *key, void *value) -{ - BitmapHashValue *v = value; - BitmapHashKey *k = key; - if (v->bm) - ass_free_bitmap(v->bm); - if (v->bm_o) - ass_free_bitmap(v->bm_o); - switch (k->type) { - case BITMAP_OUTLINE: ass_cache_dec_ref(k->u.outline.outline); break; - case BITMAP_CLIP: free(k->u.clip.text); break; - } -} - -static size_t bitmap_size(void *value, size_t value_size) +static void font_destruct(void *key, void *value) { - BitmapHashValue *val = value; - size_t size = sizeof(BitmapHashKey) + sizeof(BitmapHashValue); - if (val->bm) - size += sizeof(Bitmap) + val->bm->stride * val->bm->h; - if (val->bm_o) - size += sizeof(Bitmap) + val->bm_o->stride * val->bm_o->h; - return size; + ass_font_clear(value); } +// bitmap cache static unsigned bitmap_hash(void *key, size_t key_size) { BitmapHashKey *k = key; @@ -116,35 +99,49 @@ static unsigned bitmap_compare(void *a, void *b, size_t key_size) } } -// composite cache -static void composite_destruct(void *key, void *value) +static bool bitmap_key_copy(void *dst, void *src, size_t key_size) { - CompositeHashValue *v = value; - CompositeHashKey *k = key; + memcpy(dst, src, key_size); + BitmapHashKey *d = dst, *s = src; + switch (s->type) { + case BITMAP_OUTLINE: + ass_cache_inc_ref(s->u.outline.outline); + break; + case BITMAP_CLIP: + d->u.clip.text = strdup(s->u.clip.text); + if (!d->u.clip.text) + return false; + break; + } + return true; +} + +static void bitmap_destruct(void *key, void *value) +{ + BitmapHashValue *v = value; + BitmapHashKey *k = key; if (v->bm) ass_free_bitmap(v->bm); if (v->bm_o) ass_free_bitmap(v->bm_o); - if (v->bm_s) - ass_free_bitmap(v->bm_s); - for (size_t i = 0; i < k->bitmap_count; i++) - ass_cache_dec_ref(k->bitmaps[i].image); - free(k->bitmaps); + switch (k->type) { + case BITMAP_OUTLINE: ass_cache_dec_ref(k->u.outline.outline); break; + case BITMAP_CLIP: free(k->u.clip.text); break; + } } -static size_t composite_size(void *value, size_t value_size) +static size_t bitmap_size(void *value, size_t value_size) { - CompositeHashValue *val = value; - size_t size = sizeof(CompositeHashKey) + sizeof(CompositeHashValue); + BitmapHashValue *val = value; + size_t size = sizeof(BitmapHashKey) + sizeof(BitmapHashValue); if (val->bm) size += sizeof(Bitmap) + val->bm->stride * val->bm->h; if (val->bm_o) size += sizeof(Bitmap) + val->bm_o->stride * val->bm_o->h; - if (val->bm_s) - size += sizeof(Bitmap) + val->bm_s->stride * val->bm_s->h; return size; } +// composite cache static unsigned composite_hash(void *key, size_t key_size) { CompositeHashKey *k = key; @@ -172,8 +169,44 @@ static unsigned composite_compare(void *a, void *b, size_t key_size) return filter_compare(&ak->filter, &bk->filter, key_size); } -// outline cache +static bool composite_key_copy(void *dst, void *src, size_t key_size) +{ + memcpy(dst, src, key_size); + CompositeHashKey *k = src; + for (size_t i = 0; i < k->bitmap_count; i++) + ass_cache_inc_ref(k->bitmaps[i].image); + return true; +} +static void composite_destruct(void *key, void *value) +{ + CompositeHashValue *v = value; + CompositeHashKey *k = key; + if (v->bm) + ass_free_bitmap(v->bm); + if (v->bm_o) + ass_free_bitmap(v->bm_o); + if (v->bm_s) + ass_free_bitmap(v->bm_s); + for (size_t i = 0; i < k->bitmap_count; i++) + ass_cache_dec_ref(k->bitmaps[i].image); + free(k->bitmaps); +} + +static size_t composite_size(void *value, size_t value_size) +{ + CompositeHashValue *val = value; + size_t size = sizeof(CompositeHashKey) + sizeof(CompositeHashValue); + if (val->bm) + size += sizeof(Bitmap) + val->bm->stride * val->bm->h; + if (val->bm_o) + size += sizeof(Bitmap) + val->bm_o->stride * val->bm_o->h; + if (val->bm_s) + size += sizeof(Bitmap) + val->bm_s->stride * val->bm_s->h; + return size; +} + +// outline cache static unsigned outline_hash(void *key, size_t key_size) { OutlineHashKey *k = key; @@ -196,6 +229,23 @@ static unsigned outline_compare(void *a, void *b, size_t key_size) } } +static bool outline_key_copy(void *dst, void *src, size_t key_size) +{ + memcpy(dst, src, key_size); + OutlineHashKey *d = dst, *s = src; + switch (s->type) { + case OUTLINE_GLYPH: + ass_cache_inc_ref(s->u.glyph.font); + break; + case OUTLINE_DRAWING: + d->u.drawing.text = strdup(s->u.drawing.text); + if (!d->u.drawing.text) + return false; + break; + } + return true; +} + static void outline_destruct(void *key, void *value) { OutlineHashValue *v = value; @@ -212,6 +262,14 @@ static void outline_destruct(void *key, void *value) // glyph metric cache +static bool glyph_metric_key_copy(void *dst, void *src, size_t key_size) +{ + memcpy(dst, src, key_size); + GlyphMetricsHashKey *k = src; + ass_cache_inc_ref(k->font); + return true; +} + static void glyph_metric_destruct(void *key, void *value) { GlyphMetricsHashKey *k = key; @@ -236,6 +294,7 @@ struct cache { HashFunction hash_func; ItemSize size_func; HashCompare compare_func; + CacheKeyCopy copy_func; CacheItemDestructor destruct_func; size_t key_size; size_t value_size; @@ -271,6 +330,13 @@ static unsigned compare_simple(void *a, void *b, size_t key_size) return memcmp(a, b, key_size) == 0; } +// Default copy function +static bool copy_simple(void *dst, void *src, size_t key_size) +{ + memcpy(dst, src, key_size); + return true; +} + // Default destructor static void destruct_simple(void *key, void *value) { @@ -279,24 +345,19 @@ static void destruct_simple(void *key, void *value) // Create a cache with type-specific hash/compare/destruct/size functions Cache *ass_cache_create(HashFunction hash_func, HashCompare compare_func, - CacheItemDestructor destruct_func, ItemSize size_func, - size_t key_size, size_t value_size) + CacheKeyCopy copy_func, CacheItemDestructor destruct_func, + ItemSize size_func, size_t key_size, size_t value_size) { Cache *cache = calloc(1, sizeof(*cache)); if (!cache) return NULL; cache->buckets = 0xFFFF; cache->queue_last = &cache->queue_first; - cache->hash_func = hash_simple; - cache->compare_func = compare_simple; - cache->destruct_func = destruct_simple; + cache->hash_func = hash_func ? hash_func : hash_simple; + cache->compare_func = compare_func ? compare_func : compare_simple; + cache->copy_func = copy_func ? copy_func : copy_simple; + cache->destruct_func = destruct_func ? destruct_func : destruct_simple; cache->size_func = size_func; - if (hash_func) - cache->hash_func = hash_func; - if (compare_func) - cache->compare_func = compare_func; - if (destruct_func) - cache->destruct_func = destruct_func; cache->key_size = key_size; cache->value_size = value_size; cache->map = calloc(cache->buckets, sizeof(CacheItem *)); @@ -338,12 +399,16 @@ bool ass_cache_get(Cache *cache, void *key, void *value_ptr) item = malloc(key_offs + cache->key_size); if (!item) { *value = NULL; - return 0; + return false; } item->size = 0; item->cache = cache; + if (!cache->copy_func((char *) item + key_offs, key, cache->key_size)) { + free(item); + *value = NULL; + return false; + } *value = (char *) item + CACHE_ITEM_SIZE; - memcpy((char *) item + key_offs, key, cache->key_size); CacheItem **bucketptr = &cache->map[bucket]; if (*bucketptr) @@ -364,7 +429,6 @@ bool ass_cache_get(Cache *cache, void *key, void *value_ptr) void *ass_cache_get_key(void *value) { CacheItem *item = value_to_item(value); - assert(!item->size); return (char *) value + align_cache(item->cache->value_size); } @@ -382,21 +446,6 @@ void ass_cache_commit(void *value) cache->cache_size += item->size; } -void ass_cache_cancel(void *value) -{ - CacheItem *item = value_to_item(value); - assert(!item->size); - - if (item->queue_next) - item->queue_next->queue_prev = item->queue_prev; - *item->queue_prev = item->queue_next; - - if (item->next) - item->next->prev = item->prev; - *item->prev = item->next; - free(item); -} - static inline void destroy_item(Cache *cache, CacheItem *item) { assert(item->cache == cache); @@ -502,32 +551,35 @@ void ass_cache_done(Cache *cache) // Type-specific creation function Cache *ass_font_cache_create(void) { - return ass_cache_create(font_hash, font_compare, font_destruct, - (ItemSize)NULL, sizeof(ASS_FontDesc), sizeof(ASS_Font)); + return ass_cache_create(font_hash, font_compare, + font_key_copy, font_destruct, NULL, + sizeof(ASS_FontDesc), sizeof(ASS_Font)); } Cache *ass_outline_cache_create(void) { - return ass_cache_create(outline_hash, outline_compare, outline_destruct, - NULL, sizeof(OutlineHashKey), sizeof(OutlineHashValue)); + return ass_cache_create(outline_hash, outline_compare, + outline_key_copy, outline_destruct, NULL, + sizeof(OutlineHashKey), sizeof(OutlineHashValue)); } Cache *ass_glyph_metrics_cache_create(void) { - return ass_cache_create(glyph_metrics_hash, glyph_metrics_compare, glyph_metric_destruct, - (ItemSize) NULL, sizeof(GlyphMetricsHashKey), - sizeof(GlyphMetricsHashValue)); + return ass_cache_create(glyph_metrics_hash, glyph_metrics_compare, + glyph_metric_key_copy, glyph_metric_destruct, NULL, + sizeof(GlyphMetricsHashKey), sizeof(GlyphMetricsHashValue)); } Cache *ass_bitmap_cache_create(void) { - return ass_cache_create(bitmap_hash, bitmap_compare, bitmap_destruct, - bitmap_size, sizeof(BitmapHashKey), sizeof(BitmapHashValue)); + return ass_cache_create(bitmap_hash, bitmap_compare, + bitmap_key_copy, bitmap_destruct, bitmap_size, + sizeof(BitmapHashKey), sizeof(BitmapHashValue)); } Cache *ass_composite_cache_create(void) { return ass_cache_create(composite_hash, composite_compare, - composite_destruct, composite_size, sizeof(CompositeHashKey), - sizeof(CompositeHashValue)); + composite_key_copy, composite_destruct, composite_size, + sizeof(CompositeHashKey), sizeof(CompositeHashValue)); } diff --git a/libass/ass_cache.h b/libass/ass_cache.h index 63e9e59..c18f9d8 100644 --- a/libass/ass_cache.h +++ b/libass/ass_cache.h @@ -59,6 +59,7 @@ typedef struct { typedef unsigned(*HashFunction)(void *key, size_t key_size); typedef size_t(*ItemSize)(void *value, size_t value_size); typedef unsigned(*HashCompare)(void *a, void *b, size_t key_size); +typedef bool(*CacheKeyCopy)(void *dst, void *src, size_t key_size); typedef void(*CacheItemDestructor)(void *key, void *value); // cache hash keys @@ -104,12 +105,11 @@ typedef struct { } CompositeHashKey; Cache *ass_cache_create(HashFunction hash_func, HashCompare compare_func, - CacheItemDestructor destruct_func, ItemSize size_func, - size_t key_size, size_t value_size); + CacheKeyCopy copy_func, CacheItemDestructor destruct_func, + ItemSize size_func, size_t key_size, size_t value_size); bool ass_cache_get(Cache *cache, void *key, void *value_ptr); void *ass_cache_get_key(void *value); void ass_cache_commit(void *value); -void ass_cache_cancel(void *value); void ass_cache_inc_ref(void *value); void ass_cache_dec_ref(void *value); void ass_cache_cut(Cache *cache, size_t max_size); diff --git a/libass/ass_font.c b/libass/ass_font.c index a4c45bd..c40ff1e 100644 --- a/libass/ass_font.c +++ b/libass/ass_font.c @@ -228,17 +228,18 @@ ASS_Font *ass_font_new(Cache *font_cache, ASS_Library *library, FT_Library ftlibrary, ASS_FontSelector *fontsel, ASS_FontDesc *desc) { - int error; ASS_Font *font; if (ass_cache_get(font_cache, desc, &font)) - return font; + return font->desc.family ? font : NULL; + if (!font) + return NULL; font->library = library; font->ftlibrary = ftlibrary; font->shaper_priv = NULL; font->n_faces = 0; ASS_FontDesc *new_desc = ass_cache_get_key(font); - font->desc.family = new_desc->family = strdup(desc->family); + font->desc.family = new_desc->family; font->desc.bold = desc->bold; font->desc.italic = desc->italic; font->desc.vertical = desc->vertical; @@ -247,11 +248,11 @@ ASS_Font *ass_font_new(Cache *font_cache, ASS_Library *library, font->v.x = font->v.y = 0; font->size = 0.; - error = add_face(fontsel, font, 0); + int error = add_face(fontsel, font, 0); if (error == -1) { - ass_cache_cancel(font); - free(font->desc.family); - return 0; + font->desc.family = NULL; + ass_cache_commit(font); + return NULL; } ass_cache_commit(font); return font; diff --git a/libass/ass_render.c b/libass/ass_render.c index ef0531d..7a1dd47 100644 --- a/libass/ass_render.c +++ b/libass/ass_render.c @@ -498,23 +498,17 @@ static void blend_vector_clip(ASS_Renderer *render_priv, key.u.clip.text = drawing->text; BitmapHashValue *val; - Bitmap *clip_bm = NULL; - if (ass_cache_get(render_priv->cache.bitmap_cache, &key, &val)) { - clip_bm = val->bm; - } else { + if (!ass_cache_get(render_priv->cache.bitmap_cache, &key, &val)) { + if (!val) + return; + val->bm = val->bm_o = NULL; + // Not found in cache, parse and rasterize it ASS_Outline *outline = ass_drawing_parse(drawing, 1); if (!outline) { ass_msg(render_priv->library, MSGL_WARN, "Clip vector parsing failed. Skipping."); - ass_cache_cancel(val); - return; - } - - BitmapHashKey *new_key = ass_cache_get_key(val); - new_key->u.clip.text = strdup(drawing->text); - if (!new_key->u.clip.text) { - ass_cache_cancel(val); + ass_cache_commit(val); return; } @@ -528,14 +522,11 @@ static void blend_vector_clip(ASS_Renderer *render_priv, outline_translate(outline, trans.x, trans.y); } - clip_bm = outline_to_bitmap(render_priv, outline, 0); - - // Add to cache - val->bm = clip_bm; - val->bm_o = NULL; + val->bm = outline_to_bitmap(render_priv, outline, 0); ass_cache_commit(val); } + Bitmap *clip_bm = val->bm; if (!clip_bm) return; // Iterate through bitmaps and blend/clip them @@ -1161,19 +1152,15 @@ get_outline_glyph(ASS_Renderer *priv, GlyphInfo *info) OutlineHashValue *val; fill_glyph_hash(priv, &key, info); if (!ass_cache_get(priv->cache.outline_cache, &key, &val)) { + if (!val) + return; memset(val, 0, sizeof(*val)); if (info->drawing) { ASS_Drawing *drawing = info->drawing; ass_drawing_hash(drawing); if(!ass_drawing_parse(drawing, 0)) { - ass_cache_cancel(val); - return; - } - OutlineHashKey *new_key = ass_cache_get_key(val); - new_key->u.drawing.text = strdup(drawing->text); - if(!new_key->u.drawing.text) { - ass_cache_cancel(val); + ass_cache_commit(val); return; } val->outline = outline_copy(&drawing->outline); @@ -1205,17 +1192,23 @@ get_outline_glyph(ASS_Renderer *priv, GlyphInfo *info) } if (!val->outline) { - ass_cache_cancel(val); + ass_cache_commit(val); return; } outline_get_cbox(val->outline, &val->bbox_scaled); if (info->border_style == 3) { - FT_Vector advance; - val->border = calloc(1, sizeof(ASS_Outline)); + if (!val->border) { + outline_free(val->outline); + free(val->outline); + val->outline = NULL; + ass_cache_commit(val); + return; + } + FT_Vector advance; if (priv->settings.shaper == ASS_SHAPING_SIMPLE || info->drawing) advance = val->advance; else @@ -1235,11 +1228,12 @@ get_outline_glyph(ASS_Renderer *priv, GlyphInfo *info) double_to_d6(info->border_y * priv->border_scale)); } - if (!info->drawing) - ass_cache_inc_ref(info->font); ass_cache_commit(val); } + if (!val->outline) + return; + info->hash_key.u.outline.outline = val; info->outline = val->outline; info->border = val->border; @@ -1343,62 +1337,57 @@ get_bitmap_glyph(ASS_Renderer *render_priv, GlyphInfo *info) BitmapHashValue *val; OutlineBitmapHashKey *key = &info->hash_key.u.outline; - if (!ass_cache_get(render_priv->cache.bitmap_cache, &info->hash_key, &val)) { - FT_Vector shift; - int error; - double fax_scaled, fay_scaled; - double scale_x = render_priv->font_scale_x; + if (ass_cache_get(render_priv->cache.bitmap_cache, &info->hash_key, &val)) { + info->image = val; + return; + } + if (!val) + return; - val->bm = val->bm_o = NULL; + ASS_Outline *outline = outline_copy(info->outline); + ASS_Outline *border = outline_copy(info->border); - ASS_Outline *outline = outline_copy(info->outline); - ASS_Outline *border = outline_copy(info->border); - - // calculating rotation shift vector (from rotation origin to the glyph basepoint) - shift.x = key->shift_x; - shift.y = key->shift_y; - fax_scaled = info->fax / info->scale_y * info->scale_x; - fay_scaled = info->fay / info->scale_x * info->scale_y; - - // apply rotation - // use blur_scale because, like blurs, VSFilter forgets to scale this - transform_3d(shift, outline, border, - info->frx, info->fry, info->frz, fax_scaled, - fay_scaled, render_priv->blur_scale, info->asc); - - // PAR correction scaling - FT_Matrix m = { double_to_d16(scale_x), 0, - 0, double_to_d16(1.0) }; - - // subpixel shift - if (outline) { - if (scale_x != 1.0) - outline_transform(outline, &m); - outline_translate(outline, key->advance.x, -key->advance.y); - } - if (border) { - if (scale_x != 1.0) - outline_transform(border, &m); - outline_translate(border, key->advance.x, -key->advance.y); - } + // calculating rotation shift vector (from rotation origin to the glyph basepoint) + FT_Vector shift = { key->shift_x, key->shift_y }; + double scale_x = render_priv->font_scale_x; + double fax_scaled = info->fax / info->scale_y * info->scale_x; + double fay_scaled = info->fay / info->scale_x * info->scale_y; - // render glyph - error = outline_to_bitmap2(render_priv, outline, border, - &val->bm, &val->bm_o); - if (error) - info->symbol = 0; + // apply rotation + // use blur_scale because, like blurs, VSFilter forgets to scale this + transform_3d(shift, outline, border, + info->frx, info->fry, info->frz, fax_scaled, + fay_scaled, render_priv->blur_scale, info->asc); - assert(info->hash_key.type == BITMAP_OUTLINE); - ass_cache_inc_ref(info->hash_key.u.outline.outline); - ass_cache_commit(val); + // PAR correction scaling + FT_Matrix m = { double_to_d16(scale_x), 0, + 0, double_to_d16(1.0) }; - outline_free(outline); - free(outline); - outline_free(border); - free(border); + // subpixel shift + if (outline) { + if (scale_x != 1.0) + outline_transform(outline, &m); + outline_translate(outline, key->advance.x, -key->advance.y); + } + if (border) { + if (scale_x != 1.0) + outline_transform(border, &m); + outline_translate(border, key->advance.x, -key->advance.y); } + // render glyph + int error = outline_to_bitmap2(render_priv, outline, border, + &val->bm, &val->bm_o); + if (error) + info->symbol = 0; + + ass_cache_commit(val); info->image = val; + + outline_free(outline); + free(outline); + outline_free(border); + free(border); } /** @@ -2277,6 +2266,8 @@ static void render_and_combine_glyphs(ASS_Renderer *render_priv, free(info->bitmaps); continue; } + if (!hv) + continue; int bord = be_padding(info->filter.be); if (!bord && info->n_bm == 1) { @@ -2358,8 +2349,6 @@ static void render_and_combine_glyphs(ASS_Renderer *render_priv, hv->bm = info->bm; hv->bm_o = info->bm_o; hv->bm_s = info->bm_s; - for (int j = 0; j < info->bitmap_count; ++j) - ass_cache_inc_ref(info->bitmaps[j].image); ass_cache_commit(hv); } diff --git a/libass/ass_shaper.c b/libass/ass_shaper.c index 95ffda3..6f872e3 100644 --- a/libass/ass_shaper.c +++ b/libass/ass_shaper.c @@ -208,26 +208,28 @@ get_cached_metrics(struct ass_shaper_metrics_data *metrics, FT_Face face, { GlyphMetricsHashValue *val; metrics->hash_key.glyph_index = glyph; - if (!ass_cache_get(metrics->metrics_cache, &metrics->hash_key, &val)) { - int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH - | FT_LOAD_IGNORE_TRANSFORM; - - if (FT_Load_Glyph(face, glyph, load_flags)) { - ass_cache_cancel(val); - return NULL; - } - - memcpy(&val->metrics, &face->glyph->metrics, sizeof(FT_Glyph_Metrics)); + if (ass_cache_get(metrics->metrics_cache, &metrics->hash_key, &val)) + return val->metrics.width < 0 ? NULL : val; + if (!val) + return NULL; - // if @font rendering is enabled and the glyph should be rotated, - // make cached_h_advance pick up the right advance later - if (metrics->vertical && unicode >= VERTICAL_LOWER_BOUND) - val->metrics.horiAdvance = val->metrics.vertAdvance; + int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH + | FT_LOAD_IGNORE_TRANSFORM; - ass_cache_inc_ref(metrics->hash_key.font); + if (FT_Load_Glyph(face, glyph, load_flags)) { + val->metrics.width = -1; ass_cache_commit(val); + return NULL; } + memcpy(&val->metrics, &face->glyph->metrics, sizeof(FT_Glyph_Metrics)); + + // if @font rendering is enabled and the glyph should be rotated, + // make cached_h_advance pick up the right advance later + if (metrics->vertical && unicode >= VERTICAL_LOWER_BOUND) + val->metrics.horiAdvance = val->metrics.vertAdvance; + + ass_cache_commit(val); return val; } -- cgit v1.2.3