[PATCH weston 6/6] window: honour wl_buffer.release

Kristian Høgsberg hoegsberg at gmail.com
Tue Nov 27 12:57:30 PST 2012


On Mon, Nov 19, 2012 at 05:16:02PM +0200, Pekka Paalanen wrote:
> 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;

If we end up with both buffers released, should we
shm_surface_leaf_release() it?

> +}
> +
> +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