From c505a08e46f7c75ac25fdf30a23a6a9f8407a1e1 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 8 Sep 2024 09:46:41 -0400 Subject: [PATCH 1/8] gsk: Small optimization Avoid calling gsk_container_node_get_child in a loop. --- gsk/gpu/gskgpunodeprocessor.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/gsk/gpu/gskgpunodeprocessor.c b/gsk/gpu/gskgpunodeprocessor.c index 52a4fe90ea..96321c0da9 100644 --- a/gsk/gpu/gskgpunodeprocessor.c +++ b/gsk/gpu/gskgpunodeprocessor.c @@ -3657,7 +3657,8 @@ static void gsk_gpu_node_processor_add_container_node (GskGpuNodeProcessor *self, GskRenderNode *node) { - gsize i; + GskRenderNode **children; + guint n_children; if (self->opacity < 1.0 && !gsk_container_node_is_disjoint (node)) { @@ -3665,8 +3666,9 @@ gsk_gpu_node_processor_add_container_node (GskGpuNodeProcessor *self, return; } - for (i = 0; i < gsk_container_node_get_n_children (node); i++) - gsk_gpu_node_processor_add_node (self, gsk_container_node_get_child (node, i)); + children = gsk_container_node_get_children (node, &n_children); + for (guint i = 0; i < n_children; i++) + gsk_gpu_node_processor_add_node (self, children[i]); } static gboolean @@ -3674,10 +3676,12 @@ gsk_gpu_node_processor_add_first_container_node (GskGpuNodeProcessor *self, GskGpuFirstNodeInfo *info, GskRenderNode *node) { + GskRenderNode **children; graphene_rect_t opaque; - int i, n; + int i; + guint n; - n = gsk_container_node_get_n_children (node); + children = gsk_container_node_get_children (node, &n); if (n == 0) return FALSE; @@ -3687,17 +3691,15 @@ gsk_gpu_node_processor_add_first_container_node (GskGpuNodeProcessor *self, for (i = n; i-->0; ) { - if (gsk_gpu_node_processor_add_first_node (self, - info, - gsk_container_node_get_child (node, i))) - break; + if (gsk_gpu_node_processor_add_first_node (self, info, children[i])) + break; } if (i < 0) gsk_gpu_first_node_begin_rendering (self, info, NULL); for (i++; i < n; i++) - gsk_gpu_node_processor_add_node (self, gsk_container_node_get_child (node, i)); + gsk_gpu_node_processor_add_node (self, children[i]); return TRUE; } From 59f334622b4648ef052c609a62a9042d626297f3 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 8 Sep 2024 09:47:47 -0400 Subject: [PATCH 2/8] rendernode: Inline gsk_render_node_get_node_type This is the most-called function on render nodes. --- gsk/gskrendernode.c | 23 +++++++---------------- gsk/gskrendernodeprivate.h | 11 +++++++++++ 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/gsk/gskrendernode.c b/gsk/gskrendernode.c index 9d53efeaa7..0b132f600b 100644 --- a/gsk/gskrendernode.c +++ b/gsk/gskrendernode.c @@ -60,8 +60,6 @@ **/ G_DEFINE_QUARK (gsk-serialization-error-quark, gsk_serialization_error) -#define GSK_RENDER_NODE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_RENDER_NODE, GskRenderNodeClass)) - static void value_render_node_init (GValue *value) @@ -341,20 +339,13 @@ void * Returns: the type of the `GskRenderNode` */ GskRenderNodeType -gsk_render_node_get_node_type (const GskRenderNode *node) +(gsk_render_node_get_node_type) (const GskRenderNode *node) { g_return_val_if_fail (GSK_IS_RENDER_NODE (node), GSK_NOT_A_RENDER_NODE); return GSK_RENDER_NODE_GET_CLASS (node)->node_type; } -G_GNUC_PURE static inline -GskRenderNodeType -_gsk_render_node_get_node_type (const GskRenderNode *node) -{ - return GSK_RENDER_NODE_GET_CLASS (node)->node_type; -} - /** * gsk_render_node_get_bounds: * @node: a `GskRenderNode` @@ -535,11 +526,11 @@ gsk_render_node_can_diff (const GskRenderNode *node1, if (node1 == node2) return TRUE; - if (_gsk_render_node_get_node_type (node1) == _gsk_render_node_get_node_type (node2)) + if (gsk_render_node_get_node_type (node1) == gsk_render_node_get_node_type (node2)) return GSK_RENDER_NODE_GET_CLASS (node1)->can_diff (node1, node2); - if (_gsk_render_node_get_node_type (node1) == GSK_CONTAINER_NODE || - _gsk_render_node_get_node_type (node2) == GSK_CONTAINER_NODE) + if (gsk_render_node_get_node_type (node1) == GSK_CONTAINER_NODE || + gsk_render_node_get_node_type (node2) == GSK_CONTAINER_NODE) return TRUE; return FALSE; @@ -594,15 +585,15 @@ gsk_render_node_diff (GskRenderNode *node1, if (node1 == node2) return; - if (_gsk_render_node_get_node_type (node1) == _gsk_render_node_get_node_type (node2)) + if (gsk_render_node_get_node_type (node1) == gsk_render_node_get_node_type (node2)) { GSK_RENDER_NODE_GET_CLASS (node1)->diff (node1, node2, data); } - else if (_gsk_render_node_get_node_type (node1) == GSK_CONTAINER_NODE) + else if (gsk_render_node_get_node_type (node1) == GSK_CONTAINER_NODE) { gsk_container_node_diff_with (node1, node2, data); } - else if (_gsk_render_node_get_node_type (node2) == GSK_CONTAINER_NODE) + else if (gsk_render_node_get_node_type (node2) == GSK_CONTAINER_NODE) { gsk_container_node_diff_with (node2, node1, data); } diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h index 6847a887ec..bace10beb3 100644 --- a/gsk/gskrendernodeprivate.h +++ b/gsk/gskrendernodeprivate.h @@ -170,5 +170,16 @@ GskRenderNode * gsk_text_node_new2 (PangoFont const graphene_point_t *offset); const GdkColor *gsk_text_node_get_color2 (const GskRenderNode *node); +#define GSK_RENDER_NODE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_RENDER_NODE, GskRenderNodeClass)) + +#define gsk_render_node_get_node_type(node) _gsk_render_node_get_node_type (node) + +G_GNUC_PURE static inline +GskRenderNodeType +_gsk_render_node_get_node_type (const GskRenderNode *node) +{ + return GSK_RENDER_NODE_GET_CLASS (node)->node_type; +} + G_END_DECLS From 4f9fd5cf1d04dc31e2256fbc0347f722560c1efb Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 8 Sep 2024 11:07:28 -0400 Subject: [PATCH 3/8] Add gsk_text_node_get_font_hint_style Getting the hint style is one of the more expensive calls we do when adding glyph nodes, so cache this information in the node. --- gsk/gpu/gskgpunodeprocessor.c | 5 ++++- gsk/gskrendernodeimpl.c | 10 ++++++++++ gsk/gskrendernodeprivate.h | 3 +++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/gsk/gpu/gskgpunodeprocessor.c b/gsk/gpu/gskgpunodeprocessor.c index 96321c0da9..0e34f4312c 100644 --- a/gsk/gpu/gskgpunodeprocessor.c +++ b/gsk/gpu/gskgpunodeprocessor.c @@ -3009,6 +3009,7 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self, unsigned int flags_mask; GskGpuImage *last_image; const float inv_pango_scale = 1.f / PANGO_SCALE; + cairo_hint_style_t hint_style; if (self->opacity < 1.0 && gsk_text_node_has_color_glyphs (node)) @@ -3023,12 +3024,14 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self, glyphs = gsk_text_node_get_glyphs (node, NULL); font = gsk_text_node_get_font (node); offset = *gsk_text_node_get_offset (node); + hint_style = gsk_text_node_get_font_hint_style (node); + offset.x += self->offset.x; offset.y += self->offset.y; scale = MAX (graphene_vec2_get_x (&self->scale), graphene_vec2_get_y (&self->scale)); - if (gsk_font_get_hint_style (font) != CAIRO_HINT_STYLE_NONE) + if (hint_style != CAIRO_HINT_STYLE_NONE) { align_scale_x = scale * 4; align_scale_y = scale; diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c index c3f0c9eefc..bd85c742fa 100644 --- a/gsk/gskrendernodeimpl.c +++ b/gsk/gskrendernodeimpl.c @@ -6332,6 +6332,7 @@ struct _GskTextNode PangoFontMap *fontmap; PangoFont *font; gboolean has_color_glyphs; + cairo_hint_style_t hint_style; GdkColor color; graphene_point_t offset; @@ -6513,6 +6514,7 @@ gsk_text_node_new2 (PangoFont *font, gdk_color_init_copy (&self->color, color); self->offset = *offset; self->has_color_glyphs = FALSE; + self->hint_style = gsk_font_get_hint_style (font); glyph_infos = g_malloc_n (glyphs->num_glyphs, sizeof (PangoGlyphInfo)); @@ -6596,6 +6598,14 @@ gsk_text_node_get_font (const GskRenderNode *node) return self->font; } +cairo_hint_style_t +gsk_text_node_get_font_hint_style (const GskRenderNode *node) +{ + const GskTextNode *self = (const GskTextNode *) node; + + return self->hint_style; +} + /** * gsk_text_node_has_color_glyphs: * @node: (type GskTextNode): a text `GskRenderNode` diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h index bace10beb3..80be52c19f 100644 --- a/gsk/gskrendernodeprivate.h +++ b/gsk/gskrendernodeprivate.h @@ -100,6 +100,9 @@ bool gsk_border_node_get_uniform_color (const GskRenderNode void gsk_text_node_serialize_glyphs (GskRenderNode *self, GString *str); +cairo_hint_style_t + gsk_text_node_get_font_hint_style (const GskRenderNode *self) G_GNUC_PURE; + GskRenderNode ** gsk_container_node_get_children (const GskRenderNode *node, guint *n_children); From 2e44f3e2ffaaed2c529f1e4a30d4c1182e7e0084 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 8 Sep 2024 11:21:18 -0400 Subject: [PATCH 4/8] gsk: Get the text node color once We don't need to do this in the loop. --- gsk/gpu/gskgpunodeprocessor.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gsk/gpu/gskgpunodeprocessor.c b/gsk/gpu/gskgpunodeprocessor.c index 0e34f4312c..73e92c9909 100644 --- a/gsk/gpu/gskgpunodeprocessor.c +++ b/gsk/gpu/gskgpunodeprocessor.c @@ -3010,6 +3010,7 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self, GskGpuImage *last_image; const float inv_pango_scale = 1.f / PANGO_SCALE; cairo_hint_style_t hint_style; + const GdkColor *color; if (self->opacity < 1.0 && gsk_text_node_has_color_glyphs (node)) @@ -3025,6 +3026,7 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self, font = gsk_text_node_get_font (node); offset = *gsk_text_node_get_offset (node); hint_style = gsk_text_node_get_font_hint_style (node); + color = gsk_text_node_get_color2 (node); offset.x += self->offset.x; offset.y += self->offset.y; @@ -3108,7 +3110,7 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self, &glyph_bounds, &glyph_tex_rect }, - gsk_text_node_get_color2 (node)); + color); offset.x += glyphs[i].geometry.width * inv_pango_scale; } From 03840151ace274a0299edccc6a3d0fb1a3711def Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 8 Sep 2024 11:23:59 -0400 Subject: [PATCH 5/8] gsk: Drop an unused variable We're not using last_image for anything. --- gsk/gpu/gskgpunodeprocessor.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/gsk/gpu/gskgpunodeprocessor.c b/gsk/gpu/gskgpunodeprocessor.c index 73e92c9909..94ac03b3c5 100644 --- a/gsk/gpu/gskgpunodeprocessor.c +++ b/gsk/gpu/gskgpunodeprocessor.c @@ -3007,7 +3007,6 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self, float align_scale_x, align_scale_y; float inv_align_scale_x, inv_align_scale_y; unsigned int flags_mask; - GskGpuImage *last_image; const float inv_pango_scale = 1.f / PANGO_SCALE; cairo_hint_style_t hint_style; const GdkColor *color; @@ -3048,7 +3047,6 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self, inv_align_scale_x = 1 / align_scale_x; inv_align_scale_y = 1 / align_scale_y; - last_image = NULL; for (i = 0; i < num_glyphs; i++) { GskGpuImage *image; @@ -3085,9 +3083,6 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self, glyph_origin = GRAPHENE_POINT_INIT (glyph_origin.x - glyph_offset.x / scale, glyph_origin.y - glyph_offset.y / scale); - if (image != last_image) - last_image = image; - if (glyphs[i].attr.is_color) gsk_gpu_texture_op (self->frame, gsk_gpu_clip_get_shader_clip (&self->clip, &glyph_origin, &glyph_bounds), From 60f5d4c93ebaf00b1ceb99b545cb890dffed2de2 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 8 Sep 2024 12:41:48 -0400 Subject: [PATCH 6/8] gpu: Add a variant of gsk_gpu_colorize_op This variant takes the color_states, instead of computing it anew from the ccs and the color state of the color. This will be used to pull this work out of the loop in add_glyph_node. --- gsk/gpu/gskgpucolorizeop.c | 43 ++++++++++++++++++++++--------- gsk/gpu/gskgpucolorizeopprivate.h | 8 ++++++ 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/gsk/gpu/gskgpucolorizeop.c b/gsk/gpu/gskgpucolorizeop.c index 766845c071..cef2a1b507 100644 --- a/gsk/gpu/gskgpucolorizeop.c +++ b/gsk/gpu/gskgpucolorizeop.c @@ -50,22 +50,19 @@ static const GskGpuShaderOpClass GSK_GPU_COLORIZE_OP_CLASS = { }; void -gsk_gpu_colorize_op (GskGpuFrame *frame, - GskGpuShaderClip clip, - GdkColorState *ccs, - float opacity, - const graphene_point_t *offset, - const GskGpuShaderImage *image, - const GdkColor *color) +gsk_gpu_colorize_op2 (GskGpuFrame *frame, + GskGpuShaderClip clip, + GskGpuColorStates color_states, + float opacity, + const graphene_point_t *offset, + const GskGpuShaderImage *image, + const GdkColor *color) { GskGpuColorizeInstance *instance; - GdkColorState *alt; - - alt = gsk_gpu_color_states_find (ccs, color); gsk_gpu_shader_op_alloc (frame, &GSK_GPU_COLORIZE_OP_CLASS, - gsk_gpu_color_states_create (ccs, TRUE, alt, FALSE), + color_states, 0, clip, (GskGpuImage *[1]) { image->image }, @@ -74,5 +71,27 @@ gsk_gpu_colorize_op (GskGpuFrame *frame, gsk_gpu_rect_to_float (image->coverage ? image->coverage : image->bounds, offset, instance->rect); gsk_gpu_rect_to_float (image->bounds, offset, instance->tex_rect); - gsk_gpu_color_to_float (color, alt, opacity, instance->color); + gsk_gpu_color_to_float (color, gsk_gpu_color_states_get_alt (color_states), opacity, instance->color); +} + +void +gsk_gpu_colorize_op (GskGpuFrame *frame, + GskGpuShaderClip clip, + GdkColorState *ccs, + float opacity, + const graphene_point_t *offset, + const GskGpuShaderImage *image, + const GdkColor *color) +{ + GdkColorState *alt; + GskGpuColorStates color_states; + GdkColor color2; + + alt = gsk_gpu_color_states_find (ccs, color); + color_states = gsk_gpu_color_states_create (ccs, TRUE, alt, FALSE); + gdk_color_convert (&color2, alt, color); + + gsk_gpu_colorize_op2 (frame, clip, color_states, opacity, offset, image, &color2); + + gdk_color_finish (&color2); } diff --git a/gsk/gpu/gskgpucolorizeopprivate.h b/gsk/gpu/gskgpucolorizeopprivate.h index 6e01db57c6..e6ee91876b 100644 --- a/gsk/gpu/gskgpucolorizeopprivate.h +++ b/gsk/gpu/gskgpucolorizeopprivate.h @@ -14,6 +14,14 @@ void gsk_gpu_colorize_op (GskGpuF const GskGpuShaderImage *image, const GdkColor *color); +void gsk_gpu_colorize_op2 (GskGpuFrame *frame, + GskGpuShaderClip clip, + GskGpuColorStates color_states, + float opacity, + const graphene_point_t *offset, + const GskGpuShaderImage *image, + const GdkColor *color); + G_END_DECLS From c18cd6050b862dad3c90d8de13224d0600abb372 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 8 Sep 2024 12:43:02 -0400 Subject: [PATCH 7/8] gpu: Use gsk_gpu_colorize_op2 This reduces the cost of these calls significantly, and this is the inner loop of the node processor. --- gsk/gpu/gskgpunodeprocessor.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/gsk/gpu/gskgpunodeprocessor.c b/gsk/gpu/gskgpunodeprocessor.c index 94ac03b3c5..cdf55f3fda 100644 --- a/gsk/gpu/gskgpunodeprocessor.c +++ b/gsk/gpu/gskgpunodeprocessor.c @@ -3010,6 +3010,9 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self, const float inv_pango_scale = 1.f / PANGO_SCALE; cairo_hint_style_t hint_style; const GdkColor *color; + GdkColorState *alt; + GskGpuColorStates color_states; + GdkColor color2; if (self->opacity < 1.0 && gsk_text_node_has_color_glyphs (node)) @@ -3027,6 +3030,10 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self, hint_style = gsk_text_node_get_font_hint_style (node); color = gsk_text_node_get_color2 (node); + alt = gsk_gpu_color_states_find (self->ccs, color); + color_states = gsk_gpu_color_states_create (self->ccs, TRUE, alt, FALSE); + gdk_color_convert (&color2, alt, color); + offset.x += self->offset.x; offset.y += self->offset.y; @@ -3094,21 +3101,23 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self, &glyph_tex_rect }); else - gsk_gpu_colorize_op (self->frame, - gsk_gpu_clip_get_shader_clip (&self->clip, &glyph_origin, &glyph_bounds), - self->ccs, - self->opacity, - &glyph_origin, - &(GskGpuShaderImage) { - image, - GSK_GPU_SAMPLER_DEFAULT, - &glyph_bounds, - &glyph_tex_rect - }, - color); + gsk_gpu_colorize_op2 (self->frame, + gsk_gpu_clip_get_shader_clip (&self->clip, &glyph_origin, &glyph_bounds), + color_states, + self->opacity, + &glyph_origin, + &(GskGpuShaderImage) { + image, + GSK_GPU_SAMPLER_DEFAULT, + &glyph_bounds, + &glyph_tex_rect + }, + &color2); offset.x += glyphs[i].geometry.width * inv_pango_scale; } + + gdk_color_finish (&color2); } static void From 76a13596aa8fa688dd155a7716f8cf9a324cf26f Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 8 Sep 2024 12:57:31 -0400 Subject: [PATCH 8/8] gpu: Reduce per-glyph overhead Pull the shader clip computation out of the loop in the common case that the entire node is contained in the clip. --- gsk/gpu/gskgpunodeprocessor.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/gsk/gpu/gskgpunodeprocessor.c b/gsk/gpu/gskgpunodeprocessor.c index cdf55f3fda..2197622ece 100644 --- a/gsk/gpu/gskgpunodeprocessor.c +++ b/gsk/gpu/gskgpunodeprocessor.c @@ -3013,6 +3013,7 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self, GdkColorState *alt; GskGpuColorStates color_states; GdkColor color2; + GskGpuShaderClip node_clip; if (self->opacity < 1.0 && gsk_text_node_has_color_glyphs (node)) @@ -3034,6 +3035,8 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self, color_states = gsk_gpu_color_states_create (self->ccs, TRUE, alt, FALSE); gdk_color_convert (&color2, alt, color); + node_clip = gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &node->bounds), + offset.x += self->offset.x; offset.y += self->offset.y; @@ -3060,6 +3063,7 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self, graphene_rect_t glyph_bounds, glyph_tex_rect; graphene_point_t glyph_offset, glyph_origin; GskGpuGlyphLookupFlags flags; + GskGpuShaderClip glyph_clip; glyph_origin = GRAPHENE_POINT_INIT (offset.x + glyphs[i].geometry.x_offset * inv_pango_scale, offset.y + glyphs[i].geometry.y_offset * inv_pango_scale); @@ -3090,9 +3094,14 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self, glyph_origin = GRAPHENE_POINT_INIT (glyph_origin.x - glyph_offset.x / scale, glyph_origin.y - glyph_offset.y / scale); + if (node_clip == GSK_GPU_SHADER_CLIP_NONE) + glyph_clip = GSK_GPU_SHADER_CLIP_NONE; + else + glyph_clip = gsk_gpu_clip_get_shader_clip (&self->clip, &glyph_origin, &glyph_bounds); + if (glyphs[i].attr.is_color) gsk_gpu_texture_op (self->frame, - gsk_gpu_clip_get_shader_clip (&self->clip, &glyph_origin, &glyph_bounds), + glyph_clip, &glyph_origin, &(GskGpuShaderImage) { image, @@ -3102,7 +3111,7 @@ gsk_gpu_node_processor_add_glyph_node (GskGpuNodeProcessor *self, }); else gsk_gpu_colorize_op2 (self->frame, - gsk_gpu_clip_get_shader_clip (&self->clip, &glyph_origin, &glyph_bounds), + glyph_clip, color_states, self->opacity, &glyph_origin,