[PATCH weston 3/6] window: convert shm path to toysurface

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


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

Let's make this a uint32_t flags argument instead.

>  
>  	/*
>  	 * 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