gtk3/fix-leak.patch

160 lines
5.3 KiB
Diff

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