[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