diff --git a/clients/simple-egl.c b/clients/simple-egl.c index f2a1f77f..2ffbee2a 100644 --- a/clients/simple-egl.c +++ b/clients/simple-egl.c @@ -189,14 +189,6 @@ init_gl(struct window *window) glGetUniformLocation(window->gl.program, "rotation"); } -static void -sync_callback(void *data) -{ - int *done = data; - - *done = 1; -} - static void create_surface(struct window *window) { @@ -205,14 +197,11 @@ create_surface(struct window *window) EGLBoolean ret; int done = 0; + if (!display->premultiplied_argb_visual) + wl_display_roundtrip(display->display); if (!display->premultiplied_argb_visual) { - wl_display_sync_callback(display->display, sync_callback, &done); - while (!done) - wl_display_iterate(display->display, display->mask); - if (!display->premultiplied_argb_visual) { - fprintf(stderr, "premultiplied argb visual missing\n"); - exit(1); - } + fprintf(stderr, "premultiplied argb visual missing\n"); + exit(1); } window->surface = wl_compositor_create_surface(display->compositor); @@ -235,8 +224,10 @@ create_surface(struct window *window) assert(ret == EGL_TRUE); } +static const struct wl_callback_listener frame_listener; + static void -redraw(struct wl_surface *surface, void *data, uint32_t time) +redraw(void *data, struct wl_callback *callback, uint32_t time) { struct window *window = data; static const GLfloat verts[3][2] = { @@ -287,11 +278,17 @@ redraw(struct wl_surface *surface, void *data, uint32_t time) glFlush(); eglSwapBuffers(window->display->egl.dpy, window->egl_surface); - wl_display_frame_callback(window->display->display, - window->surface, - redraw, window); + if (callback) + wl_callback_destroy(callback); + + callback = wl_surface_frame(window->surface); + wl_callback_add_listener(callback, &frame_listener, window); } +static const struct wl_callback_listener frame_listener = { + redraw +}; + static void compositor_handle_visual(void *data, struct wl_compositor *compositor, @@ -356,12 +353,13 @@ main(int argc, char **argv) display_handle_global, &display); wl_display_get_fd(display.display, event_mask_update, &display); + wl_display_iterate(display.display, WL_DISPLAY_READABLE); init_egl(&display); create_surface(&window); init_gl(&window); - redraw(window.surface, &window, 0); + redraw(&window, NULL, 0); while (true) wl_display_iterate(display.display, display.mask); diff --git a/clients/simple-shm.c b/clients/simple-shm.c index 9e8a9784..7b45005e 100644 --- a/clients/simple-shm.c +++ b/clients/simple-shm.c @@ -112,8 +112,10 @@ create_window(struct display *display, int width, int height) return window; } +static const struct wl_callback_listener frame_listener; + static void -redraw(struct wl_surface *surface, void *data, uint32_t time) +redraw(void *data, struct wl_callback *callback, uint32_t time) { struct window *window = data; uint32_t *p; @@ -130,11 +132,17 @@ redraw(struct wl_surface *surface, void *data, uint32_t time) wl_surface_damage(window->surface, 0, 0, window->width, window->height); - wl_display_frame_callback(window->display->display, - window->surface, - redraw, window); + if (callback) + wl_callback_destroy(callback); + + callback = wl_surface_frame(window->surface); + wl_callback_add_listener(callback, &frame_listener, window); } +static const struct wl_callback_listener frame_listener = { + redraw +}; + static void compositor_handle_visual(void *data, struct wl_compositor *compositor, @@ -180,19 +188,10 @@ event_mask_update(uint32_t mask, void *data) return 0; } -static void -sync_callback(void *data) -{ - int *done = data; - - *done = 1; -} - static struct display * create_display(void) { struct display *display; - int done; display = malloc(sizeof *display); display->display = wl_display_connect(NULL); @@ -204,9 +203,8 @@ create_display(void) wl_display_get_fd(display->display, event_mask_update, display); - wl_display_sync_callback(display->display, sync_callback, &done); while (!display->xrgb_visual) - wl_display_iterate(display->display, display->mask); + wl_display_roundtrip(display->display); return display; } @@ -220,7 +218,7 @@ main(int argc, char **argv) display = create_display(); window = create_window(display, 250, 250); - redraw(window->surface, window, 0); + redraw(window, NULL, 0); while (true) wl_display_iterate(display->display, display->mask); diff --git a/clients/window.c b/clients/window.c index 5679f893..30a1179d 100644 --- a/clients/window.c +++ b/clients/window.c @@ -1887,25 +1887,6 @@ init_egl(struct display *d) return 0; } -static void -sync_callback(void *data) -{ - int *done = data; - - *done = 1; -} - -static void -force_roundtrip(struct display *d) -{ - int done = 0; - - wl_display_sync_callback(d->display, sync_callback, &done); - wl_display_iterate(d->display, WL_DISPLAY_WRITABLE); - while (!done) - wl_display_iterate(d->display, WL_DISPLAY_READABLE); -} - struct display * display_create(int *argc, char **argv[], const GOptionEntry *option_entries, display_global_handler_t handler) @@ -1966,7 +1947,7 @@ display_create(int *argc, char **argv[], const GOptionEntry *option_entries, d->destroy_image = (void *) eglGetProcAddress("eglDestroyImageKHR"); if (!d->premultiplied_argb_visual || !d->rgb_visual) { - force_roundtrip(d); + wl_display_roundtrip(d->display); if (!d->premultiplied_argb_visual || !d->rgb_visual) { fprintf(stderr, "failed to retreive visuals\n"); return NULL; diff --git a/compositor/compositor-wayland.c b/compositor/compositor-wayland.c index df63daf3..fad04aa9 100644 --- a/compositor/compositor-wayland.c +++ b/compositor/compositor-wayland.c @@ -157,14 +157,6 @@ wayland_compositor_init_egl(struct wayland_compositor *c) return 0; } -static void -frame_callback(struct wl_surface *surface, void *data, uint32_t time) -{ - struct wlsc_output *output = data; - - wlsc_output_finish_frame(output, time); -} - static int wayland_output_prepare_render(struct wlsc_output *output_base) { @@ -180,20 +172,32 @@ wayland_output_prepare_render(struct wlsc_output *output_base) return 0; } +static void +frame_done(void *data, struct wl_callback *wl_callback, uint32_t time) +{ + struct wlsc_output *output = data; + + wlsc_output_finish_frame(output, time); +} + +static const struct wl_callback_listener frame_listener = { + frame_done +}; + static int wayland_output_present(struct wlsc_output *output_base) { struct wayland_output *output = (struct wayland_output *) output_base; struct wayland_compositor *c = (struct wayland_compositor *) output->base.compositor; + struct wl_callback *callback; if (wayland_output_prepare_render(&output->base)) return -1; eglSwapBuffers(c->base.display, output->egl_surface); - wl_display_frame_callback(c->parent.display, - output->parent.surface, - frame_callback, &output->base); + callback = wl_surface_frame(output->parent.surface); + wl_callback_add_listener(callback, &frame_listener, output); return 0; } diff --git a/compositor/compositor.c b/compositor/compositor.c index bf312207..34bd3664 100644 --- a/compositor/compositor.c +++ b/compositor/compositor.c @@ -897,26 +897,31 @@ wlsc_output_repaint(struct wlsc_output *output) fade_output(output, ec->fade.spring.current, &total_damage); } +struct wlsc_frame_callback { + struct wl_resource resource; + struct wl_client *client; + struct wl_list link; +}; + static void repaint(void *data, int msecs) { struct wlsc_output *output = data; struct wlsc_compositor *compositor = output->compositor; - struct wlsc_surface *es; struct wlsc_animation *animation, *next; + struct wlsc_frame_callback *cb, *cnext; wlsc_output_repaint(output); output->repaint_needed = 0; output->repaint_scheduled = 1; output->present(output); - /* FIXME: Keep the surfaces in an per-output list. */ - wl_list_for_each(es, &compositor->surface_list, link) { - if (es->output == output) { - wl_display_post_frame(compositor->wl_display, - &es->surface, msecs); - } + wl_list_for_each_safe(cb, cnext, &output->frame_callback_list, link) { + wl_client_post_event(cb->client, &cb->resource.object, + WL_CALLBACK_DONE, msecs); + wl_resource_destroy(&cb->resource, cb->client, 0); } + wl_list_init(&output->frame_callback_list); wl_list_for_each_safe(animation, next, &compositor->animation_list, link) @@ -1052,10 +1057,39 @@ surface_damage(struct wl_client *client, wlsc_surface_damage_rectangle(es, x, y, width, height); } +static void +destroy_frame_callback(struct wl_resource *resource, struct wl_client *client) +{ + free(resource); +} + +static void +surface_frame(struct wl_client *client, + struct wl_surface *surface, uint32_t callback) +{ + struct wlsc_frame_callback *cb; + struct wlsc_surface *es = (struct wlsc_surface *) surface; + + cb = malloc(sizeof *cb); + if (cb == NULL) { + wl_client_post_no_memory(client); + return; + } + + cb->resource.object.interface = &wl_callback_interface; + cb->resource.object.id = callback; + cb->resource.destroy = destroy_frame_callback; + wl_list_insert(es->output->frame_callback_list.prev, &cb->link); + cb->client = client; + + wl_client_add_resource(client, &cb->resource); +} + const static struct wl_surface_interface surface_interface = { surface_destroy, surface_attach, - surface_damage + surface_damage, + surface_frame }; static void @@ -1820,6 +1854,7 @@ wlsc_output_init(struct wlsc_output *output, struct wlsc_compositor *c, output->scanout_buffer_destroy_listener.func = output_handle_scanout_buffer_destroy; wl_list_init(&output->scanout_buffer_destroy_listener.link); + wl_list_init(&output->frame_callback_list); output->object.interface = &wl_output_interface; wl_display_add_object(c->wl_display, &output->object); diff --git a/compositor/compositor.h b/compositor/compositor.h index db23c435..58964634 100644 --- a/compositor/compositor.h +++ b/compositor/compositor.h @@ -66,6 +66,7 @@ struct wlsc_output { struct wlsc_compositor *compositor; struct wlsc_surface *background; struct wlsc_matrix matrix; + struct wl_list frame_callback_list; int32_t x, y, mm_width, mm_height; pixman_region32_t region; pixman_region32_t previous_damage;