[PATCH weston 3/6] window: convert shm path to toysurface
Pekka Paalanen
ppaalanen at gmail.com
Mon Nov 19 07:15:59 PST 2012
Implement shm_surface as a sub-class of toysurface, and unify the
toysurface call sites removing most buffer type specific branching.
Do not destroy and create a surface, if the size does not change.
The resizing optimization of shm surfaces is retained, but the pool is
moved from struct window to struct shm_surface, since it does not apply
to egl_window_surface.
Signed-off-by: Pekka Paalanen <ppaalanen at gmail.com>
---
clients/window.c | 258 +++++++++++++++++++++++++++++++++++++-----------------
1 files changed, 178 insertions(+), 80 deletions(-)
diff --git a/clients/window.c b/clients/window.c
index 86386f3..a8c3e3a 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -1,5 +1,6 @@
/*
* Copyright © 2008 Kristian Høgsberg
+ * Copyright © 2012 Collabora, Ltd.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
@@ -148,10 +149,11 @@ struct toysurface {
* 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.
+ * If resize_hint is non-zero, the user is doing continuous resizing.
* Returns the Cairo surface to draw to.
*/
cairo_surface_t *(*prepare)(struct toysurface *base, int dx, int dy,
- int width, int height);
+ int width, int height, int resize_hint);
/*
* Post the surface to the server, returning the server allocation
@@ -203,11 +205,10 @@ struct window {
int focus_count;
enum window_buffer_type buffer_type;
-
struct toysurface *toysurface;
cairo_surface_t *cairo_surface;
- struct shm_pool *pool;
+ int resizing;
window_key_handler_t key_handler;
window_keyboard_focus_handler_t keyboard_focus_handler;
@@ -406,7 +407,7 @@ to_egl_window_surface(struct toysurface *base)
static cairo_surface_t *
egl_window_surface_prepare(struct toysurface *base, int dx, int dy,
- int width, int height)
+ int width, int height, int resize_hint)
{
struct egl_window_surface *surface = to_egl_window_surface(base);
@@ -693,20 +694,24 @@ display_create_shm_surface_from_pool(struct display *display,
static cairo_surface_t *
display_create_shm_surface(struct display *display,
struct rectangle *rectangle, uint32_t flags,
- struct window *window)
+ struct shm_pool *alternate_pool,
+ struct shm_surface_data **data_ret)
{
struct shm_surface_data *data;
struct shm_pool *pool;
cairo_surface_t *surface;
- if (window && window->pool) {
- shm_pool_reset(window->pool);
+ if (alternate_pool) {
+ shm_pool_reset(alternate_pool);
surface = display_create_shm_surface_from_pool(display,
rectangle,
flags,
- window->pool);
- if (surface)
- return surface;
+ alternate_pool);
+ if (surface) {
+ data = cairo_surface_get_user_data(surface,
+ &shm_surface_data_key);
+ goto out;
+ }
}
pool = shm_pool_create(display,
@@ -727,6 +732,10 @@ display_create_shm_surface(struct display *display,
data = cairo_surface_get_user_data(surface, &shm_surface_data_key);
data->pool = pool;
+out:
+ if (data_ret)
+ *data_ret = data;
+
return surface;
}
@@ -751,7 +760,147 @@ display_create_surface(struct display *display,
return NULL;
assert(flags & SURFACE_SHM);
- return display_create_shm_surface(display, rectangle, flags, NULL);
+ return display_create_shm_surface(display, rectangle, flags,
+ NULL, NULL);
+}
+
+struct shm_surface {
+ struct toysurface base;
+ struct display *display;
+ struct wl_surface *surface;
+ uint32_t flags;
+ int dx, dy;
+
+ cairo_surface_t *cairo_surface;
+ /* 'data' is automatically destroyed, when 'cairo_surface' is */
+ struct shm_surface_data *data;
+
+ struct shm_pool *resize_pool;
+};
+
+static struct shm_surface *
+to_shm_surface(struct toysurface *base)
+{
+ return container_of(base, struct shm_surface, base);
+}
+
+static cairo_surface_t *
+shm_surface_prepare(struct toysurface *base, int dx, int dy,
+ int width, int height, int resize_hint)
+{
+ struct shm_surface *surface = to_shm_surface(base);
+ struct rectangle rect = { 0, 0, width, height };
+
+ surface->dx = dx;
+ surface->dy = dy;
+
+ if (!resize_hint && surface->resize_pool) {
+ cairo_surface_destroy(surface->cairo_surface);
+ shm_pool_destroy(surface->resize_pool);
+ surface->resize_pool = NULL;
+ surface->cairo_surface = NULL;
+ }
+
+ if (surface->cairo_surface &&
+ cairo_image_surface_get_width(surface->cairo_surface) == width &&
+ cairo_image_surface_get_height(surface->cairo_surface) == height)
+ goto out;
+
+ if (surface->cairo_surface)
+ cairo_surface_destroy(surface->cairo_surface);
+
+ if (resize_hint && !surface->resize_pool) {
+ /* Create a big pool to allocate from, while continuously
+ * resizing. Mmapping a new pool in the server
+ * is relatively expensive, so reusing a pool performs
+ * better, but may temporarily reserve unneeded memory.
+ */
+ /* We should probably base this number on the output size. */
+ surface->resize_pool = shm_pool_create(surface->display,
+ 6 * 1024 * 1024);
+ }
+
+ surface->cairo_surface =
+ display_create_shm_surface(surface->display, &rect,
+ surface->flags,
+ surface->resize_pool,
+ &surface->data);
+
+out:
+ return cairo_surface_reference(surface->cairo_surface);
+}
+
+static void
+shm_surface_swap(struct toysurface *base,
+ struct rectangle *server_allocation)
+{
+ struct shm_surface *surface = to_shm_surface(base);
+
+ server_allocation->width =
+ cairo_image_surface_get_width(surface->cairo_surface);
+ server_allocation->height =
+ cairo_image_surface_get_height(surface->cairo_surface);
+
+ wl_surface_attach(surface->surface, surface->data->buffer,
+ surface->dx, surface->dy);
+ wl_surface_damage(surface->surface, 0, 0,
+ server_allocation->width, server_allocation->height);
+ wl_surface_commit(surface->surface);
+}
+
+static int
+shm_surface_acquire(struct toysurface *base, EGLContext ctx)
+{
+ return -1;
+}
+
+static void
+shm_surface_release(struct toysurface *base)
+{
+}
+
+static void
+shm_surface_destroy(struct toysurface *base)
+{
+ struct shm_surface *surface = to_shm_surface(base);
+
+ /* this destroys surface->data, too */
+ cairo_surface_destroy(surface->cairo_surface);
+
+ if (surface->resize_pool)
+ shm_pool_destroy(surface->resize_pool);
+
+ free(surface);
+}
+
+static struct toysurface *
+shm_surface_create(struct display *display, struct wl_surface *wl_surface,
+ uint32_t flags, struct rectangle *rectangle)
+{
+ struct shm_surface *surface;
+
+ surface = calloc(1, sizeof *surface);
+ if (!surface)
+ return NULL;
+
+ surface->base.prepare = shm_surface_prepare;
+ surface->base.swap = shm_surface_swap;
+ surface->base.acquire = shm_surface_acquire;
+ surface->base.release = shm_surface_release;
+ surface->base.destroy = shm_surface_destroy;
+
+ surface->display = display;
+ surface->surface = wl_surface;
+ surface->flags = flags;
+ surface->cairo_surface = display_create_shm_surface(display, rectangle,
+ flags, NULL,
+ &surface->data);
+ if (!surface->cairo_surface) {
+ free(surface);
+ return NULL;
+ }
+
+ return &surface->base;
}
/*
@@ -924,8 +1073,6 @@ static void
window_attach_surface(struct window *window)
{
struct display *display = window->display;
- struct wl_buffer *buffer;
- int32_t x, y;
if (window->type == TYPE_NONE) {
window->type = TYPE_TOPLEVEL;
@@ -947,29 +1094,8 @@ window_attach_surface(struct window *window)
window->input_region = NULL;
}
- switch (window->buffer_type) {
-#ifdef HAVE_CAIRO_EGL
- case WINDOW_BUFFER_TYPE_EGL_WINDOW:
- window->toysurface->swap(window->toysurface,
- &window->server_allocation);
- break;
-#endif
- case WINDOW_BUFFER_TYPE_SHM:
- buffer =
- display_get_buffer_for_surface(display,
- window->cairo_surface);
-
- window_get_resize_dx_dy(window, &x, &y);
- wl_surface_attach(window->surface, buffer, x, y);
- wl_surface_damage(window->surface, 0, 0,
- window->allocation.width,
- window->allocation.height);
- wl_surface_commit(window->surface);
- window->server_allocation = window->allocation;
- break;
- default:
- return;
- }
+ window->toysurface->swap(window->toysurface,
+ &window->server_allocation);
}
int
@@ -989,17 +1115,6 @@ window_flush(struct window *window)
window->cairo_surface = NULL;
}
-static void
-window_set_surface(struct window *window, cairo_surface_t *surface)
-{
- cairo_surface_reference(surface);
-
- if (window->cairo_surface != NULL)
- cairo_surface_destroy(window->cairo_surface);
-
- window->cairo_surface = surface;
-}
-
struct display *
window_get_display(struct window *window)
{
@@ -1009,8 +1124,8 @@ window_get_display(struct window *window)
static void
window_create_surface(struct window *window)
{
- cairo_surface_t *surface;
uint32_t flags = 0;
+ int dx, dy;
if (!window->transparent)
flags = SURFACE_OPAQUE;
@@ -1025,30 +1140,25 @@ window_create_surface(struct window *window)
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);
+ if (window->toysurface)
break;
- }
/* fall through */
#endif
case WINDOW_BUFFER_TYPE_SHM:
- surface = display_create_shm_surface(window->display,
- &window->allocation,
- flags, window);
- break;
- default:
- surface = NULL;
+ window->toysurface = shm_surface_create(window->display,
+ window->surface, flags,
+ &window->allocation);
break;
+ default:
+ assert(0);
}
- window_set_surface(window, surface);
- cairo_surface_destroy(surface);
+ window_get_resize_dx_dy(window, &dx, &dy);
+ window->cairo_surface =
+ window->toysurface->prepare(window->toysurface, dx, dy,
+ window->allocation.width,
+ window->allocation.height,
+ window->resizing);
}
static void frame_destroy(struct frame *frame);
@@ -1092,9 +1202,6 @@ window_destroy(struct window *window)
wl_surface_destroy(window->surface);
wl_list_remove(&window->link);
- if (window->cairo_surface != NULL)
- cairo_surface_destroy(window->cairo_surface);
-
if (window->toysurface)
window->toysurface->destroy(window->toysurface);
@@ -1958,15 +2065,7 @@ frame_button_handler(struct widget *widget,
break;
input_ungrab(input);
- if (!display->dpy) {
- /* If we're using shm, allocate a big
- pool to create buffers out of while
- we resize. We should probably base
- this number on the size of the output. */
- window->pool =
- shm_pool_create(display, 6 * 1024 * 1024);
- }
-
+ window->resizing = 1;
wl_shell_surface_resize(window->shell_surface,
input_get_seat(input),
display->serial, location);
@@ -2140,9 +2239,8 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer,
input->pointer_focus = wl_surface_get_user_data(surface);
window = input->pointer_focus;
- if (window->pool) {
- shm_pool_destroy(window->pool);
- window->pool = NULL;
+ if (window->resizing) {
+ window->resizing = 0;
/* Schedule a redraw to free the pool */
window_schedule_redraw(window);
}
--
1.7.8.6
More information about the wayland-devel
mailing list