From 44f36e3585cf7bb1ba8e73febabb7facf5cd6151 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Kristian=20H=C3=B8gsberg?= Date: Wed, 26 Nov 2008 12:57:31 -0500 Subject: [PATCH] Make ack event signal that the requests have been composited. --- egl-compositor.c | 2 + flower.c | 22 ++++++---- wayland.c | 34 ++++++++++++--- wayland.h | 2 + window.c | 125 ++++++++++++++++++++++++++++--------------------------- 5 files changed, 111 insertions(+), 74 deletions(-) diff --git a/egl-compositor.c b/egl-compositor.c index 57b56ce..132fcbd 100644 --- a/egl-compositor.c +++ b/egl-compositor.c @@ -541,6 +541,8 @@ repaint(void *data) eglSwapBuffers(ec->display, ec->surface); + wl_display_post_acknowledge(ec->wl_display); + animate_overlay(ec); } diff --git a/flower.c b/flower.c index e6c2e27..3356fc4 100644 --- a/flower.c +++ b/flower.c @@ -82,23 +82,30 @@ draw_stuff(int width, int height) } struct flower { + struct wl_display *display; struct wl_surface *surface; int i; int x, y, width, height; }; -static gboolean -move_flower(gpointer data) +static void +move_flower(struct flower *flower) { - struct flower *flower = data; - wl_surface_map(flower->surface, flower->x + cos(flower->i / 31.0) * 400 - flower->width / 2, flower->y + sin(flower->i / 27.0) * 300 - flower->height / 2, flower->width, flower->height); flower->i++; + wl_display_commit(flower->display, 0); +} - return TRUE; +static void +event_handler(struct wl_display *display, + uint32_t object, uint32_t opcode, + uint32_t size, uint32_t *p, void *data) +{ + if (object == 1) + move_flower(data); } int main(int argc, char *argv[]) @@ -129,6 +136,7 @@ int main(int argc, char *argv[]) source = wayland_source_new(display); g_source_attach(source, NULL); + flower.display = display; flower.x = 512; flower.y = 384; flower.width = 200; @@ -144,8 +152,8 @@ int main(int argc, char *argv[]) wl_surface_attach(flower.surface, buffer->name, flower.width, flower.height, buffer->stride); - - g_timeout_add(20, move_flower, &flower); + wl_display_set_event_handler(display, event_handler, &flower); + move_flower(&flower); g_main_loop_run(loop); diff --git a/wayland.c b/wayland.c index 766dc0a..c33d135 100644 --- a/wayland.c +++ b/wayland.c @@ -19,6 +19,8 @@ struct wl_client { struct wl_display *display; struct wl_list object_list; struct wl_list link; + uint32_t pending_acknowledge; + uint32_t acknowledge_key; }; struct wl_display { @@ -500,12 +502,8 @@ static int wl_display_commit(struct wl_client *client, struct wl_display *display, uint32_t key) { - uint32_t event[3]; - - event[0] = display->base.id; - event[1] = WL_DISPLAY_ACKNOWLEDGE | ((sizeof event) << 16); - event[2] = key; - wl_connection_write(client->connection, event, sizeof event); + client->pending_acknowledge = 1; + client->acknowledge_key = key; return 0; } @@ -687,6 +685,30 @@ wl_display_post_key_event(struct wl_display *display, wl_display_send_event(display, p, sizeof p); } +WL_EXPORT void +wl_display_post_acknowledge(struct wl_display *display) +{ + struct wl_client *client; + uint32_t event[3]; + + event[0] = display->base.id; + event[1] = WL_DISPLAY_ACKNOWLEDGE | ((sizeof event) << 16); + + client = container_of(display->client_list.next, + struct wl_client, link); + + while (&client->link != &display->client_list) { + if (client->pending_acknowledge) { + event[2] = client->acknowledge_key; + wl_connection_write(client->connection, + event, sizeof event); + client->pending_acknowledge = 0; + } + client = container_of(client->link.next, + struct wl_client, link); + } +} + void wl_display_set_compositor(struct wl_display *display, struct wl_compositor *compositor) diff --git a/wayland.h b/wayland.h index 061f4b2..ecc9de0 100644 --- a/wayland.h +++ b/wayland.h @@ -109,6 +109,8 @@ wl_display_post_button_event(struct wl_display *display, void wl_display_post_key_event(struct wl_display *display, struct wl_object *source, int key, int state); +void +wl_display_post_acknowledge(struct wl_display *display); struct wl_compositor { const struct wl_compositor_interface *interface; diff --git a/window.c b/window.c index d40e12a..fb9e28a 100644 --- a/window.c +++ b/window.c @@ -36,7 +36,6 @@ struct window { int state; uint32_t name; int fd; - int redraw_scheduled; int resized; cairo_pattern_t *background; @@ -155,12 +154,6 @@ draw_window(void *data) window->buffer->height, window->buffer->stride); - wl_surface_map(window->surface, - window->x - window->margin, - window->y - window->margin, - window->buffer->width, - window->buffer->height); - width = window->width - 20; height = window->height - 60; buffer = buffer_create(window->fd, width, height, (width * 4 + 15) & ~15); @@ -178,15 +171,54 @@ draw_window(void *data) if (window->gears == NULL) window->gears = gears_create(0, 0, 0, 0.92); + window->resized = 0; + + return FALSE; +} + + +static gboolean +animate_gears(gpointer data) +{ + struct window *window = data; + struct buffer *buffer; + static uint32_t key; + + /* Right now, resizing the window from the animation is fine, + * since the window drawing code is so slow, but once we + * implement faster resizing, this will show lag between + * pointer motion and window size even if resizing is fast. + * We need to keep processing motion events and posting new + * frames as fast as possible so when the server composites + * the next frame it will have the most recent size possible. + * In that case, we need the two ack protocol, where the first + * ack signals that the server got the request so we can free + * the buffer, to prevent us from allocating a ton of buffer + * that will never be displayed. */ + if (window->resized) + draw_window(window); + gears_draw(window->gears, window->gears_angle); + + buffer = window->egl_buffer; wl_surface_copy(window->surface, 10 + window->margin, 50 + window->margin, buffer->name, buffer->stride, 0, 0, buffer->width, buffer->height); - wl_display_commit(window->display, 0); + /* Shouldn't need to do this here, but without proper commit + * support in the server, doing this before rendering the + * gears show the window briefly before it's fully + * rendered. */ - window->redraw_scheduled = 0; + wl_surface_map(window->surface, + window->x - window->margin, + window->y - window->margin, + window->width + 2 * window->margin, + window->height + 2 * window->margin); + + wl_display_commit(window->display, key++); + window->gears_angle += 1; return FALSE; } @@ -221,22 +253,20 @@ event_handler(struct wl_display *display, /* FIXME: Object ID 1 is the display, for anything else we * assume it's an input device. */ if (object == 1 && opcode == 3) { - int key = p[0]; - /* The acknowledge event means that the server - * processed our last comit request and we can now - * safely free the buffer. key == 0 means it's an - * acknowledge event for the drawing in draw_buffer, - * key == 1 is from animating the gears, which we - * ignore. If the window was resized in the meantime, - * schedule another redraw. */ - if (key == 0) { - if (window->resized) - g_idle_add(draw_window, window); + * processed our last commit request and we can now + * safely free the buffer. */ + if (window->buffer != NULL) { buffer_destroy(window->buffer, window->fd); window->buffer = NULL; - window->resized = 0; } + + g_idle_add(animate_gears, window); + + } else if (object == 1) { + fprintf(stderr, "unexpected event from display: %d\n", + opcode); + exit(-1); } else if (opcode == 0) { int x = p[0], y = p[1]; @@ -251,6 +281,16 @@ event_handler(struct wl_display *display, window->y - window->margin, window->width + 2 * window->margin, window->height + 2 * window->margin); + /* FIXME: We should do this here: + * + * wl_display_commit(window->display, 1); + * + * to make sure the server processes the move, + * but that'll mess with the other commit from + * animate_gears with the current server + * implementation. Since the current server + * doesn't rely on commit anyway yet, we can + * just forget about it for now. */ break; case WINDOW_RESIZING_LOWER_RIGHT: window->width = window->drag_x + x; @@ -259,21 +299,7 @@ event_handler(struct wl_display *display, window->width = 400; if (window->height < 400) window->height = 400; - if (!window->redraw_scheduled) { - /* If window->buffer is NULL, it means - * we got the ack for the previous - * resize, so we can just schedule a - * redraw from idle. Otherwise, we're - * still expecting an ack and we'll - * notice that the size changed in the - * ack handler and schedule a redraw - * there. */ - if (window->buffer == NULL) - g_idle_add(draw_window, window); - else - window->resized = 1; - window->redraw_scheduled = 1; - } + window->resized = 1; break; } } else if (opcode == 1) { @@ -338,6 +364,7 @@ window_create(struct wl_display *display, int fd) window->state = WINDOW_STABLE; window->fd = fd; window->background = cairo_pattern_create_rgba (red, green, blue, alpha); + window->resized = 1; window->egl_display = eglCreateDisplayNative("/dev/dri/card0", "i965"); if (window->egl_display == NULL) @@ -354,33 +381,11 @@ window_create(struct wl_display *display, int fd) if (window->context == NULL) die("failed to create context\n"); - draw_window(window); + animate_gears(window); return window; } -static gboolean -draw(gpointer data) -{ - struct window *window = data; - struct buffer *buffer; - - if (!window->redraw_scheduled) { - gears_draw(window->gears, window->gears_angle); - - buffer = window->egl_buffer; - wl_surface_copy(window->surface, - 10 + window->margin, 50 + window->margin, - buffer->name, buffer->stride, - 0, 0, buffer->width, buffer->height); - wl_display_commit(window->display, 1); - } - - window->gears_angle += 1; - - return TRUE; -} - int main(int argc, char *argv[]) { struct wl_display *display; @@ -409,8 +414,6 @@ int main(int argc, char *argv[]) wl_display_set_event_handler(display, event_handler, window); - g_timeout_add(50, draw, window); - g_main_loop_run(loop); return 0; -- 2.7.4