window: Use window surfaces for windows
diff --git a/clients/window.c b/clients/window.c
index 0c93b9c..4792710 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -66,6 +66,7 @@
struct rectangle screen_allocation;
int authenticated;
EGLDisplay dpy;
+ EGLConfig conf;
EGLContext ctx;
cairo_device_t *device;
int fd;
@@ -188,6 +189,64 @@
#ifdef HAVE_CAIRO_EGL
+struct egl_window_surface_data {
+ struct display *display;
+ struct wl_surface *surface;
+ struct wl_egl_window *window;
+ EGLSurface surf;
+};
+
+static void
+egl_window_surface_data_destroy(void *p)
+{
+ struct egl_window_surface_data *data = p;
+ struct display *d = data->display;
+
+ eglDestroySurface(d->dpy, data->surf);
+ wl_egl_window_destroy(data->window);
+ data->surface = NULL;
+
+ free(p);
+}
+
+static cairo_surface_t *
+display_create_egl_window_surface(struct display *display,
+ struct wl_surface *surface,
+ struct rectangle *rectangle)
+{
+ cairo_surface_t *cairo_surface;
+ struct egl_window_surface_data *data;
+ struct wl_visual *visual;
+
+ data = malloc(sizeof *data);
+ if (data == NULL)
+ return NULL;
+
+ data->display = display;
+ data->surface = surface;
+
+ visual = wl_display_get_premultiplied_argb_visual(display->display);
+
+ data->window = wl_egl_window_create(display->native_dpy,
+ surface,
+ rectangle->width,
+ rectangle->height,
+ visual);
+
+ data->surf = eglCreateWindowSurface(display->dpy, display->conf,
+ data->window, NULL);
+
+ cairo_surface = cairo_gl_surface_create_for_egl(display->device,
+ data->surf,
+ rectangle->width,
+ rectangle->height);
+
+ cairo_surface_set_user_data(cairo_surface, &surface_data_key,
+ data, egl_window_surface_data_destroy);
+
+ return cairo_surface;
+}
+
struct egl_image_surface_data {
struct surface_data data;
EGLImageKHR image;
@@ -499,13 +558,20 @@
cairo_surface_t *
display_create_surface(struct display *display,
+ struct wl_surface *surface,
struct rectangle *rectangle)
{
if (check_size(rectangle) < 0)
return NULL;
#ifdef HAVE_CAIRO_EGL
if (display->dpy) {
- return display_create_egl_image_surface(display, rectangle);
+ if (surface)
+ return display_create_egl_window_surface(display,
+ surface,
+ rectangle);
+ else
+ return display_create_egl_image_surface(display,
+ rectangle);
}
#endif
return display_create_shm_surface(display, rectangle);
@@ -607,32 +673,52 @@
{
struct display *display = window->display;
struct wl_buffer *buffer;
+ struct egl_window_surface_data *data;
int32_t x, y;
+ int width = window->allocation.width;
+ int height = window->allocation.height;
- if (window->pending_surface != NULL)
- return;
-
- window->pending_surface = window->cairo_surface;
- window->cairo_surface = NULL;
-
- buffer = display_get_buffer_for_surface(display,
- window->pending_surface);
if (window->resize_edges & WINDOW_RESIZING_LEFT)
- x = window->server_allocation.width -
- window->allocation.width;
+ x = window->server_allocation.width - width;
else
x = 0;
if (window->resize_edges & WINDOW_RESIZING_TOP)
- y = window->server_allocation.height -
- window->allocation.height;
+ y = window->server_allocation.height - height;
else
y = 0;
- window->server_allocation = window->allocation;
window->resize_edges = 0;
- wl_surface_attach(window->surface, buffer, x, y);
- wl_display_sync_callback(display->display, free_surface, window);
+
+ switch (window->buffer_type) {
+ case WINDOW_BUFFER_TYPE_EGL_WINDOW:
+ data = cairo_surface_get_user_data(window->cairo_surface,
+ &surface_data_key);
+
+ wl_egl_window_resize(data->window, width, height, x, y);
+ cairo_gl_surface_swapbuffers(window->cairo_surface);
+ wl_egl_window_get_attached_size(data->window,
+ &window->server_allocation.width,
+ &window->server_allocation.height);
+ break;
+ case WINDOW_BUFFER_TYPE_EGL_IMAGE:
+ case WINDOW_BUFFER_TYPE_SHM:
+ if (window->pending_surface != NULL)
+ return;
+
+ window->pending_surface = window->cairo_surface;
+ window->cairo_surface = NULL;
+
+ buffer =
+ display_get_buffer_for_surface(display,
+ window->pending_surface);
+
+ wl_surface_attach(window->surface, buffer, x, y);
+ window->server_allocation = window->allocation;
+ wl_display_sync_callback(display->display, free_surface,
+ window);
+ break;
+ }
if (window->fullscreen)
wl_surface_map_fullscreen(window->surface);
@@ -666,6 +752,22 @@
window->cairo_surface = surface;
}
+static void
+window_resize_cairo_window_surface(struct window *window)
+{
+ struct egl_window_surface_data *data;
+
+ data = cairo_surface_get_user_data(window->cairo_surface,
+ &surface_data_key);
+
+ wl_egl_window_resize(data->window,
+ window->allocation.width,
+ window->allocation.height, 0, 0);
+ cairo_gl_surface_set_size(window->cairo_surface,
+ window->allocation.width,
+ window->allocation.height);
+}
+
void
window_create_surface(struct window *window)
{
@@ -673,8 +775,18 @@
switch (window->buffer_type) {
#ifdef HAVE_CAIRO_EGL
+ case WINDOW_BUFFER_TYPE_EGL_WINDOW:
+ if (window->cairo_surface) {
+ window_resize_cairo_window_surface(window);
+ return;
+ }
+ surface = display_create_surface(window->display,
+ window->surface,
+ &window->allocation);
+ break;
case WINDOW_BUFFER_TYPE_EGL_IMAGE:
surface = display_create_surface(window->display,
+ NULL,
&window->allocation);
break;
#endif
@@ -1325,7 +1437,8 @@
window->decoration = 1;
if (display->dpy)
- window->buffer_type = WINDOW_BUFFER_TYPE_EGL_IMAGE;
+ /* FIXME: make TYPE_EGL_IMAGE choosable for testing */
+ window->buffer_type = WINDOW_BUFFER_TYPE_EGL_WINDOW;
else
window->buffer_type = WINDOW_BUFFER_TYPE_SHM;
@@ -1595,6 +1708,17 @@
init_egl(struct display *d)
{
EGLint major, minor;
+ EGLint n;
+ static const EGLint cfg_attribs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PIXMAP_BIT,
+ EGL_RED_SIZE, 1,
+ EGL_GREEN_SIZE, 1,
+ EGL_BLUE_SIZE, 1,
+ EGL_ALPHA_SIZE, 1,
+ EGL_DEPTH_SIZE, 1,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
+ EGL_NONE
+ };
d->dpy = eglGetDisplay(d->native_dpy);
if (!eglInitialize(d->dpy, &major, &minor)) {
@@ -1607,7 +1731,12 @@
return -1;
}
- d->ctx = eglCreateContext(d->dpy, NULL, EGL_NO_CONTEXT, NULL);
+ if (!eglChooseConfig(d->dpy, cfg_attribs, &d->conf, 1, &n) || n != 1) {
+ fprintf(stderr, "failed to choose config\n");
+ return -1;
+ }
+
+ d->ctx = eglCreateContext(d->dpy, d->conf, EGL_NO_CONTEXT, NULL);
if (d->ctx == NULL) {
fprintf(stderr, "failed to create context\n");
return -1;