]> Pileus Git - ~andy/gtk/commitdiff
wayland: Add support for rendering into an SHM buffer with Cairo image backend
authorRob Bradford <rob@linux.intel.com>
Wed, 4 Apr 2012 16:20:13 +0000 (17:20 +0100)
committerRob Bradford <rob@linux.intel.com>
Mon, 16 Apr 2012 14:09:14 +0000 (15:09 +0100)
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
configure.ac
gdk/wayland/gdkdisplay-wayland.c
gdk/wayland/gdkdisplay-wayland.h
gdk/wayland/gdkwindow-wayland.c

index 93cf28125bfe6d76681b65438523e48b9fabd772..8e1d691ef6242ebc5e1761c345932135bac481a8 100644 (file)
@@ -379,13 +379,16 @@ else
 fi
 
 if test "x$enable_wayland_backend" == "xyes"; then
-  # Wayland uses cairo-gl
-  cairo_backends="$cairo_backends cairo-gl"
+  # For the cairo image backend
+  cairo_backends="$cairo_backends cairo"
   GDK_BACKENDS="$GDK_BACKENDS wayland"
   have_gio_unix=yes
   GDK_WINDOWING="$GDK_WINDOWING
 #define GDK_WINDOWING_WAYLAND"
-  WAYLAND_PACKAGES="wayland-client xkbcommon wayland-egl egl"
+  WAYLAND_PACKAGES="wayland-client xkbcommon "
+  if test "x$enable_wayland_cairo_gl" == "xyes"; then
+    WAYLAND_PACKAGES="$WAYLAND_PACKAGES wayland-egl egl"
+  fi
   AM_CONDITIONAL(USE_WAYLAND, true)
 else
   AM_CONDITIONAL(USE_WAYLAND, false)
index 6367bb0ecafe9daad9ac320757abe4d36765db95..1d813952432a395c4c9aee1878b0d778b4181fed 100644 (file)
@@ -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);
 }
index a24812550f0f769083212b06ad7905dbbad068dc..ae456bc2b7fc4ae5bcb63bc1b8b661802685f789 100644 (file)
 #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
index 80ed791129625595824841c0d6ce5e825eb55ab5..d2adc364bd5f51975b85dd8c3ba8f951f5338f00 100644 (file)
@@ -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);