160 lines
5.3 KiB
Diff
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
|
|
|