]> granicus.if.org Git - libass/commitdiff
Introduce simple cache memory management
authorGrigori Goronzy <greg@blackbox>
Sun, 19 Jul 2009 06:38:49 +0000 (08:38 +0200)
committerGrigori Goronzy <greg@blackbox>
Sun, 19 Jul 2009 13:56:23 +0000 (15:56 +0200)
libass' cache was basically unmanaged; it would grow without any limits,
depending on how complex the subtitles are.  Introduce a simple limiting
that resets the cache if certain limits are exceeded.  The bitmap cache
is limited to approx. 50 MB size by default, while the glyph cache
allows storing up to 1000 glyphs by default.  A few tests with rather
heavily softsubbed fansubs show that these limits are fine.
The API was extended with the function ass_set_cache_limits which allows
modification of these limits.

libass/ass.h
libass/ass_cache.c
libass/ass_cache.h
libass/ass_render.c
libass/libass.sym

index 6efcc0f4bb02c4c967fd7ce5f161a6f7dd2da2bc..b92960a157d32b16fdaa8be6668161865bce043f 100644 (file)
@@ -201,6 +201,17 @@ void ass_set_fonts(ass_renderer_t *priv, const char *default_font,
  */
 int ass_fonts_update(ass_renderer_t *priv);
 
+/**
+ * \brief Set hard cache limits.  Do not set, or set to zero, for reasonable
+ * defaults.
+ *
+ * \param priv renderer handle
+ * \param glyph_max maximum number of cached glyphs
+ * \param bitmap_max_size maximum bitmap cache size (in MB)
+ */
+void ass_set_cache_limits(ass_renderer_t *priv, int glyph_max,
+                          int bitmap_max_size);
+
 /**
  * \brief Render a frame, producing a list of ass_image_t.
  * \param priv renderer handle
index 4c7a3fa537519bea6d424055333fe254aecf1096..524a1c83e4326143a6db18a4e32cd2b3631668c6 100644 (file)
@@ -223,6 +223,12 @@ static void bitmap_hash_dtor(void *key, size_t key_size, void *value,
 void *cache_add_bitmap(hashmap_t *bitmap_cache, bitmap_hash_key_t *key,
                        bitmap_hash_val_t *val)
 {
+    // Note: this is only an approximation
+    if (val->bm_o)
+        bitmap_cache->cache_size += val->bm_o->w * val->bm_o->h * 3;
+    else
+        bitmap_cache->cache_size += val->bm->w * val->bm->h * 3;
+
     return hashmap_insert(bitmap_cache, key, val);
 }
 
index 83c994386546c163bf525ad457d982dedd641b70..e31d8cf682951ffdc44baf050d89c7c5ff695372 100644 (file)
@@ -45,6 +45,7 @@ typedef struct hashmap_s {
     hashmap_item_dtor_t item_dtor;      // a destructor for hashmap key/value pairs
     hashmap_key_compare_t key_compare;
     hashmap_hash_t hash;
+    size_t cache_size;
     // stats
     int hit_count;
     int miss_count;
index 5caf8ebfe1dda7ee9b8e45fffa88894a92d1535c..aeeb0acb7f3adf8e0e94141e33bd58153332ca16 100644 (file)
@@ -44,6 +44,8 @@
 #define MAX_BE 127
 #define SUBPIXEL_MASK 63
 #define SUBPIXEL_ACCURACY 7    // d6 mask for subpixel accuracy adjustment
+#define GLYPH_CACHE_MAX 1000
+#define BITMAP_CACHE_MAX_SIZE 50 * 1048576;
 
 static int last_render_id = 0;
 
@@ -206,6 +208,8 @@ typedef struct cache_store_s {
     hashmap_t *glyph_cache;
     hashmap_t *bitmap_cache;
     hashmap_t *composite_cache;
+    size_t glyph_max;
+    size_t bitmap_max_size;
 } cache_store_t;
 
 struct ass_renderer_s {
@@ -319,6 +323,8 @@ ass_renderer_t *ass_renderer_init(ass_library_t *library)
     priv->cache.bitmap_cache = ass_bitmap_cache_init(library);
     priv->cache.composite_cache = ass_composite_cache_init(library);
     priv->cache.glyph_cache = ass_glyph_cache_init(library);
+    priv->cache.glyph_max = GLYPH_CACHE_MAX;
+    priv->cache.bitmap_max_size = BITMAP_CACHE_MAX_SIZE;
 
     priv->text_info.max_glyphs = MAX_GLYPHS_INITIAL;
     priv->text_info.max_lines = MAX_LINES_INITIAL;
@@ -335,6 +341,14 @@ ass_renderer_t *ass_renderer_init(ass_library_t *library)
     return priv;
 }
 
+void ass_set_cache_limits(ass_renderer_t *render_priv, int glyph_max,
+                          int bitmap_max)
+{
+    render_priv->cache.glyph_max = glyph_max ? glyph_max : GLYPH_CACHE_MAX;
+    render_priv->cache.bitmap_max_size = bitmap_max ? 1048576 * bitmap_max :
+                                         BITMAP_CACHE_MAX_SIZE;
+}
+
 static void free_list_clear(ass_renderer_t *render_priv)
 {
     if (render_priv->free_head) {
@@ -2873,6 +2887,7 @@ ass_render_event(ass_renderer_t *render_priv, ass_event_t *event,
         }
     }
 
+
     if (text_info->length == 0) {
         // no valid symbols in the event; this can be smth like {comment}
         free_render_context(render_priv);
@@ -3223,17 +3238,18 @@ static int
 ass_start_frame(ass_renderer_t *render_priv, ass_track_t *track,
                 long long now)
 {
-    if (render_priv->library != track->library)
-        return 1;
-
-    free_list_clear(render_priv);
-
     ass_settings_t *settings_priv = &render_priv->settings;
+    cache_store_t *cache = &render_priv->cache;
 
     if (!render_priv->settings.frame_width
         && !render_priv->settings.frame_height)
         return 1;               // library not initialized
 
+    if (render_priv->library != track->library)
+        return 1;
+
+    free_list_clear(render_priv);
+
     if (track->n_events == 0)
         return 1;               // nothing to do
 
@@ -3274,6 +3290,24 @@ ass_start_frame(ass_renderer_t *render_priv, ass_track_t *track,
     render_priv->prev_images_root = render_priv->images_root;
     render_priv->images_root = 0;
 
+    if (cache->bitmap_cache->cache_size > cache->bitmap_max_size) {
+        ass_msg(render_priv->library, MSGL_V,
+                "Hitting hard bitmap cache limit (was: %ld bytes), "
+                "resetting.", (long) cache->bitmap_cache->cache_size);
+        cache->bitmap_cache = ass_bitmap_cache_reset(cache->bitmap_cache);
+        cache->composite_cache = ass_composite_cache_reset(
+            cache->composite_cache);
+        ass_free_images(render_priv->prev_images_root);
+        render_priv->prev_images_root = 0;
+    }
+
+    if (cache->glyph_cache->count > cache->glyph_max) {
+        ass_msg(render_priv->library, MSGL_V,
+            "Hitting hard glyph cache limit (was: %ld glyphs), resetting.",
+            (long) cache->glyph_cache->count);
+        cache->glyph_cache = ass_glyph_cache_reset(cache->glyph_cache);
+    }
+
     return 0;
 }
 
index c702842c98af4070d1a784134081d25efe0376e1..e813a18b2135acaa9f6af52db6f67fe1540dd12a 100644 (file)
@@ -32,3 +32,4 @@ ass_step_sub
 ass_process_force_style
 ass_set_message_cb
 ass_fonts_update
+ass_set_cache_limits