summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2019-10-15 00:14:43 -0400
committerMatthias Clasen <mclasen@redhat.com>2019-10-15 19:44:26 -0400
commitc5af4638434e39a0c224afb62252caed233c2acb (patch)
tree8fa457979f45d80eaf0739411d561b1d148d9f9b
parent49748c9c231d3c2d6d2f6b4d67186f6396e1fb30 (diff)
downloadgtk+-c5af4638434e39a0c224afb62252caed233c2acb.tar.gz
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).
-rw-r--r--gsk/gl/gskglglyphcache.c22
-rw-r--r--gsk/gl/gskglglyphcacheprivate.h3
-rw-r--r--gsk/gl/gskglrenderer.c53
-rw-r--r--gsk/gskrendernodeimpl.c20
-rw-r--r--gsk/gskrendernodeprivate.h4
5 files changed, 90 insertions, 12 deletions
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);
+ render_data->glyphs[i] = (GskGLCachedGlyph *)glyph;
+ }
- gsk_gl_glyph_cache_lookup_or_add (self->glyph_cache,
- &lookup,
- self->gl_driver,
- &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