[PATCH weston 6/6] window: honour wl_buffer.release
Pekka Paalanen
ppaalanen at gmail.com
Mon Nov 19 07:16:02 PST 2012
Listen for wl_buffer.release events in the shm path, and if a previously
posted buffer is still held by the server, allocate another one. The
maximum of two should be enough, since there is no point for a server to
hold more than one buffer at a time.
Buffer allocation happens as needed instead of window creation time.
Signed-off-by: Pekka Paalanen <ppaalanen at gmail.com>
---
clients/window.c | 113 ++++++++++++++++++++++++++++++++++++------------------
1 files changed, 76 insertions(+), 37 deletions(-)
diff --git a/clients/window.c b/clients/window.c
index bda6866..0279aae 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -782,6 +782,26 @@ display_create_surface(struct display *display,
NULL, NULL);
}
+struct shm_surface_leaf {
+ cairo_surface_t *cairo_surface;
+ /* 'data' is automatically destroyed, when 'cairo_surface' is */
+ struct shm_surface_data *data;
+
+ struct shm_pool *resize_pool;
+ int busy;
+};
+
+static void
+shm_surface_leaf_release(struct shm_surface_leaf *leaf)
+{
+ if (leaf->cairo_surface)
+ cairo_surface_destroy(leaf->cairo_surface);
+ /* leaf->data already destroyed via cairo private */
+
+ if (leaf->resize_pool)
+ shm_pool_destroy(leaf->resize_pool);
+}
+
struct shm_surface {
struct toysurface base;
struct display *display;
@@ -789,11 +809,8 @@ struct shm_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;
+ struct shm_surface_leaf leaf[2];
+ struct shm_surface_leaf *current;
};
static struct shm_surface *
@@ -802,50 +819,78 @@ to_shm_surface(struct toysurface *base)
return container_of(base, struct shm_surface, base);
}
+static void
+shm_surface_buffer_release(void *data, struct wl_buffer *buffer)
+{
+ struct shm_surface_leaf *leaf = data;
+
+ leaf->busy = 0;
+}
+
+static const struct wl_buffer_listener shm_surface_buffer_listener = {
+ shm_surface_buffer_release
+};
+
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 };
+ struct shm_surface_leaf *leaf;
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;
+ /* pick a free buffer from the two */
+ if (!surface->leaf[0].busy)
+ leaf = &surface->leaf[0];
+ else if (!surface->leaf[1].busy)
+ leaf = &surface->leaf[1];
+ else {
+ fprintf(stderr, "%s: both buffers are held by the server.\n",
+ __func__);
+ return NULL;
+ }
+
+ if (!resize_hint && leaf->resize_pool) {
+ cairo_surface_destroy(leaf->cairo_surface);
+ leaf->cairo_surface = NULL;
+ shm_pool_destroy(leaf->resize_pool);
+ leaf->resize_pool = NULL;
}
- if (surface->cairo_surface &&
- cairo_image_surface_get_width(surface->cairo_surface) == width &&
- cairo_image_surface_get_height(surface->cairo_surface) == height)
+ if (leaf->cairo_surface &&
+ cairo_image_surface_get_width(leaf->cairo_surface) == width &&
+ cairo_image_surface_get_height(leaf->cairo_surface) == height)
goto out;
- if (surface->cairo_surface)
- cairo_surface_destroy(surface->cairo_surface);
+ if (leaf->cairo_surface)
+ cairo_surface_destroy(leaf->cairo_surface);
- if (resize_hint && !surface->resize_pool) {
+ if (resize_hint && !leaf->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);
+ leaf->resize_pool = shm_pool_create(surface->display,
+ 6 * 1024 * 1024);
}
- surface->cairo_surface =
+ leaf->cairo_surface =
display_create_shm_surface(surface->display, &rect,
surface->flags,
- surface->resize_pool,
- &surface->data);
+ leaf->resize_pool,
+ &leaf->data);
+ wl_buffer_add_listener(leaf->data->buffer,
+ &shm_surface_buffer_listener, leaf);
out:
- return cairo_surface_reference(surface->cairo_surface);
+ surface->current = leaf;
+
+ return cairo_surface_reference(leaf->cairo_surface);
}
static void
@@ -853,17 +898,21 @@ shm_surface_swap(struct toysurface *base,
struct rectangle *server_allocation)
{
struct shm_surface *surface = to_shm_surface(base);
+ struct shm_surface_leaf *leaf = surface->current;
server_allocation->width =
- cairo_image_surface_get_width(surface->cairo_surface);
+ cairo_image_surface_get_width(leaf->cairo_surface);
server_allocation->height =
- cairo_image_surface_get_height(surface->cairo_surface);
+ cairo_image_surface_get_height(leaf->cairo_surface);
- wl_surface_attach(surface->surface, surface->data->buffer,
+ wl_surface_attach(surface->surface, leaf->data->buffer,
surface->dx, surface->dy);
wl_surface_damage(surface->surface, 0, 0,
server_allocation->width, server_allocation->height);
wl_surface_commit(surface->surface);
+
+ leaf->busy = 1;
+ surface->current = NULL;
}
static int
@@ -882,11 +931,8 @@ 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);
+ shm_surface_leaf_release(&surface->leaf[0]);
+ shm_surface_leaf_release(&surface->leaf[1]);
free(surface);
}
@@ -910,13 +956,6 @@ shm_surface_create(struct display *display, struct wl_surface *wl_surface,
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;
}
--
1.7.8.6
More information about the wayland-devel
mailing list