diff options
author | Jasper St. Pierre <jstpierre@mecheye.net> | 2014-02-23 13:57:24 -0500 |
---|---|---|
committer | Jasper St. Pierre <jstpierre@mecheye.net> | 2014-02-24 20:39:30 -0500 |
commit | c6007924c3eae1de2f59158e17646803f5a6ec18 (patch) | |
tree | d7daab1475160cbdb9438ff94b7db78f7c9c555b | |
parent | 6b921142ab44b2b36f5b190527a454059e8bc1ea (diff) | |
download | gtk+-wip/wayland-buffer.tar.gz |
bufferwip/wayland-buffer
-rw-r--r-- | gdk/wayland/gdkcursor-wayland.c | 45 | ||||
-rw-r--r-- | gdk/wayland/gdkdisplay-wayland.c | 168 | ||||
-rw-r--r-- | gdk/wayland/gdkprivate-wayland.h | 12 | ||||
-rw-r--r-- | gdk/wayland/gdkwindow-wayland.c | 209 |
4 files changed, 204 insertions, 230 deletions
diff --git a/gdk/wayland/gdkcursor-wayland.c b/gdk/wayland/gdkcursor-wayland.c index e88fff5f89..677f500bc2 100644 --- a/gdk/wayland/gdkcursor-wayland.c +++ b/gdk/wayland/gdkcursor-wayland.c @@ -56,7 +56,7 @@ struct _GdkWaylandCursor { int hotspot_x, hotspot_y; int width, height, scale; - struct wl_buffer *buffer; + cairo_surface_t *cairo_surface; } surface; struct wl_cursor *wl_cursor; @@ -168,8 +168,8 @@ gdk_wayland_cursor_finalize (GObject *object) GdkWaylandCursor *cursor = GDK_WAYLAND_CURSOR (object); g_free (cursor->name); - if (cursor->surface.buffer) - wl_buffer_destroy (cursor->surface.buffer); + if (cursor->surface.cairo_surface) + cairo_surface_destroy (cursor->surface.cairo_surface); G_OBJECT_CLASS (_gdk_wayland_cursor_parent_class)->finalize (object); } @@ -225,7 +225,10 @@ _gdk_wayland_cursor_get_buffer (GdkCursor *cursor, *h = wayland_cursor->surface.height / wayland_cursor->surface.scale; *scale = wayland_cursor->surface.scale; - return wayland_cursor->surface.buffer; + if (wayland_cursor->surface.cairo_surface) + return _gdk_wayland_shm_surface_get_wl_buffer (wayland_cursor->surface.cairo_surface); + else + return NULL; } } @@ -339,11 +342,6 @@ _gdk_wayland_display_get_cursor_for_surface (GdkDisplay *display, { GdkWaylandCursor *cursor; GdkWaylandDisplay *wayland_display = GDK_WAYLAND_DISPLAY (display); - int stride; - size_t size; - gpointer data; - struct wl_shm_pool *pool; - cairo_surface_t *buffer_surface; cairo_t *cr; cursor = g_object_new (GDK_TYPE_WAYLAND_CURSOR, @@ -375,36 +373,17 @@ _gdk_wayland_display_get_cursor_for_surface (GdkDisplay *display, cursor->surface.height = 1; } - pool = _create_shm_pool (wayland_display->shm, - cursor->surface.width, - cursor->surface.height, - &size, - &data); - + cursor->surface.cairo_surface = _gdk_wayland_display_create_shm_surface (wayland_display, + cursor->surface.width, + cursor->surface.height, + cursor->surface.scale); if (surface) { - buffer_surface = cairo_image_surface_create_for_data (data, - CAIRO_FORMAT_ARGB32, - cursor->surface.width, - cursor->surface.height, - cursor->surface.width * 4); - cr = cairo_create (buffer_surface); + cr = cairo_create (cursor->surface.cairo_surface); cairo_set_source_surface (cr, surface, 0, 0); cairo_paint (cr); cairo_destroy (cr); - cairo_surface_destroy (buffer_surface); } - else - memset (data, 0, 4); - - stride = cursor->surface.width * 4; - cursor->surface.buffer = wl_shm_pool_create_buffer (pool, 0, - cursor->surface.width, - cursor->surface.height, - stride, - WL_SHM_FORMAT_ARGB8888); - - wl_shm_pool_destroy (pool); return GDK_CURSOR (cursor); } diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c index 3df219dc02..757fe8bb25 100644 --- a/gdk/wayland/gdkdisplay-wayland.c +++ b/gdk/wayland/gdkdisplay-wayland.c @@ -22,6 +22,7 @@ #include <errno.h> #include <unistd.h> #include <fcntl.h> +#include <sys/mman.h> #include <glib.h> #include "gdkwayland.h" @@ -762,3 +763,170 @@ gdk_wayland_display_get_xdg_shell (GdkDisplay *display) return wayland_display->xdg_shell; } + +static const cairo_user_data_key_t gdk_wayland_cairo_key; + +typedef struct _GdkWaylandCairoSurfaceData { + gpointer buf; + size_t buf_length; + struct wl_shm_pool *pool; + struct wl_buffer *buffer; + GdkWaylandDisplay *display; + uint32_t scale; + gboolean busy; +} GdkWaylandCairoSurfaceData; + +static void +buffer_release_callback (void *_data, + struct wl_buffer *wl_buffer) +{ + cairo_surface_t *surface = _data; + GdkWaylandCairoSurfaceData *data = cairo_surface_get_user_data (surface, &gdk_wayland_cairo_key); + + data->busy = FALSE; + cairo_surface_destroy (surface); +} + +static const struct wl_buffer_listener buffer_listener = { + buffer_release_callback +}; + +struct wl_shm_pool * +create_shm_pool (struct wl_shm *shm, + int width, + int height, + size_t *buf_length, + void **data_out) +{ + char filename[] = "/tmp/wayland-shm-XXXXXX"; + struct wl_shm_pool *pool; + int fd, size, stride; + void *data; + + fd = mkstemp (filename); + if (fd < 0) + { + g_critical (G_STRLOC ": Unable to create temporary file (%s): %s", + filename, g_strerror (errno)); + return NULL; + } + + stride = width * 4; + size = stride * height; + if (ftruncate (fd, size) < 0) + { + g_critical (G_STRLOC ": Truncating temporary file failed: %s", + g_strerror (errno)); + close (fd); + return NULL; + } + + data = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + unlink (filename); + + if (data == MAP_FAILED) + { + g_critical (G_STRLOC ": mmap'ping temporary file failed: %s", + g_strerror (errno)); + close (fd); + return NULL; + } + + pool = wl_shm_create_pool(shm, fd, size); + + close (fd); + + *data_out = data; + *buf_length = size; + + return pool; +} + +static void +gdk_wayland_cairo_surface_destroy (void *p) +{ + GdkWaylandCairoSurfaceData *data = p; + + if (data->buffer) + wl_buffer_destroy (data->buffer); + + if (data->pool) + wl_shm_pool_destroy (data->pool); + + munmap (data->buf, data->buf_length); + g_free (data); +} + +cairo_surface_t * +_gdk_wayland_display_create_shm_surface (GdkWaylandDisplay *display, + int width, + int height, + guint scale) +{ + GdkWaylandCairoSurfaceData *data; + cairo_surface_t *surface = NULL; + cairo_status_t status; + int stride; + + data = g_new (GdkWaylandCairoSurfaceData, 1); + data->display = display; + data->buffer = NULL; + data->scale = scale; + data->busy = FALSE; + + stride = width * 4; + + data->pool = create_shm_pool (display->shm, + width*scale, height*scale, + &data->buf_length, + &data->buf); + + surface = cairo_image_surface_create_for_data (data->buf, + CAIRO_FORMAT_ARGB32, + width*scale, + height*scale, + stride*scale); + + data->buffer = wl_shm_pool_create_buffer (data->pool, 0, + width*scale, height*scale, + stride*scale, 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); + +#ifdef HAVE_CAIRO_SURFACE_SET_DEVICE_SCALE + cairo_surface_set_device_scale (surface, scale, scale); +#endif + + 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); + 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; +} diff --git a/gdk/wayland/gdkprivate-wayland.h b/gdk/wayland/gdkprivate-wayland.h index 03016ca7a6..d6d2375429 100644 --- a/gdk/wayland/gdkprivate-wayland.h +++ b/gdk/wayland/gdkprivate-wayland.h @@ -178,10 +178,12 @@ void _gdk_wayland_window_set_device_grabbed (GdkWindow *window, guint32 _gdk_wayland_display_get_serial (GdkWaylandDisplay *wayland_display); void _gdk_wayland_display_update_serial (GdkWaylandDisplay *wayland_display, guint32 serial); -struct wl_shm_pool * _create_shm_pool (struct wl_shm *shm, - int width, - int height, - size_t *buf_length, - void **data_out); +cairo_surface_t * _gdk_wayland_display_create_shm_surface (GdkWaylandDisplay *display, + int width, + int height, + guint scale); +struct wl_buffer *_gdk_wayland_shm_surface_get_wl_buffer (cairo_surface_t *surface); +void _gdk_wayland_shm_surface_set_busy (cairo_surface_t *surface); +gboolean _gdk_wayland_shm_surface_get_busy (cairo_surface_t *surface); #endif /* __GDK_PRIVATE_WAYLAND_H__ */ diff --git a/gdk/wayland/gdkwindow-wayland.c b/gdk/wayland/gdkwindow-wayland.c index 82dafb21ff..71710d3510 100644 --- a/gdk/wayland/gdkwindow-wayland.c +++ b/gdk/wayland/gdkwindow-wayland.c @@ -34,7 +34,6 @@ #include <stdlib.h> #include <stdio.h> #include <string.h> -#include <sys/mman.h> #include <errno.h> #define WL_SURFACE_HAS_BUFFER_SCALE 3 @@ -379,25 +378,11 @@ on_frame_clock_before_paint (GdkFrameClock *clock, } } -static const cairo_user_data_key_t gdk_wayland_cairo_key; - -typedef struct _GdkWaylandCairoSurfaceData { - gpointer buf; - size_t buf_length; - struct wl_shm_pool *pool; - struct wl_buffer *buffer; - GdkWaylandDisplay *display; - int32_t width, height; - uint32_t scale; - gboolean busy; -} GdkWaylandCairoSurfaceData; - static void on_frame_clock_after_paint (GdkFrameClock *clock, GdkWindow *window) { GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl); - GdkWaylandCairoSurfaceData *data; struct wl_callback *callback; if (!impl->pending_commit) @@ -411,14 +396,7 @@ on_frame_clock_after_paint (GdkFrameClock *clock, _gdk_frame_clock_freeze (clock); wl_surface_commit (impl->surface); - - data = cairo_surface_get_user_data (impl->cairo_surface, - &gdk_wayland_cairo_key); - if (!data->busy) - { - data->busy = TRUE; - cairo_surface_reference (impl->cairo_surface); - } + _gdk_wayland_shm_surface_set_busy (impl->cairo_surface); } static void @@ -542,7 +520,6 @@ gdk_wayland_window_attach_image (GdkWindow *window) { GdkWaylandDisplay *display; GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl); - GdkWaylandCairoSurfaceData *data; int32_t server_width, server_height, dx, dy; if (GDK_WINDOW_DESTROYED (window)) @@ -553,12 +530,9 @@ gdk_wayland_window_attach_image (GdkWindow *window) */ if (impl->server_surface) { - data = cairo_surface_get_user_data (impl->server_surface, - &gdk_wayland_cairo_key); - /* Save the old dimensions used for the surface */ - server_width = data->width; - server_height = data->height; + server_width = cairo_image_surface_get_width (impl->server_surface); + server_height = cairo_image_surface_get_height (impl->server_surface); cairo_surface_destroy (impl->server_surface); } @@ -571,181 +545,41 @@ gdk_wayland_window_attach_image (GdkWindow *window) /* Save the current "drawn to" surface for future calls into here */ impl->server_surface = cairo_surface_reference (impl->cairo_surface); - /* Get a Wayland buffer from this new surface */ - data = cairo_surface_get_user_data (impl->cairo_surface, - &gdk_wayland_cairo_key); - if (impl->resize_edges & XDG_SURFACE_RESIZE_EDGE_LEFT) - dx = server_width - data->width; + dx = server_width - cairo_image_surface_get_width (impl->cairo_surface); else dx = 0; if (impl->resize_edges & XDG_SURFACE_RESIZE_EDGE_TOP) - dy = server_height - data->height; + dy = server_height - cairo_image_surface_get_height (impl->cairo_surface); else dy = 0; /* Attach this new buffer to the surface */ - wl_surface_attach (impl->surface, data->buffer, dx, dy); + wl_surface_attach (impl->surface, + _gdk_wayland_shm_surface_get_wl_buffer (impl->cairo_surface), + dx, dy); /* Only set the buffer scale if supported by the compositor */ display = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window)); if (display->compositor_version >= WL_SURFACE_HAS_BUFFER_SCALE) - wl_surface_set_buffer_scale (impl->surface, data->scale); + wl_surface_set_buffer_scale (impl->surface, impl->scale); impl->pending_commit = TRUE; } static void -gdk_wayland_cairo_surface_destroy (void *p) -{ - GdkWaylandCairoSurfaceData *data = p; - - if (data->buffer) - wl_buffer_destroy (data->buffer); - - if (data->pool) - wl_shm_pool_destroy (data->pool); - - munmap (data->buf, data->buf_length); - g_free (data); -} - -struct wl_shm_pool * -_create_shm_pool (struct wl_shm *shm, - int width, - int height, - size_t *buf_length, - void **data_out) -{ - char filename[] = "/tmp/wayland-shm-XXXXXX"; - struct wl_shm_pool *pool; - int fd, size, stride; - void *data; - - fd = mkstemp (filename); - if (fd < 0) - { - g_critical (G_STRLOC ": Unable to create temporary file (%s): %s", - filename, g_strerror (errno)); - return NULL; - } - - stride = width * 4; - size = stride * height; - if (ftruncate (fd, size) < 0) - { - g_critical (G_STRLOC ": Truncating temporary file failed: %s", - g_strerror (errno)); - close (fd); - return NULL; - } - - data = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - unlink (filename); - - if (data == MAP_FAILED) - { - g_critical (G_STRLOC ": mmap'ping temporary file failed: %s", - g_strerror (errno)); - close (fd); - return NULL; - } - - pool = wl_shm_create_pool(shm, fd, size); - - close (fd); - - *data_out = data; - *buf_length = size; - - return pool; -} - - -static void -buffer_release_callback (void *_data, - struct wl_buffer *wl_buffer) -{ - cairo_surface_t *surface = _data; - GdkWaylandCairoSurfaceData *data = cairo_surface_get_user_data (surface, &gdk_wayland_cairo_key); - - data->busy = FALSE; - cairo_surface_destroy (surface); -} - -static const struct wl_buffer_listener buffer_listener = { - buffer_release_callback -}; - -static cairo_surface_t * -gdk_wayland_create_cairo_surface (GdkWaylandDisplay *display, - int width, - int height, - guint scale) -{ - GdkWaylandCairoSurfaceData *data; - cairo_surface_t *surface = NULL; - cairo_status_t status; - int stride; - - data = g_new (GdkWaylandCairoSurfaceData, 1); - data->display = display; - data->buffer = NULL; - data->width = width; - data->height = height; - data->scale = scale; - data->busy = FALSE; - - stride = width * 4; - - data->pool = _create_shm_pool (display->shm, - width*scale, height*scale, - &data->buf_length, - &data->buf); - - surface = cairo_image_surface_create_for_data (data->buf, - CAIRO_FORMAT_ARGB32, - width*scale, - height*scale, - stride*scale); - - data->buffer = wl_shm_pool_create_buffer (data->pool, 0, - width*scale, height*scale, - stride*scale, 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); - -#ifdef HAVE_CAIRO_SURFACE_SET_DEVICE_SCALE - cairo_surface_set_device_scale (surface, scale, scale); -#endif - - 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; -} - -static void gdk_wayland_window_ensure_cairo_surface (GdkWindow *window) { GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl); if (!impl->cairo_surface) { - GdkWaylandDisplay *display_wayland = - GDK_WAYLAND_DISPLAY (gdk_window_get_display (impl->wrapper)); - - impl->cairo_surface = - gdk_wayland_create_cairo_surface (display_wayland, - impl->wrapper->width, - impl->wrapper->height, - impl->scale); + GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_window_get_display (impl->wrapper)); + + impl->cairo_surface = _gdk_wayland_display_create_shm_surface (display_wayland, + impl->wrapper->width, + impl->wrapper->height, + impl->scale); } } @@ -781,13 +615,8 @@ gdk_window_impl_wayland_begin_paint_region (GdkWindow *window, const cairo_region_t *region) { GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl); - GdkWaylandCairoSurfaceData *data; - gdk_wayland_window_ensure_cairo_surface (window); - data = cairo_surface_get_user_data (impl->cairo_surface, - &gdk_wayland_cairo_key); - - return data->busy; + return _gdk_wayland_shm_surface_get_busy (impl->cairo_surface); } static void @@ -1469,11 +1298,7 @@ gdk_wayland_window_destroy (GdkWindow *window, gdk_wayland_window_hide_surface (window, TRUE); if (impl->cairo_surface) - { - cairo_surface_finish (impl->cairo_surface); - cairo_surface_set_user_data (impl->cairo_surface, &gdk_wayland_cairo_key, - NULL, NULL); - } + cairo_surface_finish (impl->cairo_surface); } static void |