[PATCH weston] simple-shm: honour wl_buffer.release

Kristian Høgsberg hoegsberg at gmail.com
Mon Nov 19 12:56:23 PST 2012


On Mon, Nov 19, 2012 at 03:29:09PM +0200, Pekka Paalanen wrote:
> Change simple-shm to properly process the wl_buffer.release event, and
> not reuse a buffer until it is released by the server, as specified in
> the protocol.
> 
> In case the server has not released the buffer, but signals that it has
> been shown (frame callback), allocate a second buffer. Simple-shm will
> now automatically do double-buffering if needed.

Looks fine, but simple-shm is less and less simple.

Kristian

> Signed-off-by: Pekka Paalanen <ppaalanen at gmail.com>
> ---
>  clients/simple-shm.c |  113 ++++++++++++++++++++++++++++++++++++++-----------
>  1 files changed, 87 insertions(+), 26 deletions(-)
> 
> diff --git a/clients/simple-shm.c b/clients/simple-shm.c
> index a09ec91..5bc26bf 100644
> --- a/clients/simple-shm.c
> +++ b/clients/simple-shm.c
> @@ -42,22 +42,39 @@ struct display {
>  	uint32_t formats;
>  };
>  
> +struct buffer {
> +	struct wl_buffer *buffer;
> +	void *shm_data;
> +	int busy;
> +};
> +
>  struct window {
>  	struct display *display;
>  	int width, height;
>  	struct wl_surface *surface;
>  	struct wl_shell_surface *shell_surface;
> -	struct wl_buffer *buffer;
> -	void *shm_data;
> +	struct buffer buffers[2];
> +	struct buffer *prev_buffer;
>  	struct wl_callback *callback;
>  };
>  
> -static struct wl_buffer *
> -create_shm_buffer(struct display *display,
> -		  int width, int height, uint32_t format, void **data_out)
> +static void
> +buffer_release(void *data, struct wl_buffer *buffer)
> +{
> +	struct buffer *mybuf = data;
> +
> +	mybuf->busy = 0;
> +}
> +
> +static const struct wl_buffer_listener buffer_listener = {
> +	buffer_release
> +};
> +
> +static int
> +create_shm_buffer(struct display *display, struct buffer *buffer,
> +		  int width, int height, uint32_t format)
>  {
>  	struct wl_shm_pool *pool;
> -	struct wl_buffer *buffer;
>  	int fd, size, stride;
>  	void *data;
>  
> @@ -68,25 +85,27 @@ create_shm_buffer(struct display *display,
>  	if (fd < 0) {
>  		fprintf(stderr, "creating a buffer file for %d B failed: %m\n",
>  			size);
> -		return NULL;
> +		return -1;
>  	}
>  
>  	data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
>  	if (data == MAP_FAILED) {
>  		fprintf(stderr, "mmap failed: %m\n");
>  		close(fd);
> -		return NULL;
> +		return -1;
>  	}
>  
>  	pool = wl_shm_create_pool(display->shm, fd, size);
> -	buffer = wl_shm_pool_create_buffer(pool, 0,
> -					   width, height, stride, format);
> +	buffer->buffer = wl_shm_pool_create_buffer(pool, 0,
> +						   width, height,
> +						   stride, format);
> +	wl_buffer_add_listener(buffer->buffer, &buffer_listener, buffer);
>  	wl_shm_pool_destroy(pool);
>  	close(fd);
>  
> -	*data_out = data;
> +	buffer->shm_data = data;
>  
> -	return buffer;
> +	return 0;
>  }
>  
>  static void
> @@ -117,18 +136,10 @@ static struct window *
>  create_window(struct display *display, int width, int height)
>  {
>  	struct window *window;
> -	
> -	window = malloc(sizeof *window);
> -
> -	window->buffer = create_shm_buffer(display,
> -					   width, height,
> -					   WL_SHM_FORMAT_XRGB8888,
> -					   &window->shm_data);
>  
> -	if (!window->buffer) {
> -		free(window);
> +	window = calloc(1, sizeof *window);
> +	if (!window)
>  		return NULL;
> -	}
>  
>  	window->callback = NULL;
>  	window->display = display;
> @@ -155,12 +166,45 @@ destroy_window(struct window *window)
>  	if (window->callback)
>  		wl_callback_destroy(window->callback);
>  
> -	wl_buffer_destroy(window->buffer);
> +	if (window->buffers[0].buffer)
> +		wl_buffer_destroy(window->buffers[0].buffer);
> +	if (window->buffers[1].buffer)
> +		wl_buffer_destroy(window->buffers[1].buffer);
> +
>  	wl_shell_surface_destroy(window->shell_surface);
>  	wl_surface_destroy(window->surface);
>  	free(window);
>  }
>  
> +static struct buffer *
> +window_next_buffer(struct window *window)
> +{
> +	struct buffer *buffer;
> +	int ret = 0;
> +
> +	if (!window->buffers[0].busy)
> +		buffer = &window->buffers[0];
> +	else if (!window->buffers[1].busy)
> +		buffer = &window->buffers[1];
> +	else
> +		return NULL;
> +
> +	if (!buffer->buffer) {
> +		ret = create_shm_buffer(window->display, buffer,
> +					window->width, window->height,
> +					WL_SHM_FORMAT_XRGB8888);
> +
> +		if (ret < 0)
> +			return NULL;
> +
> +		/* paint the padding */
> +		memset(buffer->shm_data, 0xff,
> +		       window->width * window->height * 4);
> +	}
> +
> +	return buffer;
> +}
> +
>  static void
>  paint_pixels(void *image, int padding, int width, int height, uint32_t time)
>  {
> @@ -213,8 +257,23 @@ static void
>  redraw(void *data, struct wl_callback *callback, uint32_t time)
>  {
>  	struct window *window = data;
> +	struct buffer *buffer;
> +
> +	buffer = window_next_buffer(window);
> +	if (!buffer) {
> +		fprintf(stderr,
> +			!callback ? "Failed to create the first buffer.\n" :
> +			"Both buffers busy at redraw(). Server bug?\n");
> +		abort();
> +	}
> +
> +	paint_pixels(buffer->shm_data, 20, window->width, window->height, time);
> +
> +	if (window->prev_buffer != buffer) {
> +		wl_surface_attach(window->surface, buffer->buffer, 0, 0);
> +		window->prev_buffer = buffer;
> +	}
>  
> -	paint_pixels(window->shm_data, 20, window->width, window->height, time);
>  	wl_surface_damage(window->surface,
>  			  20, 20, window->width - 40, window->height - 40);
>  
> @@ -224,6 +283,7 @@ redraw(void *data, struct wl_callback *callback, uint32_t time)
>  	window->callback = wl_surface_frame(window->surface);
>  	wl_callback_add_listener(window->callback, &frame_listener, window);
>  	wl_surface_commit(window->surface);
> +	buffer->busy = 1;
>  }
>  
>  static const struct wl_callback_listener frame_listener = {
> @@ -340,8 +400,9 @@ main(int argc, char **argv)
>  	sigint.sa_flags = SA_RESETHAND;
>  	sigaction(SIGINT, &sigint, NULL);
>  
> -	memset(window->shm_data, 0xff, window->width * window->height * 4);
> -	wl_surface_attach(window->surface, window->buffer, 0, 0);
> +	/* Initialise damage to full surface, so the padding gets painted */
> +	wl_surface_damage(window->surface, 0, 0,
> +			  window->width, window->height);
>  
>  	redraw(window, NULL, 0);
>  
> -- 
> 1.7.8.6
> 


More information about the wayland-devel mailing list