From ccfeae2ad7e024c04676fff0563a34fe04edb301 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Tue, 4 Dec 2012 15:58:14 +0200 Subject: [PATCH] compositor: add early wl_buffer.release A client can reliably avoid allocating a second buffer per surface, if the compositor sends the wl_buffer.release event before the frame callback. To enable clients' single-buffering, release the wl_buffer early if possible. Otherwise clients will double-buffer. Releasing early is not possible, if the backend needs the buffer for migrating a surface to or from a non-primary weston_plane. In that case, a new buffer must arrive, before the old can be released. Backends will indicate this by setting weston_surface:keep_buffer to 1 in assign_planes(). A proper buffer reference in the backends would be better than the keep_buffer flag, but that would require a per-surface backend private. The rpi and DRM backends are updated to set keep_buffer, other backends do not support planes, so do not have to set it. Signed-off-by: Pekka Paalanen --- src/compositor-drm.c | 10 ++++++++++ src/compositor-rpi.c | 3 +++ src/compositor.c | 14 +++++++++++++- src/compositor.h | 1 + 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/compositor-drm.c b/src/compositor-drm.c index da36cd3f..11d99818 100644 --- a/src/compositor-drm.c +++ b/src/compositor-drm.c @@ -805,6 +805,16 @@ drm_assign_planes(struct weston_output *output) pixman_region32_init(&overlap); primary = &c->base.primary_plane; wl_list_for_each_safe(es, next, &c->base.surface_list, link) { + /* test whether this buffer can ever go into a plane: + * non-shm, or small enough to be a cursor + */ + if ((es->buffer_ref.buffer && + !wl_buffer_is_shm(es->buffer_ref.buffer)) || + (es->geometry.width <= 64 && es->geometry.height <= 64)) + es->keep_buffer = 1; + else + es->keep_buffer = 0; + pixman_region32_init(&surface_overlap); pixman_region32_intersect(&surface_overlap, &overlap, &es->transform.boundingbox); diff --git a/src/compositor-rpi.c b/src/compositor-rpi.c index e77c5c6f..df9ce79d 100644 --- a/src/compositor-rpi.c +++ b/src/compositor-rpi.c @@ -798,6 +798,9 @@ rpi_output_assign_planes(struct weston_output *base) pixman_region32_init(&overlap); wl_list_for_each(surface, &compositor->base.surface_list, link) { + /* always, since all buffers are shm on rpi */ + surface->keep_buffer = 1; + pixman_region32_init(&surface_overlap); pixman_region32_intersect(&surface_overlap, &overlap, &surface->transform.boundingbox); diff --git a/src/compositor.c b/src/compositor.c index 869fffa2..38bc6bc5 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -1084,9 +1084,21 @@ weston_output_repaint(struct weston_output *output, uint32_t msecs) pixman_region32_fini(&ec->primary_plane.opaque); pixman_region32_init(&ec->primary_plane.opaque); - wl_list_for_each(es, &ec->surface_list, link) + wl_list_for_each(es, &ec->surface_list, link) { surface_accumulate_damage(es, &opaque); + /* Both the renderer and the backend have seen the buffer + * by now. If renderer needs the buffer, it has its own + * reference set. If the backend wants to keep the buffer + * around for migrating the surface into a non-primary plane + * later, keep_buffer is true. Otherwise, drop the core + * reference now, and allow early buffer release. This enables + * clients to use single-buffering. + */ + if (!es->keep_buffer) + weston_buffer_reference(&es->buffer_ref, NULL); + } + pixman_region32_fini(&opaque); pixman_region32_init(&output_damage); diff --git a/src/compositor.h b/src/compositor.h index 53f9cfb7..bbf9bde9 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -444,6 +444,7 @@ struct weston_surface { struct weston_buffer_reference buffer_ref; uint32_t buffer_transform; + int keep_buffer; /* bool for backends to prevent early release */ /* All the pending state, that wl_surface.commit will apply. */ struct {