diff --git a/gsk/gl/gskglglyphcache.c b/gsk/gl/gskglglyphcache.c index 7cc899e82c..5571293ee5 100644 --- a/gsk/gl/gskglglyphcache.c +++ b/gsk/gl/gskglglyphcache.c @@ -269,13 +269,7 @@ gsk_gl_glyph_cache_lookup_or_add (GskGLGlyphCache *cache, if (value) { - 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; - + gsk_gl_glyph_cache_entry_validate (cache, value); *cached_glyph_out = value; return; } @@ -334,6 +328,8 @@ gsk_gl_glyph_cache_begin_frame (GskGLGlyphCache *self, { guint dropped = 0; + self->atlas_timestamp++; + g_hash_table_iter_init (&iter, self->hash_table); while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value)) { @@ -375,3 +371,15 @@ gsk_gl_glyph_cache_begin_frame (GskGLGlyphCache *self, GSK_NOTE(GLYPH_CACHE, g_message ("%d glyphs cached", g_hash_table_size (self->hash_table))); } } + +void +gsk_gl_glyph_cache_entry_validate (GskGLGlyphCache *cache, + GskGLCachedGlyph *value) +{ + value->accessed = TRUE; + if (value->atlas && !value->used) + { + gsk_gl_texture_atlas_mark_used (value->atlas, value->draw_width, value->draw_height); + value->used = TRUE; + } +} diff --git a/gsk/gl/gskglglyphcacheprivate.h b/gsk/gl/gskglglyphcacheprivate.h index 16a6feb471..4c2920bee6 100644 --- a/gsk/gl/gskglglyphcacheprivate.h +++ b/gsk/gl/gskglglyphcacheprivate.h @@ -16,6 +16,7 @@ typedef struct GskGLTextureAtlases *atlases; int timestamp; + int atlas_timestamp; /* incremented whenever an atlas is dropped */ } GskGLGlyphCache; typedef struct @@ -79,5 +80,7 @@ void gsk_gl_glyph_cache_lookup_or_add (GskGLGlyphCache GlyphCacheKey *lookup, GskGLDriver *driver, const GskGLCachedGlyph **cached_glyph_out); +void gsk_gl_glyph_cache_entry_validate (GskGLGlyphCache *cache, + GskGLCachedGlyph *entry); #endif diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index 229d634023..886b9fdc4e 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -536,6 +536,39 @@ render_fallback_node (GskGLRenderer *self, ops_draw (builder, offscreen_vertex_data); } +typedef struct { + int timestamp; + GskGLCachedGlyph *glyphs[]; +} TextRenderData; + +static inline TextRenderData * +ensure_render_data (GskRenderNode *node, + GskGLGlyphCache *cache) +{ + TextRenderData *data; + int num_glyphs; + + num_glyphs = gsk_text_node_get_num_glyphs (node); + data = gsk_text_node_get_render_data (node); + if (data) + { + if (data->timestamp < cache->atlas_timestamp) + { + memset (data->glyphs, 0, sizeof (gpointer) * num_glyphs); + data->timestamp = cache->atlas_timestamp; + } + } + else + { + data = g_new0 (TextRenderData, sizeof (TextRenderData) + sizeof (gpointer) * num_glyphs); + data->timestamp = cache->atlas_timestamp; + + gsk_text_node_set_render_data (node, data); + } + + return data; +} + static inline void render_text_node (GskGLRenderer *self, GskRenderNode *node, @@ -553,6 +586,7 @@ render_text_node (GskGLRenderer *self, float x = offset->x + builder->dx; float y = offset->y + builder->dy; GlyphCacheKey lookup; + TextRenderData *render_data; /* If the font has color glyphs, we don't need to recolor anything */ if (!force_color && gsk_text_node_has_color_glyphs (node)) @@ -565,6 +599,8 @@ render_text_node (GskGLRenderer *self, ops_set_color (builder, color); } + render_data = ensure_render_data (node, self->glyph_cache); + lookup.font = (PangoFont *)font; lookup.scale = (guint) (text_scale * 1024); @@ -585,12 +621,19 @@ render_text_node (GskGLRenderer *self, cx = (float)(x_position + gi->geometry.x_offset) / PANGO_SCALE; cy = (float)(gi->geometry.y_offset) / PANGO_SCALE; - glyph_cache_key_set_glyph_and_shift (&lookup, gi->glyph, x + cx, y + cy); + glyph = render_data->glyphs[i]; + if (!glyph) + { + glyph_cache_key_set_glyph_and_shift (&lookup, gi->glyph, x + cx, y + cy); - gsk_gl_glyph_cache_lookup_or_add (self->glyph_cache, - &lookup, - self->gl_driver, - &glyph); + gsk_gl_glyph_cache_lookup_or_add (self->glyph_cache, + &lookup, + self->gl_driver, + &glyph); + render_data->glyphs[i] = (GskGLCachedGlyph *)glyph; + } + + gsk_gl_glyph_cache_entry_validate (self->glyph_cache, render_data->glyphs[i]); if (glyph->texture_id == 0) goto next; diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c index 8c7be01555..b8bd749fa5 100644 --- a/gsk/gskrendernodeimpl.c +++ b/gsk/gskrendernodeimpl.c @@ -3414,6 +3414,7 @@ struct _GskTextNode GdkRGBA color; graphene_point_t offset; + gpointer render_data; guint num_glyphs; PangoGlyphInfo glyphs[]; }; @@ -3423,6 +3424,7 @@ gsk_text_node_finalize (GskRenderNode *node) { GskTextNode *self = (GskTextNode *) node; + g_free (self->render_data); g_object_unref (self->font); } @@ -3625,6 +3627,24 @@ gsk_text_node_get_offset (GskRenderNode *node) return &self->offset; } +void +gsk_text_node_set_render_data (GskRenderNode *node, + gpointer data) +{ + GskTextNode *self = (GskTextNode *) node; + + self->render_data = data; +} + +gpointer +gsk_text_node_get_render_data (GskRenderNode *node) +{ + GskTextNode *self = (GskTextNode *) node; + + return self->render_data; +} + + /*** GSK_BLUR_NODE ***/ typedef struct _GskBlurNode GskBlurNode; diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h index 2ced79738b..f2fe034444 100644 --- a/gsk/gskrendernodeprivate.h +++ b/gsk/gskrendernodeprivate.h @@ -46,6 +46,10 @@ void gsk_render_node_diff (GskRenderNode *nod void gsk_render_node_diff_impossible (GskRenderNode *node1, GskRenderNode *node2, cairo_region_t *region); +void gsk_text_node_set_render_data (GskRenderNode *node, + gpointer data); +gpointer gsk_text_node_get_render_data (GskRenderNode *node); + G_END_DECLS