diff options
author | Rob Bradford <rob@linux.intel.com> | 2012-04-04 17:20:13 +0100 |
---|---|---|
committer | Rob Bradford <rob@linux.intel.com> | 2012-04-16 15:09:14 +0100 |
commit | cdf5c2af628a1ca202cd8c6a8d3529b46718183b (patch) | |
tree | b3b1c3f36ab7394ab75d26507866547120948000 /gdk/wayland | |
parent | 6977ea0bd1aa91e757a08d2d6a8fcc2adb08588c (diff) | |
download | gtk+-cdf5c2af628a1ca202cd8c6a8d3529b46718183b.tar.gz |
wayland: Add support for rendering into an SHM buffer with Cairo image backend
The first version of this change included a bug that meant that if you don't
compile for any other backend then it wouldn't search for cairo. Credit for
identifying the bug goes to darxus@chaosreigns.com.
Fixes: https://bugzilla.gnome.org/show_bug.cgi?id=672361
Diffstat (limited to 'gdk/wayland')
-rw-r--r-- | gdk/wayland/gdkdisplay-wayland.c | 11 | ||||
-rw-r--r-- | gdk/wayland/gdkdisplay-wayland.h | 10 | ||||
-rw-r--r-- | gdk/wayland/gdkwindow-wayland.c | 121 |
3 files changed, 139 insertions, 3 deletions
diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c index 6367bb0eca..1d81395243 100644 --- a/gdk/wayland/gdkdisplay-wayland.c +++ b/gdk/wayland/gdkdisplay-wayland.c @@ -17,7 +17,9 @@ #include "config.h" +#ifdef GDK_WAYLAND_USE_EGL #include <wayland-egl.h> +#endif #include <stdlib.h> #include <string.h> @@ -145,6 +147,7 @@ gdk_display_handle_global(struct wl_display *display, uint32_t id, } } +#ifdef GDK_WAYLAND_USE_EGL static gboolean gdk_display_init_egl(GdkDisplay *display) { @@ -200,6 +203,7 @@ gdk_display_init_egl(GdkDisplay *display) return TRUE; } +#endif GdkDisplay * _gdk_wayland_display_open (const gchar *display_name) @@ -225,7 +229,12 @@ _gdk_wayland_display_open (const gchar *display_name) wl_display_add_global_listener(display_wayland->wl_display, gdk_display_handle_global, display_wayland); +#ifdef GDK_WAYLAND_USE_EGL gdk_display_init_egl(display); +#else + wl_display_iterate(wl_display, WL_DISPLAY_READABLE); + wl_display_roundtrip(wl_display); +#endif display_wayland->event_source = _gdk_wayland_display_event_source_new (display); @@ -257,7 +266,9 @@ gdk_wayland_display_dispose (GObject *object) display_wayland->event_source = NULL; } +#ifdef GDK_WAYLAND_USE_EGL eglTerminate(display_wayland->egl_display); +#endif G_OBJECT_CLASS (_gdk_display_wayland_parent_class)->dispose (object); } diff --git a/gdk/wayland/gdkdisplay-wayland.h b/gdk/wayland/gdkdisplay-wayland.h index a24812550f..ae456bc2b7 100644 --- a/gdk/wayland/gdkdisplay-wayland.h +++ b/gdk/wayland/gdkdisplay-wayland.h @@ -22,14 +22,19 @@ #ifndef __GDK_DISPLAY_WAYLAND__ #define __GDK_DISPLAY_WAYLAND__ +#include <config.h> #include <stdint.h> #include <wayland-client.h> + +#ifdef GDK_WAYLAND_USE_EGL #include <wayland-egl.h> #include <EGL/egl.h> #include <EGL/eglext.h> #include <GL/gl.h> #include <GL/glext.h> #include <cairo-gl.h> +#endif + #include <glib.h> #include <gdk/gdkkeys.h> #include <gdk/gdkwindow.h> @@ -76,15 +81,20 @@ struct _GdkDisplayWayland struct wl_input_device *input_device; struct wl_data_device_manager *data_device_manager; GSource *event_source; + +#ifdef GDK_WAYLAND_USE_EGL EGLDisplay egl_display; EGLContext egl_context; cairo_device_t *cairo_device; +#endif GdkCursor **cursors; +#ifdef GDK_WAYLAND_USE_EGL PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d; PFNEGLCREATEIMAGEKHRPROC create_image; PFNEGLDESTROYIMAGEKHRPROC destroy_image; +#endif }; struct _GdkDisplayWaylandClass diff --git a/gdk/wayland/gdkwindow-wayland.c b/gdk/wayland/gdkwindow-wayland.c index 80ed791129..d2adc364bd 100644 --- a/gdk/wayland/gdkwindow-wayland.c +++ b/gdk/wayland/gdkwindow-wayland.c @@ -33,6 +33,7 @@ #include <stdlib.h> #include <stdio.h> #include <string.h> +#include <sys/mman.h> #include <wayland-egl.h> @@ -300,9 +301,14 @@ _gdk_wayland_display_create_window_impl (GdkDisplay *display, static const cairo_user_data_key_t gdk_wayland_cairo_key; typedef struct _GdkWaylandCairoSurfaceData { +#ifdef GDK_WAYLAND_USE_EGL EGLImageKHR image; GLuint texture; struct wl_egl_pixmap *pixmap; +#else + gpointer buf; + size_t buf_length; +#endif struct wl_buffer *buffer; GdkDisplayWayland *display; int32_t width, height; @@ -366,6 +372,7 @@ gdk_wayland_window_attach_image (GdkWindow *window) wl_surface_attach (impl->surface, data->buffer, dx, dy); } +#ifdef GDK_WAYLAND_USE_EGL static void gdk_wayland_cairo_surface_destroy (void *p) { @@ -419,6 +426,100 @@ gdk_wayland_create_cairo_surface (GdkDisplayWayland *display, return surface; } +#else +static struct wl_buffer * +create_shm_buffer (struct wl_shm *shm, + int width, + int height, + uint32_t format, + size_t *buf_length, + void **data_out) +{ + char filename[] = "/tmp/wayland-shm-XXXXXX"; + struct wl_buffer *buffer; + int fd, size, stride; + void *data; + + fd = mkstemp(filename); + if (fd < 0) { + fprintf(stderr, "open %s failed: %m\n", filename); + return NULL; + } + stride = width * 4; + size = stride * height; + if (ftruncate(fd, size) < 0) { + fprintf(stderr, "ftruncate failed: %m\n"); + close(fd); + return NULL; + } + + data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + unlink(filename); + + if (data == MAP_FAILED) { + fprintf(stderr, "mmap failed: %m\n"); + close(fd); + return NULL; + } + + buffer = wl_shm_create_buffer(shm, fd, + width, height, + stride, format); + + close(fd); + + *data_out = data; + *buf_length = size; + return buffer; +} + +static void +gdk_wayland_cairo_surface_destroy (void *p) +{ + GdkWaylandCairoSurfaceData *data = p; + + if (data->buffer) + wl_buffer_destroy(data->buffer); + + munmap(data->buf, data->buf_length); + g_free(data); +} + +static cairo_surface_t * +gdk_wayland_create_cairo_surface (GdkDisplayWayland *display, + int width, int height) +{ + GdkWaylandCairoSurfaceData *data; + cairo_surface_t *surface; + + data = g_new (GdkWaylandCairoSurfaceData, 1); + data->display = display; + data->buffer = NULL; + data->width = width; + data->height = height; + + data->buffer = create_shm_buffer (display->shm, + width, + height, + WL_SHM_FORMAT_XRGB8888, + &data->buf_length, + &data->buf); + + surface = cairo_image_surface_create_for_data (data->buf, + CAIRO_FORMAT_RGB24, + width, + height, + width * 4); + + cairo_surface_set_user_data (surface, &gdk_wayland_cairo_key, + data, gdk_wayland_cairo_surface_destroy); + + if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) + fprintf (stderr, "create image surface failed\n"); + + return surface; +} +#endif /* On this first call this creates a double reference - the first reference * is held by the GdkWindowImplWayland struct - since unlike other backends @@ -1360,10 +1461,13 @@ gdk_wayland_window_destroy_notify (GdkWindow *window) } static void -gdk_wayland_window_process_updates_recurse (GdkWindow *window, - cairo_region_t *region) +gdk_wayland_window_process_updates_recurse (GdkWindow *window, + cairo_region_t *region) { GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl); +#ifndef GDK_WAYLAND_USE_EGL + GdkWaylandCairoSurfaceData *data = NULL; +#endif cairo_rectangle_int_t rect; int i, n; @@ -1372,12 +1476,23 @@ gdk_wayland_window_process_updates_recurse (GdkWindow *window, if (impl->cairo_surface) gdk_wayland_window_attach_image (window); +#ifndef GDK_WAYLAND_USE_EGL + if (impl->server_surface) + data = cairo_surface_get_user_data (impl->server_surface, + &gdk_wayland_cairo_key); +#endif + n = cairo_region_num_rectangles(region); for (i = 0; i < n; i++) { cairo_region_get_rectangle (region, i, &rect); +#ifndef GDK_WAYLAND_USE_EGL + if (data && data->buffer) + wl_buffer_damage (data->buffer, + rect.x, rect.y, rect.width, rect.height); +#endif wl_surface_damage (impl->surface, - rect.x, rect.y, rect.width, rect.height); + rect.x, rect.y, rect.width, rect.height); } _gdk_window_process_updates_recurse (window, region); |