forked from AuroraMiddleware/gtk
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:
parent
49748c9c23
commit
c5af463843
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user