[RFC Weston 06/10] window: implement shm triple-buffering

Pekka Paalanen ppaalanen at gmail.com
Fri Feb 22 07:07:50 PST 2013


Increase the maximum number of shm "leaves" to three, and rewrite the
leaf release and pick algorithms. The new algorithms hopefully improve
on buffer re-use while freeing unused buffers.

The goal of the new release algorithm is to always leave one free leaf
with storage allocated, so that the next redraw could start straight on
it.

The new leaf picking algorithm will prefer a free leaf that already has
some storage allocated, instead of just picking the first free leaf that
may need to allocate a new buffer.

Triple-buffering is especially for sub-surfaces, where the compositor
may have one wl_buffer busy on screen, and another wl_buffer busy in the
sub-surface cached state due to the parent-cached commit mode. To be
able to forcibly repaint at that situation for e.g. resize, we need a
third buffer.
---
 clients/window.c | 66 +++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 41 insertions(+), 25 deletions(-)

diff --git a/clients/window.c b/clients/window.c
index 249ba6f..d17fc2f 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -818,6 +818,8 @@ shm_surface_leaf_release(struct shm_surface_leaf *leaf)
 	memset(leaf, 0, sizeof *leaf);
 }
 
+#define MAX_LEAVES 3
+
 struct shm_surface {
 	struct toysurface base;
 	struct display *display;
@@ -825,7 +827,7 @@ struct shm_surface {
 	uint32_t flags;
 	int dx, dy;
 
-	struct shm_surface_leaf leaf[2];
+	struct shm_surface_leaf leaf[MAX_LEAVES];
 	struct shm_surface_leaf *current;
 };
 
@@ -839,16 +841,32 @@ static void
 shm_surface_buffer_release(void *data, struct wl_buffer *buffer)
 {
 	struct shm_surface *surface = data;
+	struct shm_surface_leaf *leaf;
+	int i;
+	int free_found;
 
-	if (surface->leaf[0].data->buffer == buffer)
-		surface->leaf[0].busy = 0;
-	else if (surface->leaf[1].data->buffer == buffer)
-		surface->leaf[1].busy = 0;
-	else
-		assert(0 && "shm_surface_buffer_release: unknown buffer");
+	for (i = 0; i < MAX_LEAVES; i++) {
+		leaf = &surface->leaf[i];
+		if (leaf->data && leaf->data->buffer == buffer) {
+			leaf->busy = 0;
+			break;
+		}
+	}
+	assert(i < MAX_LEAVES && "unknown buffer released");
+
+	/* Leave one free leaf with storage, release others */
+	free_found = 0;
+	for (i = 0; i < MAX_LEAVES; i++) {
+		leaf = &surface->leaf[i];
+
+		if (!leaf->cairo_surface || leaf->busy)
+			continue;
 
-	if (!surface->leaf[0].busy && !surface->leaf[1].busy)
-		shm_surface_leaf_release(&surface->leaf[1]);
+		if (!free_found)
+			free_found = 1;
+		else
+			shm_surface_leaf_release(leaf);
+	}
 }
 
 static const struct wl_buffer_listener shm_surface_buffer_listener = {
@@ -862,25 +880,22 @@ shm_surface_prepare(struct toysurface *base, int dx, int dy,
 	int resize_hint = !!(flags & SURFACE_HINT_RESIZE);
 	struct shm_surface *surface = to_shm_surface(base);
 	struct rectangle rect = { 0, 0, width, height };
-	struct shm_surface_leaf *leaf;
+	struct shm_surface_leaf *leaf = NULL;
+	int i;
 
 	surface->dx = dx;
 	surface->dy = dy;
 
-	/* See shm_surface_buffer_release() */
-	if (!surface->leaf[0].busy && !surface->leaf[1].busy &&
-	    surface->leaf[1].cairo_surface) {
-		fprintf(stderr, "window.c:%s: TODO: release leaf[1]\n",
-			__func__);
-	}
+	/* pick a free buffer, preferrably one that already has storage */
+	for (i = 0; i < MAX_LEAVES; i++) {
+		if (surface->leaf[i].busy)
+			continue;
 
-	/* pick a free buffer from the two */
-	if (!surface->leaf[0].busy)
-		leaf = &surface->leaf[0];
-	else if (!surface->leaf[1].busy)
-		leaf = &surface->leaf[1];
-	else {
-		fprintf(stderr, "%s: both buffers are held by the server.\n",
+		if (!leaf || surface->leaf[i].cairo_surface)
+			leaf = &surface->leaf[i];
+	}
+	if (!leaf) {
+		fprintf(stderr, "%s: all buffers are held by the server.\n",
 			__func__);
 		return NULL;
 	}
@@ -962,9 +977,10 @@ static void
 shm_surface_destroy(struct toysurface *base)
 {
 	struct shm_surface *surface = to_shm_surface(base);
+	int i;
 
-	shm_surface_leaf_release(&surface->leaf[0]);
-	shm_surface_leaf_release(&surface->leaf[1]);
+	for (i = 0; i < MAX_LEAVES; i++)
+		shm_surface_leaf_release(&surface->leaf[i]);
 
 	free(surface);
 }
-- 
1.7.12.4



More information about the wayland-devel mailing list