From ddc2b1ec326e7b1a178cf5aebf871985fb6b8aca Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Thu, 12 Dec 2013 12:57:56 +0100 Subject: [PATCH] pixman: Destroy pixman images when underlying buffer is destroyed While the pixman image might be attached, the underlying buffer might be already gone under certain circumstances. This is easily reproduced by attempting to resize gnome-terminal on a fbdev backend. $ WAYLAND_DEBUG=1 strace -emunmap weston --backend=fbdev-backend.so ... [1524826.942] wl_shm@7.create_pool(new id wl_shm_pool@23, fd 40, 1563540) [1524827.315] wl_shm_pool@23.create_buffer(new id wl_buffer@24, 0, 759, 515, 3036, 0) ... [1524829.488] wl_surface@14.attach(wl_buffer@24, 0, 0) [1524829.766] wl_surface@14.set_buffer_scale(1) [1524829.904] wl_surface@14.damage(0, 0, 759, 515) [1524830.248] wl_surface@14.frame(new id wl_callback@25) [1524830.450] wl_surface@14.commit() ... [1524846.706] wl_shm@7.create_pool(new id wl_shm_pool@26, fd 40, 1545000) [1524847.215] wl_shm_pool@26.create_buffer(new id wl_buffer@27, 0, 750, 515, 3000, 0) [1524847.735] wl_buffer@24.destroy() [1524847.953] -> wl_display@1.delete_id(24) [1524848.144] wl_shm_pool@23.destroy() munmap(0xb5b2e000, 1563540) = 0 [1524849.021] -> wl_display@1.delete_id(23) [1524849.425] wl_surface@14.attach(wl_buffer@27, 0, 0) [1524849.730] wl_surface@14.set_buffer_scale(1) [1524849.821] wl_surface@14.damage(0, 0, 750, 515) Signed-off-by: Lubomir Rintel --- src/pixman-renderer.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/pixman-renderer.c b/src/pixman-renderer.c index 7a695787..129affcd 100644 --- a/src/pixman-renderer.c +++ b/src/pixman-renderer.c @@ -42,6 +42,7 @@ struct pixman_surface_state { pixman_image_t *image; struct weston_buffer_reference buffer_ref; + struct wl_listener buffer_destroy_listener; struct wl_listener surface_destroy_listener; struct wl_listener renderer_destroy_listener; }; @@ -467,6 +468,22 @@ pixman_renderer_flush_damage(struct weston_surface *surface) /* No-op for pixman renderer */ } +static void +buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data) +{ + struct pixman_surface_state *ps; + + ps = container_of(listener, struct pixman_surface_state, + buffer_destroy_listener); + + if (ps->image) { + pixman_image_unref(ps->image); + ps->image = NULL; + } + + ps->buffer_destroy_listener.notify = NULL; +} + static void pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer) { @@ -476,6 +493,11 @@ pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer) weston_buffer_reference(&ps->buffer_ref, buffer); + if (ps->buffer_destroy_listener.notify) { + wl_list_remove(&ps->buffer_destroy_listener.link); + ps->buffer_destroy_listener.notify = NULL; + } + if (ps->image) { pixman_image_unref(ps->image); ps->image = NULL; @@ -517,6 +539,11 @@ pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer) buffer->width, buffer->height, wl_shm_buffer_get_data(shm_buffer), wl_shm_buffer_get_stride(shm_buffer)); + + ps->buffer_destroy_listener.notify = + buffer_state_handle_buffer_destroy; + wl_signal_add(&buffer->destroy_signal, + &ps->buffer_destroy_listener); } static void @@ -524,7 +551,10 @@ pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps) { wl_list_remove(&ps->surface_destroy_listener.link); wl_list_remove(&ps->renderer_destroy_listener.link); - + if (ps->buffer_destroy_listener.notify) { + wl_list_remove(&ps->buffer_destroy_listener.link); + ps->buffer_destroy_listener.notify = NULL; + } ps->surface->renderer_state = NULL;