Codebase list clutter-gtk / 770f020
Fix high CPU usage (particularly in Wayland sessions) when clutter redraws Hardware redraws of the clutter stage were unexpectedly triggering software redraws of the backing window and its decorations. On _every_ frame. This halves the CPU usage of totem and gnome-maps. (LP: #1698282) Jeremy Bicha 6 years ago
3 changed file(s) with 126 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 clutter-gtk (1.8.4-2) UNRELEASED; urgency=medium
1
2 * Fix high CPU usage (particularly in Wayland sessions) when clutter redraws.
3 Hardware redraws of the clutter stage were unexpectedly triggering software
4 redraws of the backing window and its decorations. On _every_ frame.
5 This halves the CPU usage of totem and gnome-maps. (LP: #1698282)
6
7 -- Daniel van Vugt <daniel.van.vugt@canonical.com> Thu, 05 Oct 2017 16:18:52 +0800
8
09 clutter-gtk (1.8.4-1) unstable; urgency=medium
110
211 * New upstream release.
0 Description: Fix high CPU usage (particularly in Wayland sessions)
1 Hardware redraws of the clutter stage were unexpectedly triggering software
2 redraws of the backing window and its decorations. On _every_ frame.
3 .
4 This halves the CPU usage of totem and gnome-maps.
5 Author: Daniel van Vugt <daniel.van.vugt@canonical.com>
6 Bug-Ubuntu: https://bugs.launchpad.net/bugs/1698282
7 Bug: https://bugzilla.gnome.org/show_bug.cgi?id=787001
8 Forwarded: yes
9 Last-Update: 2017-09-26
10
11 ---
12 clutter-gtk/gtk-clutter-embed.c | 66 ++++++++++++++++++++++++++++++++++++++++-
13 1 file changed, 65 insertions(+), 1 deletion(-)
14
15 diff --git a/clutter-gtk/gtk-clutter-embed.c b/clutter-gtk/gtk-clutter-embed.c
16 index e8c31d4..d9e1aee 100644
17 --- a/clutter-gtk/gtk-clutter-embed.c
18 +++ b/clutter-gtk/gtk-clutter-embed.c
19 @@ -418,6 +418,10 @@ gtk_clutter_embed_draw (GtkWidget *widget, cairo_t *cr)
20 #if defined(CLUTTER_WINDOWING_GDK)
21 GtkClutterEmbedPrivate *priv = GTK_CLUTTER_EMBED (widget)->priv;
22
23 + /* This is probably unnecessary. clutter_stage_ensure_redraw is more of a
24 + * scheduling/queuing thing and is already called by
25 + * gtk_clutter_embed_queue_draw_region below.
26 + */
27 if (clutter_check_windowing_backend (CLUTTER_WINDOWING_GDK))
28 clutter_stage_ensure_redraw (CLUTTER_STAGE (priv->stage));
29 #endif
30 @@ -425,6 +429,62 @@ gtk_clutter_embed_draw (GtkWidget *widget, cairo_t *cr)
31 return GTK_WIDGET_CLASS (gtk_clutter_embed_parent_class)->draw (widget, cr);
32 }
33
34 +static void
35 +gtk_clutter_embed_queue_draw_region (GtkWidget *widget,
36 + const cairo_region_t *region)
37 +{
38 + GtkClutterEmbedPrivate *priv = GTK_CLUTTER_EMBED (widget)->priv;
39 +
40 +#if defined(CLUTTER_WINDOWING_GDK)
41 + if (clutter_check_windowing_backend (CLUTTER_WINDOWING_GDK))
42 + {
43 + GdkWindow *window = gtk_widget_get_window (widget);
44 + GdkWindow *native = NULL;
45 +
46 + /* Try to be more efficient than the default queue_draw_region. The
47 + * default implementation will invalidate our parent widgets/window too
48 + * since embed is using a non-native window. So it would trigger a full
49 + * window/decoration redraw (in software on Wayland!) every time we want
50 + * to just redraw the clutter stage. That's obviously bad and incurs high
51 + * CPU. So instead we have a look inside the widget to see if it still
52 + * contains a trivial single native window for the clutter stage. If so
53 + * then just redraw that, avoiding a full redraw of app window backing
54 + * and decorations.
55 + */
56 + if (gdk_window_has_native (window))
57 + native = window;
58 + else
59 + {
60 + GList *children = gdk_window_get_children (window);
61 + if (children)
62 + {
63 + GdkWindow *single_child = children->data && !children->next ?
64 + GDK_WINDOW (children->data) : NULL;
65 + if (single_child && gdk_window_has_native (single_child))
66 + native = single_child;
67 + }
68 + }
69 +
70 + if (native)
71 + {
72 + /* Now do as gtk_widget_real_queue_draw_region does. Although this
73 + * may be overkill. Doing nothing is probably fine too.
74 + */
75 + gdk_window_invalidate_region (native, region, TRUE);
76 + }
77 + else
78 + {
79 + GTK_WIDGET_CLASS (gtk_clutter_embed_parent_class)->queue_draw_region (widget, region);
80 + }
81 + }
82 +#endif
83 +
84 + /* Ensuring a redraw is more analogous to queuing than actually drawing, so
85 + * set up the stage redraw here.
86 + */
87 + clutter_stage_ensure_redraw (CLUTTER_STAGE (priv->stage));
88 +}
89 +
90 static void
91 gtk_clutter_embed_realize (GtkWidget *widget)
92 {
93 @@ -1066,6 +1126,7 @@ gtk_clutter_embed_class_init (GtkClutterEmbedClass *klass)
94 widget_class->style_updated = gtk_clutter_embed_style_updated;
95 widget_class->size_allocate = gtk_clutter_embed_size_allocate;
96 widget_class->draw = gtk_clutter_embed_draw;
97 + widget_class->queue_draw_region = gtk_clutter_embed_queue_draw_region;
98 widget_class->realize = gtk_clutter_embed_realize;
99 widget_class->unrealize = gtk_clutter_embed_unrealize;
100 widget_class->show = gtk_clutter_embed_show;
101 @@ -1151,7 +1212,10 @@ gtk_clutter_embed_init (GtkClutterEmbed *embed)
102 /* we accept key focus */
103 gtk_widget_set_can_focus (widget, TRUE);
104
105 - /* we own the whole drawing of this widget, including the background */
106 + /* We own the whole drawing of this widget, including the background.
107 + * This call is actually ignored by GTK for most classes including our own,
108 + * but it's still good to declare your intentions...
109 + */
110 gtk_widget_set_app_paintable (widget, TRUE);
111
112 /* this widget should expand in both directions */
113 --
114 2.14.1
115
0 Avoid-stage-redraws-triggering-window-redraws.patch