summaryrefslogtreecommitdiff
path: root/gdk/wayland
diff options
context:
space:
mode:
authorRob Bradford <rob@linux.intel.com>2012-04-04 17:20:13 +0100
committerRob Bradford <rob@linux.intel.com>2012-04-16 15:09:14 +0100
commitcdf5c2af628a1ca202cd8c6a8d3529b46718183b (patch)
treeb3b1c3f36ab7394ab75d26507866547120948000 /gdk/wayland
parent6977ea0bd1aa91e757a08d2d6a8fcc2adb08588c (diff)
downloadgtk+-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.c11
-rw-r--r--gdk/wayland/gdkdisplay-wayland.h10
-rw-r--r--gdk/wayland/gdkwindow-wayland.c121
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);