summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristian Høgsberg <krh@redhat.com>2008-11-26 12:57:31 -0500
committerKristian Høgsberg <krh@redhat.com>2008-11-26 12:57:31 -0500
commit44f36e3585cf7bb1ba8e73febabb7facf5cd6151 (patch)
tree5a9de67f6de5443613b1d380dd9bd3d6fced2461
parentf3723fe79e7bafcd663160ee8f7798faf9a2c2f9 (diff)
Make ack event signal that the requests have been composited.
-rw-r--r--egl-compositor.c2
-rw-r--r--flower.c22
-rw-r--r--wayland.c34
-rw-r--r--wayland.h2
-rw-r--r--window.c125
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;