summaryrefslogtreecommitdiff
path: root/fix-leak.patch
blob: be499dfcf89253bf41e527f4169332c80bdc2f46 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
From 4bb5bc005f8ffea31fa104a7238b855c7c20cba6 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 29 Jan 2016 11:19:03 -0500
Subject: [PATCH] wayland: Don't call set_busy twice on the same surface

If the compositor is using a shared memory buffer allocated by
a client, then it's the client's responsibility to refrain from
destroying the buffer until the compositor releases it.

This is accomplished by taking a reference to the cairo surface
assocatiated with the buffer after a frame, and dropping the
reference when the compositor releases the buffer.

In some cases though, the compositor doesn't release the buffer
until a new buffer is set, so if we have staged drawing before
the frame completes we can end up taking multiple references to
the buffer and keeping it alive after it's released.

This commit solves the problem by ensuring we only call
_gdk_wayland_shm_surface_set_busy if isn't already busy.

https://bugzilla.gnome.org/show_bug.cgi?id=761312
---
 gdk/wayland/gdkdisplay-wayland.c | 3 +++
 gdk/wayland/gdkwindow-wayland.c  | 2 +-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c
index f200800..a589756 100644
--- a/gdk/wayland/gdkdisplay-wayland.c
+++ b/gdk/wayland/gdkdisplay-wayland.c
@@ -1020,54 +1020,57 @@ _gdk_wayland_display_create_shm_surface (GdkWaylandDisplay *display,
                                             width*scale, height*scale,
                                             stride, WL_SHM_FORMAT_ARGB8888);
   wl_buffer_add_listener (data->buffer, &buffer_listener, surface);
 
   cairo_surface_set_user_data (surface, &gdk_wayland_cairo_key,
                                data, gdk_wayland_cairo_surface_destroy);
 
   cairo_surface_set_device_scale (surface, scale, scale);
 
   status = cairo_surface_status (surface);
   if (status != CAIRO_STATUS_SUCCESS)
     {
       g_critical (G_STRLOC ": Unable to create Cairo image surface: %s",
                   cairo_status_to_string (status));
     }
 
   return surface;
 }
 
 struct wl_buffer *
 _gdk_wayland_shm_surface_get_wl_buffer (cairo_surface_t *surface)
 {
   GdkWaylandCairoSurfaceData *data = cairo_surface_get_user_data (surface, &gdk_wayland_cairo_key);
   return data->buffer;
 }
 
 void
 _gdk_wayland_shm_surface_set_busy (cairo_surface_t *surface)
 {
   GdkWaylandCairoSurfaceData *data = cairo_surface_get_user_data (surface, &gdk_wayland_cairo_key);
+
+  g_assert (!data->busy);
+
   data->busy = TRUE;
   cairo_surface_reference (surface);
 }
 
 gboolean
 _gdk_wayland_shm_surface_get_busy (cairo_surface_t *surface)
 {
   GdkWaylandCairoSurfaceData *data = cairo_surface_get_user_data (surface, &gdk_wayland_cairo_key);
   return data->busy;
 }
 
 gboolean
 _gdk_wayland_is_shm_surface (cairo_surface_t *surface)
 {
   return cairo_surface_get_user_data (surface, &gdk_wayland_cairo_key) != NULL;
 }
 
 GdkWaylandSelection *
 gdk_wayland_display_get_selection (GdkDisplay *display)
 {
   GdkWaylandDisplay *wayland_display = GDK_WAYLAND_DISPLAY (display);
 
   return wayland_display->selection;
 }
diff --git a/gdk/wayland/gdkwindow-wayland.c b/gdk/wayland/gdkwindow-wayland.c
index 8e74ef4..6dac820 100644
--- a/gdk/wayland/gdkwindow-wayland.c
+++ b/gdk/wayland/gdkwindow-wayland.c
@@ -420,61 +420,61 @@ on_frame_clock_before_paint (GdkFrameClock *clock,
       timings->predicted_presentation_time = presentation_time + refresh_interval;
     }
   else
     {
       /* As above, but we don't actually know the phase of the vblank,
        * so just assume that we're half way through a refresh cycle.
        */
       timings->predicted_presentation_time = timings->frame_time + refresh_interval / 2 + refresh_interval;
     }
 }
 
 static void
 on_frame_clock_after_paint (GdkFrameClock *clock,
                             GdkWindow     *window)
 {
   GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
   struct wl_callback *callback;
 
   if (!impl->pending_commit)
     return;
 
   impl->pending_commit = FALSE;
   impl->pending_frame_counter = gdk_frame_clock_get_frame_counter (clock);
   impl->awaiting_frame = TRUE;
 
   callback = wl_surface_frame (impl->surface);
   wl_callback_add_listener (callback, &frame_listener, window);
   _gdk_frame_clock_freeze (clock);
 
   wl_surface_commit (impl->surface);
-  if (_gdk_wayland_is_shm_surface (impl->cairo_surface))
+  if (_gdk_wayland_is_shm_surface (impl->cairo_surface) && !_gdk_wayland_shm_surface_get_busy (impl->cairo_surface))
     _gdk_wayland_shm_surface_set_busy (impl->cairo_surface);
 
   g_signal_emit (impl, signals[COMMITTED], 0);
 }
 
 static void
 window_update_scale (GdkWindow *window)
 {
   GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
   GdkWaylandDisplay *wayland_display = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
   guint32 scale;
   GSList *l;
 
   if (wayland_display->compositor_version < WL_SURFACE_HAS_BUFFER_SCALE)
     {
       /* We can't set the scale on this surface */
       return;
     }
 
   scale = 1;
   for (l = impl->outputs; l != NULL; l = l->next)
     {
       guint32 output_scale =
         _gdk_wayland_screen_get_output_scale (wayland_display->screen, l->data);
       scale = MAX (scale, output_scale);
     }
 
   /* Notify app that scale changed */
   gdk_wayland_window_configure (window, window->width, window->height, scale);
 }
-- 
2.7.0

bgstack15