|
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 |
|