[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