summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPekka Paalanen <ppaalanen@gmail.com>2013-04-25 13:57:47 +0300
committerKristian Høgsberg <krh@bitplanet.net>2013-05-10 14:35:53 -0400
commitaef0254dd58bcfd4310f5e3986c3485f32d48284 (patch)
tree9565062ade8239dc68fa3a6e40e713af50c0eefc
parentb836664c4249d496416f7c8a99dac03d04a3cf77 (diff)
window: implement shm triple-buffering
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 synchronized commit mode. To be able to forcibly repaint at that situation for e.g. resize, we need a third buffer. Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
-rw-r--r--clients/window.c66
1 files changed, 41 insertions, 25 deletions
diff --git a/clients/window.c b/clients/window.c
index 2540cc9a..695cf5d6 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -820,6 +820,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;
@@ -827,7 +829,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;
};
@@ -841,16 +843,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 = {
@@ -864,25 +882,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;
}
@@ -964,9 +979,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);
}