Cache glyph textures in render nodes

This is a quick implementation that avoids many
glyph cache lookups. We keep an array of direct
pointers in the text render node, and throw those
cached pointers away whenever any atlases have
been dropped (since that may invalidate the cached
glyphs).
This commit is contained in:
Matthias Clasen 2019-10-15 00:14:43 -04:00
parent 49748c9c23
commit c5af463843
5 changed files with 90 additions and 12 deletions

View File

@ -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;
}
}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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