glyph cache: Fix handling of big glyphs
authorMatthias Clasen <mclasen@redhat.com>
Sat, 12 Oct 2019 22:26:09 +0000 (18:26 -0400)
committerMatthias Clasen <mclasen@redhat.com>
Sat, 12 Oct 2019 22:53:22 +0000 (18:53 -0400)
We were putting big glyphs in the cache, in their
own texture, but forgetting to mark the texture
as permanent, so it could be reused, leading to
occasional misrendering. Fix this by marking these
textures as permanent, and explicitly freeing them
when the cache entry gets old.

gsk/gl/gskglglyphcache.c
gsk/gl/gskglglyphcacheprivate.h
gsk/gl/gskglrenderer.c

index f6c00d30469e872eb21f5feecd856aed4cecad81..7cc899e82c286f760be3a3a9dfe9237865b6dd93 100644 (file)
 
 /* Cache eviction strategy
  *
- * 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 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
- * atlas and all the items it contained.
+ * 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 atlas and all the items it
+ * contained.
+ *
+ * Big glyphs are not stored in the atlas, they get their
+ * own texture, but they are still cached.
  */
 
 #define MAX_FRAME_AGE (60)
@@ -239,6 +243,7 @@ add_to_cache (GskGLGlyphCache  *self,
     {
       value->atlas = NULL;
       value->texture_id = gsk_gl_driver_create_texture (driver, width, height);
+      gsk_gl_driver_mark_texture_permanent (driver, value->texture_id);
 
       gsk_gl_driver_bind_source_texture (driver, value->texture_id);
       gsk_gl_driver_init_texture_empty (driver, value->texture_id, GL_LINEAR, GL_LINEAR);
@@ -316,6 +321,7 @@ gsk_gl_glyph_cache_lookup_or_add (GskGLGlyphCache         *cache,
 
 void
 gsk_gl_glyph_cache_begin_frame (GskGLGlyphCache *self,
+                                GskGLDriver     *driver,
                                 GPtrArray       *removed_atlases)
 {
   GHashTableIter iter;
@@ -348,14 +354,22 @@ gsk_gl_glyph_cache_begin_frame (GskGLGlyphCache *self,
         {
           if (!value->accessed)
             {
-              if (value->atlas && value->used)
+              if (value->atlas)
+                {
+                  if (value->used)
+                    {
+                      gsk_gl_texture_atlas_mark_unused (value->atlas, value->draw_width, value->draw_height);
+                      value->used = FALSE;
+                    }
+                }
+              else
                 {
-                  gsk_gl_texture_atlas_mark_unused (value->atlas, value->draw_width, value->draw_height);
-                  value->used = FALSE;
+                  gsk_gl_driver_destroy_texture (driver, value->texture_id);
+                  g_hash_table_iter_remove (&iter);
                 }
             }
-
-          value->accessed = FALSE;
+          else
+            value->accessed = FALSE;
        }
 
       GSK_NOTE(GLYPH_CACHE, g_message ("%d glyphs cached", g_hash_table_size (self->hash_table)));
index 75f7a8de19efc246d01bff07ec6bf791ffaf07d1..16a6feb47108371d1293ace9ba22b7ed104311ff 100644 (file)
@@ -73,6 +73,7 @@ GskGLGlyphCache *        gsk_gl_glyph_cache_new             (GdkDisplay *display
 GskGLGlyphCache *        gsk_gl_glyph_cache_ref             (GskGLGlyphCache *self);
 void                     gsk_gl_glyph_cache_unref           (GskGLGlyphCache        *self);
 void                     gsk_gl_glyph_cache_begin_frame     (GskGLGlyphCache        *self,
+                                                             GskGLDriver            *driver,
                                                              GPtrArray              *removed_atlases);
 void                     gsk_gl_glyph_cache_lookup_or_add   (GskGLGlyphCache        *self,
                                                              GlyphCacheKey          *lookup,
index 913472f3af81a97c70f1b2efd2fa59b56902537c..82b5e3018cfb26c0a7011862ddb551c33ec25541 100644 (file)
@@ -3207,7 +3207,7 @@ gsk_gl_renderer_do_render (GskRenderer           *renderer,
 
   removed = g_ptr_array_new ();
   gsk_gl_texture_atlases_begin_frame (self->atlases, removed);
-  gsk_gl_glyph_cache_begin_frame (self->glyph_cache, removed);
+  gsk_gl_glyph_cache_begin_frame (self->glyph_cache, self->gl_driver, removed);
   gsk_gl_icon_cache_begin_frame (self->icon_cache, removed);
   gsk_gl_shadow_cache_begin_frame (&self->shadow_cache, self->gl_driver);
   g_ptr_array_unref (removed);