diff --git a/gsk/gl/gskglglyphcache.c b/gsk/gl/gskglglyphcache.c index 21121b1ce5..f68837444c 100644 --- a/gsk/gl/gskglglyphcache.c +++ b/gsk/gl/gskglglyphcache.c @@ -15,9 +15,9 @@ /* Cache eviction strategy * - * Each cached glyph has an age that gets reset every time a cached - * glyph gets used. Glyphs that have not been used for the - * MAX_FRAME_AGE frames are considered old. + * We mark glyphs as accessed every time we use them. Every + * few frames, we mark glyphs that haven't been accessed since + * the last check as old. * * We keep count of the pixels of each atlas that are taken up by old * data. When the fraction of old pixels gets too high, we drop the @@ -264,12 +264,12 @@ gsk_gl_glyph_cache_lookup_or_add (GskGLGlyphCache *cache, if (value) { - value->timestamp = cache->timestamp; if (value->atlas && !value->used) { gsk_gl_texture_atlas_mark_used (value->atlas, value->draw_width, value->draw_height); value->used = TRUE; } + value->accessed = TRUE; *cached_glyph_out = value; return; @@ -292,7 +292,7 @@ gsk_gl_glyph_cache_lookup_or_add (GskGLGlyphCache *cache, value->draw_y = ink_rect.y; value->draw_width = ink_rect.width; value->draw_height = ink_rect.height; - value->timestamp = cache->timestamp; + value->accessed = TRUE; value->atlas = NULL; /* For now */ key = g_new0 (GlyphCacheKey, 1); @@ -341,20 +341,21 @@ gsk_gl_glyph_cache_begin_frame (GskGLGlyphCache *self, GSK_NOTE(GLYPH_CACHE, if (dropped > 0) g_message ("Dropped %d glyphs", dropped)); } - g_hash_table_iter_init (&iter, self->hash_table); - while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value)) + if (self->timestamp % MAX_FRAME_AGE == 0) { - const guint age = self->timestamp - value->timestamp; - - if (age > MAX_FRAME_AGE) + g_hash_table_iter_init (&iter, self->hash_table); + while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value)) { - GskGLTextureAtlas *atlas = value->atlas; - - if (atlas && value->used) + if (!value->accessed) { - gsk_gl_texture_atlas_mark_unused (atlas, value->draw_width, value->draw_height); - value->used = FALSE; + if (value->atlas && value->used) + { + gsk_gl_texture_atlas_mark_unused (value->atlas, value->draw_width, value->draw_height); + value->used = FALSE; + } } - } + + value->accessed = FALSE; + } } } diff --git a/gsk/gl/gskglglyphcacheprivate.h b/gsk/gl/gskglglyphcacheprivate.h index 259688fbb7..75f7a8de19 100644 --- a/gsk/gl/gskglglyphcacheprivate.h +++ b/gsk/gl/gskglglyphcacheprivate.h @@ -15,7 +15,7 @@ typedef struct GHashTable *hash_table; GskGLTextureAtlases *atlases; - guint64 timestamp; + int timestamp; } GskGLGlyphCache; typedef struct @@ -63,8 +63,8 @@ struct _GskGLCachedGlyph int draw_width; int draw_height; - guint used: 1; - guint64 timestamp; + guint accessed : 1; /* accessed since last check */ + guint used : 1; /* accounted as used in the atlas */ }; diff --git a/gsk/gl/gskgliconcache.c b/gsk/gl/gskgliconcache.c index 318c87fb0c..ea733939b9 100644 --- a/gsk/gl/gskgliconcache.c +++ b/gsk/gl/gskgliconcache.c @@ -11,9 +11,9 @@ typedef struct { graphene_rect_t texture_rect; GskGLTextureAtlas *atlas; - int frame_age; /* Number of frames this icon is unused */ - guint used: 1; GdkTexture *source_texture; + guint accessed : 1; + guint used : 1; } IconData; static void @@ -71,6 +71,8 @@ gsk_gl_icon_cache_begin_frame (GskGLIconCache *self, GdkTexture *texture; IconData *icon_data; + self->timestamp++; + /* Drop icons on removed atlases */ if (removed_atlases->len > 0) { @@ -81,26 +83,24 @@ gsk_gl_icon_cache_begin_frame (GskGLIconCache *self, g_hash_table_iter_remove (&iter); } } - - /* Increase frame age of all remaining icons */ - g_hash_table_iter_init (&iter, self->icons); - while (g_hash_table_iter_next (&iter, (gpointer *)&texture, (gpointer *)&icon_data)) - { - icon_data->frame_age ++; - if (icon_data->frame_age > MAX_FRAME_AGE) + if (self->timestamp % MAX_FRAME_AGE == 0) + { + g_hash_table_iter_init (&iter, self->icons); + while (g_hash_table_iter_next (&iter, (gpointer *)&texture, (gpointer *)&icon_data)) { - if (icon_data->used) + if (!icon_data->accessed) { - const int w = icon_data->texture_rect.size.width * icon_data->atlas->width; - const int h = icon_data->texture_rect.size.height * icon_data->atlas->height; - gsk_gl_texture_atlas_mark_unused (icon_data->atlas, w + 2, h + 2); - icon_data->used = FALSE; + if (icon_data->used) + { + const int w = icon_data->texture_rect.size.width * icon_data->atlas->width; + const int h = icon_data->texture_rect.size.height * icon_data->atlas->height; + gsk_gl_texture_atlas_mark_unused (icon_data->atlas, w + 2, h + 2); + icon_data->used = FALSE; + } } - /* We do NOT remove the icon here. Instead, We wait until we drop the entire atlas. - * This way we can revive it when we use it again. - */ + icon_data->accessed = FALSE; } } } @@ -115,7 +115,6 @@ gsk_gl_icon_cache_lookup_or_add (GskGLIconCache *self, if (icon_data) { - icon_data->frame_age = 0; if (!icon_data->used) { const int w = icon_data->texture_rect.size.width * icon_data->atlas->width; @@ -124,6 +123,7 @@ gsk_gl_icon_cache_lookup_or_add (GskGLIconCache *self, gsk_gl_texture_atlas_mark_used (icon_data->atlas, w + 2, h + 2); icon_data->used = TRUE; } + icon_data->accessed = TRUE; *out_texture_id = icon_data->atlas->texture_id; *out_texture_rect = icon_data->texture_rect; @@ -144,7 +144,7 @@ gsk_gl_icon_cache_lookup_or_add (GskGLIconCache *self, icon_data = g_new0 (IconData, 1); icon_data->atlas = atlas; - icon_data->frame_age = 0; + icon_data->accessed = TRUE; icon_data->used = TRUE; icon_data->source_texture = g_object_ref (texture); graphene_rect_init (&icon_data->texture_rect, diff --git a/gsk/gl/gskgliconcacheprivate.h b/gsk/gl/gskgliconcacheprivate.h index 5785871bf2..367e08ceb4 100644 --- a/gsk/gl/gskgliconcacheprivate.h +++ b/gsk/gl/gskgliconcacheprivate.h @@ -18,6 +18,7 @@ typedef struct GskGLTextureAtlases *atlases; GHashTable *icons; /* GdkTexture -> IconData */ + int timestamp; } GskGLIconCache; GskGLIconCache * gsk_gl_icon_cache_new (GdkDisplay *display,