[gtk+/wip/alexl/broadway4] broadway: Add node cache for text
- From: Alexander Larsson <alexl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/alexl/broadway4] broadway: Add node cache for text
- Date: Wed, 22 Nov 2017 16:32:54 +0000 (UTC)
commit 9c550f75e6fe5c9913ac78e84a93789584f86b16
Author: Alexander Larsson <alexl redhat com>
Date: Wed Nov 22 15:39:09 2017 +0100
broadway: Add node cache for text
gdk/broadway/broadway.js | 2 +-
gsk/gskbroadwayrenderer.c | 220 +++++++++++++++++++++++++++++++++++++++++----
2 files changed, 205 insertions(+), 17 deletions(-)
---
diff --git a/gdk/broadway/broadway.js b/gdk/broadway/broadway.js
index 45dae02..dd9ea1c 100644
--- a/gdk/broadway/broadway.js
+++ b/gdk/broadway/broadway.js
@@ -438,7 +438,7 @@ SwapNodes.prototype.handle_node = function(parent, offset_x, offset_y)
{
case 0: // TEXTURE
{
- var rect = this.decode_irect();
+ var rect = this.decode_rect();
var texture_id = this.decode_uint32();
var image = new Image();
image.width = rect.width;
diff --git a/gsk/gskbroadwayrenderer.c b/gsk/gskbroadwayrenderer.c
index b2ead65..07d8d18 100644
--- a/gsk/gskbroadwayrenderer.c
+++ b/gsk/gskbroadwayrenderer.c
@@ -152,6 +152,197 @@ add_color_stop (GArray *nodes, const GskColorStop *stop)
add_rgba (nodes, &stop->color);
}
+static gboolean
+float_is_int32 (float f)
+{
+ gint32 i = (gint32)f;
+ float f2 = (float)i;
+ return f2 == f;
+}
+
+static GHashTable *gsk_broadway_node_cache;
+
+typedef struct {
+ GdkTexture *texture;
+ GskRenderNode *node;
+ float off_x;
+ float off_y;
+} NodeCacheElement;
+
+static void
+node_cache_element_free (NodeCacheElement *element)
+{
+ gsk_render_node_unref (element->node);
+ g_free (element);
+}
+
+static guint
+glyph_info_hash (const PangoGlyphInfo *info)
+{
+ return info->glyph ^
+ info->geometry.width << 6 ^
+ info->geometry.x_offset << 12 ^
+ info->geometry.y_offset << 18 ^
+ info->attr.is_cluster_start << 30;
+}
+
+static gboolean
+glyph_info_equal (const PangoGlyphInfo *a,
+ const PangoGlyphInfo *b)
+{
+ return
+ a->glyph == b->glyph &&
+ a->geometry.width == b->geometry.width &&
+ a->geometry.x_offset == b->geometry.x_offset &&
+ a->geometry.y_offset == b->geometry.y_offset &&
+ a->attr.is_cluster_start == b->attr.is_cluster_start;
+ }
+
+static guint
+node_cache_hash (GskRenderNode *node)
+{
+ if (gsk_render_node_get_node_type (node) == GSK_TEXT_NODE &&
+ float_is_int32 (gsk_text_node_get_x (node)) &&
+ float_is_int32 (gsk_text_node_get_y (node)))
+ {
+ guint i;
+ const PangoFont *font = gsk_text_node_peek_font (node);
+ guint n_glyphs = gsk_text_node_get_num_glyphs (node);
+ const PangoGlyphInfo *infos = gsk_text_node_peek_glyphs (node);
+ const GdkRGBA *color = gsk_text_node_peek_color (node);
+ guint h;
+
+ h = g_direct_hash (font) ^ n_glyphs << 16 ^ gdk_rgba_hash (color);
+ for (i = 0; i < n_glyphs; i++)
+ h ^= glyph_info_hash (&infos[i]);
+
+ return h;
+ }
+
+ return 0;
+}
+
+static gboolean
+node_cache_equal (GskRenderNode *a,
+ GskRenderNode *b)
+{
+ if (gsk_render_node_get_node_type (a) != gsk_render_node_get_node_type (b))
+ return FALSE;
+
+ if (gsk_render_node_get_node_type (a) == GSK_TEXT_NODE &&
+ float_is_int32 (gsk_text_node_get_x (a)) &&
+ float_is_int32 (gsk_text_node_get_y (a)) &&
+ float_is_int32 (gsk_text_node_get_x (b)) &&
+ float_is_int32 (gsk_text_node_get_y (b)))
+ {
+ const PangoFont *a_font = gsk_text_node_peek_font (a);
+ guint a_n_glyphs = gsk_text_node_get_num_glyphs (a);
+ const PangoGlyphInfo *a_infos = gsk_text_node_peek_glyphs (a);
+ const GdkRGBA *a_color = gsk_text_node_peek_color (a);
+ const PangoFont *b_font = gsk_text_node_peek_font (b);
+ guint b_n_glyphs = gsk_text_node_get_num_glyphs (b);
+ const PangoGlyphInfo *b_infos = gsk_text_node_peek_glyphs (b);
+ const GdkRGBA *b_color = gsk_text_node_peek_color (a);
+ guint i;
+
+ if (a_font != b_font)
+ return FALSE;
+
+ if (a_n_glyphs != b_n_glyphs)
+ return FALSE;
+
+ for (i = 0; i < a_n_glyphs; i++)
+ {
+ if (!glyph_info_equal (&a_infos[i], &b_infos[i]))
+ return FALSE;
+ }
+
+ if (!gdk_rgba_equal (a_color, b_color))
+ return FALSE;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static GdkTexture *
+node_cache_lookup (GskRenderNode *node,
+ float *off_x, float *off_y)
+{
+ NodeCacheElement *hit;
+
+ if (gsk_broadway_node_cache == NULL)
+ gsk_broadway_node_cache = g_hash_table_new_full ((GHashFunc)node_cache_hash,
+ (GEqualFunc)node_cache_equal,
+ NULL,
+ (GDestroyNotify)node_cache_element_free);
+
+ hit = g_hash_table_lookup (gsk_broadway_node_cache, node);
+ if (hit)
+ {
+ *off_x = hit->off_x;
+ *off_y = hit->off_y;
+ return g_object_ref (hit->texture);
+ }
+
+ return NULL;
+}
+
+static void
+cached_texture_gone (gpointer data,
+ GObject *where_the_object_was)
+{
+ NodeCacheElement *element = data;
+ g_hash_table_remove (gsk_broadway_node_cache, element->node);
+}
+
+static void
+node_cache_store (GskRenderNode *node,
+ GdkTexture *texture,
+ float off_x,
+ float off_y)
+{
+ if (gsk_render_node_get_node_type (node) == GSK_TEXT_NODE &&
+ float_is_int32 (gsk_text_node_get_x (node)) &&
+ float_is_int32 (gsk_text_node_get_y (node)))
+ {
+ NodeCacheElement *element = g_new0 (NodeCacheElement, 1);
+ element->texture = texture;
+ element->node = gsk_render_node_ref (node);
+ element->off_x = off_x;
+ element->off_y = off_y;
+ g_object_weak_ref (G_OBJECT (texture), cached_texture_gone, element);
+ g_hash_table_insert (gsk_broadway_node_cache, element->node, element);
+ }
+}
+
+static GdkTexture *
+node_texture_fallback (GskRenderNode *node,
+ float *off_x,
+ float *off_y)
+{
+ cairo_surface_t *surface;
+ cairo_t *cr;
+ int x = floorf (node->bounds.origin.x);
+ int y = floorf (node->bounds.origin.y);
+ int width = ceil (node->bounds.origin.x + node->bounds.size.width) - x;
+ int height = ceil (node->bounds.origin.y + node->bounds.size.height) - y;
+ GdkTexture *texture;
+
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+ cr = cairo_create (surface);
+ cairo_translate (cr, -x, -y);
+ gsk_render_node_draw (node, cr);
+ cairo_destroy (cr);
+
+ texture = gdk_texture_new_for_surface (surface);
+ *off_x = x - node->bounds.origin.x;
+ *off_y = y - node->bounds.origin.y;
+
+ return texture;
+}
+
static void
gsk_broadway_renderer_add_node (GskRenderer *self,
GArray *nodes,
@@ -159,10 +350,6 @@ gsk_broadway_renderer_add_node (GskRenderer *self,
GskRenderNode *node)
{
GdkDisplay *display = gsk_renderer_get_display (self);
- int x = floorf (node->bounds.origin.x);
- int y = floorf (node->bounds.origin.y);
- int width = ceil (node->bounds.origin.x + node->bounds.size.width) - x;
- int height = ceil (node->bounds.origin.y + node->bounds.size.height) - y;
switch (gsk_render_node_get_node_type (node))
{
@@ -250,27 +437,28 @@ gsk_broadway_renderer_add_node (GskRenderer *self,
}
return;
+ case GSK_TEXT_NODE:
default:
{
- cairo_surface_t *surface;
GdkTexture *texture;
guint32 texture_id;
- cairo_t *cr;
+ float off_x = 0, off_y = 0;
+
+ texture = node_cache_lookup (node, &off_x, &off_y);
- surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
- cr = cairo_create (surface);
- cairo_translate (cr, -x, -y);
- gsk_render_node_draw (node, cr);
- cairo_destroy (cr);
+ if (!texture)
+ {
+ texture = node_texture_fallback (node, &off_x, &off_y);
+ node_cache_store (node, texture, off_x, off_y);
+ }
- texture = gdk_texture_new_for_surface (surface);
g_ptr_array_add (node_textures, texture); /* Transfers ownership to node_textures */
texture_id = gdk_broadway_display_ensure_texture (display, texture);
add_uint32 (nodes, BROADWAY_NODE_TEXTURE);
- add_uint32 (nodes, x);
- add_uint32 (nodes, y);
- add_uint32 (nodes, width);
- add_uint32 (nodes, height);
+ add_float (nodes, node->bounds.origin.x + off_x);
+ add_float (nodes, node->bounds.origin.y + off_y);
+ add_float (nodes, gdk_texture_get_width (texture));
+ add_float (nodes, gdk_texture_get_height (texture));
add_uint32 (nodes, texture_id);
}
return;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]