[PATCH weston 2/6] window: add toysurface abstraction and port EGL path
Pekka Paalanen
ppaalanen at gmail.com
Mon Nov 19 07:15:58 PST 2012
We need more structure to the way we handle the backing storage in
toytoolkit, to make it possible to double-buffer the shm case properly.
The existing buffer handling is very complex with the three
different cases:
- EGLSurface backed Cairo surface with a window associated
- wl_shm backed Cairo surface with a window associated
- wl_shm backed Cairo surface without a window, as used by dnd.c
Introduce the toysurface abstraction, which defines the interface for
the both buffer handling cases that have a window associated. It also
means, that windows will not have a valid Cairo surface outside of their
repaint cycle.
Convert the EGLsurface case into toysurface for starters. For EGL-based
Cairo surfaces, the private data is no longer needed. Destroying
egl_window_surface will trigger the destruction of the cairo_surface_t,
not vice versa. This is possible because display_create_surface() is
shm-only.
The shm cases are left untouched.
As a side-effect, display_acquire_window_surface() and
display_release_window_surface() will no longer use the 'display'
argument. Instead, display will be the one inherited from the window.
Signed-off-by: Pekka Paalanen <ppaalanen at gmail.com>
---
clients/window.c | 305 ++++++++++++++++++++++++++++++++---------------------
1 files changed, 184 insertions(+), 121 deletions(-)
diff --git a/clients/window.c b/clients/window.c
index 8cf53d3..86386f3 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -142,6 +142,44 @@ struct window_output {
struct wl_list link;
};
+struct toysurface {
+ /*
+ * Prepare the surface for drawing. Makes sure there is a surface
+ * of the right size available for rendering, and returns it.
+ * dx,dy are the x,y of wl_surface.attach.
+ * width,height are the new surface size.
+ * Returns the Cairo surface to draw to.
+ */
+ cairo_surface_t *(*prepare)(struct toysurface *base, int dx, int dy,
+ int width, int height);
+
+ /*
+ * Post the surface to the server, returning the server allocation
+ * rectangle. The Cairo surface from prepare() must be destroyed
+ * after calling this.
+ */
+ void (*swap)(struct toysurface *base,
+ struct rectangle *server_allocation);
+
+ /*
+ * Make the toysurface current with the given EGL context.
+ * Returns 0 on success, and negative of failure.
+ */
+ int (*acquire)(struct toysurface *base, EGLContext ctx);
+
+ /*
+ * Release the toysurface from the EGL context, returning control
+ * to Cairo.
+ */
+ void (*release)(struct toysurface *base);
+
+ /*
+ * Destroy the toysurface, including the Cairo surface, any
+ * backing storage, and the Wayland protocol objects.
+ */
+ void (*destroy)(struct toysurface *base);
+};
+
struct window {
struct display *display;
struct window *parent;
@@ -166,6 +204,7 @@ struct window {
enum window_buffer_type buffer_type;
+ struct toysurface *toysurface;
cairo_surface_t *cairo_surface;
struct shm_pool *pool;
@@ -347,68 +386,142 @@ enum window_location {
};
static const cairo_user_data_key_t shm_surface_data_key;
-static const cairo_user_data_key_t egl_window_surface_data_key;
#ifdef HAVE_CAIRO_EGL
-struct egl_window_surface_data {
+struct egl_window_surface {
+ struct toysurface base;
+ cairo_surface_t *cairo_surface;
struct display *display;
struct wl_surface *surface;
- struct wl_egl_window *window;
- EGLSurface surf;
+ struct wl_egl_window *egl_window;
+ EGLSurface egl_surface;
};
+static struct egl_window_surface *
+to_egl_window_surface(struct toysurface *base)
+{
+ return container_of(base, struct egl_window_surface, base);
+}
+
+static cairo_surface_t *
+egl_window_surface_prepare(struct toysurface *base, int dx, int dy,
+ int width, int height)
+{
+ struct egl_window_surface *surface = to_egl_window_surface(base);
+
+ wl_egl_window_resize(surface->egl_window, width, height, dx, dy);
+ cairo_gl_surface_set_size(surface->cairo_surface, width, height);
+
+ return cairo_surface_reference(surface->cairo_surface);
+}
+
static void
-egl_window_surface_data_destroy(void *p)
+egl_window_surface_swap(struct toysurface *base,
+ struct rectangle *server_allocation)
+{
+ struct egl_window_surface *surface = to_egl_window_surface(base);
+
+ cairo_gl_surface_swapbuffers(surface->cairo_surface);
+ wl_egl_window_get_attached_size(surface->egl_window,
+ &server_allocation->width,
+ &server_allocation->height);
+}
+
+static int
+egl_window_surface_acquire(struct toysurface *base, EGLContext ctx)
{
- struct egl_window_surface_data *data = p;
- struct display *d = data->display;
+ struct egl_window_surface *surface = to_egl_window_surface(base);
+ cairo_device_t *device;
- eglDestroySurface(d->dpy, data->surf);
- wl_egl_window_destroy(data->window);
- data->surface = NULL;
+ device = cairo_surface_get_device(surface->cairo_surface);
+ if (!device)
+ return -1;
- free(p);
+ if (!ctx) {
+ if (device == surface->display->argb_device)
+ ctx = surface->display->argb_ctx;
+ else
+ assert(0);
+ }
+
+ cairo_device_flush(device);
+ cairo_device_acquire(device);
+ if (!eglMakeCurrent(surface->display->dpy, surface->egl_surface,
+ surface->egl_surface, ctx))
+ fprintf(stderr, "failed to make surface current\n");
+
+ return 0;
}
-static cairo_surface_t *
-display_create_egl_window_surface(struct display *display,
- struct wl_surface *surface,
- uint32_t flags,
- struct rectangle *rectangle)
+static void
+egl_window_surface_release(struct toysurface *base)
{
- cairo_surface_t *cairo_surface;
- struct egl_window_surface_data *data;
- EGLConfig config;
+ struct egl_window_surface *surface = to_egl_window_surface(base);
cairo_device_t *device;
- data = malloc(sizeof *data);
- if (data == NULL)
- return NULL;
+ device = cairo_surface_get_device(surface->cairo_surface);
+ if (!device)
+ return;
+
+ if (!eglMakeCurrent(surface->display->dpy, NULL, NULL,
+ surface->display->argb_ctx))
+ fprintf(stderr, "failed to make context current\n");
+
+ cairo_device_release(device);
+}
+
+static void
+egl_window_surface_destroy(struct toysurface *base)
+{
+ struct egl_window_surface *surface = to_egl_window_surface(base);
+ struct display *d = surface->display;
+
+ cairo_surface_destroy(surface->cairo_surface);
+ eglDestroySurface(d->dpy, surface->egl_surface);
+ wl_egl_window_destroy(surface->egl_window);
+ surface->surface = NULL;
+
+ free(surface);
+}
+
+static struct toysurface *
+egl_window_surface_create(struct display *display,
+ struct wl_surface *wl_surface,
+ uint32_t flags,
+ struct rectangle *rectangle)
+{
+ struct egl_window_surface *surface;
- data->display = display;
- data->surface = surface;
+ surface = calloc(1, sizeof *surface);
+ if (!surface)
+ return NULL;
- config = display->argb_config;
- device = display->argb_device;
+ surface->base.prepare = egl_window_surface_prepare;
+ surface->base.swap = egl_window_surface_swap;
+ surface->base.acquire = egl_window_surface_acquire;
+ surface->base.release = egl_window_surface_release;
+ surface->base.destroy = egl_window_surface_destroy;
- data->window = wl_egl_window_create(surface,
- rectangle->width,
- rectangle->height);
+ surface->display = display;
+ surface->surface = wl_surface;
- data->surf = eglCreateWindowSurface(display->dpy, config,
- data->window, NULL);
+ surface->egl_window = wl_egl_window_create(surface->surface,
+ rectangle->width,
+ rectangle->height);
- cairo_surface = cairo_gl_surface_create_for_egl(device,
- data->surf,
- rectangle->width,
- rectangle->height);
+ surface->egl_surface = eglCreateWindowSurface(display->dpy,
+ display->argb_config,
+ surface->egl_window,
+ NULL);
- cairo_surface_set_user_data(cairo_surface,
- &egl_window_surface_data_key,
- data, egl_window_surface_data_destroy);
+ surface->cairo_surface =
+ cairo_gl_surface_create_for_egl(display->argb_device,
+ surface->egl_surface,
+ rectangle->width,
+ rectangle->height);
- return cairo_surface;
+ return &surface->base;
}
#endif
@@ -812,9 +925,6 @@ window_attach_surface(struct window *window)
{
struct display *display = window->display;
struct wl_buffer *buffer;
-#ifdef HAVE_CAIRO_EGL
- struct egl_window_surface_data *data;
-#endif
int32_t x, y;
if (window->type == TYPE_NONE) {
@@ -840,13 +950,8 @@ window_attach_surface(struct window *window)
switch (window->buffer_type) {
#ifdef HAVE_CAIRO_EGL
case WINDOW_BUFFER_TYPE_EGL_WINDOW:
- data = cairo_surface_get_user_data(window->cairo_surface,
- &egl_window_surface_data_key);
-
- cairo_gl_surface_swapbuffers(window->cairo_surface);
- wl_egl_window_get_attached_size(data->window,
- &window->server_allocation.width,
- &window->server_allocation.height);
+ window->toysurface->swap(window->toysurface,
+ &window->server_allocation);
break;
#endif
case WINDOW_BUFFER_TYPE_SHM:
@@ -876,8 +981,12 @@ window_has_focus(struct window *window)
static void
window_flush(struct window *window)
{
- if (window->cairo_surface)
- window_attach_surface(window);
+ if (!window->cairo_surface)
+ return;
+
+ window_attach_surface(window);
+ cairo_surface_destroy(window->cairo_surface);
+ window->cairo_surface = NULL;
}
static void
@@ -891,28 +1000,6 @@ window_set_surface(struct window *window, cairo_surface_t *surface)
window->cairo_surface = surface;
}
-#ifdef HAVE_CAIRO_EGL
-static void
-window_resize_cairo_window_surface(struct window *window)
-{
- struct egl_window_surface_data *data;
- int x, y;
-
- data = cairo_surface_get_user_data(window->cairo_surface,
- &egl_window_surface_data_key);
-
- window_get_resize_dx_dy(window, &x, &y),
- wl_egl_window_resize(data->window,
- window->allocation.width,
- window->allocation.height,
- x,y);
-
- cairo_gl_surface_set_size(window->cairo_surface,
- window->allocation.width,
- window->allocation.height);
-}
-#endif
-
struct display *
window_get_display(struct window *window)
{
@@ -924,21 +1011,28 @@ window_create_surface(struct window *window)
{
cairo_surface_t *surface;
uint32_t flags = 0;
-
+
if (!window->transparent)
flags = SURFACE_OPAQUE;
-
+
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;
- }
- if (window->display->dpy) {
- surface = display_create_egl_window_surface(
- window->display, window->surface,
- flags, &window->allocation);
+ if (!window->toysurface && window->display->dpy)
+ window->toysurface =
+ egl_window_surface_create(window->display,
+ window->surface,
+ flags,
+ &window->allocation);
+
+ if (window->toysurface) {
+ int dx, dy;
+
+ window_get_resize_dx_dy(window, &dx, &dy);
+ surface = window->toysurface->prepare(window->toysurface,
+ dx, dy,
+ window->allocation.width,
+ window->allocation.height);
break;
}
/* fall through */
@@ -1001,6 +1095,9 @@ window_destroy(struct window *window)
if (window->cairo_surface != NULL)
cairo_surface_destroy(window->cairo_surface);
+ if (window->toysurface)
+ window->toysurface->destroy(window->toysurface);
+
if (window->frame_cb)
wl_callback_destroy(window->frame_cb);
free(window->title);
@@ -3874,8 +3971,6 @@ display_create(int argc, char *argv[])
{
struct display *d;
- assert(&egl_window_surface_data_key != &shm_surface_data_key);
-
d = malloc(sizeof *d);
if (d == NULL)
return NULL;
@@ -4053,52 +4148,20 @@ display_acquire_window_surface(struct display *display,
struct window *window,
EGLContext ctx)
{
-#ifdef HAVE_CAIRO_EGL
- struct egl_window_surface_data *data;
- cairo_device_t *device;
-
- if (!window->cairo_surface)
- return -1;
- device = cairo_surface_get_device(window->cairo_surface);
- if (!device)
+ if (window->buffer_type != WINDOW_BUFFER_TYPE_EGL_WINDOW)
return -1;
- if (!ctx) {
- if (device == display->argb_device)
- ctx = display->argb_ctx;
- else
- assert(0);
- }
-
- data = cairo_surface_get_user_data(window->cairo_surface,
- &egl_window_surface_data_key);
-
- cairo_device_flush(device);
- cairo_device_acquire(device);
- if (!eglMakeCurrent(display->dpy, data->surf, data->surf, ctx))
- fprintf(stderr, "failed to make surface current\n");
-
- return 0;
-#else
- return -1;
-#endif
+ return window->toysurface->acquire(window->toysurface, ctx);
}
void
display_release_window_surface(struct display *display,
struct window *window)
{
-#ifdef HAVE_CAIRO_EGL
- cairo_device_t *device;
-
- device = cairo_surface_get_device(window->cairo_surface);
- if (!device)
+ if (window->buffer_type != WINDOW_BUFFER_TYPE_EGL_WINDOW)
return;
- if (!eglMakeCurrent(display->dpy, NULL, NULL, display->argb_ctx))
- fprintf(stderr, "failed to make context current\n");
- cairo_device_release(device);
-#endif
+ window->toysurface->release(window->toysurface);
}
void
--
1.7.8.6
More information about the wayland-devel
mailing list