diff options
author | Alexander Larsson <alexl@redhat.com> | 2019-03-22 15:29:24 +0100 |
---|---|---|
committer | Alexander Larsson <alexl@redhat.com> | 2019-03-26 17:07:47 +0100 |
commit | 311aa01e013e735d403700ed1e602bb0aa831f79 (patch) | |
tree | a417814a7f0a3dadb3797b7c6c61c085c88ca108 | |
parent | 3bbbe9f71be62fe34ebca656558dc90bc7a04681 (diff) | |
download | gtk+-311aa01e013e735d403700ed1e602bb0aa831f79.tar.gz |
broadway: Simplify fallback node cache
Since nodes are now cached we just store the fallback as a
texture in a hashtable indexed by the node. If its unused for
5 frames we drop it.
-rw-r--r-- | gsk/gskbroadwayrenderer.c | 326 |
1 files changed, 48 insertions, 278 deletions
diff --git a/gsk/gskbroadwayrenderer.c b/gsk/gskbroadwayrenderer.c index 9350a2ab1f..dc09829724 100644 --- a/gsk/gskbroadwayrenderer.c +++ b/gsk/gskbroadwayrenderer.c @@ -13,6 +13,8 @@ struct _GskBroadwayRenderer { GskRenderer parent_instance; GdkBroadwayDrawContext *draw_context; + GHashTable *fallback_cache; + guint32 frame_nr; }; struct _GskBroadwayRendererClass @@ -177,289 +179,22 @@ add_string (GArray *nodes, const char *str) add_uint32 (nodes, v); } -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; + GdkTexture *texture; float off_x; float off_y; -} NodeCacheElement; + int used_in_frame; +} FallbackCacheElement; static void -node_cache_element_free (NodeCacheElement *element) +fallback_cache_element_free (FallbackCacheElement *element) { gsk_render_node_unref (element->node); + g_object_unref (element->texture); 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 -hash_matrix (const graphene_matrix_t *matrix) -{ - float m[16]; - guint h = 0; - int i; - - graphene_matrix_to_float (matrix, m); - for (i = 0; i < 16; i++) - h ^= (guint) m[i]; - - return h; -} - -static gboolean -matrix_equal (const graphene_matrix_t *a, - const graphene_matrix_t *b) -{ - float ma[16]; - float mb[16]; - int i; - - graphene_matrix_to_float (a, ma); - graphene_matrix_to_float (b, mb); - for (i = 0; i < 16; i++) - { - if (ma[i] != mb[i]) - return FALSE; - } - - return TRUE; -} - -static guint -hash_vec4 (const graphene_vec4_t *vec4) -{ - float v[4]; - guint h = 0; - int i; - - graphene_vec4_to_float (vec4, v); - for (i = 0; i < 4; i++) - h ^= (guint) v[i]; - - return h; -} - -static gboolean -vec4_equal (const graphene_vec4_t *a, - const graphene_vec4_t *b) -{ - float va[4]; - float vb[4]; - int i; - - graphene_vec4_to_float (a, va); - graphene_vec4_to_float (b, vb); - for (i = 0; i < 4; i++) - { - if (va[i] != vb[i]) - return FALSE; - } - - return TRUE; -} - -static guint -node_cache_hash (GskRenderNode *node) -{ - GskRenderNodeType type; - guint h; - - type = gsk_render_node_get_node_type (node); - h = type << 28; - if (type == 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); - - 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; - } - - if (type == GSK_COLOR_MATRIX_NODE && - gsk_render_node_get_node_type (gsk_color_matrix_node_get_child (node)) == GSK_TEXTURE_NODE) - { - const graphene_matrix_t *matrix = gsk_color_matrix_node_peek_color_matrix (node); - const graphene_vec4_t *offset = gsk_color_matrix_node_peek_color_offset (node); - GskRenderNode *child = gsk_color_matrix_node_get_child (node); - GdkTexture *texture = gsk_texture_node_get_texture (child); - - h ^= g_direct_hash (texture) ^ hash_matrix (matrix) ^ hash_vec4 (offset); - - return h; - } - - return 0; -} - -static gboolean -node_cache_equal (GskRenderNode *a, - GskRenderNode *b) -{ - GskRenderNodeType type; - - type = gsk_render_node_get_node_type (a); - if (type != gsk_render_node_get_node_type (b)) - return FALSE; - - if (type == 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; - } - - if (type == GSK_COLOR_MATRIX_NODE && - gsk_render_node_get_node_type (gsk_color_matrix_node_get_child (a)) == GSK_TEXTURE_NODE && - gsk_render_node_get_node_type (gsk_color_matrix_node_get_child (b)) == GSK_TEXTURE_NODE) - { - const graphene_matrix_t *a_matrix = gsk_color_matrix_node_peek_color_matrix (a); - const graphene_vec4_t *a_offset = gsk_color_matrix_node_peek_color_offset (a); - GskRenderNode *a_child = gsk_color_matrix_node_get_child (a); - GdkTexture *a_texture = gsk_texture_node_get_texture (a_child); - const graphene_matrix_t *b_matrix = gsk_color_matrix_node_peek_color_matrix (b); - const graphene_vec4_t *b_offset = gsk_color_matrix_node_peek_color_offset (b); - GskRenderNode *b_child = gsk_color_matrix_node_get_child (b); - GdkTexture *b_texture = gsk_texture_node_get_texture (b_child); - - if (a_texture != b_texture) - return FALSE; - - if (!matrix_equal (a_matrix, b_matrix)) - return FALSE; - - if (!vec4_equal (a_offset, b_offset)) - 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) -{ - GskRenderNodeType type; - - type = gsk_render_node_get_node_type (node); - if ((type == GSK_TEXT_NODE && - float_is_int32 (gsk_text_node_get_x (node)) && - float_is_int32 (gsk_text_node_get_y (node))) || - (type == GSK_COLOR_MATRIX_NODE && - gsk_render_node_get_node_type (gsk_color_matrix_node_get_child (node)) == GSK_TEXTURE_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); - - return; - } -} - static GdkTexture * node_texture_fallback (GskRenderNode *node, float *off_x, @@ -499,6 +234,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer, float offset_y) { GdkDisplay *display = gdk_surface_get_display (gsk_renderer_get_surface (renderer)); + GskBroadwayRenderer *self = GSK_BROADWAY_RENDERER (renderer); switch (gsk_render_node_get_node_type (node)) { @@ -733,18 +469,32 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer, { GdkTexture *texture; guint32 texture_id; + FallbackCacheElement *hit; float t_off_x = 0, t_off_y = 0; - texture = node_cache_lookup (node, &t_off_x, &t_off_y); - - if (!texture) + hit = g_hash_table_lookup (self->fallback_cache, node); + if (hit) { + texture = g_object_ref (hit->texture); + t_off_x = hit->off_x; + t_off_y = hit->off_y; + hit->used_in_frame = self->frame_nr; + } + else + { + FallbackCacheElement *element; + texture = node_texture_fallback (node, &t_off_x, &t_off_y); -#if 0 +#if 1 g_print ("Fallback %p for %s\n", texture, node->node_class->type_name); #endif - - node_cache_store (node, texture, t_off_x, t_off_y); + element = g_new0 (FallbackCacheElement, 1); + element->texture = g_object_ref (texture); + element->node = gsk_render_node_ref (node); + element->off_x = t_off_x; + element->off_y = t_off_y; + element->used_in_frame = self->frame_nr; + g_hash_table_insert (self->fallback_cache, element->node, element); } g_ptr_array_add (node_textures, texture); /* Transfers ownership to node_textures */ @@ -758,6 +508,18 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer, } } +static gboolean +clean_old_fallbacks (gpointer key, + gpointer value, + gpointer user_data) +{ + GskBroadwayRenderer *self = GSK_BROADWAY_RENDERER (user_data); + FallbackCacheElement *element = value; + + /* Remove cached fallbacks not used for 5 frames */ + return self->frame_nr - element->used_in_frame > 5; +} + static void gsk_broadway_renderer_render (GskRenderer *renderer, GskRenderNode *root, @@ -765,9 +527,13 @@ gsk_broadway_renderer_render (GskRenderer *renderer, { GskBroadwayRenderer *self = GSK_BROADWAY_RENDERER (renderer); + self->frame_nr++; + gdk_draw_context_begin_frame (GDK_DRAW_CONTEXT (self->draw_context), update_area); gsk_broadway_renderer_add_node (renderer, self->draw_context->nodes, self->draw_context->node_textures, root, 0, 0); gdk_draw_context_end_frame (GDK_DRAW_CONTEXT (self->draw_context)); + + g_hash_table_foreach_remove (self->fallback_cache, clean_old_fallbacks, renderer); } static void @@ -784,4 +550,8 @@ gsk_broadway_renderer_class_init (GskBroadwayRendererClass *klass) static void gsk_broadway_renderer_init (GskBroadwayRenderer *self) { + self->fallback_cache = g_hash_table_new_full ((GHashFunc)g_direct_hash, + (GEqualFunc)g_direct_equal, + NULL, + (GDestroyNotify)fallback_cache_element_free); } |