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
This commit is contained in:
Rob Bradford 2012-04-04 17:20:13 +01:00
parent 6977ea0bd1
commit cdf5c2af62
4 changed files with 145 additions and 6 deletions

View 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)

View 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);
}

View File

@ -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

View 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);