compositor: add early wl_buffer.release
authorPekka Paalanen <ppaalanen@gmail.com>
Tue, 4 Dec 2012 13:58:14 +0000 (15:58 +0200)
committerKristian Høgsberg <krh@bitplanet.net>
Thu, 6 Dec 2012 21:55:41 +0000 (16:55 -0500)
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 <ppaalanen@gmail.com>
src/compositor-drm.c
src/compositor-rpi.c
src/compositor.c
src/compositor.h

index da36cd3..11d9981 100644 (file)
@@ -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);
index e77c5c6..df9ce79 100644 (file)
@@ -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);
index 869fffa..38bc6bc 100644 (file)
@@ -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);
index 53f9cfb..bbf9bde 100644 (file)
@@ -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 {