Make ack event signal that the requests have been composited.
authorKristian Høgsberg <krh@redhat.com>
Wed, 26 Nov 2008 17:57:31 +0000 (12:57 -0500)
committerKristian Høgsberg <krh@redhat.com>
Wed, 26 Nov 2008 17:57:31 +0000 (12:57 -0500)
egl-compositor.c
flower.c
wayland.c
wayland.h
window.c

index 57b56ce..132fcbd 100644 (file)
@@ -541,6 +541,8 @@ repaint(void *data)
 
        eglSwapBuffers(ec->display, ec->surface);
 
+       wl_display_post_acknowledge(ec->wl_display);
+
        animate_overlay(ec);
 }
 
index e6c2e27..3356fc4 100644 (file)
--- 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);
 
index 766dc0a..c33d135 100644 (file)
--- 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)
index 061f4b2..ecc9de0 100644 (file)
--- 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;
index d40e12a..fb9e28a 100644 (file)
--- 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;